From: Chris Duncan Date: Mon, 4 Aug 2025 21:55:24 +0000 (-0700) Subject: Refactor BIP-44 to allow additional chain and address parameters, allowing Nano which... X-Git-Tag: v0.10.5~46^2~6 X-Git-Url: https://git.codecow.com/?a=commitdiff_plain;h=5cdfaf37acd26bccd85745abb853173497675405;p=libnemo.git Refactor BIP-44 to allow additional chain and address parameters, allowing Nano which uses neither to still resolve. --- diff --git a/src/lib/bip44-ckd.ts b/src/lib/bip44-ckd.ts index 5377a64..82bfdc3 100644 --- a/src/lib/bip44-ckd.ts +++ b/src/lib/bip44-ckd.ts @@ -1,39 +1,40 @@ //! SPDX-FileCopyrightText: 2025 Chris Duncan //! SPDX-License-Identifier: GPL-3.0-or-later +import { BIP44_PURPOSE, HARDENED_OFFSET, SLIP10_ED25519 } from './constants' + type ExtendedKey = { privateKey: DataView chainCode: DataView } export class Bip44Ckd { - static BIP44_COIN_NANO = 165 - static BIP44_PURPOSE = 44 - static HARDENED_OFFSET = 0x80000000 - static SLIP10_ED25519 = 'ed25519 seed' - /** * Derives a private child key for a coin by following the specified BIP-32 and * BIP-44 derivation path. Purpose is always 44'. Only hardened child keys are * defined. * * @param {ArrayBuffer} seed - Hexadecimal seed derived from mnemonic phrase - * @param {number} index - Account number between 0 and 2^31-1 - * @param {number} coin - Number registered to a specific coin in SLIP-044. Default: 165 (Nano) + * @param {number} coin - Number registered to a specific coin in SLIP-044 + * @param {number} account - Account number between 0 and 2^31-1 * @returns {Promise} Private child key for the account */ - static async ckd (seed: ArrayBuffer, index: number, coin: number = this.BIP44_COIN_NANO): Promise { + static async ckd (seed: ArrayBuffer, coin: number, account: number, chain?: number, address?: number): Promise { if (seed.byteLength < 16 || seed.byteLength > 64) { throw new RangeError(`Invalid seed length`) } - if (!Number.isSafeInteger(index) || index < 0 || index > 0x7fffffff) { - throw new RangeError(`Invalid child key index 0x${index.toString(16)}`) + if (!Number.isSafeInteger(account) || account < 0 || account > 0x7fffffff) { + throw new RangeError(`Invalid child key index 0x${account.toString(16)}`) } - const masterKey = await this.slip10(this.SLIP10_ED25519, seed) - const purposeKey = await this.CKDpriv(masterKey, this.BIP44_PURPOSE + this.HARDENED_OFFSET) - const coinKey = await this.CKDpriv(purposeKey, coin + this.HARDENED_OFFSET) - const accountKey = await this.CKDpriv(coinKey, index + this.HARDENED_OFFSET) - return accountKey.privateKey.buffer + const masterKey = await this.slip10(SLIP10_ED25519, seed) + const purposeKey = await this.CKDpriv(masterKey, BIP44_PURPOSE + HARDENED_OFFSET) + const coinKey = await this.CKDpriv(purposeKey, coin + HARDENED_OFFSET) + const accountKey = await this.CKDpriv(coinKey, account + HARDENED_OFFSET) + if (chain == null) return accountKey.privateKey.buffer + const chainKey = await this.CKDpriv(accountKey, chain) + if (address == null) return chainKey.privateKey.buffer + const addressKey = await this.CKDpriv(chainKey, address) + return addressKey.privateKey.buffer } static async slip10 (curve: string, S: ArrayBuffer): Promise { diff --git a/src/lib/safe.ts b/src/lib/safe.ts index 9838fc9..81e7516 100644 --- a/src/lib/safe.ts +++ b/src/lib/safe.ts @@ -145,7 +145,7 @@ export class Safe { throw new Error('Invalid wallet account index') } const prv = this.#type === 'BIP-44' - ? await Bip44Ckd.ckd(this.#seed, index) + ? await Bip44Ckd.ckd(this.#seed, BIP44_COIN_NANO, index) : await Blake2bCkd.ckd(this.#seed, index) const pub = await NanoNaCl.convert(new Uint8Array(prv)) return { index, publicKey: pub.buffer } @@ -233,7 +233,7 @@ export class Safe { if (data == null) { throw new Error('Data to sign not found') } - const prv = await Bip44Ckd.ckd(this.#seed, index) + const prv = await Bip44Ckd.ckd(this.#seed, BIP44_COIN_NANO, index) const sig = await NanoNaCl.detached(new Uint8Array(data), new Uint8Array(prv)) return { signature: sig.buffer } } catch (err) {