//! SPDX-License-Identifier: GPL-3.0-or-later
import { ALPHABET, HEXCHAR } from '../constants'
-import { decode } from '../tools'
+
+const decoder = Object.freeze(new TextDecoder())
export const bytes = Object.freeze({
/**
* @returns {string} UTF-8 encoded text string
*/
toUtf8 (bytes: Bytes): string {
- return decode(bytes)
+ return decoder.decode(bytes)
},
})
//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
//! SPDX-License-Identifier: GPL-3.0-or-later
-import { encode } from '../tools'
import { bytes } from './bytes'
+const encoder = Object.freeze(new TextEncoder())
+
export const utf8 = Object.freeze({
/**
* Convert a UTF-8 text string to an ArrayBuffer.
* @returns {Uint8Array} Byte array representation of the input string
*/
toBytes (utf8: string): Bytes {
- return encode(utf8)
+ return encoder.encode(utf8)
},
/**
//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>\r
//! SPDX-License-Identifier: GPL-3.0-or-later\r
\r
-import { bytes } from '../convert'\r
-import { encode } from '../tools'\r
+import { bytes, utf8 } from '../convert'\r
import { wordlist } from './wordlist'\r
\r
/**\r
return Promise.resolve(seed)\r
} else {\r
const salt = (typeof passphrase === 'string') ? passphrase : ''\r
- const keyData = encode(this.phrase)\r
+ const keyData = utf8.toBuffer(this.phrase)\r
return crypto.subtle.importKey('raw', keyData, 'PBKDF2', false, ['deriveBits', 'deriveKey'])\r
.then(phraseKey => {\r
const algorithm: Pbkdf2Params = {\r
name: 'PBKDF2',\r
hash: 'SHA-512',\r
- salt: encode(`mnemonic${salt.normalize('NFKD')}`),\r
+ salt: utf8.toBuffer(`mnemonic${salt.normalize('NFKD')}`),\r
iterations: 2048\r
}\r
return crypto.subtle.deriveBits(algorithm, phraseKey, 512)\r
//! SPDX-License-Identifier: GPL-3.0-or-later
import { Point, getPublicKey as secp256k1_getPublicKey } from '@noble/secp256k1'
-import { dec } from '../convert'
-import { encode } from '../tools'
+import { dec, utf8 } from '../convert'
type Curve = 'Bitcoin seed' | 'ed25519 seed'
type ExtendedKey = {
}
function slip10 (curve: string, S: ArrayBuffer): Promise<ExtendedKey> {
- const key = encode(curve).buffer
+ const key = utf8.toBuffer(curve)
const data = S
return hmac(key, data)
.then(I => {
//! SPDX-FileCopyrightText: 2025 Chris Duncan <chris@codecow.com>
//! SPDX-License-Identifier: GPL-3.0-or-later
-import { encode } from "../tools"
+import { utf8 } from "../convert"
+
export class WalletAesGcm {
static decrypt (type: string, key: CryptoKey, iv: ArrayBuffer, encrypted: ArrayBuffer): Promise<Record<string, ArrayBuffer>> {
const seedLength = type === 'BLAKE2b' ? 32 : 64
- const additionalData = encode(type)
+ const additionalData = utf8.toBuffer(type)
return crypto.subtle
.decrypt({ name: 'AES-GCM', iv, additionalData }, key, encrypted)
.then(decrypted => {
}
// restrict iv to 96 bits per GCM best practice
const iv = crypto.getRandomValues(new Uint8Array(12)).buffer
- const additionalData = encode(type)
+ const additionalData = utf8.toBuffer(type)
const encoded = new Uint8Array([...new Uint8Array(seed), ...new Uint8Array(mnemonic ?? [])])
return crypto.subtle
.encrypt({ name: 'AES-GCM', iv, additionalData }, key, encoded)
import { TransportStatusError } from '@ledgerhq/errors'
import { APDU_CODES, LISTEN_TIMEOUT, LedgerResponse, LedgerTransport, OPEN_TIMEOUT, STATUS_CODES } from '.'
-import { bytes } from '../convert'
-import { encode } from '../tools'
+import { bytes, utf8 } from '../convert'
export async function _open (transport: LedgerTransport): Promise<LedgerResponse> {
- const name = encode('Nano')
+ const name = utf8.toBytes('Nano')
const t = await transport.create(OPEN_TIMEOUT, LISTEN_TIMEOUT)
const response = await t
.send(0xe0, 0xd8, APDU_CODES.paramUnused, APDU_CODES.paramUnused, name as Buffer)
message: string
}
-/**
- * Decodes bytes to a UTF-8 string.
- *
- * @param {AllowSharedBufferSource} [input]
- * @param {TextDecodeOptions} [options]
- * @returns {string} Decoded string
- */
-export function decode (input?: AllowSharedBufferSource, options?: TextDecodeOptions): string {
- return decoder.decode(input, options)
-}
-
-/**
- * Encodes a UTF-8 string to bytes.
- *
- * @param {string} [input]
- * @returns {Bytes} Encoded bytes
- */
-export function encode (input?: string): Bytes {
- return encoder.encode(input)
-}
-
/**
* Converts a decimal amount of nano from one unit divider to another.
*
? new Uint8Array(input.slice())
: input
}
-
-const decoder = Object.freeze(new TextDecoder())
-const encoder = Object.freeze(new TextEncoder())
import { derive as nano25519_derive, sign as nano25519_sign } from 'nano25519/sync'
import { parentPort, threadId } from 'node:worker_threads'
import { BIP44_COIN_NANO } from '../constants'
-import { dec } from '../convert'
+import { dec, utf8 } from '../convert'
import { Bip39, Bip44, Blake2b, WalletAesGcm } from '../crypto'
-import { encode } from '../tools'
import { WalletType } from '../wallet'
import { parseAction, parseData, parseIv, parseKeySalt, parseType } from './parsers'
import { Passkey } from './passkey'
}
if (mnemonicPhrase != null) {
let diff = 0
- const userMnemonic = encode(mnemonicPhrase)
+ const userMnemonic = utf8.toBytes(mnemonicPhrase)
const thisMnemonic = new Uint8Array(_mnemonic ?? [])
for (let i = 0; i < userMnemonic.byteLength; i++) {
diff |= userMnemonic[i] ^ thisMnemonic[i]
if (type === 'BLAKE2b') {
seed = Bip39.fromEntropy(new Uint8Array(secret))
.then(bip39 => {
- _mnemonic = new Uint8Array(encode(bip39.phrase ?? '')).buffer
+ _mnemonic = utf8.toBuffer(bip39.phrase ?? '')
return secret
})
} else {
} else {
seed = Bip39.fromPhrase(secret)
.then(bip39 => {
- _mnemonic = new Uint8Array(encode(bip39.phrase ?? '')).buffer
+ _mnemonic = utf8.toBuffer(bip39.phrase ?? '')
const derive = type === 'BLAKE2b'
? Promise.resolve(bip39.toBlake2bSeed())
: bip39.toBip39Seed(mnemonicSalt ?? '')