From: Chris Duncan Date: Wed, 12 Aug 2026 10:00:06 +0000 (-0700) Subject: Add output buffer support to sign function. Adjust variable names. X-Git-Url: https://git.codecow.com/?a=commitdiff_plain;h=c64defb3828159130762c4879a32442e3adc7a39;p=nano25519.git Add output buffer support to sign function. Adjust variable names. --- diff --git a/src/lib/nano25519.ts b/src/lib/nano25519.ts index ed8723e..4d86043 100644 --- a/src/lib/nano25519.ts +++ b/src/lib/nano25519.ts @@ -67,42 +67,48 @@ const nano25519_init = (bytes: number[]): { derive: typeof derive, sign: typeof } }) as Exports - function derive (prv: unknown, pub?: unknown): string | Uint8Array { + function derive (k: unknown, out?: unknown): string | Uint8Array { let privateKey = new Uint8Array(32) let buffer = new DataView(exports.memory.buffer) - pub ??= new Uint8Array(32) - if (!(pub instanceof Uint8Array && pub.buffer instanceof ArrayBuffer && pub.byteLength === 32)) { - throw new TypeError('Output buffer must be 32-byte Uint8Array') - } - privateKey.set(normalize('private key', 32, 32, prv)) - let inPtr = exports.getInputPointer() - for (let i = 0; i < 32; i++) { - buffer.setUint8(inPtr + i, privateKey[i]) - } - privateKey.fill(0) - exports.derive() - const outPtr = exports.getOutputPointer() - const publicKey = new Uint8Array(pub.buffer) - buffer = new DataView(exports.memory.buffer) - for (let i = 0; i < 32; i++) { - publicKey[i] = buffer.getUint8(outPtr + i + 32) - } - clear(buffer) - if (typeof prv === 'string') { - let hex = '' - for (const byte of publicKey) { - hex += byte.toString(16).padStart(2, '0') + try { + out ??= new Uint8Array(32) + if (!(out instanceof Uint8Array && out.buffer instanceof ArrayBuffer && out.byteLength === 32)) { + throw new TypeError('Derive output buffer must be 32-byte Uint8Array') } - return hex - } else { - return publicKey + privateKey.set(normalize('private key', 32, 32, k)) + let inPtr = exports.getInputPointer() + for (let i = 0; i < 32; i++) { + buffer.setUint8(inPtr + i, privateKey[i]) + } + privateKey.fill(0) + exports.derive() + const outPtr = exports.getOutputPointer() + const publicKey = new Uint8Array(out.buffer) + buffer = new DataView(exports.memory.buffer) + for (let i = 0; i < 32; i++) { + publicKey[i] = buffer.getUint8(outPtr + i + 32) + } + clear(buffer) + if (typeof k === 'string') { + let hex = '' + for (const byte of publicKey) { + hex += byte.toString(16).padStart(2, '0') + } + return hex + } else { + return publicKey + } + } finally { + privateKey.fill(0) + clear(buffer) } } - function sign (m: unknown, k: unknown): string | Uint8Array { - const message = normalize('message', 0, 32768, m) - const secretKey = normalize('secret key', 64, 64, k) + function sign (m: unknown, k: unknown, s?: unknown): string | Uint8Array { + let secretKey = new Uint8Array(64) let buffer: DataView | undefined = new DataView(exports.memory.buffer) + secretKey.set(normalize('secret key', 64, 64, k)) + const message = normalize('message', 0, 32768, m) let mPtr = exports.getMessagePointer() let inPtr = exports.getInputPointer() for (let i = 0; i < message.byteLength; i++) { @@ -113,15 +119,19 @@ const nano25519_init = (bytes: number[]): { derive: typeof derive, sign: typeof } exports.sign(message.byteLength) const outPtr = exports.getOutputPointer() - const s = new Uint8Array(64) + s ??= new Uint8Array(64) + if (!(s instanceof Uint8Array && s.buffer instanceof ArrayBuffer && s.byteLength === 64)) { + throw new TypeError('Sign output buffer must be 64-byte Uint8Array') + } + const signature = new Uint8Array(s.buffer) buffer = new DataView(exports.memory.buffer) for (let i = 0; i < 64; i++) { - s[i] = buffer.getUint8(outPtr + i) + signature[i] = buffer.getUint8(outPtr + i) } clear(buffer) return typeof k === 'string' - ? [...s].map(b => b.toString(16).padStart(2, '0')).join('') - : s + ? [...signature].map(b => b.toString(16).padStart(2, '0')).join('') + : signature } function verify (s: unknown, m: unknown, k: unknown): boolean { diff --git a/src/sync.ts b/src/sync.ts index 6839b82..59e192e 100644 --- a/src/sync.ts +++ b/src/sync.ts @@ -21,13 +21,13 @@ export function derive (k: Uint8Array): Uint8Array * Technically, the buffer is also returned for API consistency, but the * location in memory is the same as the output buffer, so the return value can * be ignored. - * @param {Uint8Array} input - 32-byte private key - * @param {Uint8Array} output - buffer to receive 32-byte public key - * @returns the same buffer allocated in memory to `output` + * @param {Uint8Array} prv - 32-byte private key + * @param {Uint8Array} pub - buffer to receive 32-byte public key + * @returns the same buffer allocated in memory to `pub` */ -export function derive (input: Uint8Array, output: Uint8Array): Uint8Array -export function derive (prv: string | Uint8Array, pub?: Uint8Array): string | Uint8Array { - return nano25519.derive(prv, pub) +export function derive (k: Uint8Array, out: Uint8Array): Uint8Array +export function derive (k: string | Uint8Array, out?: Uint8Array): string | Uint8Array { + return nano25519.derive(k, out) } /** @@ -46,8 +46,20 @@ export function sign (m: string, k: string): string * @returns 64-byte detached signature */ export function sign (m: Uint8Array, k: Uint8Array): Uint8Array -export function sign (m: string | Uint8Array, k: string | Uint8Array): string | Uint8Array { - return nano25519.sign(m, k) +/** + * Signing using WebAssembly. To sign Nano blocks, the message should be a + * 32-byte block hash. Signature bytes are written to the user-supplied output + * buffer instead of being allocated internally. Technically, the buffer is also + * returned for API consistency, but the location in memory is the same as the + * output buffer, so the return value can be ignored. + * @param {Uint8Array} m - Variable-byte-length message up to 32 KiB + * @param {Uint8Array} k - 64-byte secret key (prv + pub) + * @param {Uint8Array} out - buffer to receive 64-byte detached signature + * @returns the same buffer allocated in memory to `s` + */ +export function sign (m: Uint8Array, k: Uint8Array, out: Uint8Array): Uint8Array +export function sign (m: string | Uint8Array, k: string | Uint8Array, out?: Uint8Array): string | Uint8Array { + return nano25519.sign(m, k, out) } /**