From 0975d6157d913ca07777dd68ff4731a4072ddb86 Mon Sep 17 00:00:00 2001 From: Chris Duncan Date: Sun, 22 Mar 2026 22:29:56 -0700 Subject: [PATCH] Fix extra type emissions and exports. Update integration and input guidance in README. Emit declarations to types directory. Use esbuild to copy specific type definitions. Move implementation file and delete duplicated exports. Expand on test vector authorship. Include unlicense for tweetnacl origins. --- AUTHORS.md | 4 +++ LICENSES/Unlicense.txt | 10 +++++++ README.md | 23 ++++++++++----- esbuild/config.mjs | 21 +++++-------- esbuild/prod.mjs | 11 ++++++- package.json | 2 +- src/async.ts | 2 +- src/{ => lib}/nano25519.ts | 60 +------------------------------------- src/sync.ts | 2 +- tsconfig.json | 3 +- vectors.mjs | 5 +++- 11 files changed, 58 insertions(+), 85 deletions(-) create mode 100644 LICENSES/Unlicense.txt rename src/{ => lib}/nano25519.ts (78%) diff --git a/AUTHORS.md b/AUTHORS.md index 037ceac..768b0c8 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -31,3 +31,7 @@ SPDX-License-Identifier: GPL-3.0-or-later [Poly1305-donna](https://github.com/floodyberry/poly1305-donna) - Andrew Moon (@floodyberry) + +[python-ed25519-blake2b](https://github.com/Matoking/python-ed25519-blake2b) + +- Janne Pulkkinen (@Matoking) diff --git a/LICENSES/Unlicense.txt b/LICENSES/Unlicense.txt new file mode 100644 index 0000000..cde4ac6 --- /dev/null +++ b/LICENSES/Unlicense.txt @@ -0,0 +1,10 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. + +In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/README.md b/README.md index f564061..c30e864 100644 --- a/README.md +++ b/README.md @@ -45,17 +45,25 @@ nano25519 can be used directly on a webpage with a script module: nano25519 can be imported into NodeJS projects: ```javascript -import { derive, sign, verify } from "nano25519"; +import * as nano25519 from "nano25519"; +``` + +Sync and async modules can be imported separately depending on requirements. + +```javascript +import { derive, sign, verify } from "nano25519/sync"; +import { deriveAsync, signAsync, verifyAsync } from "nano25519/async"; ``` ## Usage Each function has a synchronous implementation which is preferable for speed. -These versions require Uint8Array byte arrays and return the same. If a non-blocking solution is required, asynchronous implementations are -provided which use Web Workers in the browser or Worker threads in NodeJS. These -versions require hex strings and return the same. +provided which use Web Workers in the browser or Worker threads in NodeJS. + +Inputs can be passed as Uint8Array byte arrays (preferable) or strings. The +output will return the same type as the input. ### Derive @@ -145,8 +153,7 @@ after, libsodium became the reference from which functionality was ported. For this project, the internal hash mechanism was altered to use BLAKE2b instead of SHA-512 so that it aligns with the Nano protocol. It has also been -optimized specifically for Nano needs; many functions have been modified or -removed due to the very narrow use case to which it is applied here. +optimized to take advantage of SIMD parallelism using WebAssembly vector types. ## Tests @@ -154,7 +161,9 @@ A few basic tests are availabe in the source repository. - `index.html` is a web interface to test browser execution and compare performance with other browser-based implementations. -- `test.mjs` is a basic test for NodeJS to check result validity. +- `test.mjs` is a test for NodeJS to check result validity. It runs a + derive-sign-verify sequence for public test vectors obtained from the + python-ed25519-blake2b library. ## Building diff --git a/esbuild/config.mjs b/esbuild/config.mjs index 96e8502..9dc1265 100644 --- a/esbuild/config.mjs +++ b/esbuild/config.mjs @@ -7,22 +7,14 @@ const commonOptions = { bundle: true, loader: { - '.wasm': 'binary' + '.wasm': 'binary', + '.d.ts': 'copy' }, format: 'esm', legalComments: 'inline', outdir: 'dist', } -/** - * @type {import('esbuild').BuildOptions} - */ -export const prodOptions = { - drop: ['console', 'debugger'], - minify: true, - sourcemap: false -} - /** * @type import("esbuild").BuildOptions */ @@ -44,9 +36,12 @@ export const nodeOptions = { platform: 'node', target: 'node22', entryPoints: [ - { in: './src/index.ts', out: 'index' }, - { in: './src/async.ts', out: 'async' }, - { in: './src/sync.ts', out: 'sync' } + { in: './src/*.ts', out: '' }, + // { in: './src/async.ts', out: 'async' }, + // { in: './src/sync.ts', out: 'sync' }, + { in: './types/index.d.ts', out: 'index.d' }, + { in: './types/async.d.ts', out: 'async.d' }, + { in: './types/sync.d.ts', out: 'sync.d' } ], packages: 'external', dropLabels: ['BROWSER'] diff --git a/esbuild/prod.mjs b/esbuild/prod.mjs index 26ded3e..cd72ba0 100644 --- a/esbuild/prod.mjs +++ b/esbuild/prod.mjs @@ -2,7 +2,16 @@ //! SPDX-License-Identifier: GPL-3.0-or-later import { build } from 'esbuild' -import { browserOptions, nodeOptions, prodOptions } from './config.mjs' +import { browserOptions, nodeOptions } from './config.mjs' + +/** + * @type {import('esbuild').BuildOptions} + */ +export const prodOptions = { + drop: ['console', 'debugger'], + minify: true, + sourcemap: false +} await build({ ...browserOptions, ...prodOptions }) await build({ ...nodeOptions, ...prodOptions }) diff --git a/package.json b/package.json index ecda40d..5602c7a 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "scripts": { "build": "npm run clean && npm run compile && node ./esbuild/dev.mjs", "build:prod": "npm run clean && npm run compile && node ./esbuild/prod.mjs", - "clean": "rm -rf {build,dist}", + "clean": "rm -rf {build,dist,types}", "compile": "asc ./src/assembly/index.ts && tsc", "prepublishOnly": "npm run test:prod", "test": "npm run build && node ./test.mjs", diff --git a/src/async.ts b/src/async.ts index 0db6a36..b99a1c0 100644 --- a/src/async.ts +++ b/src/async.ts @@ -1,7 +1,7 @@ //! SPDX-FileCopyrightText: 2026 Chris Duncan //! SPDX-License-Identifier: GPL-3.0-or-later -import { run } from './nano25519' +import { run } from './lib/nano25519' /** * Asynchronous Nano public key derivation using WebAssembly. diff --git a/src/nano25519.ts b/src/lib/nano25519.ts similarity index 78% rename from src/nano25519.ts rename to src/lib/nano25519.ts index b799c42..32a7eb4 100644 --- a/src/nano25519.ts +++ b/src/lib/nano25519.ts @@ -3,7 +3,7 @@ import { Worker as NodeWorker } from 'node:worker_threads' //@ts-expect-error -import nano25519_wasm from '../build/nano25519.wasm' +import nano25519_wasm from '../../build/nano25519.wasm' type Data = { action: string @@ -411,61 +411,3 @@ export async function run (data: Record } } } - -/** - * Asynchronous Nano public key derivation using WebAssembly. - * @param {Uint8Array} k - 64-character private key hex string - * @returns Promise for 64-character public key hex string - */ -export async function deriveAsync (privateKey: Uint8Array): Promise> -/** - * Asynchronous Nano public key derivation using WebAssembly. - * @param {string} k - 64-character private key hex string - * @returns Promise for 64-character public key hex string - */ -export async function deriveAsync (privateKey: string): Promise -export async function deriveAsync (privateKey: string | Uint8Array): Promise> { - return run({ action: 'derive', privateKey }) -} - -/** - * Asynchronous signing using WebAssembly. To sign Nano blocks, the message - * should be a 64-character block hash. - * @param {Uint8Array} m - Variable-length message hex string up to 65536 characters - * @param {Uint8Array} k - 128-character secret key (prv + pub) hex string - * @returns Promise for 128-character detached signature hex string - */ -export async function signAsync (message: Uint8Array, secretKey: Uint8Array): Promise> -/** - * Asynchronous signing using WebAssembly. To sign Nano blocks, the message - * should be a 64-character block hash. - * @param {Uint8Array} m - Variable-length message hex string up to 65536 characters - * @param {Uint8Array} k - 128-character secret key (prv + pub) hex string - * @returns Promise for 128-character detached signature hex string - */ -export async function signAsync (message: string, secretKey: string): Promise -export async function signAsync (message: string | Uint8Array, secretKey: string | Uint8Array): Promise> { - return run({ action: 'sign', message, secretKey }) -} - -/** - * Asynchronous signature verification using WebAssembly. To verify Nano block - * signatures, the message should be a 64-character block hash. - * @param {Uint8Array} s - 128-character detached signature hex string - * @param {Uint8Array} m - Variable-length message hex string to up 65536 characters - * @param {Uint8Array} k - 64-character public key hex string - * @returns Promise resolving to true if signature matches block hash and public key, else false - */ -export async function verifyAsync (signature: Uint8Array, message: Uint8Array, publicKey: Uint8Array): Promise -/** - * Asynchronous signature verification using WebAssembly. To verify Nano block - * signatures, the message should be a 64-character block hash. - * @param {Uint8Array} s - 128-character detached signature hex string - * @param {Uint8Array} m - Variable-length message hex string to up 65536 characters - * @param {Uint8Array} k - 64-character public key hex string - * @returns Promise resolving to true if signature matches block hash and public key, else false - */ -export async function verifyAsync (signature: string, message: string, publicKey: string): Promise -export async function verifyAsync (signature: string | Uint8Array, message: string | Uint8Array, publicKey: string | Uint8Array): Promise { - return !!(await run({ action: 'verify', signature, message, publicKey })) -} diff --git a/src/sync.ts b/src/sync.ts index 1125afb..0e2b3b6 100644 --- a/src/sync.ts +++ b/src/sync.ts @@ -1,7 +1,7 @@ //! SPDX-FileCopyrightText: 2026 Chris Duncan //! SPDX-License-Identifier: GPL-3.0-or-later -import { nano25519 } from "./nano25519" +import { nano25519 } from "./lib/nano25519" /** * Nano public key derivation using WebAssembly. diff --git a/tsconfig.json b/tsconfig.json index 4513fd8..b002923 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,7 +10,7 @@ "strict": true, "declaration": true, "emitDeclarationOnly": true, - "outDir": "dist", + "outDir": "types", "declarationMap": true, "lib": [ "DOM", @@ -24,6 +24,7 @@ ], "exclude": [ "assembly", + "build", "dist" ] } diff --git a/vectors.mjs b/vectors.mjs index 8f932de..b481c1a 100644 --- a/vectors.mjs +++ b/vectors.mjs @@ -16,7 +16,10 @@ export const NANO_ORG_VECTOR = { badSignature: '74BCC59DBA39A1E34A5F75F96D6DE9154E3477AAD7DE30EA563DFCFE501A804215d484f5f757b4b7a9f4fcb2057fa423f76732c3a74b0fec5b0dd67b574a5910' } -// https://github.com/Matoking/python-ed25519-blake2b/blob/master/kat-ed25519-blake2b.txt +/** + * Test vectors derived from "python-ed25519-blake2b" by Janne Pulkkinen. + * https://github.com/Matoking/python-ed25519-blake2b + */ export const PYTHON_ED25519_BLAKE2B_VECTORS = [ { privateKey: '9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60', -- 2.47.3