Optimize Argon2 on the Web/JS platform#36
Merged
Conversation
…nction Replace the `BigInt`-based `_fBlaMka` in the Web/JS Argon2 implementation with 32-bit integer math: a 16-bit-limb multiply and carry-based addition, keeping every intermediate below 2^53 so results stay exact on the web. Output is byte-identical to the previous implementation (verified against the cited Argon2 vectors on node) and roughly 15x faster on the JS platform. Claude-Session: https://claude.ai/code/session_017eisc4WSZNcgCUna825rS8
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Optimizes the Web/JS (Node/browser) implementation of Argon2 by removing
BigIntfrom the compression function's hot path. This resolves the long-standing- Support for Argon2 in Node platform (TODO: requires optimization)note inCHANGELOG.md.Problem
Argon2's hottest operation is the BLaMka G-function's 64-bit fused multiply-add,
z = x + y + 2 * (lo32(x) * lo32(y)). On the VM this runs in nativeUint64Listarithmetic, but JS has no 64-bit integers, so the web twin_fBlaMkainlib/src/algorithms/argon2/argon2_32bit.dartimplemented it with heap-allocatingBigInt._fBlaMkais called 4× per_mix, 8_mixper mixer, 16 mixers per block, over thousands of blocks — soBigIntallocation and arbitrary-precision math sat on the single hottest line of the whole KDF.Change
Replace the
BigInt-based_fBlaMkawith pure 32-bit integer math:(low, high)pairs,with every intermediate kept below
2^53so results stay exact on IEEE-754 doubles. This mirrors theBigInt-free pattern the siblingblake2b_32bit.dartalready uses (_add2/_add3carry idiom). No public API, signature, or exported symbol changes — it is an internal swap behind the existing conditional import.Correctness
Output is byte-identical to the previous implementation. The Argon2 known-answer vectors (
test/argon2_test.dart, sourced from argon2.online, argon2i/d/id at m=16 and m=256) are not vm-only, so they exercise the JS path directly — all pass, which is the proof a carry bug would break.dart format --output=none --set-exit-if-changed .— cleandart analyze --fatal-infos— zero infosdart test -p vm— 736 passeddart test -p node— 601 passedPerformance
Measured on the compiled JS build under Node,
argon2idatArgon2Security.moderate, averaged over 10 rounds:BigInt)≈ 15.6× faster on the web platform. The VM path (
argon2_64bit.dart) is unchanged.Notes
versionto2.4.3and adds the matchingCHANGELOG.mdentry.BENCHMARK.mdis intentionally untouched (regenerated only on the maintainer's reference hardware).🤖 Generated by Claude Code