if (!Number.isSafeInteger(account) || account < 0 || account > 0x7fffffff) {
throw new RangeError(`Invalid account index 0x${account.toString(16)}`)
}
- if (change != null && (!Number.isSafeInteger(change) || change < 0 || change > 1)) {
+ if (change !== undefined && (!Number.isSafeInteger(change) || change < 0 || change > 1)) {
throw new RangeError(`Invalid change index 0x${account.toString(16)}`)
}
- if (address != null && (!Number.isSafeInteger(address) || address < 0 || address > 0x7fffffff)) {
+ if (address !== undefined && (!Number.isSafeInteger(address) || address < 0 || address > 0x7fffffff)) {
throw new RangeError(`Invalid address index 0x${account.toString(16)}`)
}
- return this.#slip10(SLIP10_ED25519, seed)
- .then(masterKey => {
- return this.#CKDpriv(masterKey, BIP44_PURPOSE + HARDENED_OFFSET)
- .then(purposeKey => {
- return this.#CKDpriv(purposeKey, coin + HARDENED_OFFSET)
- .then(coinKey => {
- return this.#CKDpriv(coinKey, account + HARDENED_OFFSET)
- .then(accountKey => {
- if (change == null) return accountKey.privateKey
- return this.#CKDpriv(accountKey, change + HARDENED_OFFSET)
- .then(chainKey => {
- if (address == null) return chainKey.privateKey
- return this.#CKDpriv(chainKey, address + HARDENED_OFFSET)
- .then(addressKey => {
- return addressKey.privateKey
- })
- })
- })
- })
- })
- })
+ return this.slip10(SLIP10_ED25519, seed)
+ .then(masterKey => this.CKDpriv(masterKey, BIP44_PURPOSE))
+ .then(purposeKey => this.CKDpriv(purposeKey, coin))
+ .then(coinKey => this.CKDpriv(coinKey, account))
+ .then(accountKey => this.CKDpriv(accountKey, change))
+ .then(chainKey => this.CKDpriv(chainKey, address))
+ .then(addressKey => addressKey.privateKey)
}
- static #slip10 (curve: string, S: ArrayBuffer): Promise<ExtendedKey> {
+ static slip10 (curve: string, S: ArrayBuffer): Promise<ExtendedKey> {
const key = new Uint8Array(new TextEncoder().encode(curve))
const data = new Uint8Array(S)
- return this.#hmac(key, data)
+ return this.hmac(key, data)
.then(I => {
const IL = I.slice(0, I.byteLength / 2)
const IR = I.slice(I.byteLength / 2)
})
}
- static #CKDpriv ({ privateKey, chainCode }: ExtendedKey, index: number): Promise<ExtendedKey> {
+ static CKDpriv ({ privateKey, chainCode }: ExtendedKey, index?: number): Promise<ExtendedKey> {
+ if (index === undefined) {
+ return Promise.resolve({ privateKey, chainCode })
+ }
+ index += HARDENED_OFFSET
const key = new Uint8Array(chainCode)
const data = new Uint8Array(37)
data.set([0])
- data.set(this.#ser256(privateKey), 1)
- data.set(this.#ser32(index), 33)
- return this.#hmac(key, data)
+ data.set(this.ser256(privateKey), 1)
+ data.set(this.ser32(index), 33)
+ return this.hmac(key, data)
.then(I => {
const IL = I.slice(0, I.byteLength / 2)
const IR = I.slice(I.byteLength / 2)
})
}
- static #ser32 (integer: number): Uint8Array<ArrayBuffer> {
+ static ser32 (integer: number): Uint8Array<ArrayBuffer> {
const view = new DataView(new ArrayBuffer(4))
view.setUint32(0, integer, false)
return new Uint8Array(view.buffer)
}
- static #ser256 (integer: ArrayBuffer): Uint8Array<ArrayBuffer> {
+ static ser256 (integer: ArrayBuffer): Uint8Array<ArrayBuffer> {
return new Uint8Array(integer)
}
- static #hmac (key: Uint8Array<ArrayBuffer>, data: Uint8Array<ArrayBuffer>): Promise<ArrayBuffer> {
+ static hmac (key: Uint8Array<ArrayBuffer>, data: Uint8Array<ArrayBuffer>): Promise<ArrayBuffer> {
return crypto.subtle.importKey('raw', key, { name: 'HMAC', hash: 'SHA-512' }, false, ['sign'])
.then(pk => {
return crypto.subtle.sign('HMAC', pk, data)