Skip to content

Optimize Argon2 on the Web/JS platform#36

Merged
dipu-bd merged 1 commit into
masterfrom
claude/todo-comments-audit-piylwg
Jul 9, 2026
Merged

Optimize Argon2 on the Web/JS platform#36
dipu-bd merged 1 commit into
masterfrom
claude/todo-comments-audit-piylwg

Conversation

@dipu-bd

@dipu-bd dipu-bd commented Jul 9, 2026

Copy link
Copy Markdown
Member

Summary

Optimizes the Web/JS (Node/browser) implementation of Argon2 by removing BigInt from the compression function's hot path. This resolves the long-standing - Support for Argon2 in Node platform (TODO: requires optimization) note in CHANGELOG.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 native Uint64List arithmetic, but JS has no 64-bit integers, so the web twin _fBlaMka in lib/src/algorithms/argon2/argon2_32bit.dart implemented it with heap-allocating BigInt. _fBlaMka is called 4× per _mix, 8 _mix per mixer, 16 mixers per block, over thousands of blocks — so BigInt allocation and arbitrary-precision math sat on the single hottest line of the whole KDF.

Change

Replace the BigInt-based _fBlaMka with pure 32-bit integer math:

  • a full 32×32→64 low-word product built from 16-bit limbs, and
  • carry-based addition of the (low, high) pairs,

with every intermediate kept below 2^53 so results stay exact on IEEE-754 doubles. This mirrors the BigInt-free pattern the sibling blake2b_32bit.dart already uses (_add2/_add3 carry 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 . — clean
  • dart analyze --fatal-infos — zero infos
  • dart test -p vm — 736 passed
  • dart test -p node — 601 passed

Performance

Measured on the compiled JS build under Node, argon2id at Argon2Security.moderate, averaged over 10 rounds:

ms/op
Before (BigInt) 13,738.90
After (32-bit math) 882.80

15.6× faster on the web platform. The VM path (argon2_64bit.dart) is unchanged.

Notes

  • Bumps version to 2.4.3 and adds the matching CHANGELOG.md entry.
  • BENCHMARK.md is intentionally untouched (regenerated only on the maintainer's reference hardware).

🤖 Generated by Claude Code

…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
@dipu-bd dipu-bd merged commit 205d0f4 into master Jul 9, 2026
0 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants