static #locked: boolean = true
static #type?: 'BIP-44' | 'BLAKE2b'
static #seed?: ArrayBuffer
- static #mnemonic?: string
+ static #mnemonic?: ArrayBuffer
static #parentPort?: any
static {
NODE: this.#parentPort = parentPort
if (this.#seed == null || this.#mnemonic == null) {
throw new Error('Failed to generate seed and mnemonic')
}
- return { ...record, seed: this.#seed.slice(), mnemonic: utf8.toBuffer(this.#mnemonic) }
+ return { ...record, seed: this.#seed.slice(), mnemonic: this.#mnemonic.slice() }
} catch (err) {
throw new Error('Failed to create wallet', { cause: err })
} finally {
if (!(this.#seed instanceof ArrayBuffer)) {
throw new TypeError('Invalid seed')
}
- if (this.#mnemonic != null && typeof this.#mnemonic !== 'string') {
- throw new TypeError('Invalid seed')
+ if (this.#mnemonic != null && !(this.#mnemonic instanceof ArrayBuffer)) {
+ throw new TypeError('Invalid mnemonic')
}
this.#locked = false
return { isUnlocked: !this.#locked }
let diff = 0
const userSeed = new Uint8Array(seed)
const thisSeed = new Uint8Array(this.#seed)
- for (let i = 0; i < seed.byteLength; i++) {
+ for (let i = 0; i < userSeed.byteLength; i++) {
diff |= userSeed[i] ^ thisSeed[i]
}
isVerified = diff === 0
}
- if (mnemonicPhrase != null && mnemonicPhrase === this.#mnemonic) {
- isVerified = true
+ if (mnemonicPhrase != null) {
+ let diff = 0
+ const userMnemonic = utf8.toBytes(mnemonicPhrase)
+ const thisMnemonic = new Uint8Array(this.#mnemonic ?? [])
+ for (let i = 0; i < userMnemonic.byteLength; i++) {
+ diff |= userMnemonic[i] ^ thisMnemonic[i]
+ }
+ isVerified = diff === 0
}
return { isVerified }
} catch (err) {
const additionalData = utf8.toBytes(type)
const decrypted = new Uint8Array(await crypto.subtle.decrypt({ name: 'AES-GCM', iv, additionalData }, key, encrypted))
this.#seed = decrypted.buffer.slice(0, seedLength)
- this.#mnemonic = bytes.toUtf8(decrypted.slice(seedLength))
+ this.#mnemonic = decrypted.buffer.slice(seedLength)
decrypted.fill(0)
}
throw new Error('Wallet seed not found')
}
const seed = new Uint8Array(this.#seed)
- const mnemonic = utf8.toBytes(this.#mnemonic ?? '')
+ const mnemonic = new Uint8Array(this.#mnemonic ?? [])
// restrict iv to 96 bits per GCM best practice
const iv = crypto.getRandomValues(new Uint8Array(12)).buffer
const additionalData = utf8.toBytes(this.#type)
if (secret instanceof ArrayBuffer) {
this.#seed = secret
if (type === 'BLAKE2b') {
- this.#mnemonic = (await Bip39.fromEntropy(new Uint8Array(secret))).phrase
+ this.#mnemonic = utf8.toBuffer((await Bip39.fromEntropy(new Uint8Array(secret))).phrase ?? '')
}
} else {
const mnemonic = await Bip39.fromPhrase(secret)
- this.#mnemonic = mnemonic.phrase
+ this.#mnemonic = utf8.toBuffer(mnemonic.phrase ?? '')
this.#seed = type === 'BIP-44'
? (await mnemonic.toBip39Seed(mnemonicSalt ?? '')).buffer
: (await mnemonic.toBlake2bSeed()).buffer