"version": "0.0.19",
"license": "(GPL-3.0-or-later AND MIT)",
"dependencies": {
- "blake2b": "^2.1.4",
- "blake2b-wasm": "^2.4.0",
- "blakejs": "^1.2.1"
+ "blake2b": "^2.1.4"
},
"devDependencies": {
- "@types/blake2b-wasm": "^2.4.3",
+ "@types/blake2b": "^2.1.3",
"@types/node": "^22.8.6",
"@types/w3c-web-hid": "^1.0.6",
"@types/w3c-web-usb": "^1.0.10",
"license": "Apache-2.0",
"optional": true
},
- "node_modules/@types/blake2b-wasm": {
- "version": "2.4.3",
- "resolved": "https://registry.npmjs.org/@types/blake2b-wasm/-/blake2b-wasm-2.4.3.tgz",
- "integrity": "sha512-emsOJOuF5shxg5zhN3CHOy4BO/a26O++yk0ncFW9fePquKSGs1g6PIps8u8zFmApJjIkMQr7neVUqvoic4BRFw==",
+ "node_modules/@types/blake2b": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/@types/blake2b/-/blake2b-2.1.3.tgz",
+ "integrity": "sha512-MFCdX0MNxFBP/xEILO5Td0kv6nI7+Q2iRWZbTL/yzH2/eDVZS5Wd1LHdsmXClvsCyzqaZfHFzZaN6BUeUCfSDA==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/node": {
- "version": "22.8.6",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.8.6.tgz",
- "integrity": "sha512-tosuJYKrIqjQIlVCM4PEGxOmyg3FCPa/fViuJChnGeEIhjA46oy8FMVoF9su1/v8PNs2a8Q0iFNyOx0uOF91nw==",
+ "version": "22.9.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz",
+ "integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"nanoassert": "^2.0.0"
}
},
- "node_modules/blakejs": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz",
- "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==",
- "license": "MIT"
- },
"node_modules/esbuild": {
"version": "0.24.0",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.0.tgz",
"test:coverage:report": "npm run test:coverage -- --test-reporter=lcov --test-reporter-destination=coverage.info && genhtml coverage.info --output-directory test/coverage && rm coverage.info && xdg-open test/coverage/index.html"
},
"dependencies": {
- "blake2b": "^2.1.4",
- "blake2b-wasm": "^2.4.0",
- "blakejs": "^1.2.1"
+ "blake2b": "^2.1.4"
},
"optionalDependencies": {
"@ledgerhq/hw-transport-web-ble": "^6.29.4",
"@ledgerhq/hw-transport-webusb": "^6.29.4"
},
"devDependencies": {
- "@types/blake2b-wasm": "^2.4.3",
+ "@types/blake2b": "^2.1.3",
"@types/node": "^22.8.6",
"@types/w3c-web-hid": "^1.0.6",
"@types/w3c-web-usb": "^1.0.10",
// SPDX-FileCopyrightText: 2024 Chris Duncan <chris@zoso.dev>\r
// SPDX-License-Identifier: GPL-3.0-or-later\r
\r
-import { blake2b } from 'blakejs'\r
+import blake2b from 'blake2b'\r
import { ACCOUNT_KEY_LENGTH, ALPHABET, PREFIX, PREFIX_LEGACY } from './constants.js'\r
import { base32, bytes, hex } from './convert.js'\r
import Ed25519 from './ed25519.js'\r
const expectedChecksum = address.slice(-8)\r
const keyBase32 = address.slice(address.indexOf('_') + 1, -8)\r
const keyBuf = base32.toBytes(keyBase32)\r
- const actualChecksumBuf = blake2b(keyBuf, undefined, 5).reverse()\r
+ const actualChecksumBuf = blake2b(5, undefined, undefined, undefined, true).update(keyBuf).digest().reverse()\r
const actualChecksum = bytes.toBase32(actualChecksumBuf)\r
\r
if (expectedChecksum !== actualChecksum) {\r
static #addressToKey (v: string): string {\r
const keyBytes = base32.toBytes(v.substring(0, 52))\r
const checksumBytes = base32.toBytes(v.substring(52, 60))\r
- const blakeHash = blake2b(keyBytes, undefined, 5).reverse()\r
+ const blakeHash = blake2b(5, undefined, undefined, undefined, true).update(keyBytes).digest().reverse()\r
if (bytes.toHex(checksumBytes) !== bytes.toHex(blakeHash)) {\r
throw new Error('Checksum mismatch in address')\r
}\r
\r
static async #keyToAddress (key: string): Promise<string> {\r
const publicKeyBytes = hex.toBytes(key)\r
- const checksum = blake2b(publicKeyBytes, undefined, 5).reverse()\r
+ const checksum = blake2b(5, undefined, undefined, undefined, true).update(publicKeyBytes).digest().reverse()\r
const encoded = bytes.toBase32(publicKeyBytes)\r
const encodedChecksum = bytes.toBase32(checksum)\r
return `${PREFIX}${encoded}${encodedChecksum}`\r
+++ /dev/null
-// SPDX-FileCopyrightText: 2024 Chris Duncan <chris@zoso.dev>
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-import blake2b from 'blake2b-wasm'
-import { nanoCKD } from './bip32-key-derivation.js'
-
-let addEventListener = globalThis.addEventListener
-let postMessage = globalThis.postMessage
-if (addEventListener == null || postMessage == null) {
- const { isMainThread, parentPort } = await import('node:worker_threads')
- if (!isMainThread && parentPort) {
- addEventListener = Object.getPrototypeOf(parentPort).addListener.bind(parentPort)
- postMessage = Object.getPrototypeOf(parentPort).postMessage.bind(parentPort)
- }
-}
-
-/**
-* Derives BIP-44 Nano account private keys.
-*
-* @param {number} index - Index of the account
-* @returns {Promise<Account>}
-*/
-addEventListener('message', (message) => {
- const { type, seed, index } = message.data ?? message
- switch (type) {
- case 'bip44': {
- ckdBip44(seed, index).then(postMessage)
- break
- }
- case 'blake2b': {
- ckdBlake2b(seed, index).then(postMessage)
- break
- }
- }
-})
-
-/**
-* Derives BIP-44 Nano account private keys.
-*
-* @param {number} index - Index of the account
-* @returns {Promise<Account>}
-*/
-async function ckdBip44 (seed: string, index: number): Promise<string> {
- return nanoCKD(seed, index)
-}
-
-/**
-* Derives BLAKE2b account private keys.
-*
-* @param {number} index - Index of the account
-* @returns {Promise<Account>}
-*/
-async function ckdBlake2b (seed: string, index: number): Promise<string> {
- const indexHex = index.toString(16).padStart(8, '0').toUpperCase()
- const inputHex = `${seed}${indexHex}`.padStart(72, '0')
- const inputArray = (inputHex.match(/.{1,2}/g) ?? []).map(h => parseInt(h, 16))
- const inputBytes = Uint8Array.from(inputArray)
- const hash = blake2b().update(inputBytes).digest('hex')
- return hash
-}
// SPDX-FileCopyrightText: 2024 Chris Duncan <chris@zoso.dev>
// SPDX-License-Identifier: GPL-3.0-or-later
-import { blake2b } from 'blakejs'
+import blake2b from 'blake2b'
/**
* Derived from:
for (let i = 0; i < n; ++i) {
input[i] = m[i]
}
- const hash = blake2b(input)
+ const hash = blake2b(64).update(input).digest()
for (let i = 0; i < 64; ++i) {
out[i] = hash[i]
}
// SPDX-FileCopyrightText: 2024 Chris Duncan <chris@zoso.dev>\r
// SPDX-License-Identifier: GPL-3.0-or-later\r
\r
-import blakejs from 'blakejs'\r
-const { blake2b, blake2bInit, blake2bUpdate, blake2bFinal } = blakejs\r
+import blake2b from 'blake2b'\r
import { bytes, hex } from './convert.js'\r
import Curve25519 from './curve25519.js'\r
\r
function getPublicKey (privateKey: string): string {\r
const pk = new Uint8Array(32)\r
const p = [curve.gf(), curve.gf(), curve.gf(), curve.gf()]\r
- const h = blake2b(hex.toBytes(privateKey), undefined, 64).slice(0, 32)\r
+ const h = blake2b(64).update(hex.toBytes(privateKey)).digest().slice(0, 32)\r
\r
h[0] &= 0xf8\r
h[31] &= 0x7f\r
return false\r
}\r
\r
- const ctx = blake2bInit(64, undefined)\r
- blake2bUpdate(ctx, signature.subarray(0, 32))\r
- blake2bUpdate(ctx, publicKey)\r
- blake2bUpdate(ctx, msg)\r
- let k = blake2bFinal(ctx)\r
+ const k = blake2b(64)\r
+ .update(signature.subarray(0, 32))\r
+ .update(publicKey)\r
+ .update(msg)\r
+ .digest()\r
reduce(k)\r
scalarmult(p, q, k)\r
\r
import { buffer, hex, utf8 } from './convert.js'
import { Entropy } from './entropy.js'
-// import { Thread } from './thread.js'
const { subtle } = globalThis.crypto
const ERR_MSG = 'Failed to store item in Safe'
export class Safe {
#storage = globalThis.sessionStorage
- // #thread = new Thread(new URL('./ckd.js', import.meta.url))
/**
* Encrypts data with a password and stores it in the Safe.
+++ /dev/null
-// SPDX-FileCopyrightText: 2024 Chris Duncan <chris@zoso.dev>
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-if (globalThis.Worker == null) {
- const { Worker } = await import('node:worker_threads')
- //@ts-expect-error
- Worker.prototype.addEventListener = Worker.prototype.addListener
- //@ts-expect-error
- globalThis.Worker = Worker
-}
-
-type Task = {
- data: object,
- resolve: Function
-}
-
-/**
-* Processes tasks from a queue using a Web Worker.
-*/
-export class Thread {
- #isAvailable: boolean = true
- #queue: Task[] = []
- #task?: Task
- #worker: Worker
-
- #post (next: Task) {
- this.#isAvailable = false
- this.#task = next
- this.#worker.postMessage(next.data)
- }
-
- constructor (url: string | URL) {
- this.#worker = new Worker(new URL(url, import.meta.url), { type: 'module' })
- this.#worker.addEventListener('message', (event) => {
- const result = event.data ?? event
- if (this.#task == null) {
- throw new ReferenceError(`Error resolving Worker result: ${result}`)
- }
- const resolve = this.#task.resolve
- const next = this.#queue.shift()
- if (next == null) {
- this.#isAvailable = true
- } else {
- this.#post(next)
- }
- resolve(result)
- })
- }
-
- async work (data: object): Promise<any> {
- return new Promise(resolve => {
- if (this.#isAvailable) {
- this.#post({ data, resolve })
- } else {
- this.#queue.push({ data, resolve })
- }
- })
- }
-}
// SPDX-FileCopyrightText: 2024 Chris Duncan <chris@zoso.dev>
// SPDX-License-Identifier: GPL-3.0-or-later
-import blakejs from 'blakejs'
-const { blake2bInit, blake2bUpdate, blake2bFinal } = blakejs
+import blake from 'blake2b'
import { Account } from './account.js'
import { UNITS } from './constants.js'
import { bytes, hex } from './convert.js'
*/
export async function blake2b (data: string | string[]): Promise<Uint8Array> {
if (!Array.isArray(data)) data = [data]
- const ctx = blake2bInit(32)
- data.forEach(str => blake2bUpdate(ctx, hex.toBytes(str)))
- return blake2bFinal(ctx)
+ const hash = blake(32)
+ data.forEach(str => hash.update(hex.toBytes(str)))
+ return hash.digest()
}
/**
// SPDX-FileCopyrightText: 2024 Chris Duncan <chris@zoso.dev>\r
// SPDX-License-Identifier: GPL-3.0-or-later\r
\r
-import blake2b from 'blake2b-wasm'\r
+import blake2b from 'blake2b'\r
import { Account } from './account.js'\r
import { nanoCKD } from './bip32-key-derivation.js'\r
import { Bip39Mnemonic } from './bip39-mnemonic.js'\r
*/\r
async ckd (index: number): Promise<Account> {\r
const input = `${this.seed}${dec.toHex(index, 8)}`\r
- const key = blake2b().update(hex.toBytes(input)).digest('hex')\r
+ const key = blake2b(32).update(hex.toBytes(input)).digest('hex')\r
if (typeof key !== 'string') {\r
throw new TypeError('BLAKE2b child key derivation returned invalid data')\r
}\r
const wallet = await Bip44Wallet.fromSeed(NANO_TEST_VECTORS.PASSWORD, NANO_TEST_VECTORS.BIP39_SEED)\r
await wallet.unlock(NANO_TEST_VECTORS.PASSWORD)\r
\r
- it('should derive the first account from the given BIP-44 seed', async function () {\r
+ it('should derive the first account from the given BIP-44 seed', async () => {\r
const accounts = await wallet.accounts()\r
\r
assert.equal(accounts.length, 1)\r
assert.equal(accounts[0].address, NANO_TEST_VECTORS.ADDRESS_0)\r
})\r
\r
- it('should derive low indexed accounts from the given BIP-44 seed', async function () {\r
+ it('should derive low indexed accounts from the given BIP-44 seed', async () => {\r
const accounts = await wallet.accounts(1, 2)\r
\r
assert.equal(accounts.length, 2)\r
assert.equal(accounts[1].address, NANO_TEST_VECTORS.ADDRESS_2)\r
})\r
\r
- it('should derive high indexed accounts from the given seed', async function () {\r
+ it('should derive high indexed accounts from the given seed', async () => {\r
const accounts = await wallet.accounts(0x70000000, 0x700000ff)\r
\r
assert.equal(accounts.length, 0x100)\r
}\r
})\r
\r
- it('should derive accounts for a BLAKE2b wallet', async function () {\r
+ it('should derive accounts for a BLAKE2b wallet', async () => {\r
const bwallet = await Blake2bWallet.create(NANO_TEST_VECTORS.PASSWORD)\r
await bwallet.unlock(NANO_TEST_VECTORS.PASSWORD)\r
const lowAccounts = await bwallet.accounts(0, 2)\r
describe('Ledger device accounts', { skip: true }, async () => {\r
const wallet = await LedgerWallet.create()\r
\r
- it('should fetch the first account from a Ledger device', async function () {\r
+ it('should fetch the first account from a Ledger device', async () => {\r
const accounts = await wallet.accounts()\r
\r
assert.equal(accounts.length, 1)\r