diff --git a/CHANGELOG.md b/CHANGELOG.md index f02f3be..7bad628 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 2.4.3 + +- Optimize Argon2 on the Web/JS platform by replacing `BigInt` arithmetic in the compression function with 32-bit integer math + # 2.4.2 - Bump `convertlib` to `^3.5.1` diff --git a/lib/src/algorithms/argon2/argon2_32bit.dart b/lib/src/algorithms/argon2/argon2_32bit.dart index 4a197b9..dac272e 100644 --- a/lib/src/algorithms/argon2/argon2_32bit.dart +++ b/lib/src/algorithms/argon2/argon2_32bit.dart @@ -421,13 +421,36 @@ class Argon2Internal { } /// `v[x] += v[y] + 2 * ((v[x] & _mask32) * (v[y] & _mask32))` + /// + /// The 64-bit words are stored as (low, high) 32-bit pairs. To stay correct + /// on the web where integers are IEEE-754 doubles, the low-word product is + /// built from 16-bit limbs and every carry is propagated with `~/`/`%` by + /// `2^32`; all intermediate values remain below `2^53`, so no precision is + /// lost and no `BigInt` allocation is needed. static void _fBlaMka(Uint32List v, int x, int y) { - var t = (BigInt.from(v[x]) * BigInt.from(v[y])) << 1; - t += (BigInt.from(v[x + 1]) << 32) + BigInt.from(v[x]); - t += (BigInt.from(v[y + 1]) << 32) + BigInt.from(v[y]); - - v[x] = t.toUnsigned(32).toInt(); - v[x + 1] = (t >> 32).toUnsigned(32).toInt(); + int xl = v[x], xh = v[x + 1]; + int yl = v[y], yh = v[y + 1]; + + // Full 32x32 -> 64 product of the low words via 16-bit limbs. + int a0 = xl & _mask16, a1 = xl >>> 16; + int b0 = yl & _mask16, b1 = yl >>> 16; + int m0 = a0 * b0; + int m1 = a0 * b1 + a1 * b0; + int m2 = a1 * b1; + int lo = m0 + (m1 % 0x10000) * 0x10000; + int pLo = lo % 0x100000000; + int pHi = m2 + m1 ~/ 0x10000 + lo ~/ 0x100000000; + + // Double the product: 2 * p (mod 2^64). + int dLo = pLo * 2; + int dHi = pHi * 2 + dLo ~/ 0x100000000; + dLo %= 0x100000000; + + // v[x] = (xl,xh) + (yl,yh) + (dLo,dHi) (mod 2^64). + int sumLo = xl + yl + dLo; + int sumHi = xh + yh + dHi + sumLo ~/ 0x100000000; + v[x] = sumLo; // Uint32List store truncates to the low 32 bits + v[x + 1] = sumHi; } // v[k] = (v[i] << (64 - n)) | (v[i] >>> n) diff --git a/pubspec.yaml b/pubspec.yaml index a08966d..08aa35d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: hashlib description: Secure hash functions, checksum generators, and key derivation algorithms optimized for Dart. homepage: https://github.com/bitanon/hashlib -version: 2.4.2 +version: 2.4.3 environment: sdk: '>=2.19.0 <4.0.0'