From 8b672a33ab6dc061c7981cb6e52b11744c90b73d Mon Sep 17 00:00:00 2001 From: Chris Duncan Date: Sun, 17 Aug 2025 00:36:47 -0700 Subject: [PATCH] Revert nacl to floats now that I understand the algorithm a little better. --- src/lib/crypto/nano-nacl.ts | 253 ++++++++++++++++++------------------ 1 file changed, 125 insertions(+), 128 deletions(-) diff --git a/src/lib/crypto/nano-nacl.ts b/src/lib/crypto/nano-nacl.ts index 04c17f9..0649861 100644 --- a/src/lib/crypto/nano-nacl.ts +++ b/src/lib/crypto/nano-nacl.ts @@ -19,12 +19,12 @@ export class NanoNaCl { static crypto_sign_PUBLICKEYBYTES: 32 = 32 static crypto_sign_PRIVATEKEYBYTES: 32 = 32 static crypto_sign_SEEDBYTES: 32 = 32 - static D: BigInt64Array = new BigInt64Array([0x78a3n, 0x1359n, 0x4dcan, 0x75ebn, 0xd8abn, 0x4141n, 0x0a4dn, 0x0070n, 0xe898n, 0x7779n, 0x4079n, 0x8cc7n, 0xfe73n, 0x2b6fn, 0x6ceen, 0x5203n]) - static D2: BigInt64Array = new BigInt64Array([0xf159n, 0x26b2n, 0x9b94n, 0xebd6n, 0xb156n, 0x8283n, 0x149an, 0x00e0n, 0xd130n, 0xeef3n, 0x80f2n, 0x198en, 0xfce7n, 0x56dfn, 0xd9dcn, 0x2406n]) - static X: BigInt64Array = new BigInt64Array([0xd51an, 0x8f25n, 0x2d60n, 0xc956n, 0xa7b2n, 0x9525n, 0xc760n, 0x692cn, 0xdc5cn, 0xfdd6n, 0xe231n, 0xc0a4n, 0x53fen, 0xcd6en, 0x36d3n, 0x2169n]) - static Y: BigInt64Array = new BigInt64Array([0x6658n, 0x6666n, 0x6666n, 0x6666n, 0x6666n, 0x6666n, 0x6666n, 0x6666n, 0x6666n, 0x6666n, 0x6666n, 0x6666n, 0x6666n, 0x6666n, 0x6666n, 0x6666n]) - static I: BigInt64Array = new BigInt64Array([0xa0b0n, 0x4a0en, 0x1b27n, 0xc4een, 0xe478n, 0xad2fn, 0x1806n, 0x2f43n, 0xd7a7n, 0x3dfbn, 0x0099n, 0x2b4dn, 0xdf0bn, 0x4fc1n, 0x2480n, 0x2b83n]) - static XY: BigInt64Array = new BigInt64Array([0xdd90n, 0xa5b7n, 0x8ab3n, 0x6dden, 0x52f5n, 0x7751n, 0x9f80n, 0x20f0n, 0xe37dn, 0x64abn, 0x4e8en, 0x66ean, 0x7665n, 0xd78bn, 0x5f0fn, 0xe787n]) + static D: Float64Array = new Float64Array([0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203]) + static D2: Float64Array = new Float64Array([0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406]) + static X: Float64Array = new Float64Array([0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169]) + static Y: Float64Array = new Float64Array([0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666]) + static I: Float64Array = new Float64Array([0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83]) + static XY: Float64Array = new Float64Array([0xdd90, 0xa5b7, 0x8ab3, 0x6dde, 0x52f5, 0x7751, 0x9f80, 0x20f0, 0xe37d, 0x64ab, 0x4e8e, 0x66ea, 0x7665, 0xd78b, 0x5f0f, 0xe787]) static #vn (x: Uint8Array, xi: number, y: Uint8Array, yi: number, n: number): number { let d: number = 0 @@ -34,8 +34,8 @@ export class NanoNaCl { return (1 & ((d - 1) >>> 8)) - 1 } - static pow2523 (out: BigInt64Array, i: BigInt64Array): void { - const c: BigInt64Array = new BigInt64Array(16) + static pow2523 (out: Float64Array, i: Float64Array): void { + const c: Float64Array = new Float64Array(16) c.set(i.subarray(0, 16), 0) for (let a = 0; a < 249; a++) { this.Square(c, c) @@ -47,20 +47,20 @@ export class NanoNaCl { out.set(c, 0) } - static car25519 (out: BigInt64Array): void { - let v: bigint, c: bigint - const s: bigint = 1n << 16n - c = 0n + static car25519 (out: Float64Array): void { + let v, c + const s = 1 << 16 + c = 0 for (let i = 0; i < 16; i++) { v = out[i] + c + s out[i] = v % s - c = v / s - 1n + c = (v / s - 1) | 0 } - out[0] += 38n * c + out[0] += 38 * c } - static inv25519 (out: BigInt64Array, i: BigInt64Array): void { - const c: BigInt64Array = new BigInt64Array(16) + static inv25519 (out: Float64Array, i: Float64Array): void { + const c: Float64Array = new Float64Array(16) c.set(i.subarray(0, 16), 0) for (let a = 253; a >= 0; a--) { this.Square(c, c) @@ -71,7 +71,7 @@ export class NanoNaCl { out.set(c, 0) } - static neq25519 (a: BigInt64Array, b: BigInt64Array): number { + static neq25519 (a: Float64Array, b: Float64Array): number { const c: Uint8Array = new Uint8Array(32) const d: Uint8Array = new Uint8Array(32) this.pack25519(c, a) @@ -79,40 +79,40 @@ export class NanoNaCl { return this.#vn(c, 0, d, 0, 32) } - static pack25519 (out: Uint8Array, n: BigInt64Array): void { - let b: bigint - const m: BigInt64Array = new BigInt64Array(16) - const t: BigInt64Array = new BigInt64Array(16) + static pack25519 (out: Uint8Array, n: Float64Array): void { + let b: number + const m: Float64Array = new Float64Array(16) + const t: Float64Array = new Float64Array(16) t.set(n.subarray(0, 16), 0) this.car25519(t) this.car25519(t) this.car25519(t) for (let j = 0; j < 2; j++) { - m[0] = t[0] - 0xffedn + m[0] = t[0] - 0xffed for (let i = 1; i < 15; i++) { - m[i] = t[i] - 0xffffn - ((m[i - 1] >> 16n) & 1n) - m[i - 1] &= 0xffffn + m[i] = t[i] - 0xffff - ((m[i - 1] >> 16) & 1) + m[i - 1] &= 0xffff } - m[15] = t[15] - 0x7fffn - ((m[14] >> 16n) & 1n) - b = (m[15] >> 16n) & 1n - m[14] &= 0xffffn - this.sel25519(t, m, 1n - b) + m[15] = t[15] - 0x7fff - ((m[14] >> 16) & 1) + b = (m[15] >> 16) & 1 + m[14] &= 0xffff + this.sel25519(t, m, 1 - b) } for (let i = 0; i < 16; i++) { - out[2 * i] = Number(t[i] & 0xffn) - out[2 * i + 1] = Number(t[i] >> 8n) + out[2 * i] = t[i] & 0xff + out[2 * i + 1] = t[i] >> 8 } } - static par25519 (a: BigInt64Array): number { + static par25519 (a: Float64Array): number { const d: Uint8Array = new Uint8Array(32) this.pack25519(d, a) return d[0] & 1 } - static sel25519 (p: BigInt64Array, q: BigInt64Array, b: bigint): void { - let t: bigint - const c: bigint = ~(b - 1n) + static sel25519 (p: Float64Array, q: Float64Array, b: number): void { + let t + const c = ~(b - 1) for (let i = 0; i < 16; i++) { t = c & (p[i] ^ q[i]) p[i] ^= t @@ -120,30 +120,30 @@ export class NanoNaCl { } } - static unpack25519 (out: BigInt64Array, n: Uint8Array): void { + static unpack25519 (out: Float64Array, n: Uint8Array): void { for (let i = 0; i < 16; i++) { - out[i] = BigInt(n[2 * i]) + (BigInt(n[2 * i + 1]) << 8n) + out[i] = n[2 * i] + (n[2 * i + 1] << 8) } - out[15] &= (1n << 15n) - 1n + out[15] &= (1 << 15) - 1 } - static Add (out: BigInt64Array, a: BigInt64Array, b: BigInt64Array): void { + static Add (out: Float64Array, a: Float64Array, b: Float64Array): void { for (let i = 0; i < 16; i++) { out[i] = a[i] + b[i] } } - static Subtract (out: BigInt64Array, a: BigInt64Array, b: BigInt64Array): void { + static Subtract (out: Float64Array, a: Float64Array, b: Float64Array): void { for (let i = 0; i < 16; i++) { out[i] = a[i] - b[i] } } - static Multiply (out: BigInt64Array, a: BigInt64Array, b: BigInt64Array): void { - let v: bigint, c: bigint - const s: bigint = 1n << 16n - const t: BigInt64Array = new BigInt64Array(31) - t.fill(0n) + static Multiply (out: Float64Array, a: Float64Array, b: Float64Array): void { + let v, c + const s = 1 << 16 + const t = new Float64Array(31) + t.fill(0) // init t values for (let i = 0; i < 16; i++) { @@ -153,83 +153,83 @@ export class NanoNaCl { } for (let i = 0; i < 15; i++) { - t[i] += 38n * t[i + 16] + t[i] += 38 * t[i + 16] } // t15 left as is // first carry - c = 0n + c = 0 for (let i = 0; i < 16; i++) { v = t[i] + c t[i] = v % s - c = v / s + c = (v / s) | 0 } - t[0] += 38n * c + t[0] += 38 * c // second carry - c = 0n + c = 0 for (let i = 0; i < 16; i++) { v = t[i] + c t[i] = v % s - c = v / s + c = (v / s) | 0 } - t[0] += 38n * c + t[0] += 38 * c // assign result to output out.set(t.slice(0, 16), 0) } - static Square (out: BigInt64Array, a: BigInt64Array): void { - let v: bigint, c: bigint - const s: bigint = 1n << 16n - const t: BigInt64Array = new BigInt64Array(31) - t.fill(0n) + static Square (out: Float64Array, a: Float64Array): void { + let v, c + const s = 1 << 16 + const t = new Float64Array(31) + t.fill(0) // init t values, same as Multiply except we can skip some iterations of // the inner loop since a[x]*a[y] + a[y]*a[x] = 2*a[x]*a[y] for (let i = 0; i < 16; i++) { for (let j = i; j < 16; j++) { - t[i + j] += a[i] * a[j] * (i < j ? 2n : 1n) + t[i + j] += a[i] * a[j] * (i < j ? 2 : 1) } } for (let i = 0; i < 15; i++) { - t[i] += 38n * t[i + 16] + t[i] += 38 * t[i + 16] } // t15 left as is // first carry - c = 0n + c = 0 for (let i = 0; i < 16; i++) { v = t[i] + c t[i] = v % s - c = v / s + c = (v / s) | 0 } - t[0] += 38n * c + t[0] += 38 * c // second carry - c = 0n + c = 0 for (let i = 0; i < 16; i++) { v = t[i] + c t[i] = v % s - c = v / s + c = (v / s) | 0 } - t[0] += 38n * c + t[0] += 38 * c // assign result to output out.set(t.slice(0, 16), 0) } - static add (p: BigInt64Array[], q: BigInt64Array[]): void { - const a: BigInt64Array = new BigInt64Array(16) - const b: BigInt64Array = new BigInt64Array(16) - const c: BigInt64Array = new BigInt64Array(16) - const d: BigInt64Array = new BigInt64Array(16) - const e: BigInt64Array = new BigInt64Array(16) - const f: BigInt64Array = new BigInt64Array(16) - const g: BigInt64Array = new BigInt64Array(16) - const h: BigInt64Array = new BigInt64Array(16) - const t: BigInt64Array = new BigInt64Array(16) + static add (p: Float64Array[], q: Float64Array[]): void { + const a: Float64Array = new Float64Array(16) + const b: Float64Array = new Float64Array(16) + const c: Float64Array = new Float64Array(16) + const d: Float64Array = new Float64Array(16) + const e: Float64Array = new Float64Array(16) + const f: Float64Array = new Float64Array(16) + const g: Float64Array = new Float64Array(16) + const h: Float64Array = new Float64Array(16) + const t: Float64Array = new Float64Array(16) this.Subtract(a, p[1], p[0]) this.Subtract(t, q[1], q[0]) @@ -252,16 +252,16 @@ export class NanoNaCl { this.Multiply(p[3], e, h) } - static cswap (p: BigInt64Array[], q: BigInt64Array[], b: bigint): void { + static cswap (p: Float64Array[], q: Float64Array[], b: number): void { for (let i = 0; i < 4; i++) { this.sel25519(p[i], q[i], b) } } - static pack (r: Uint8Array, p: BigInt64Array[]): void { - const tx: BigInt64Array = new BigInt64Array(16) - const ty: BigInt64Array = new BigInt64Array(16) - const zi: BigInt64Array = new BigInt64Array(16) + static pack (r: Uint8Array, p: Float64Array[]): void { + const tx: Float64Array = new Float64Array(16) + const ty: Float64Array = new Float64Array(16) + const zi: Float64Array = new Float64Array(16) this.inv25519(zi, p[2]) this.Multiply(tx, p[0], zi) this.Multiply(ty, p[1], zi) @@ -269,14 +269,13 @@ export class NanoNaCl { r[31] ^= this.par25519(tx) << 7 } - static scalarmult (p: BigInt64Array[], q: BigInt64Array[], s: Uint8Array): void { - let b: bigint - p[0].fill(0n) - p[1].fill(0n).set([1n], 0) - p[2].fill(0n).set([1n], 0) - p[3].fill(0n) + static scalarmult (p: Float64Array[], q: Float64Array[], s: Uint8Array): void { + p[0].fill(0) + p[1].fill(0).set([1], 0) + p[2].fill(0).set([1], 0) + p[3].fill(0) for (let i = 255; i >= 0; --i) { - b = (BigInt(s[(i / 8) | 0]) >> (BigInt(i) & 7n)) & 1n + const b = (s[(i / 8) | 0] >> (i & 7)) & 1 this.cswap(p, q, b) this.add(q, p) this.add(p, p) @@ -284,69 +283,67 @@ export class NanoNaCl { } } - static scalarbase (p: BigInt64Array[], s: Uint8Array): void { - const q: BigInt64Array[] = [new BigInt64Array(16), new BigInt64Array(16), new BigInt64Array(16), new BigInt64Array(16)] + static scalarbase (p: Float64Array[], s: Uint8Array): void { + const q: Float64Array[] = [new Float64Array(16), new Float64Array(16), new Float64Array(16), new Float64Array(16)] q[0].set(this.X, 0) q[1].set(this.Y, 0) - q[2].set([1n], 0) + q[2].set([1], 0) q[3].set(this.XY, 0) this.scalarmult(p, q, s) } - static L = new BigInt64Array([ - 0xedn, 0xd3n, 0xf5n, 0x5cn, 0x1an, 0x63n, 0x12n, 0x58n, - 0xd6n, 0x9cn, 0xf7n, 0xa2n, 0xden, 0xf9n, 0xden, 0x14n, - 0x00n, 0x00n, 0x00n, 0x00n, 0x00n, 0x00n, 0x00n, 0x00n, - 0x00n, 0x00n, 0x00n, 0x00n, 0x00n, 0x00n, 0x00n, 0x10n + static L = new Float64Array([ + 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, + 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 ]) - static modL (r: Uint8Array, x: BigInt64Array): void { - let c: bigint, t: bigint, v: bigint + static modL (r: Uint8Array, x: Float64Array): void { + let c, t, v for (let i = 63; i >= 32; --i) { - c = 0n + c = 0 for (let j = i - 32, k = i - 12; j < k; j++) { - t = 16n * x[i] * this.L[j - (i - 32)] + t = 16 * x[i] * this.L[j - (i - 32)] v = x[j] + c - t - c = (v + 128n) / 256n - x[j] = v - (c * 256n) + c = ((v + 128) / 256) | 0 + x[j] = v - (c * 256) } x[i - 12] += c - x[i] = 0n + x[i] = 0 } - c = 0n + c = 0 for (let j = 0; j < 32; j++) { - x[j] += c - (x[31] >> 4n) * this.L[j] - c = x[j] >> 8n - x[j] &= 255n + x[j] += c - (x[31] >> 4) * this.L[j] + c = x[j] >> 8 + x[j] &= 255 } for (let j = 0; j < 32; j++) { x[j] -= c * this.L[j] } for (let i = 0; i < 32; i++) { - x[i + 1] += x[i] >> 8n - r[i] = Number(x[i] & 255n) + x[i + 1] += x[i] >> 8 + r[i] = x[i] & 255 } } static reduce (r: Uint8Array): void { - const x: BigInt64Array = new BigInt64Array(64) - for (let i = 0; i < 64; i++) { - x[i] = BigInt(r[i]) - } + let x = new Float64Array(64) + x.set(r, 0) r.fill(0) this.modL(r, x) } - static unpackneg (r: BigInt64Array[], p: Uint8Array): -1 | 0 { - const t: BigInt64Array = new BigInt64Array(16) - const chk: BigInt64Array = new BigInt64Array(16) - const num: BigInt64Array = new BigInt64Array(16) - const den: BigInt64Array = new BigInt64Array(16) - const den2: BigInt64Array = new BigInt64Array(16) - const den4: BigInt64Array = new BigInt64Array(16) - const den6: BigInt64Array = new BigInt64Array(16) + static unpackneg (r: Float64Array[], p: Uint8Array): -1 | 0 { + const t: Float64Array = new Float64Array(16) + const chk: Float64Array = new Float64Array(16) + const num: Float64Array = new Float64Array(16) + const den: Float64Array = new Float64Array(16) + const den2: Float64Array = new Float64Array(16) + const den4: Float64Array = new Float64Array(16) + const den6: Float64Array = new Float64Array(16) - r[2].fill(0n).set([1n], 0) + r[2].fill(0).set([1], 0) this.unpack25519(r[1], p) this.Square(num, r[1]) this.Multiply(den, num, this.D) @@ -375,14 +372,14 @@ export class NanoNaCl { if (this.neq25519(chk, num)) return -1 if (this.par25519(r[0]) === (p[31] >> 7)) { - this.Subtract(r[0], new BigInt64Array(16), r[0]) + this.Subtract(r[0], new Float64Array(16), r[0]) } this.Multiply(r[3], r[0], r[1]) return 0 } static crypto_sign (sm: Uint8Array, m: Uint8Array, n: number, sk: Uint8Array, pk: Uint8Array): void { - const p: BigInt64Array[] = [new BigInt64Array(16), new BigInt64Array(16), new BigInt64Array(16), new BigInt64Array(16)] + const p: Float64Array[] = [new Float64Array(16), new Float64Array(16), new Float64Array(16), new Float64Array(16)] const d = new Blake2b(64).update(sk).digest() d[0] &= 248 @@ -401,11 +398,11 @@ export class NanoNaCl { const h = new Blake2b(64).update(sm).digest() this.reduce(h) - const x = new BigInt64Array(64) - for (let i = 0; i < 32; i++) x[i] = BigInt(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] += BigInt(h[i]) * BigInt(d[j]) + x[i + j] += h[i] * d[j] } } @@ -414,8 +411,8 @@ export class NanoNaCl { static crypto_sign_open (m: Uint8Array, sm: Uint8Array, n: number, pk: Uint8Array): number { const t = new Uint8Array(32) - const p: BigInt64Array[] = [new BigInt64Array(16), new BigInt64Array(16), new BigInt64Array(16), new BigInt64Array(16)] - const q: BigInt64Array[] = [new BigInt64Array(16), new BigInt64Array(16), new BigInt64Array(16), new BigInt64Array(16)] + const p: Float64Array[] = [new Float64Array(16), new Float64Array(16), new Float64Array(16), new Float64Array(16)] + const q: Float64Array[] = [new Float64Array(16), new Float64Array(16), new Float64Array(16), new Float64Array(16)] if (n < 64) return -1 @@ -475,7 +472,7 @@ export class NanoNaCl { throw new Error('Invalid seed size to convert to public key') } const pk = new Uint8Array(this.crypto_sign_PUBLICKEYBYTES) - const p: BigInt64Array[] = [new BigInt64Array(16), new BigInt64Array(16), new BigInt64Array(16), new BigInt64Array(16)] + const p: Float64Array[] = [new Float64Array(16), new Float64Array(16), new Float64Array(16), new Float64Array(16)] const hash = new Blake2b(64).update(s).digest() hash[0] &= 248 -- 2.47.3