]> git.codecow.com Git - nano25519.git/commitdiff
Add layer of abstraction to wasm functions.
authorChris Duncan <chris@zoso.dev>
Sun, 15 Feb 2026 23:50:27 +0000 (15:50 -0800)
committerChris Duncan <chris@zoso.dev>
Sun, 15 Feb 2026 23:50:27 +0000 (15:50 -0800)
assembly/nano-nacl.ts
index.ts

index f7691ef9b5050c1d4aaa45298c8ee76d3d8b9a90..592498cf02511b194bd5f12690eb1a0731321ec0 100644 (file)
@@ -650,7 +650,8 @@ export function derive (k0: u64, k1: u64, k2: u64, k3: u64): Uint8Array {
 }\r
 \r
 /**\r
-* Signs the message using the private key and returns a signature.\r
+* Signs the message using the private key and returns a signature. This mirrors\r
+* the functionality of `nacl.sign.detached()`.\r
 *\r
 * @param {Uint8Array} message - Message to sign\r
 * @param {Uint8Array} privateKey - 32-byte key to use for signing\r
@@ -677,14 +678,15 @@ export function sign (h0: u64, h1: u64, h2: u64, h3: u64, k0: u64, k1: u64, k2:
 }\r
 \r
 /**\r
-* Verifies a signature on a blockhash against a public key.\r
+* Verifies a signature on a blockhash against a public key. This mirrors the\r
+* functionality of `nacl.sign.detached.verify()`.\r
 *\r
 * @param {Uint8Array} blockhash - 32-byte hash of signed Nano block\r
 * @param {Uint8Array} signature - 64-byte signature\r
 * @param {Uint8Array} publicKey - 32-byte key used for signing\r
 * @returns {boolean} - True if `publicKey` was used to sign `blockhash` and generate `signature`, else false\r
 */\r
-export function verify (h0: u64, h1: u64, h2: u64, h3: u64, s0: u64, s1: u64, s2: u64, s3: u64, s4: u64, s5: u64, s6: u64, s7: u64, k0: u64, k1: u64, k2: u64, k3: u64): boolean {\r
+export function verify (h0: u64, h1: u64, h2: u64, h3: u64, s0: u64, s1: u64, s2: u64, s3: u64, s4: u64, s5: u64, s6: u64, s7: u64, k0: u64, k1: u64, k2: u64, k3: u64): i32 {\r
        const h = new Uint64Array(4); h.set([h0, h1, h2, h3])\r
        const s = new Uint64Array(8); s.set([s0, s1, s2, s3, s4, s5, s6, s7])\r
        const k = new Uint64Array(4); k.set([k0, k1, k2, k3])\r
index 735ab3e0f10e10e19bc1183d7b3fdec02ee8ce88..d58f8547834cb7cede08a1a7bb94795d89a54136 100644 (file)
--- a/index.ts
+++ b/index.ts
@@ -2,9 +2,9 @@
 //! SPDX-License-Identifier: GPL-3.0-or-later
 
 import nacl from './build/nano-nacl.wasm'
-type Derive = (k0: bigint, k1: bigint, k2: bigint, k3: bigint) => Uint8Array
-type Sign = (h0: bigint, h1: bigint, h2: bigint, h3: bigint, k0: bigint, k1: bigint, k2: bigint, k3: bigint) => Uint8Array
-type Verify = (h0: bigint, h1: bigint, h2: bigint, h3: bigint, s0: bigint, s1: bigint, s2: bigint, s3: bigint, s4: bigint, s5: bigint, s6: bigint, s7: bigint, k0: bigint, k1: bigint, k2: bigint, k3: bigint) => boolean
+type Derive = (k0: bigint, k1: bigint, k2: bigint, k3: bigint) => number
+type Sign = (h0: bigint, h1: bigint, h2: bigint, h3: bigint, k0: bigint, k1: bigint, k2: bigint, k3: bigint) => number
+type Verify = (h0: bigint, h1: bigint, h2: bigint, h3: bigint, s0: bigint, s1: bigint, s2: bigint, s3: bigint, s4: bigint, s5: bigint, s6: bigint, s7: bigint, k0: bigint, k1: bigint, k2: bigint, k3: bigint) => number
 type Data = {
        action: string
        hash?: string
@@ -18,10 +18,10 @@ const NanoNaCl = async (bytes: number[]): Promise<void> => {
        let wasm
        let module
        let instance
+       let derive: (k: BigUint64Array) => Uint8Array<ArrayBuffer>
+       let sign: (h: BigUint64Array, k: BigUint64Array) => Uint8Array<ArrayBuffer>
+       let verify: (h: BigUint64Array, s: BigUint64Array, k: BigUint64Array) => boolean
        let memory: WebAssembly.Memory
-       let derive: Derive
-       let sign: Sign
-       let verify: Verify
 
        async function setup (): Promise<void> {
                try {
@@ -44,10 +44,8 @@ const NanoNaCl = async (bytes: number[]): Promise<void> => {
                                        memory: new WebAssembly.Memory({ initial: 256, maximum: 1024 })
                                }
                        })
-                       const { exports } = instance as any
-                       derive = exports.derive
-                       verify = exports.verify
-                       memory = instance.exports.memory as WebAssembly.Memory
+                       const { exports } = instance as { exports: { derive: Derive, sign: Sign, verify: Verify, memory: WebAssembly.Memory } }
+                       memory = exports.memory
                        function __liftString (pointer: number) {
                                if (!pointer) return null
                                const
@@ -70,28 +68,50 @@ const NanoNaCl = async (bytes: number[]): Promise<void> => {
                                return new Uint8Array(memory.buffer, offset, length).slice()
                        }
 
-                       derive = function (k0, k1, k2, k3) {
+                       derive = function (k: BigUint64Array): Uint8Array<ArrayBuffer> {
                                // assembly/nano-nacl/derive(u64, u64, u64, u64) => ~lib/typedarray/Uint8Array
-                               k0 = k0 || 0n
-                               k1 = k1 || 0n
-                               k2 = k2 || 0n
-                               k3 = k3 || 0n
+                               const k0 = k[0] ?? 0n
+                               const k1 = k[1] ?? 0n
+                               const k2 = k[2] ?? 0n
+                               const k3 = k[3] ?? 0n
                                return __liftTypedArray(exports.derive(k0, k1, k2, k3) >>> 0)
                        }
 
-                       sign = function (h0, h1, h2, h3, k0, k1, k2, k3) {
+                       sign = function (h: BigUint64Array, k: BigUint64Array): Uint8Array<ArrayBuffer> {
                                // assembly/nano-nacl/sign(u64, u64, u64, u64, u64, u64, u64, u64) => ~lib/typedarray/Uint8Array
-                               h0 = h0 || 0n
-                               h1 = h1 || 0n
-                               h2 = h2 || 0n
-                               h3 = h3 || 0n
-                               k0 = k0 || 0n
-                               k1 = k1 || 0n
-                               k2 = k2 || 0n
-                               k3 = k3 || 0n
+                               const h0 = h[0] ?? 0n
+                               const h1 = h[1] ?? 0n
+                               const h2 = h[2] ?? 0n
+                               const h3 = h[3] ?? 0n
+                               const k0 = k[0] ?? 0n
+                               const k1 = k[1] ?? 0n
+                               const k2 = k[2] ?? 0n
+                               const k3 = k[3] ?? 0n
                                return __liftTypedArray(exports.sign(h0, h1, h2, h3, k0, k1, k2, k3) >>> 0)
                        }
 
+                       verify = function (h: BigUint64Array, s: BigUint64Array, k: BigUint64Array): boolean {
+                               // assembly/nano-nacl/sign(u64, u64, u64, u64, u64, u64, u64, u64) => ~lib/typedarray/Uint8Array
+                               const h0 = h[0] || 0n
+                               const h1 = h[1] || 0n
+                               const h2 = h[2] || 0n
+                               const h3 = h[3] || 0n
+                               const s0 = s[0] || 0n
+                               const s1 = s[1] || 0n
+                               const s2 = s[2] || 0n
+                               const s3 = s[3] || 0n
+                               const s4 = s[4] || 0n
+                               const s5 = s[5] || 0n
+                               const s6 = s[6] || 0n
+                               const s7 = s[7] || 0n
+                               const k0 = k[0] || 0n
+                               const k1 = k[1] || 0n
+                               const k2 = k[2] || 0n
+                               const k3 = k[3] || 0n
+                               const result = exports.verify(h0, h1, h2, h3, s0, s1, s2, s3, s4, s5, s6, s7, k0, k1, k2, k3)
+                               return result === 1
+                       }
+
                        isReady = true
                } catch (err) {
                        throw new Error('Error instantiating WebAssembly', { cause: err })
@@ -107,9 +127,9 @@ const NanoNaCl = async (bytes: number[]): Promise<void> => {
                        const privateKeyArray = new BigUint64Array(4)
                        const privateKeyView = new DataView(privateKeyArray.buffer)
                        const publicKeyArray = new BigUint64Array(4)
-                       const publicKeyView = new DataView(privateKeyArray.buffer)
-                       const signatureArray = new BigUint64Array(4)
-                       const signatureView = new DataView(privateKeyArray.buffer)
+                       const publicKeyView = new DataView(publicKeyArray.buffer)
+                       const signatureArray = new BigUint64Array(8)
+                       const signatureView = new DataView(signatureArray.buffer)
 
                        if (msg.data === 'start') {
                                result = 'started'
@@ -128,7 +148,7 @@ const NanoNaCl = async (bytes: number[]): Promise<void> => {
                                                const u64 = privateKey.slice(i, i + 16)
                                                privateKeyView.setBigUint64(i / 2, BigInt(`0x${u64}`))
                                        }
-                                       const publicKey = derive(privateKeyArray[0], privateKeyArray[1], privateKeyArray[2], privateKeyArray[3])
+                                       const publicKey = derive(privateKeyArray)
                                        if (publicKey == null) {
                                                throw new TypeError('Invalid verification response from WASM')
                                        }
@@ -149,7 +169,7 @@ const NanoNaCl = async (bytes: number[]): Promise<void> => {
                                                const u64 = privateKey.slice(i, i + 16)
                                                privateKeyView.setBigUint64(i / 2, BigInt(`0x${u64}`))
                                        }
-                                       const signature = sign(hashArray[0], hashArray[1], hashArray[2], hashArray[3], privateKeyArray[0], privateKeyArray[1], privateKeyArray[2], privateKeyArray[3])
+                                       const signature = sign(hashArray, privateKeyArray)
                                        if (signature == null) {
                                                throw new TypeError('Invalid signature from WASM')
                                        }
@@ -170,15 +190,15 @@ const NanoNaCl = async (bytes: number[]): Promise<void> => {
                                                const u64 = hash.slice(i, i + 16)
                                                hashView.setBigUint64(i / 2, BigInt(`0x${u64}`))
                                        }
-                                       for (let i = 0; i < publicKey.length; i += 16) {
-                                               const u64 = publicKey.slice(i, i + 16)
-                                               publicKeyView.setBigUint64(i / 2, BigInt(`0x${u64}`))
-                                       }
                                        for (let i = 0; i < signature.length; i += 16) {
                                                const u64 = signature.slice(i, i + 16)
                                                signatureView.setBigUint64(i / 2, BigInt(`0x${u64}`))
                                        }
-                                       const isVerified = verify(hashArray[0], hashArray[1], hashArray[2], hashArray[3], signatureArray[0], signatureArray[1], signatureArray[2], signatureArray[3], signatureArray[4], signatureArray[5], signatureArray[6], signatureArray[7], publicKeyArray[0], publicKeyArray[1], publicKeyArray[2], publicKeyArray[3])
+                                       for (let i = 0; i < publicKey.length; i += 16) {
+                                               const u64 = publicKey.slice(i, i + 16)
+                                               publicKeyView.setBigUint64(i / 2, BigInt(`0x${u64}`))
+                                       }
+                                       const isVerified = verify(hashArray, signatureArray, publicKeyArray)
                                        if (isVerified == null) {
                                                throw new TypeError('Invalid verification response from WASM')
                                        }