From aa8ffde9a5dce23eb66626c2bc4a78b41483cfe0 Mon Sep 17 00:00:00 2001 From: Chris Duncan Date: Fri, 27 Mar 2026 11:14:49 -0700 Subject: [PATCH] Swtich from internal NanoNaCl to nano25519 package. --- src/lib/account/index.ts | 4 ++-- src/lib/block.ts | 9 +++++---- src/lib/crypto/index.ts | 4 ++-- src/lib/tools.ts | 7 ++++--- src/lib/vault/vault-worker.ts | 14 +++++++++----- test/test.tools.mjs | 4 ++-- 6 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/lib/account/index.ts b/src/lib/account/index.ts index 7c780a9..cedc753 100644 --- a/src/lib/account/index.ts +++ b/src/lib/account/index.ts @@ -1,10 +1,10 @@ //! SPDX-FileCopyrightText: 2025 Chris Duncan //! SPDX-License-Identifier: GPL-3.0-or-later +import * as nano25519 from 'nano25519' import { Block } from '../block' import { ACCOUNT_KEY_BYTE_LENGTH, ACCOUNT_KEY_HEX_LENGTH } from '../constants' import { bytes, hex } from '../convert' -import { NanoNaCl } from '../crypto' import { Rpc } from '../rpc' import { Address } from './address' import { _refresh } from './refresh' @@ -302,7 +302,7 @@ export class Account { if (privateKey.byteLength !== ACCOUNT_KEY_BYTE_LENGTH) { throw new TypeError(`Private key must be ${ACCOUNT_KEY_BYTE_LENGTH} bytes`) } - const publicKey = await NanoNaCl.convert(privateKey) + const publicKey = nano25519.derive(privateKey) const address = new Address(publicKey) this.#isInternal = true const account = new this(address, publicKey, index) diff --git a/src/lib/block.ts b/src/lib/block.ts index e5cd617..4fa64f7 100644 --- a/src/lib/block.ts +++ b/src/lib/block.ts @@ -2,10 +2,11 @@ //! SPDX-License-Identifier: GPL-3.0-or-later import { NanoPow } from 'nano-pow' +import * as nano25519 from 'nano25519' import { Account } from './account' -import { BURN_PUBLIC_KEY, PREAMBLE, DIFFICULTY_RECEIVE, DIFFICULTY_SEND, UNITS } from './constants' +import { BURN_PUBLIC_KEY, DIFFICULTY_RECEIVE, DIFFICULTY_SEND, PREAMBLE, UNITS } from './constants' import { bytes, dec, hex } from './convert' -import { Blake2b, NanoNaCl } from './crypto' +import { Blake2b } from './crypto' import { Rpc } from './rpc' import { Tools } from './tools' import { Wallet } from './wallet' @@ -411,7 +412,7 @@ export class Block { return new Promise(async (resolve, reject) => { try { if (typeof input === 'string' && /^[A-F0-9]{64}$/i.test(input)) { - const signature = await NanoNaCl.detached(hex.toBytes(this.hash), hex.toBytes(input)) + const signature = nano25519.sign(hex.toBytes(this.hash), hex.toBytes(input)) this.signature = bytes.toHex(signature) } else if (input instanceof Wallet && typeof index === 'number' && (frontier === undefined || frontier instanceof (this.constructor as typeof Block)) @@ -443,7 +444,7 @@ export class Block { if (typeof key !== 'string') { throw new Error('Invalid key') } - return await NanoNaCl.verify(hex.toBytes(this.hash), hex.toBytes(this.signature ?? ''), hex.toBytes(key)) + return await nano25519.verify(hex.toBytes(this.signature ?? ''), hex.toBytes(this.hash), hex.toBytes(key)) } catch (err) { throw new Error('Failed to verify block signature', { cause: err }) } diff --git a/src/lib/crypto/index.ts b/src/lib/crypto/index.ts index c0f3d8c..127f952 100644 --- a/src/lib/crypto/index.ts +++ b/src/lib/crypto/index.ts @@ -4,8 +4,8 @@ import { Bip39 } from './bip39' import { Bip44 } from './bip44' import { Blake2b } from './blake2b' -import { NanoNaCl } from './nano-nacl' import { Secp256k1 } from './secp256k1' import { WalletAesGcm } from './wallet-aes-gcm' -export { Bip39, Bip44, Blake2b, NanoNaCl, Secp256k1, WalletAesGcm } +export { Bip39, Bip44, Blake2b, Secp256k1, WalletAesGcm } + diff --git a/src/lib/tools.ts b/src/lib/tools.ts index 59ca5d4..d93cbe2 100644 --- a/src/lib/tools.ts +++ b/src/lib/tools.ts @@ -1,11 +1,12 @@ //! SPDX-FileCopyrightText: 2025 Chris Duncan //! SPDX-License-Identifier: GPL-3.0-or-later +import * as nano25519 from 'nano25519' import { Account } from './account' import { Block } from './block' import { MAX_SUPPLY, UNITS } from './constants' import { bytes, hex } from './convert' -import { Blake2b, NanoNaCl } from './crypto' +import { Blake2b } from './crypto' import { Rpc } from './rpc' import { Wallet } from './wallet' @@ -140,7 +141,7 @@ export class Tools { static async sign (key: string | Uint8Array, ...input: string[]): Promise { if (typeof key === 'string') key = hex.toBytes(key) try { - const signature = await NanoNaCl.detached(this.hash(input), key) + const signature = nano25519.sign(this.hash(input), key) return bytes.toHex(signature) } catch (err) { throw new Error(`Failed to sign message with private key`, { cause: err }) @@ -218,7 +219,7 @@ export class Tools { static async verify (key: string | Uint8Array, signature: string, ...input: string[]): Promise { if (typeof key === 'string') key = hex.toBytes(key) try { - return await NanoNaCl.verify(this.hash(input), hex.toBytes(signature), key) + return nano25519.verify(hex.toBytes(signature), this.hash(input), key) } catch (err) { throw new Error('Failed to verify signature', { cause: err }) } finally { diff --git a/src/lib/vault/vault-worker.ts b/src/lib/vault/vault-worker.ts index 88a9b25..e813cd6 100644 --- a/src/lib/vault/vault-worker.ts +++ b/src/lib/vault/vault-worker.ts @@ -1,8 +1,9 @@ //! SPDX-FileCopyrightText: 2025 Chris Duncan //! SPDX-License-Identifier: GPL-3.0-or-later +import * as nano25519 from 'nano25519' import { BIP44_COIN_NANO } from '../constants' -import { Bip39, Bip44, Blake2b, NanoNaCl, WalletAesGcm } from '../crypto' +import { Bip39, Bip44, Blake2b, WalletAesGcm } from '../crypto' import { WalletType } from '../wallet' import { Passkey } from './passkey' import { VaultTimer } from './vault-timer' @@ -192,8 +193,9 @@ export class VaultWorker { : this.#type === 'Exodus' ? Bip44.ckd('Bitcoin seed', this.#seed, 0x100, index, 0, 0) : Blake2b.ckd(this.#seed, index) - return derive.then(prv => { - const pub = NanoNaCl.convert(new Uint8Array(prv)) + return derive.then(result => { + const prv = new Uint8Array(result) + const pub = nano25519.derive(prv) this.#timer = new VaultTimer(() => this.lock(), this.#timeout) return { index, publicKey: pub.buffer } }) @@ -258,8 +260,10 @@ export class VaultWorker { const derive = this.#type === 'BLAKE2b' ? Blake2b.ckd(this.#seed, index) : Bip44.ckd(this.#type === 'Exodus' ? 'Bitcoin seed' : 'ed25519 seed', this.#seed, BIP44_COIN_NANO, index) - return derive.then(prv => { - const sig = NanoNaCl.detached(new Uint8Array(data), new Uint8Array(prv)) + return derive.then(result => { + const prv = new Uint8Array(result) + const pub = nano25519.derive(prv) + const sig = nano25519.sign(new Uint8Array(data), new Uint8Array([...prv, ...pub])) this.#timer = new VaultTimer(() => this.lock(), this.#timeout) return { signature: sig.buffer } }) diff --git a/test/test.tools.mjs b/test/test.tools.mjs index 81ba67d..2965c1c 100644 --- a/test/test.tools.mjs +++ b/test/test.tools.mjs @@ -101,12 +101,12 @@ await Promise.all([ suite('signature tests', async () => { await test('should sign data with a single parameter', async () => { - const result = await Tools.sign(NANO_TEST_VECTORS.PRIVATE_0, 'miro@metsanheimo.fi') + const result = await Tools.sign(NANO_TEST_VECTORS.PRIVATE_0 + NANO_TEST_VECTORS.PUBLIC_0, 'miro@metsanheimo.fi') assert.equal(result, 'FECB9B084065ADC969904B55A0099C63746B68DF41FECB713244D387EED83A80B9D4907278C5EBC0998A5FC8BA597FBAAABBFCE0ABD2CA2212ACFE788637040C') }) await test('should sign data with multiple parameters', async () => { - const result = await Tools.sign(NANO_TEST_VECTORS.PRIVATE_0, 'miro@metsanheimo.fi', 'somePassword') + const result = await Tools.sign(NANO_TEST_VECTORS.PRIVATE_0 + NANO_TEST_VECTORS.PUBLIC_0, 'miro@metsanheimo.fi', 'somePassword') assert.equal(result, 'BB534F9B469AF451B1941FFEF8EE461FC5D284B5D393140900C6E13A65EF08D0AE2BC77131EE182922F66C250C7237A83878160457D5C39A70E55F7FCE925804') }) -- 2.47.3