// SPDX-License-Identifier: GPL-3.0-or-later
type ExtendedKey = {
- privateKey: string
- chainCode: string
+ privateKey: DataView
+ chainCode: DataView
}
async function ckdBip44 () {
const BIP44_PURPOSE = 44
const HARDENED_OFFSET = 0x80000000
const SLIP10_ED25519 = 'ed25519 seed'
- let bytes: any
- let hex: any
let addEventListener = globalThis.addEventListener
let postMessage = globalThis.postMessage
if (addEventListener == null || postMessage == null) {
- ({ bytes, hex } = await import(new URL('./dist/lib/convert.js', import.meta.url).toString()))
const { isMainThread, parentPort } = await import('node:worker_threads')
if (!isMainThread && parentPort) {
addEventListener = Object.getPrototypeOf(parentPort).addListener.bind(parentPort)
* @returns Private child key for the account
*/
async function nanoCKD (seed: string, index: number): Promise<string> {
+ if (seed.length < 32 || seed.length > 128) {
+ 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)}`)
}
const purposeKey = await CKDpriv(masterKey, BIP44_PURPOSE + HARDENED_OFFSET)
const coinKey = await CKDpriv(purposeKey, BIP44_COIN_NANO + HARDENED_OFFSET)
const accountKey = await CKDpriv(coinKey, index + HARDENED_OFFSET)
- return accountKey.privateKey
+ const privateKey = new Uint8Array(accountKey.privateKey.buffer)
+ return privateKey.reduce((key, byte) => key.concat(byte.toString(16).padStart(2, '0')), '')
}
async function slip10 (curve: string, S: string): Promise<ExtendedKey> {
const key = new TextEncoder().encode(curve)
- const data = hex.toBytes(S)
+ const data = new Uint8Array(64)
+ data.set(S.match(/.{1,2}/g)!.map(byte => parseInt(byte, 16)))
const I = await hmac(key, data)
- const IL = I.slice(0, I.length / 2)
- const IR = I.slice(I.length / 2)
+ const IL = new DataView(I.buffer.slice(0, I.length / 2))
+ const IR = new DataView(I.buffer.slice(I.length / 2))
return ({ privateKey: IL, chainCode: IR })
}
async function CKDpriv ({ privateKey, chainCode }: ExtendedKey, index: number): Promise<ExtendedKey> {
- const key = hex.toBytes(chainCode)
- const data = hex.toBytes(`00${bytes.toHex(ser256(privateKey))}${bytes.toHex(ser32(index))}`)
+ const key = new Uint8Array(chainCode.buffer)
+ const data = new Uint8Array(37)
+ data.set([0])
+ data.set(ser256(privateKey), 1)
+ data.set(ser32(index), 33)
const I = await hmac(key, data)
- const IL = I.slice(0, I.length / 2)
- const IR = I.slice(I.length / 2)
+ const IL = new DataView(I.buffer.slice(0, I.length / 2))
+ const IR = new DataView(I.buffer.slice(I.length / 2))
return ({ privateKey: IL, chainCode: IR })
}
return new Uint8Array(view.buffer)
}
- function ser256 (integer: string): Uint8Array {
- if (typeof integer !== 'string') {
- throw new TypeError(`Expected string, received ${typeof integer}`)
+ function ser256 (integer: DataView): Uint8Array {
+ if (integer.constructor !== DataView) {
+ throw new TypeError(`Expected DataView, received ${typeof integer}`)
}
- const bits = hex.toBin(integer)
- if (bits.length > 256) {
- throw new RangeError(`Expected 256-bit integer, received ${bits.length}-bit value: ${integer}`)
+ if (integer.byteLength > 32) {
+ throw new RangeError(`Expected 32-byte integer, received ${integer.byteLength}-byte value: ${integer}`)
}
- return hex.toBytes(integer, 32)
+ return new Uint8Array(integer.buffer)
}
- async function hmac (key: Uint8Array, data: Uint8Array): Promise<string> {
+ async function hmac (key: Uint8Array, data: Uint8Array): Promise<Uint8Array> {
const { subtle } = globalThis.crypto
const pk = await subtle.importKey('raw', key, { name: 'HMAC', hash: 'SHA-512' }, false, ['sign'])
const signature = await subtle.sign('HMAC', pk, data)
- return bytes.toHex(new Uint8Array(signature))
+ return new Uint8Array(signature)
}
}
const ckdBip44Worker = `(${ckdBip44.toString()})()`
-// const ckdBip44Worker = `data:text/javascript,(${ckdBip44.toString()})()`
export { ckdBip44Worker }