From 1f36c56af6f305fd0249ae3c3e902ccf10d8b13e Mon Sep 17 00:00:00 2001 From: Chris Duncan Date: Tue, 15 Jul 2025 12:36:05 -0700 Subject: [PATCH] Fix account derivation. Start extracting types to bespoke type definition file. --- package.json | 1 + src/lib/account.ts | 5 +++-- src/lib/blake2b.ts | 5 ++--- src/lib/rolodex.ts | 3 ++- src/lib/wallets/bip44-wallet.ts | 14 +++++++++----- src/lib/wallets/blake2b-wallet.ts | 5 +++-- src/lib/wallets/index.ts | 1 - src/lib/wallets/ledger-wallet.ts | 3 ++- src/lib/wallets/wallet.ts | 9 ++------- src/lib/workers/bip44-ckd.ts | 8 ++++---- src/lib/workers/index.ts | 8 -------- src/lib/workers/nano-nacl.ts | 2 +- src/lib/workers/queue.ts | 2 +- src/lib/workers/safe.ts | 7 +------ src/lib/workers/worker-interface.ts | 3 ++- src/types.d.ts | 25 +++++++++++++++++++++++++ 16 files changed, 58 insertions(+), 43 deletions(-) create mode 100644 src/types.d.ts diff --git a/package.json b/package.json index e166e50..186d89d 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "imports": { "#dist/*": "./dist/*", "#src/*": "./src/*", + "#types": "./src/types.d.ts", "#workers": "./src/lib/workers/index.js" }, "dependencies": { diff --git a/src/lib/account.ts b/src/lib/account.ts index afeb38b..e9706f7 100644 --- a/src/lib/account.ts +++ b/src/lib/account.ts @@ -137,10 +137,10 @@ export class Account { method: 'convert' } const data = { - privateKey: privateKey.buffer + privateKey: new Uint8Array(privateKey).buffer } const result = await NanoNaClWorker.add(headers, data) - publicKey = bytes.toHex(new Uint8Array(result.publicKey)) + publicKey = result[0] } catch (err) { throw new Error(`Failed to derive public key from private key`, { cause: err }) } @@ -242,6 +242,7 @@ export class Account { if (id == null || id !== this.#pub) { throw null } + debugger this.#prv.set(obj.toBytes(privateKey)) } catch (err) { console.error(`Failed to unlock account ${this.address}`, err) diff --git a/src/lib/blake2b.ts b/src/lib/blake2b.ts index 4622813..b9e25df 100644 --- a/src/lib/blake2b.ts +++ b/src/lib/blake2b.ts @@ -1,6 +1,8 @@ // SPDX-FileCopyrightText: 2025 Chris Duncan // SPDX-License-Identifier: GPL-3.0-or-later AND ISC +import { UnknownNumber, UnknownUint8Array } from "#types" + /** * Implementation derived from blake2b@2.1.4. Copyright 2017 Emil Bay * (https://github.com/emilbayes/blake2b). See LICENSES/ISC.txt @@ -11,9 +13,6 @@ * Original source commit: https://github.com/emilbayes/blake2b/blob/1f63e02e3f226642959506cdaa67c8819ff145cd/index.js */ -type UnknownNumber = number | unknown -type UnknownUint8Array = Uint8Array | unknown - export class Blake2b { static get OUTBYTES_MIN (): 1 { return 1 } static get OUTBYTES_MAX (): 64 { return 64 } diff --git a/src/lib/rolodex.ts b/src/lib/rolodex.ts index 203f4a2..aa72f70 100644 --- a/src/lib/rolodex.ts +++ b/src/lib/rolodex.ts @@ -3,7 +3,8 @@ import { Account } from './account' -type RolodexEntry = { + +export type RolodexEntry = { name: string account: Account } diff --git a/src/lib/wallets/bip44-wallet.ts b/src/lib/wallets/bip44-wallet.ts index 3a49d34..69a2316 100644 --- a/src/lib/wallets/bip44-wallet.ts +++ b/src/lib/wallets/bip44-wallet.ts @@ -1,11 +1,12 @@ // SPDX-FileCopyrightText: 2025 Chris Duncan // SPDX-License-Identifier: GPL-3.0-or-later -import { KeyPair, Wallet } from '.' +import { Wallet } from '.' import { Bip39Mnemonic } from '#src/lib/bip39-mnemonic.js' import { SEED_LENGTH_BIP44 } from '#src/lib/constants.js' -import { hex, utf8 } from '#src/lib/convert.js' +import { bytes, hex, utf8 } from '#src/lib/convert.js' import { Entropy } from '#src/lib/entropy.js' +import { KeyPair } from '#types' import { Bip44CkdWorker } from '#workers' /** @@ -216,11 +217,14 @@ export class Bip44Wallet extends Wallet { const data = { seed: hex.toBytes(this.seed).buffer } - const privateKeys: KeyPair[] = await Bip44CkdWorker.add(headers, data) - for (let i = 0; i < privateKeys.length; i++) { - if (privateKeys[i].privateKey == null) { + const results = (await Bip44CkdWorker.add(headers, data))[0] + const privateKeys: KeyPair[] = [] + for (const i of Object.keys(results)) { + if (results[i] == null || !(results[i] instanceof ArrayBuffer)) { throw new Error('Failed to derive private keys') } + const keyBytes = new Uint8Array(results[i]) + privateKeys.push({ index: +i, privateKey: bytes.toHex(keyBytes) }) } return privateKeys } diff --git a/src/lib/wallets/blake2b-wallet.ts b/src/lib/wallets/blake2b-wallet.ts index 462750d..178d474 100644 --- a/src/lib/wallets/blake2b-wallet.ts +++ b/src/lib/wallets/blake2b-wallet.ts @@ -1,12 +1,13 @@ // SPDX-FileCopyrightText: 2025 Chris Duncan // SPDX-License-Identifier: GPL-3.0-or-later -import { KeyPair, Wallet } from '.' +import { Wallet } from '.' import { Bip39Mnemonic } from '#src/lib/bip39-mnemonic.js' import { Blake2b } from '#src/lib/blake2b.js' import { SEED_LENGTH_BLAKE2B } from '#src/lib/constants.js' -import { bytes, hex, utf8 } from '#src/lib/convert.js' +import { hex, utf8 } from '#src/lib/convert.js' import { Entropy } from '#src/lib/entropy.js' +import { KeyPair } from '#types' /** * BLAKE2b wallet created by deriving a mnemonic phrase from a seed or vice diff --git a/src/lib/wallets/index.ts b/src/lib/wallets/index.ts index 24452fb..d1bc77c 100644 --- a/src/lib/wallets/index.ts +++ b/src/lib/wallets/index.ts @@ -1,7 +1,6 @@ // SPDX-FileCopyrightText: 2025 Chris Duncan // SPDX-License-Identifier: GPL-3.0-or-later -export type { KeyPair } from './wallet' export { Wallet } from './wallet' export { Bip44Wallet } from './bip44-wallet' export { Blake2bWallet } from './blake2b-wallet' diff --git a/src/lib/wallets/ledger-wallet.ts b/src/lib/wallets/ledger-wallet.ts index 2401659..feb0545 100644 --- a/src/lib/wallets/ledger-wallet.ts +++ b/src/lib/wallets/ledger-wallet.ts @@ -5,12 +5,13 @@ import { ledgerUSBVendorId } from '@ledgerhq/devices' import { default as TransportBLE } from '@ledgerhq/hw-transport-web-ble' import { default as TransportUSB } from '@ledgerhq/hw-transport-webusb' import { default as TransportHID } from '@ledgerhq/hw-transport-webhid' -import { KeyPair, Wallet } from '.' +import { Wallet } from '.' import { ChangeBlock, ReceiveBlock, SendBlock } from '#src/lib/block.js' import { BIP44_COIN_NANO, BIP44_PURPOSE, HARDENED_OFFSET, LEDGER_ADPU_CODES, LEDGER_STATUS_CODES } from '#src/lib/constants.js' import { bytes, dec, hex } from '#src/lib/convert.js' import { Entropy } from '#src/lib/entropy.js' import { Rpc } from '#src/lib/rpc.js' +import { KeyPair } from '#types' type DeviceStatus = 'DISCONNECTED' | 'BUSY' | 'LOCKED' | 'CONNECTED' diff --git a/src/lib/wallets/wallet.ts b/src/lib/wallets/wallet.ts index 4834b5a..fec4e39 100644 --- a/src/lib/wallets/wallet.ts +++ b/src/lib/wallets/wallet.ts @@ -7,13 +7,8 @@ import { ADDRESS_GAP } from '#src/lib/constants.js' import { bytes, utf8 } from '#src/lib/convert.js' import { Entropy } from '#src/lib/entropy.js' import { Rpc } from '#src/lib/rpc.js' -import { Data, SafeWorker } from '#workers' - -export type KeyPair = { - publicKey?: string, - privateKey?: string, - index?: number -} +import { Data, KeyPair } from '#types' +import { SafeWorker } from '#workers' /** * Represents a wallet containing numerous Nano accounts derived from a single diff --git a/src/lib/workers/bip44-ckd.ts b/src/lib/workers/bip44-ckd.ts index 9b212c0..d5dd65c 100644 --- a/src/lib/workers/bip44-ckd.ts +++ b/src/lib/workers/bip44-ckd.ts @@ -1,8 +1,8 @@ // SPDX-FileCopyrightText: 2025 Chris Duncan // SPDX-License-Identifier: GPL-3.0-or-later -import { Data, Headers } from '.' import { WorkerInterface } from './worker-interface' +import { Data, Headers } from '#types' type ExtendedKey = { privateKey: DataView @@ -19,21 +19,21 @@ export class Bip44Ckd extends WorkerInterface { Bip44Ckd.listen() } - static async work (headers: Headers, data: Data): Promise { + static async work (headers: Headers, data: Data): Promise { let { coin, indexes } = headers let { seed } = data if (coin != null && (typeof coin !== 'number' || !Number.isInteger(coin))) { throw new TypeError('BIP-44 coin derivation level must be an integer') } if (!Array.isArray(indexes)) indexes = [indexes] - const privateKeys: ArrayBuffer[] = [] + const privateKeys: Data = {} for (const i of indexes) { if (typeof i !== 'number' || !Number.isInteger(i)) { throw new TypeError('BIP-44 account derivation level must be an integer') } try { const pk = await this.ckd(seed, coin, i) - privateKeys.push(pk) + privateKeys[i] = pk } catch (err) { console.log(err) } diff --git a/src/lib/workers/index.ts b/src/lib/workers/index.ts index e4143f0..e363171 100644 --- a/src/lib/workers/index.ts +++ b/src/lib/workers/index.ts @@ -1,12 +1,4 @@ // SPDX-FileCopyrightText: 2025 Chris Duncan // SPDX-License-Identifier: GPL-3.0-or-later -export type Data = { - [key: string]: ArrayBuffer -} - -export type Headers = { - [key: string]: any -} - export { Bip44CkdWorker, NanoNaClWorker, SafeWorker } from './queue' diff --git a/src/lib/workers/nano-nacl.ts b/src/lib/workers/nano-nacl.ts index b90a644..8edf1f9 100644 --- a/src/lib/workers/nano-nacl.ts +++ b/src/lib/workers/nano-nacl.ts @@ -3,10 +3,10 @@ 'use strict' -import { Data, Headers } from '.' import { WorkerInterface } from './worker-interface' import { Blake2b } from '#src/lib/blake2b.js' import { default as Convert, bytes, hex } from '#src/lib/convert.js' +import { Data, Headers } from '#types' /** * Ported in 2014 by Dmitry Chestnykh and Devi Mandiri. diff --git a/src/lib/workers/queue.ts b/src/lib/workers/queue.ts index 09b3f2a..d8a6d26 100644 --- a/src/lib/workers/queue.ts +++ b/src/lib/workers/queue.ts @@ -1,10 +1,10 @@ // SPDX-FileCopyrightText: 2025 Chris Duncan // SPDX-License-Identifier: GPL-3.0-or-later -import { Data, Headers } from '.' import { default as bip44 } from './bip44-ckd' import { default as nacl } from './nano-nacl' import { default as safe } from './safe' +import { Data, Headers } from '#types' type Task = { id: number diff --git a/src/lib/workers/safe.ts b/src/lib/workers/safe.ts index ece1735..2bb00c5 100644 --- a/src/lib/workers/safe.ts +++ b/src/lib/workers/safe.ts @@ -3,15 +3,10 @@ 'use strict' -import { Data, Headers } from '.' import { WorkerInterface } from './worker-interface' import { default as Convert, bytes } from '#src/lib/convert.js' import { Entropy } from '#src/lib/entropy.js' - -type SafeRecord = { - iv: string - data: Data -} +import { Data, Headers, SafeRecord } from '#types' /** * Encrypts and stores data in the browser using IndexedDB. diff --git a/src/lib/workers/worker-interface.ts b/src/lib/workers/worker-interface.ts index 5fa0560..c915760 100644 --- a/src/lib/workers/worker-interface.ts +++ b/src/lib/workers/worker-interface.ts @@ -1,7 +1,8 @@ // SPDX-FileCopyrightText: 2025 Chris Duncan // SPDX-License-Identifier: GPL-3.0-or-later -import { Data, Headers } from '.' +import { Data, Headers } from '#types' + /** * Provides basic worker event messaging to extending classes. * diff --git a/src/types.d.ts b/src/types.d.ts new file mode 100644 index 0000000..7a360ae --- /dev/null +++ b/src/types.d.ts @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: 2025 Chris Duncan +// SPDX-License-Identifier: GPL-3.0-or-later + +export type Data = { + [key: string]: ArrayBuffer +} + +export type Headers = { + [key: string]: any +} + +export type KeyPair = { + publicKey?: string, + privateKey?: string, + index?: number +} + +export type SafeRecord = { + iv: string + data: Data +} + +export type UnknownNumber = number | unknown + +export type UnknownUint8Array = Uint8Array | unknown -- 2.47.3