]> git.codecow.com Git - nano25519.git/commitdiff
Add output buffer support to sign function. Adjust variable names.
authorChris Duncan <chris@zoso.dev>
Wed, 12 Aug 2026 10:00:06 +0000 (03:00 -0700)
committerChris Duncan <chris@zoso.dev>
Wed, 12 Aug 2026 10:00:06 +0000 (03:00 -0700)
src/lib/nano25519.ts
src/sync.ts

index ed8723eb098463d08740546585d9e8edd52fc68c..4d86043aa7ee8a8ac88e3267ac1e2e35a2494883 100644 (file)
@@ -67,42 +67,48 @@ const nano25519_init = (bytes: number[]): { derive: typeof derive, sign: typeof
                }
        }) as Exports
 
-       function derive (prv: unknown, pub?: unknown): string | Uint8Array<ArrayBuffer> {
+       function derive (k: unknown, out?: unknown): string | Uint8Array<ArrayBuffer> {
                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<ArrayBuffer>')
-               }
-               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<ArrayBuffer>')
                        }
-                       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<ArrayBuffer> {
-               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<ArrayBuffer> {
+               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<ArrayBuffer>')
+               }
+               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 {
index 6839b82b21b297711854c119c84d7d55a4f13332..59e192ef41e6c599b4f945447e34ffa503fd7ef8 100644 (file)
@@ -21,13 +21,13 @@ export function derive (k: Uint8Array<ArrayBuffer>): Uint8Array<ArrayBuffer>
  * 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<ArrayBuffer>} input - 32-byte private key
- * @param {Uint8Array<ArrayBuffer>} output - buffer to receive 32-byte public key
- * @returns the same buffer allocated in memory to `output`
+ * @param {Uint8Array<ArrayBuffer>} prv - 32-byte private key
+ * @param {Uint8Array<ArrayBuffer>} pub - buffer to receive 32-byte public key
+ * @returns the same buffer allocated in memory to `pub`
  */
-export function derive (input: Uint8Array<ArrayBuffer>, output: Uint8Array<ArrayBuffer>): Uint8Array<ArrayBuffer>
-export function derive (prv: string | Uint8Array<ArrayBuffer>, pub?: Uint8Array<ArrayBuffer>): string | Uint8Array<ArrayBuffer> {
-       return nano25519.derive(prv, pub)
+export function derive (k: Uint8Array<ArrayBuffer>, out: Uint8Array<ArrayBuffer>): Uint8Array<ArrayBuffer>
+export function derive (k: string | Uint8Array<ArrayBuffer>, out?: Uint8Array<ArrayBuffer>): string | Uint8Array<ArrayBuffer> {
+       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<ArrayBuffer>, k: Uint8Array<ArrayBuffer>): Uint8Array<ArrayBuffer>
-export function sign (m: string | Uint8Array<ArrayBuffer>, k: string | Uint8Array<ArrayBuffer>): string | Uint8Array<ArrayBuffer> {
-       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<ArrayBuffer>} m - Variable-byte-length message up to 32 KiB
+ * @param {Uint8Array<ArrayBuffer>} k - 64-byte secret key (prv + pub)
+ * @param {Uint8Array<ArrayBuffer>} out - buffer to receive 64-byte detached signature
+ * @returns the same buffer allocated in memory to `s`
+ */
+export function sign (m: Uint8Array<ArrayBuffer>, k: Uint8Array<ArrayBuffer>, out: Uint8Array<ArrayBuffer>): Uint8Array<ArrayBuffer>
+export function sign (m: string | Uint8Array<ArrayBuffer>, k: string | Uint8Array<ArrayBuffer>, out?: Uint8Array<ArrayBuffer>): string | Uint8Array<ArrayBuffer> {
+       return nano25519.sign(m, k, out)
 }
 
 /**