From bd2b02829296f4717700f9d52cb019e8fe8050ef Mon Sep 17 00:00:00 2001 From: Chris Duncan Date: Sun, 3 Aug 2025 00:22:34 -0700 Subject: [PATCH] Use set to copy buffer values more efficiently than setting up many for loops. Remove redundant crypto_hash and call blake directly. --- src/lib/nano-nacl.ts | 98 ++++++++++++-------------------------------- 1 file changed, 27 insertions(+), 71 deletions(-) diff --git a/src/lib/nano-nacl.ts b/src/lib/nano-nacl.ts index 09f0be1..51efcb4 100644 --- a/src/lib/nano-nacl.ts +++ b/src/lib/nano-nacl.ts @@ -78,9 +78,7 @@ export class NanoNaCl { let b: number const m: Float64Array = this.gf() const t: Float64Array = this.gf() - for (let i = 0; i < 16; i++) { - t[i] = n[i] - } + t.set(n.slice(0, 16), 0) this.car25519(t) this.car25519(t) this.car25519(t) @@ -135,7 +133,8 @@ export class NanoNaCl { } static M (o: Float64Array, a: Float64Array, b: Float64Array): void { - let v, c, s = 1 << 16, t = new Array(31) + let v, c, s = 1 << 16 + const t = new Array(31) t.fill(0) // init t values @@ -169,9 +168,7 @@ export class NanoNaCl { t[0] += 38 * (c - 1) // assign result to output - for (let i = 0; i < 16; i++) { - o[i] = t[i] - } + o.set(t.slice(0, 16), 0) } static S (o: Float64Array, a: Float64Array): void { @@ -180,39 +177,26 @@ export class NanoNaCl { static inv25519 (o: Float64Array, i: Float64Array): void { const c: Float64Array = new Float64Array(16) - for (let a = 0; a < 16; a++) { - c[a] = i[a] - } + c.set(i.slice(0, 16), 0) for (let a = 253; a >= 0; a--) { this.S(c, c) - if (a !== 2 && a !== 4) this.M(c, c, i) - } - for (let a = 0; a < 16; a++) { - o[a] = c[a] + if (a !== 2 && a !== 4) { + this.M(c, c, i) + } } + o.set(c, 0) } static pow2523 (o: Float64Array, i: Float64Array): void { const c: Float64Array = this.gf() - for (let a = 0; a < 16; a++) { - c[a] = i[a] - } + c.set(i.slice(0, 16), 0) for (let a = 250; a >= 0; a--) { this.S(c, c) - if (a !== 1) this.M(c, c, i) - } - for (let a = 0; a < 16; a++) { - o[a] = c[a] - } - } - - // Note: difference from TweetNaCl - BLAKE2b used to hash instead of SHA-512. - static crypto_hash (out: Uint8Array, m: Uint8Array): number { - const hash = new Blake2b(64).update(m).digest() - for (let i = 0; i < 64; ++i) { - out[i] = hash[i] + if (a !== 1) { + this.M(c, c, i) + } } - return 0 + o.set(c, 0) } static add (p: Float64Array[], q: Float64Array[]): void { @@ -323,18 +307,13 @@ export class NanoNaCl { static reduce (r: Uint8Array): void { let x = new Float64Array(64) - for (let i = 0; i < 64; i++) { - x[i] = r[i] - } - for (let i = 0; i < 64; i++) { - r[i] = 0 - } + x.set(r.slice(0, 64), 0) + r.fill(0, 0, 64) this.modL(r, x) } // Note: difference from C - smlen returned, not passed as argument. static crypto_sign (sm: Uint8Array, m: Uint8Array, n: number, sk: Uint8Array, pk: Uint8Array): number { - const x = new Float64Array(64) const p: Float64Array[] = [this.gf(), this.gf(), this.gf(), this.gf()] const d = new Blake2b(64).update(sk).digest() @@ -343,30 +322,20 @@ export class NanoNaCl { d[31] |= 64 const smlen = n + 64 - for (let i = 0; i < n; i++) { - sm[64 + i] = m[i] - } - for (let i = 0; i < 32; i++) { - sm[32 + i] = d[32 + i] - } + sm.set(m.subarray(0, n), 64) + sm.set(d.subarray(32, 64), 32) const r = new Blake2b(64).update(sm.subarray(32)).digest() this.reduce(r) this.scalarbase(p, r) this.pack(sm, p) - for (let i = 0; i < 32; i++) { - sm[i + 32] = pk[i] - } + sm.set(pk, 32) const h = new Blake2b(64).update(sm).digest() this.reduce(h) - for (let i = 0; i < 64; i++) { - x[i] = 0 - } - for (let i = 0; i < 32; i++) { - x[i] = r[i] - } + const x = new Float64Array(64) + x.set(r.subarray(0, 32)) for (let i = 0; i < 32; i++) { for (let j = 0; j < 32; j++) { x[i + j] += h[i] * d[j] @@ -428,12 +397,8 @@ export class NanoNaCl { if (this.unpackneg(q, pk)) return -1 - for (let i = 0; i < n; i++) { - m[i] = sm[i] - } - for (let i = 0; i < 32; i++) { - m[i + 32] = pk[i] - } + m.set(sm.slice(0, n), 0) + m.set(pk.slice(0, 32), 32) const h = new Blake2b(64).update(m).digest() this.reduce(h) this.scalarmult(p, q, h) @@ -444,15 +409,10 @@ export class NanoNaCl { n -= 64 if (this.crypto_verify_32(sm, 0, t, 0)) { - for (let i = 0; i < n; i++) { - m[i] = 0 - } + m.fill(0, 0, n) return -1 } - - for (let i = 0; i < n; i++) { - m[i] = sm[i + 64] - } + m.set(sm.slice(64, n + 64), 0) return n } @@ -611,12 +571,8 @@ export class NanoNaCl { } const sm = new Uint8Array(this.crypto_sign_BYTES + msg.length) const m = new Uint8Array(this.crypto_sign_BYTES + msg.length) - for (let i = 0; i < this.crypto_sign_BYTES; i++) { - sm[i] = sig[i] - } - for (let i = 0; i < msg.length; i++) { - sm[i + this.crypto_sign_BYTES] = msg[i] - } + sm.set(sig, 0) + sm.set(msg, this.crypto_sign_BYTES) return (this.crypto_sign_open(m, sm, sm.length, pub) >= 0) } catch (err) { throw new Error('Failed to sign and return signature', { cause: err }) -- 2.47.3