]> git.codecow.com Git - nano25519.git/commitdiff
Deprecate complicated worker state management and just determine if it's listening...
authorChris Duncan <chris@zoso.dev>
Sat, 15 Aug 2026 09:47:47 +0000 (02:47 -0700)
committerChris Duncan <chris@zoso.dev>
Sat, 15 Aug 2026 09:47:47 +0000 (02:47 -0700)
index.html
src/lib/worker.ts

index a4c7061a5d450ac61368b7d8aa8070dd127a767b..aef52239f1aa43abec6b4b3f8c20300260e60225 100644 (file)
@@ -289,50 +289,50 @@ SPDX-License-Identifier: GPL-3.0-or-later
                        passes += +test
                        failures += +!test
 
-                       // // test both strings and bytes as input
-                       // for (const { privateKey, publicKey, message, signature } of PYTHON_ED25519_BLAKE2B_VECTORS) {
-                       //      result = nano25519.derive(privateKey)
-                       //      test = result.toLowerCase() === publicKey
-                       //      check(`derive from ${privateKey}`, test)
-                       //      passes += +test
-                       //      failures += +!test
-
-                       //      result = nano25519.sign(message, privateKey + publicKey)
-                       //      test = result.toLowerCase() === signature.slice(0, 128)
-                       //      check(`sign message ${message}`, test)
-                       //      passes += +test
-                       //      failures += +!test
-
-                       //      result = nano25519.verify(signature.slice(0, 128), message, publicKey)
-                       //      test = result === true
-                       //      check(`verify signature ${signature.slice(0, 128)}`, test)
-                       //      passes += +test
-                       //      failures += +!test
-
-                       //      const privateKeyBytes = new Uint8Array(privateKey.match(/.{2}/g)?.map(b => parseInt(b, 16)) ?? [])
-                       //      const publicKeyBytes = new Uint8Array(publicKey.match(/.{2}/g)?.map(b => parseInt(b, 16)) ?? [])
-                       //      const secretKeyBytes = new Uint8Array([...privateKeyBytes, ...publicKeyBytes])
-                       //      const messageBytes = new Uint8Array(message.match(/.{2}/g)?.map(b => parseInt(b, 16)) ?? [])
-                       //      const signatureBytes = new Uint8Array(signature.match(/.{2}/g)?.slice(0, 64).map(b => parseInt(b, 16)) ?? [])
-
-                       //      result = nano25519.derive(privateKeyBytes)
-                       //      test = [...result].map(b => b.toString(16).padStart(2, '0')).join('').toLowerCase() === publicKey
-                       //      check(`derive from ${privateKey}`, test)
-                       //      passes += +test
-                       //      failures += +!test
-
-                       //      result = nano25519.sign(messageBytes, secretKeyBytes)
-                       //      test = [...result].map(b => b.toString(16).padStart(2, '0')).join('').toLowerCase() === signature.slice(0, 128)
-                       //      check(`sign message ${message}`, test)
-                       //      passes += +test
-                       //      failures += +!test
-
-                       //      result = nano25519.verify(signatureBytes, messageBytes, publicKeyBytes)
-                       //      test = result === true
-                       //      check(`verify signature ${signature.slice(0, 128)}`, test)
-                       //      passes += +test
-                       //      failures += +!test
-                       // }
+                       // test both strings and bytes as input
+                       for (const { privateKey, publicKey, message, signature } of PYTHON_ED25519_BLAKE2B_VECTORS) {
+                               result = nano25519.derive(privateKey)
+                               test = result.toLowerCase() === publicKey
+                               check(`derive from ${privateKey}`, test)
+                               passes += +test
+                               failures += +!test
+
+                               result = nano25519.sign(message, privateKey + publicKey)
+                               test = result.toLowerCase() === signature.slice(0, 128)
+                               check(`sign message ${message}`, test)
+                               passes += +test
+                               failures += +!test
+
+                               result = nano25519.verify(signature.slice(0, 128), message, publicKey)
+                               test = result === true
+                               check(`verify signature ${signature.slice(0, 128)}`, test)
+                               passes += +test
+                               failures += +!test
+
+                               const privateKeyBytes = new Uint8Array(privateKey.match(/.{2}/g)?.map(b => parseInt(b, 16)) ?? [])
+                               const publicKeyBytes = new Uint8Array(publicKey.match(/.{2}/g)?.map(b => parseInt(b, 16)) ?? [])
+                               const secretKeyBytes = new Uint8Array([...privateKeyBytes, ...publicKeyBytes])
+                               const messageBytes = new Uint8Array(message.match(/.{2}/g)?.map(b => parseInt(b, 16)) ?? [])
+                               const signatureBytes = new Uint8Array(signature.match(/.{2}/g)?.slice(0, 64).map(b => parseInt(b, 16)) ?? [])
+
+                               result = nano25519.derive(privateKeyBytes)
+                               test = [...result].map(b => b.toString(16).padStart(2, '0')).join('').toLowerCase() === publicKey
+                               check(`derive from ${privateKey}`, test)
+                               passes += +test
+                               failures += +!test
+
+                               result = nano25519.sign(messageBytes, secretKeyBytes)
+                               test = [...result].map(b => b.toString(16).padStart(2, '0')).join('').toLowerCase() === signature.slice(0, 128)
+                               check(`sign message ${message}`, test)
+                               passes += +test
+                               failures += +!test
+
+                               result = nano25519.verify(signatureBytes, messageBytes, publicKeyBytes)
+                               test = result === true
+                               check(`verify signature ${signature.slice(0, 128)}`, test)
+                               passes += +test
+                               failures += +!test
+                       }
 
                        // XFAIL
                        try {
index f62fb4e47f89f6cb6502a8a8a65b116394051476..175f9cad0497c261506795f5e00e56070f17f79f 100644 (file)
@@ -7,10 +7,10 @@ import { MessagePort as NodeMessagePort, Worker as NodeWorker } from 'node:worke
 import nano25519_wasm from '../../build/nano25519.wasm'
 import { nano25519_init } from './nano25519'
 
-type Action = 'derive' | 'sign' | 'start' | 'stop' | 'verify'
+type Action = 'derive' | 'sign' | 'start' | 'verify'
 
 type Data = {
-       id: string
+       id: UUID
        action: string
        message?: string | ArrayBuffer
        privateKey?: string
@@ -20,7 +20,6 @@ type Data = {
 }
 
 const nano25519_worker_init = ({ derive, sign, verify }: ReturnType<typeof nano25519_init>) => {
-       let isListening = false
        let host: NodeMessagePort | null = null
 
        /**
@@ -41,40 +40,45 @@ const nano25519_worker_init = ({ derive, sign, verify }: ReturnType<typeof nano2
                        || typeof message.data.action !== 'string'
                ) return
                let result: undefined | boolean | string | Uint8Array<ArrayBuffer>
-               let id: undefined | string
+               let id: undefined | UUID
                try {
-                       const data: Data = message.data as object & { id: string, action: string }
+                       const data: Data = message.data as object & { id: UUID, action: Action }
                        id = data.id
 
-                       if (data.action === 'start') {
-                               isListening = true
-                               result = 'started'
-                       } else if (data.action === 'stop') {
-                               isListening = false
-                               result = 'stopped'
-                       } else if (isListening) {
-                               const { action } = data
-                               if (action === 'derive') {
+                       switch (data.action) {
+                               case 'start': {
+                                       result = 'listening'
+                                       break
+                               }
+                               case 'derive': {
                                        const { privateKey } = data
                                        const publicKey = derive(privateKey)
                                        if (publicKey == null) {
                                                throw new TypeError('Invalid public key from WASM derive()')
                                        }
                                        result = publicKey
-                               } else if (action === 'sign') {
+                                       break
+                               }
+                               case 'sign': {
                                        const { message, secretKey } = data
                                        const signature = sign(message, secretKey)
                                        if (signature == null) {
                                                throw new TypeError('Invalid signature from WASM sign()')
                                        }
                                        result = signature
-                               } else if (action === 'verify') {
+                                       break
+                               }
+                               case 'verify': {
                                        const { message, publicKey, signature } = data
                                        const verification = verify(signature, message, publicKey)
                                        if (verification == null) {
                                                throw new TypeError('Invalid verification from WASM verify()')
                                        }
                                        result = verification
+                                       break
+                               }
+                               default: {
+                                       throw new TypeError(`Invalid action '${data.action}'`)
                                }
                        }
                } catch (err: unknown) {
@@ -123,6 +127,7 @@ function isBytes (a: unknown): a is Uint8Array<ArrayBuffer> {
 function init (): void {
        try {
                BROWSER: {
+                       if (url) URL.revokeObjectURL(url)
                        url = URL.createObjectURL(new Blob([nano25519_worker], { type: 'text/javascript' }))
                        worker = new Worker(url, { type: 'module' })
                        worker.onmessage = report
@@ -165,6 +170,7 @@ function report (msg: { data: Record<string, unknown> }): void {
        const { result } = data
        console.log('received result from worker')
        if (typeof result !== 'boolean' && typeof result !== 'string' && !isBytes(result)) {
+               console.error(result)
                return err('Invalid return type')
        }
        return ok(result)
@@ -173,7 +179,6 @@ function report (msg: { data: Record<string, unknown> }): void {
 // Reconstruct worker when errors occur
 function reset (): void {
        console.warn(`nano25519 encountered an error. Reinitializing...`)
-       isWorkerReady = false
        worker.terminate()
        init()
 }
@@ -181,6 +186,7 @@ function reset (): void {
 // Check that the worker is running and listening before sending messages
 async function start (): Promise<unknown> {
        return starting ??= new Promise((resolve, reject): void => {
+               console.log('starting worker')
                if (!isWorkerReady) init()
                const id = crypto.randomUUID()
                tasks.set(id, [resolve, reject])
@@ -206,16 +212,9 @@ async function dispatch (data: Record<'action', Action> & Record<string, string
        })
 }
 
-// Request that the worker stop listening without terminating
-async function stop (): Promise<void> {
-       console.log('stopping worker')
-       const result = await dispatch({ action: 'stop' })
-       if (result === 'stopped') {
-               console.log('worker stopped successfully')
-       } else if (typeof result === 'string') {
-               throw new Error(result)
-       } else {
-               throw new Error('unknown error while stopping worker')
+class Nano25519ResultError extends Error {
+       constructor (action: string, cause?: unknown) {
+               super(`${action} result invalid`, { cause })
        }
 }
 
@@ -224,44 +223,38 @@ export async function run (data: Record<'action', 'sign'> & Record<string, strin
 export async function run (data: Record<'action', 'verify'> & Record<string, string | Uint8Array<ArrayBuffer>>): Promise<boolean>
 export async function run (data: Record<'action', 'derive' | 'sign' | 'verify'> & Record<string, string | Uint8Array<ArrayBuffer>>): Promise<boolean | string | Uint8Array<ArrayBuffer>> {
        try {
-               await start()
-               if (url) URL.revokeObjectURL(url)
-       } catch (err: any) {
-               throw new Error('Error initializing worker')
+               const result = await start()
+               if (result === 'listening') {
+                       console.log('worker listening')
+               } else if (typeof result === 'string') {
+                       throw new Error(result)
+               } else {
+                       throw new Error('unknown error')
+               }
+       } catch (e: any) {
+               throw new Error('failed to start worker', { cause: e })
        }
-       try {
-               const result = await dispatch(data)
-               switch (data.action) {
-                       case 'derive': {
-                               if ((isBytes(result) && result.byteLength === 32) || (typeof result === 'string' && /^[0-9a-f]{64}$/i.test(result))) {
-                                       return result
-                               } else {
-                                       throw new Error('derive result invalid')
-                               }
-                       }
-                       case 'sign': {
-                               if ((isBytes(result) && result.byteLength === 64) || (typeof result === 'string' && /^[0-9a-f]{128}$/i.test(result))) {
-                                       return result
-                               } else {
-                                       throw new Error('sign result invalid')
-                               }
+
+       const result = await dispatch(data)
+       switch (data.action) {
+               case 'derive': {
+                       if ((isBytes(result) && result.byteLength === 32) || (typeof result === 'string' && /^[0-9a-f]{64}$/i.test(result))) {
+                               return result
                        }
-                       case 'verify': {
-                               if (typeof result === 'boolean') {
-                                       return result
-                               } else {
-                                       throw new Error('verify result invalid')
-                               }
+                       break
+               }
+               case 'sign': {
+                       if ((isBytes(result) && result.byteLength === 64) || (typeof result === 'string' && /^[0-9a-f]{128}$/i.test(result))) {
+                               return result
                        }
+                       break
                }
-       } catch (err: any) {
-               try {
-                       await stop()
-               } catch (e: any) {
-                       console.error('failed to stop worker')
-                       reset()
-               } finally {
-                       throw new Error('Error dispatching async request')
+               case 'verify': {
+                       if (typeof result === 'boolean') {
+                               return result
+                       }
+                       break
                }
        }
+       throw new Nano25519ResultError(data.action, result)
 }