}
});
-// dist/lib/pool.js
-var Pool, WorkerInterface;
-var init_pool = __esm({
- "dist/lib/pool.js"() {
- "use strict";
- Pool = class _Pool {
- static #cores = Math.max(1, navigator.hardwareConcurrency - 1);
- #queue = [];
- #threads = [];
- #url;
- get threadsBusy() {
- let n = 0;
- for (const thread of this.#threads) {
- n += +(thread.job != null);
- }
- return n;
- }
- get threadsIdle() {
- let n = 0;
- for (const thread of this.#threads) {
- n += +(thread.job == null);
- }
- return n;
- }
- async assign(data) {
- if (!(data instanceof ArrayBuffer || Array.isArray(data)))
- data = [data];
- return new Promise((resolve, reject) => {
- const job = {
- id: performance.now(),
- results: [],
- data,
- resolve,
- reject
- };
- if (this.#queue.length > 0) {
- this.#queue.push(job);
- } else {
- for (const thread of this.#threads)
- this.#assign(thread, job);
- }
- });
- }
- /**
- *
- * @param {string} worker - Stringified worker class
- * @param {number} [count=1] - Integer between 1 and CPU thread count shared among all Pools
- */
- constructor(worker, count = 1) {
- count = Math.min(_Pool.#cores, Math.max(1, Math.floor(Math.abs(count))));
- this.#url = URL.createObjectURL(new Blob([worker], { type: "text/javascript" }));
- for (let i = 0; i < count; i++) {
- const thread = {
- worker: new Worker(this.#url, { type: "module" }),
- job: null
- };
- thread.worker.addEventListener("message", (message) => {
- let result = JSON.parse(new TextDecoder().decode(message.data) || "[]");
- if (!Array.isArray(result))
- result = [result];
- this.#report(thread, result);
- });
- this.#threads.push(thread);
- _Pool.#cores = Math.max(1, _Pool.#cores - this.#threads.length);
- }
- }
- #assign(thread, job) {
- if (job.data instanceof ArrayBuffer) {
- if (job.data.byteLength > 0) {
- thread.job = job;
- thread.worker.postMessage({ buffer: job.data }, [job.data]);
- }
- } else {
- const chunk = 1 + job.data.length / this.threadsIdle;
- const next = job.data.slice(0, chunk);
- job.data = job.data.slice(chunk);
- if (job.data.length === 0)
- this.#queue.shift();
- if (next?.length > 0) {
- const buffer2 = new TextEncoder().encode(JSON.stringify(next)).buffer;
- thread.job = job;
- thread.worker.postMessage({ buffer: buffer2 }, [buffer2]);
- }
- }
- }
- #isJobDone(jobId) {
- for (const thread of this.#threads) {
- if (thread.job?.id === jobId)
- return false;
- }
- return true;
- }
- #report(thread, results) {
- if (thread.job == null) {
- throw new Error("Thread returned results but had nowhere to report it.");
- }
- const job = thread.job;
- if (this.#queue.length > 0) {
- this.#assign(thread, this.#queue[0]);
- } else {
- thread.job = null;
- }
- if (results.length > 0) {
- job.results.push(...results);
- }
- if (this.#isJobDone(job.id)) {
- job.resolve(job.results);
- }
- }
- };
- WorkerInterface = class {
- /**
- * Processes data through a worker.
- *
- * Extending classes must override this template by implementing the same
- * function signature and providing their own processing call in the try-catch
- * block.
- *
- * @param {any[]} data - Array of data to process
- * @returns Promise for that data after being processed
- */
- static async work(data) {
- return new Promise(async (resolve, reject) => {
- for (let d of data) {
- try {
- d = await d;
- } catch (err) {
- reject(err);
- }
- }
- resolve(data);
- });
- }
- /**
- * Encodes worker results as an ArrayBuffer so it can be transferred back to
- * the main thread.
- *
- * @param {any[]} results - Array of processed data
- */
- static report(results) {
- const buffer2 = new TextEncoder().encode(JSON.stringify(results)).buffer;
- postMessage(buffer2, [buffer2]);
- }
- /**
- * Listens for messages from the main thread.
- *
- * Extending classes must call this in a static initialization block:
- * ```
- * static {
- * Pow.listen()
- * }
- * ```
- */
- static listen() {
- addEventListener("message", (message) => {
- const { name, buffer: buffer2 } = message.data;
- if (name === "STOP") {
- close();
- const buffer3 = new ArrayBuffer(0);
- postMessage(buffer3, [buffer3]);
- } else {
- const data = JSON.parse(new TextDecoder().decode(buffer2));
- this.work(data).then(this.report);
- }
- });
- }
- };
- }
-});
-
-// dist/lib/workers/nano-nacl.js
-var NanoNaCl, nano_nacl_default;
-var init_nano_nacl = __esm({
- "dist/lib/workers/nano-nacl.js"() {
+// src/lib/blake2b.ts
+var Blake2b2, blake2b_default2;
+var init_blake2b2 = __esm({
+ "src/lib/blake2b.ts"() {
"use strict";
- init_blake2b();
- init_pool();
- NanoNaCl = class _NanoNaCl extends WorkerInterface {
- static {
- _NanoNaCl.listen();
- }
- static async work(data) {
- return new Promise(async (resolve, reject) => {
- for (let d of data) {
- try {
- d.publicKey = await this.convert(d.privateKey);
- } catch (err) {
- reject(err);
- }
- }
- resolve(data);
- });
- }
- static gf = function(init) {
- const r = new Float64Array(16);
- if (init)
- for (let i = 0; i < init.length; i++)
- r[i] = init[i];
- return r;
- };
- static gf0 = this.gf();
- static gf1 = this.gf([1]);
- static D = this.gf([30883, 4953, 19914, 30187, 55467, 16705, 2637, 112, 59544, 30585, 16505, 36039, 65139, 11119, 27886, 20995]);
- static D2 = this.gf([61785, 9906, 39828, 60374, 45398, 33411, 5274, 224, 53552, 61171, 33010, 6542, 64743, 22239, 55772, 9222]);
- static X = this.gf([54554, 36645, 11616, 51542, 42930, 38181, 51040, 26924, 56412, 64982, 57905, 49316, 21502, 52590, 14035, 8553]);
- static Y = this.gf([26200, 26214, 26214, 26214, 26214, 26214, 26214, 26214, 26214, 26214, 26214, 26214, 26214, 26214, 26214, 26214]);
- static I = this.gf([41136, 18958, 6951, 50414, 58488, 44335, 6150, 12099, 55207, 15867, 153, 11085, 57099, 20417, 9344, 11139]);
- static vn(x, xi, y, yi, n) {
- let d = 0;
- for (let i = 0; i < n; i++)
- d |= x[xi + i] ^ y[yi + i];
- return (1 & d - 1 >>> 8) - 1;
- }
- static crypto_verify_32(x, xi, y, yi) {
- return this.vn(x, xi, y, yi, 32);
- }
- static set25519(r, a) {
- for (let i = 0; i < 16; i++)
- r[i] = a[i] | 0;
- }
- static car25519(o) {
- let v, c = 1;
- for (let i = 0; i < 16; i++) {
- v = o[i] + c + 65535;
- c = Math.floor(v / 65536);
- o[i] = v - c * 65536;
- }
- o[0] += c - 1 + 37 * (c - 1);
- }
- static sel25519(p, q, b) {
- let t;
- const c = ~(b - 1);
- for (let i = 0; i < 16; i++) {
- t = c & (p[i] ^ q[i]);
- p[i] ^= t;
- q[i] ^= t;
- }
- }
- static pack25519(o, n) {
- let b;
- const m = this.gf();
- const t = this.gf();
- for (let i = 0; i < 16; i++)
- t[i] = n[i];
- this.car25519(t);
- this.car25519(t);
- this.car25519(t);
- for (let j = 0; j < 2; j++) {
- m[0] = t[0] - 65517;
- for (let i = 1; i < 15; i++) {
- m[i] = t[i] - 65535 - (m[i - 1] >> 16 & 1);
- m[i - 1] &= 65535;
- }
- m[15] = t[15] - 32767 - (m[14] >> 16 & 1);
- b = m[15] >> 16 & 1;
- m[14] &= 65535;
- this.sel25519(t, m, 1 - b);
+ Blake2b2 = class _Blake2b {
+ static BYTES_MIN = 1;
+ static BYTES_MAX = 64;
+ static KEYBYTES_MIN = 16;
+ static KEYBYTES_MAX = 64;
+ static SALTBYTES = 16;
+ static PERSONALBYTES = 16;
+ // Initialization Vector
+ static BLAKE2B_IV32 = new Uint32Array([
+ 4089235720,
+ 1779033703,
+ 2227873595,
+ 3144134277,
+ 4271175723,
+ 1013904242,
+ 1595750129,
+ 2773480762,
+ 2917565137,
+ 1359893119,
+ 725511199,
+ 2600822924,
+ 4215389547,
+ 528734635,
+ 327033209,
+ 1541459225
+ ]);
+ static SIGMA8 = [
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 14,
+ 10,
+ 4,
+ 8,
+ 9,
+ 15,
+ 13,
+ 6,
+ 1,
+ 12,
+ 0,
+ 2,
+ 11,
+ 7,
+ 5,
+ 3,
+ 11,
+ 8,
+ 12,
+ 0,
+ 5,
+ 2,
+ 15,
+ 13,
+ 10,
+ 14,
+ 3,
+ 6,
+ 7,
+ 1,
+ 9,
+ 4,
+ 7,
+ 9,
+ 3,
+ 1,
+ 13,
+ 12,
+ 11,
+ 14,
+ 2,
+ 6,
+ 5,
+ 10,
+ 4,
+ 0,
+ 15,
+ 8,
+ 9,
+ 0,
+ 5,
+ 7,
+ 2,
+ 4,
+ 10,
+ 15,
+ 14,
+ 1,
+ 11,
+ 12,
+ 6,
+ 8,
+ 3,
+ 13,
+ 2,
+ 12,
+ 6,
+ 10,
+ 0,
+ 11,
+ 8,
+ 3,
+ 4,
+ 13,
+ 7,
+ 5,
+ 15,
+ 14,
+ 1,
+ 9,
+ 12,
+ 5,
+ 1,
+ 15,
+ 14,
+ 13,
+ 4,
+ 10,
+ 0,
+ 7,
+ 6,
+ 3,
+ 9,
+ 2,
+ 8,
+ 11,
+ 13,
+ 11,
+ 7,
+ 14,
+ 12,
+ 1,
+ 3,
+ 9,
+ 5,
+ 0,
+ 15,
+ 4,
+ 8,
+ 6,
+ 2,
+ 10,
+ 6,
+ 15,
+ 14,
+ 9,
+ 11,
+ 3,
+ 0,
+ 8,
+ 12,
+ 2,
+ 13,
+ 7,
+ 1,
+ 4,
+ 10,
+ 5,
+ 10,
+ 2,
+ 8,
+ 4,
+ 7,
+ 6,
+ 1,
+ 5,
+ 15,
+ 11,
+ 9,
+ 14,
+ 3,
+ 12,
+ 13,
+ 0,
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 12,
+ 13,
+ 14,
+ 15,
+ 14,
+ 10,
+ 4,
+ 8,
+ 9,
+ 15,
+ 13,
+ 6,
+ 1,
+ 12,
+ 0,
+ 2,
+ 11,
+ 7,
+ 5,
+ 3
+ ];
+ /**
+ * These are offsets into a uint64 buffer.
+ * Multiply them all by 2 to make them offsets into a uint32 buffer,
+ * because this is Javascript and we don't have uint64s
+ */
+ static SIGMA82 = new Uint8Array(this.SIGMA8.map((x) => x * 2));
+ // reusable parameter_block
+ static parameter_block = new Uint8Array([
+ 0,
+ 0,
+ 0,
+ 0,
+ // 0: outlen, keylen, fanout, depth
+ 0,
+ 0,
+ 0,
+ 0,
+ // 4: leaf length, sequential mode
+ 0,
+ 0,
+ 0,
+ 0,
+ // 8: node offset
+ 0,
+ 0,
+ 0,
+ 0,
+ // 12: node offset
+ 0,
+ 0,
+ 0,
+ 0,
+ // 16: node depth, inner length, rfu
+ 0,
+ 0,
+ 0,
+ 0,
+ // 20: rfu
+ 0,
+ 0,
+ 0,
+ 0,
+ // 24: rfu
+ 0,
+ 0,
+ 0,
+ 0,
+ // 28: rfu
+ 0,
+ 0,
+ 0,
+ 0,
+ // 32: salt
+ 0,
+ 0,
+ 0,
+ 0,
+ // 36: salt
+ 0,
+ 0,
+ 0,
+ 0,
+ // 40: salt
+ 0,
+ 0,
+ 0,
+ 0,
+ // 44: salt
+ 0,
+ 0,
+ 0,
+ 0,
+ // 48: personal
+ 0,
+ 0,
+ 0,
+ 0,
+ // 52: personal
+ 0,
+ 0,
+ 0,
+ 0,
+ // 56: personal
+ 0,
+ 0,
+ 0,
+ 0
+ // 60: personal
+ ]);
+ static v = new Uint32Array(32);
+ static m = new Uint32Array(32);
+ /**
+ * 64-bit unsigned addition
+ * Sets v[a,a+1] += v[b,b+1]
+ * v should be a Uint32Array
+ */
+ static ADD64AA(v, a, b) {
+ var o0 = v[a] + v[b];
+ var o1 = v[a + 1] + v[b + 1];
+ if (o0 >= 4294967296) {
+ o1++;
+ }
+ v[a] = o0;
+ v[a + 1] = o1;
+ }
+ /**
+ * 64-bit unsigned addition
+ * Sets v[a,a+1] += b
+ * b0 is the low 32 bits of b, b1 represents the high 32 bits
+ */
+ static ADD64AC(v, a, b0, b1) {
+ var o0 = v[a] + b0;
+ if (b0 < 0) {
+ o0 += 4294967296;
+ }
+ var o1 = v[a + 1] + b1;
+ if (o0 >= 4294967296) {
+ o1++;
+ }
+ v[a] = o0;
+ v[a + 1] = o1;
+ }
+ // Little-endian byte access
+ static B2B_GET32(arr, i) {
+ return arr[i] ^ arr[i + 1] << 8 ^ arr[i + 2] << 16 ^ arr[i + 3] << 24;
+ }
+ /**
+ * G Mixing function
+ * The ROTRs are inlined for speed
+ */
+ static B2B_G(a, b, c, d, ix, iy) {
+ var x0 = _Blake2b.m[ix];
+ var x1 = _Blake2b.m[ix + 1];
+ var y0 = _Blake2b.m[iy];
+ var y1 = _Blake2b.m[iy + 1];
+ _Blake2b.ADD64AA(_Blake2b.v, a, b);
+ _Blake2b.ADD64AC(_Blake2b.v, a, x0, x1);
+ var xor0 = _Blake2b.v[d] ^ _Blake2b.v[a];
+ var xor1 = _Blake2b.v[d + 1] ^ _Blake2b.v[a + 1];
+ _Blake2b.v[d] = xor1;
+ _Blake2b.v[d + 1] = xor0;
+ _Blake2b.ADD64AA(_Blake2b.v, c, d);
+ xor0 = _Blake2b.v[b] ^ _Blake2b.v[c];
+ xor1 = _Blake2b.v[b + 1] ^ _Blake2b.v[c + 1];
+ _Blake2b.v[b] = xor0 >>> 24 ^ xor1 << 8;
+ _Blake2b.v[b + 1] = xor1 >>> 24 ^ xor0 << 8;
+ _Blake2b.ADD64AA(_Blake2b.v, a, b);
+ _Blake2b.ADD64AC(_Blake2b.v, a, y0, y1);
+ xor0 = _Blake2b.v[d] ^ _Blake2b.v[a];
+ xor1 = _Blake2b.v[d + 1] ^ _Blake2b.v[a + 1];
+ _Blake2b.v[d] = xor0 >>> 16 ^ xor1 << 16;
+ _Blake2b.v[d + 1] = xor1 >>> 16 ^ xor0 << 16;
+ _Blake2b.ADD64AA(_Blake2b.v, c, d);
+ xor0 = _Blake2b.v[b] ^ _Blake2b.v[c];
+ xor1 = _Blake2b.v[b + 1] ^ _Blake2b.v[c + 1];
+ _Blake2b.v[b] = xor1 >>> 31 ^ xor0 << 1;
+ _Blake2b.v[b + 1] = xor0 >>> 31 ^ xor1 << 1;
+ }
+ /**
+ * Compression function. 'last' flag indicates last block.
+ * Note we're representing 16 uint64s as 32 uint32s
+ */
+ static blake2bCompress(ctx, last2) {
+ let i = 0;
+ for (i = 0; i < 16; i++) {
+ _Blake2b.v[i] = ctx.h[i];
+ _Blake2b.v[i + 16] = _Blake2b.BLAKE2B_IV32[i];
+ }
+ _Blake2b.v[24] = _Blake2b.v[24] ^ ctx.t;
+ _Blake2b.v[25] = _Blake2b.v[25] ^ ctx.t / 4294967296;
+ if (last2) {
+ _Blake2b.v[28] = ~_Blake2b.v[28];
+ _Blake2b.v[29] = ~_Blake2b.v[29];
+ }
+ for (i = 0; i < 32; i++) {
+ _Blake2b.m[i] = _Blake2b.B2B_GET32(ctx.b, 4 * i);
+ }
+ for (i = 0; i < 12; i++) {
+ _Blake2b.B2B_G(0, 8, 16, 24, _Blake2b.SIGMA82[i * 16 + 0], _Blake2b.SIGMA82[i * 16 + 1]);
+ _Blake2b.B2B_G(2, 10, 18, 26, _Blake2b.SIGMA82[i * 16 + 2], _Blake2b.SIGMA82[i * 16 + 3]);
+ _Blake2b.B2B_G(4, 12, 20, 28, _Blake2b.SIGMA82[i * 16 + 4], _Blake2b.SIGMA82[i * 16 + 5]);
+ _Blake2b.B2B_G(6, 14, 22, 30, _Blake2b.SIGMA82[i * 16 + 6], _Blake2b.SIGMA82[i * 16 + 7]);
+ _Blake2b.B2B_G(0, 10, 20, 30, _Blake2b.SIGMA82[i * 16 + 8], _Blake2b.SIGMA82[i * 16 + 9]);
+ _Blake2b.B2B_G(2, 12, 22, 24, _Blake2b.SIGMA82[i * 16 + 10], _Blake2b.SIGMA82[i * 16 + 11]);
+ _Blake2b.B2B_G(4, 14, 16, 26, _Blake2b.SIGMA82[i * 16 + 12], _Blake2b.SIGMA82[i * 16 + 13]);
+ _Blake2b.B2B_G(6, 8, 18, 28, _Blake2b.SIGMA82[i * 16 + 14], _Blake2b.SIGMA82[i * 16 + 15]);
+ }
+ for (i = 0; i < 16; i++) {
+ ctx.h[i] = ctx.h[i] ^ _Blake2b.v[i] ^ _Blake2b.v[i + 16];
+ }
+ }
+ /**
+ * Updates a BLAKE2b streaming hash
+ * Requires hash context and Uint8Array (byte array)
+ */
+ static blake2bUpdate(ctx, input) {
+ for (var i = 0; i < input.length; i++) {
+ if (ctx.c === 128) {
+ ctx.t += ctx.c;
+ _Blake2b.blake2bCompress(ctx, false);
+ ctx.c = 0;
+ }
+ ctx.b[ctx.c++] = input[i];
+ }
+ }
+ /**
+ * Completes a BLAKE2b streaming hash
+ * Returns a Uint8Array containing the message digest
+ */
+ static blake2bFinal(ctx, out) {
+ ctx.t += ctx.c;
+ while (ctx.c < 128) {
+ ctx.b[ctx.c++] = 0;
+ }
+ _Blake2b.blake2bCompress(ctx, true);
+ for (var i = 0; i < ctx.outlen; i++) {
+ out[i] = ctx.h[i >> 2] >> 8 * (i & 3);
+ }
+ return out;
+ }
+ static hexSlice(buf) {
+ let str = "";
+ for (let i = 0; i < buf.length; i++) str += _Blake2b.toHex(buf[i]);
+ return str;
+ }
+ static toHex(n) {
+ if (typeof n !== "number")
+ throw new TypeError(`expected number to convert to hex; received ${typeof n}`);
+ if (n < 0 || n > 255)
+ throw new RangeError(`expected byte value 0-255; received ${n}`);
+ return n.toString(16).padStart(2, "0");
+ }
+ b;
+ h;
+ t;
+ c;
+ outlen;
+ /**
+ * Creates a BLAKE2b hashing context
+ * Requires an output length between 1 and 64 bytes
+ * Takes an optional Uint8Array key
+ */
+ constructor(outlen, key, salt, personal, noAssert) {
+ if (noAssert !== true) {
+ if (outlen < _Blake2b.BYTES_MIN) throw new RangeError(`expected outlen >= ${_Blake2b.BYTES_MIN}; actual ${outlen}`);
+ if (outlen > _Blake2b.BYTES_MAX) throw new RangeError(`expectd outlen <= ${_Blake2b.BYTES_MAX}; actual ${outlen}`);
+ if (key != null) {
+ if (!(key instanceof Uint8Array)) throw new TypeError(`key must be Uint8Array or Buffer`);
+ if (key.length < _Blake2b.KEYBYTES_MIN) throw new RangeError(`expected key >= ${_Blake2b.KEYBYTES_MIN}; actual ${key.length}`);
+ if (key.length > _Blake2b.KEYBYTES_MAX) throw new RangeError(`expected key <= ${_Blake2b.KEYBYTES_MAX}; actual ${key.length}`);
+ }
+ if (salt != null) {
+ if (!(salt instanceof Uint8Array)) throw new TypeError(`salt must be Uint8Array or Buffer`);
+ if (salt.length !== _Blake2b.SALTBYTES) throw new RangeError(`expected salt ${_Blake2b.SALTBYTES} bytes; actual ${salt.length} bytes`);
+ }
+ if (personal != null) {
+ if (!(personal instanceof Uint8Array)) throw new TypeError(`personal must be Uint8Array or Buffer`);
+ if (personal.length !== _Blake2b.PERSONALBYTES) throw new RangeError(`expected personal ${_Blake2b.PERSONALBYTES} bytes; actual ${personal.length} bytes`);
+ }
+ }
+ this.b = new Uint8Array(128);
+ this.h = new Uint32Array(16);
+ this.t = 0;
+ this.c = 0;
+ this.outlen = outlen;
+ _Blake2b.parameter_block.fill(0);
+ _Blake2b.parameter_block[0] = outlen;
+ if (key) _Blake2b.parameter_block[1] = key.length;
+ _Blake2b.parameter_block[2] = 1;
+ _Blake2b.parameter_block[3] = 1;
+ if (salt) _Blake2b.parameter_block.set(salt, 32);
+ if (personal) _Blake2b.parameter_block.set(personal, 48);
+ for (var i = 0; i < 16; i++) {
+ this.h[i] = _Blake2b.BLAKE2B_IV32[i] ^ _Blake2b.B2B_GET32(_Blake2b.parameter_block, i * 4);
+ }
+ if (key) {
+ _Blake2b.blake2bUpdate(this, key);
+ this.c = 128;
+ }
+ }
+ update(input) {
+ if (!(input instanceof Uint8Array))
+ throw new TypeError(`input must be Uint8Array or Buffer`);
+ _Blake2b.blake2bUpdate(this, input);
+ return this;
+ }
+ digest(out) {
+ const buf = !out || out === "binary" || out === "hex" ? new Uint8Array(this.outlen) : out;
+ if (!(buf instanceof Uint8Array)) throw new TypeError(`out must be "binary", "hex", Uint8Array, or Buffer`);
+ if (buf.length < this.outlen) throw new RangeError(`out must have at least outlen bytes of space`);
+ _Blake2b.blake2bFinal(this, buf);
+ if (out === "hex") return _Blake2b.hexSlice(buf);
+ return buf;
+ }
+ };
+ blake2b_default2 = Blake2b2.toString();
+ }
+});
+
+// src/lib/pool.ts
+var Pool, WorkerInterface;
+var init_pool = __esm({
+ "src/lib/pool.ts"() {
+ "use strict";
+ Pool = class _Pool {
+ static #cores = Math.max(1, navigator.hardwareConcurrency - 1);
+ #queue = [];
+ #threads = [];
+ #url;
+ get threadsBusy() {
+ let n = 0;
+ for (const thread of this.#threads) {
+ n += +(thread.job != null);
+ }
+ return n;
+ }
+ get threadsIdle() {
+ let n = 0;
+ for (const thread of this.#threads) {
+ n += +(thread.job == null);
+ }
+ return n;
+ }
+ async assign(data) {
+ if (!(data instanceof ArrayBuffer || Array.isArray(data))) data = [data];
+ return new Promise((resolve, reject) => {
+ const job = {
+ id: performance.now(),
+ results: [],
+ data,
+ resolve,
+ reject
+ };
+ if (this.#queue.length > 0) {
+ this.#queue.push(job);
+ } else {
+ for (const thread of this.#threads) this.#assign(thread, job);
+ }
+ });
+ }
+ /**
+ *
+ * @param {string} worker - Stringified worker class
+ * @param {number} [count=1] - Integer between 1 and CPU thread count shared among all Pools
+ */
+ constructor(worker, count = 1) {
+ count = Math.min(_Pool.#cores, Math.max(1, Math.floor(Math.abs(count))));
+ this.#url = URL.createObjectURL(new Blob([worker], { type: "text/javascript" }));
+ for (let i = 0; i < count; i++) {
+ const thread = {
+ worker: new Worker(this.#url, { type: "module" }),
+ job: null
+ };
+ thread.worker.addEventListener("message", (message) => {
+ let result = JSON.parse(new TextDecoder().decode(message.data) || "[]");
+ if (!Array.isArray(result)) result = [result];
+ this.#report(thread, result);
+ });
+ this.#threads.push(thread);
+ _Pool.#cores = Math.max(1, _Pool.#cores - this.#threads.length);
+ }
+ }
+ #assign(thread, job) {
+ if (job.data instanceof ArrayBuffer) {
+ if (job.data.byteLength > 0) {
+ thread.job = job;
+ thread.worker.postMessage({ buffer: job.data }, [job.data]);
+ }
+ } else {
+ const chunk = 1 + job.data.length / this.threadsIdle;
+ const next = job.data.slice(0, chunk);
+ job.data = job.data.slice(chunk);
+ if (job.data.length === 0) this.#queue.shift();
+ if (next?.length > 0) {
+ const buffer2 = new TextEncoder().encode(JSON.stringify(next)).buffer;
+ thread.job = job;
+ thread.worker.postMessage({ buffer: buffer2 }, [buffer2]);
+ }
+ }
+ }
+ #isJobDone(jobId) {
+ for (const thread of this.#threads) {
+ if (thread.job?.id === jobId) return false;
+ }
+ return true;
+ }
+ #report(thread, results) {
+ if (thread.job == null) {
+ throw new Error("Thread returned results but had nowhere to report it.");
+ }
+ const job = thread.job;
+ if (this.#queue.length > 0) {
+ this.#assign(thread, this.#queue[0]);
+ } else {
+ thread.job = null;
+ }
+ if (results.length > 0) {
+ job.results.push(...results);
+ }
+ if (this.#isJobDone(job.id)) {
+ job.resolve(job.results);
+ }
+ }
+ };
+ WorkerInterface = class {
+ /**
+ * Processes data through a worker.
+ *
+ * Extending classes must override this template by implementing the same
+ * function signature and providing their own processing call in the try-catch
+ * block.
+ *
+ * @param {any[]} data - Array of data to process
+ * @returns Promise for that data after being processed
+ */
+ static async work(data) {
+ return new Promise(async (resolve, reject) => {
+ for (let d of data) {
+ try {
+ d = await d;
+ } catch (err) {
+ reject(err);
+ }
+ }
+ resolve(data);
+ });
+ }
+ /**
+ * Encodes worker results as an ArrayBuffer so it can be transferred back to
+ * the main thread.
+ *
+ * @param {any[]} results - Array of processed data
+ */
+ static report(results) {
+ const buffer2 = new TextEncoder().encode(JSON.stringify(results)).buffer;
+ postMessage(buffer2, [buffer2]);
+ }
+ /**
+ * Listens for messages from the main thread.
+ *
+ * Extending classes must call this in a static initialization block:
+ * ```
+ * static {
+ * Pow.listen()
+ * }
+ * ```
+ */
+ static listen() {
+ addEventListener("message", (message) => {
+ const { name, buffer: buffer2 } = message.data;
+ if (name === "STOP") {
+ close();
+ const buffer3 = new ArrayBuffer(0);
+ postMessage(buffer3, [buffer3]);
+ } else {
+ const data = JSON.parse(new TextDecoder().decode(buffer2));
+ this.work(data).then(this.report);
+ }
+ });
+ }
+ };
+ }
+});
+
+// src/lib/workers/nano-nacl.ts
+var NanoNaCl, nano_nacl_default;
+var init_nano_nacl = __esm({
+ "src/lib/workers/nano-nacl.ts"() {
+ "use strict";
+ init_blake2b2();
+ init_pool();
+ NanoNaCl = class _NanoNaCl extends WorkerInterface {
+ static {
+ _NanoNaCl.listen();
+ }
+ static async work(data) {
+ return new Promise(async (resolve, reject) => {
+ for (let d of data) {
+ try {
+ d.publicKey = await this.convert(d.privateKey);
+ } catch (err) {
+ reject(err);
+ }
+ }
+ resolve(data);
+ });
+ }
+ static gf = function(init) {
+ const r = new Float64Array(16);
+ if (init) for (let i = 0; i < init.length; i++) r[i] = init[i];
+ return r;
+ };
+ static gf0 = this.gf();
+ static gf1 = this.gf([1]);
+ static D = this.gf([30883, 4953, 19914, 30187, 55467, 16705, 2637, 112, 59544, 30585, 16505, 36039, 65139, 11119, 27886, 20995]);
+ static D2 = this.gf([61785, 9906, 39828, 60374, 45398, 33411, 5274, 224, 53552, 61171, 33010, 6542, 64743, 22239, 55772, 9222]);
+ static X = this.gf([54554, 36645, 11616, 51542, 42930, 38181, 51040, 26924, 56412, 64982, 57905, 49316, 21502, 52590, 14035, 8553]);
+ static Y = this.gf([26200, 26214, 26214, 26214, 26214, 26214, 26214, 26214, 26214, 26214, 26214, 26214, 26214, 26214, 26214, 26214]);
+ static I = this.gf([41136, 18958, 6951, 50414, 58488, 44335, 6150, 12099, 55207, 15867, 153, 11085, 57099, 20417, 9344, 11139]);
+ static vn(x, xi, y, yi, n) {
+ let d = 0;
+ for (let i = 0; i < n; i++) d |= x[xi + i] ^ y[yi + i];
+ return (1 & d - 1 >>> 8) - 1;
+ }
+ static crypto_verify_32(x, xi, y, yi) {
+ return this.vn(x, xi, y, yi, 32);
+ }
+ static set25519(r, a) {
+ for (let i = 0; i < 16; i++) r[i] = a[i] | 0;
+ }
+ static car25519(o) {
+ let v, c = 1;
+ for (let i = 0; i < 16; i++) {
+ v = o[i] + c + 65535;
+ c = Math.floor(v / 65536);
+ o[i] = v - c * 65536;
+ }
+ o[0] += c - 1 + 37 * (c - 1);
+ }
+ static sel25519(p, q, b) {
+ let t;
+ const c = ~(b - 1);
+ for (let i = 0; i < 16; i++) {
+ t = c & (p[i] ^ q[i]);
+ p[i] ^= t;
+ q[i] ^= t;
+ }
+ }
+ static pack25519(o, n) {
+ let b;
+ const m = this.gf();
+ const t = this.gf();
+ for (let i = 0; i < 16; i++) t[i] = n[i];
+ this.car25519(t);
+ this.car25519(t);
+ this.car25519(t);
+ for (let j = 0; j < 2; j++) {
+ m[0] = t[0] - 65517;
+ for (let i = 1; i < 15; i++) {
+ m[i] = t[i] - 65535 - (m[i - 1] >> 16 & 1);
+ m[i - 1] &= 65535;
+ }
+ m[15] = t[15] - 32767 - (m[14] >> 16 & 1);
+ b = m[15] >> 16 & 1;
+ m[14] &= 65535;
+ this.sel25519(t, m, 1 - b);
}
for (let i = 0; i < 16; i++) {
o[2 * i] = t[i] & 255;
return d[0] & 1;
}
static unpack25519(o, n) {
- for (let i = 0; i < 16; i++)
- o[i] = n[2 * i] + (n[2 * i + 1] << 8);
+ for (let i = 0; i < 16; i++) o[i] = n[2 * i] + (n[2 * i + 1] << 8);
o[15] &= 32767;
}
static A(o, a, b) {
- for (let i = 0; i < 16; i++)
- o[i] = a[i] + b[i];
+ for (let i = 0; i < 16; i++) o[i] = a[i] + b[i];
}
static Z(o, a, b) {
- for (let i = 0; i < 16; i++)
- o[i] = a[i] - b[i];
+ for (let i = 0; i < 16; i++) o[i] = a[i] - b[i];
}
static M(o, a, b) {
let v, c, t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0, t7 = 0, t8 = 0, t9 = 0, t10 = 0, t11 = 0, t12 = 0, t13 = 0, t14 = 0, t15 = 0, t16 = 0, t17 = 0, t18 = 0, t19 = 0, t20 = 0, t21 = 0, t22 = 0, t23 = 0, t24 = 0, t25 = 0, t26 = 0, t27 = 0, t28 = 0, t29 = 0, t30 = 0, b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5], b6 = b[6], b7 = b[7], b8 = b[8], b9 = b[9], b10 = b[10], b11 = b[11], b12 = b[12], b13 = b[13], b14 = b[14], b15 = b[15];
}
static inv25519(o, i) {
const c = this.gf();
- for (let a = 0; a < 16; a++)
- c[a] = i[a];
+ for (let a = 0; a < 16; a++) c[a] = i[a];
for (let a = 253; a >= 0; a--) {
this.S(c, c);
- if (a !== 2 && a !== 4)
- this.M(c, c, i);
+ if (a !== 2 && a !== 4) this.M(c, c, i);
}
- for (let a = 0; a < 16; a++)
- o[a] = c[a];
+ for (let a = 0; a < 16; a++) o[a] = c[a];
}
static pow2523(o, i) {
const c = this.gf();
- for (let a = 0; a < 16; a++)
- c[a] = i[a];
+ for (let a = 0; a < 16; a++) c[a] = i[a];
for (let a = 250; a >= 0; a--) {
this.S(c, c);
- if (a !== 1)
- this.M(c, c, i);
+ if (a !== 1) this.M(c, c, i);
}
- for (let a = 0; a < 16; a++)
- o[a] = c[a];
+ for (let a = 0; a < 16; a++) o[a] = c[a];
}
// Note: difference from TweetNaCl - BLAKE2b used to hash instead of SHA-512.
static crypto_hash(out, m, n) {
const input = new Uint8Array(n);
- for (let i = 0; i < n; ++i)
- input[i] = m[i];
- const hash2 = new Blake2b(64).update(m).digest();
- for (let i = 0; i < 64; ++i)
- out[i] = hash2[i];
+ for (let i = 0; i < n; ++i) input[i] = m[i];
+ const hash2 = new Blake2b2(64).update(m).digest();
+ for (let i = 0; i < 64; ++i) out[i] = hash2[i];
return 0;
}
static add(p, q) {
carry = x[j] >> 8;
x[j] &= 255;
}
- for (j = 0; j < 32; j++)
- x[j] -= carry * this.L[j];
+ for (j = 0; j < 32; j++) x[j] -= carry * this.L[j];
for (i = 0; i < 32; i++) {
x[i + 1] += x[i] >> 8;
r[i] = x[i] & 255;
}
- }
- static reduce(r) {
- let x = new Float64Array(64);
- for (let i = 0; i < 64; i++)
- x[i] = r[i];
- for (let i = 0; i < 64; i++)
- r[i] = 0;
+ }
+ static reduce(r) {
+ let x = new Float64Array(64);
+ for (let i = 0; i < 64; i++) x[i] = r[i];
+ for (let i = 0; i < 64; i++) r[i] = 0;
this.modL(r, x);
}
// Note: difference from C - smlen returned, not passed as argument.
d[31] &= 127;
d[31] |= 64;
const smlen = n + 64;
- for (let i = 0; i < n; i++)
- sm[64 + i] = m[i];
- for (let i = 0; i < 32; i++)
- sm[32 + i] = d[32 + i];
+ for (let i = 0; i < n; i++) sm[64 + i] = m[i];
+ for (let i = 0; i < 32; i++) sm[32 + i] = d[32 + i];
this.crypto_hash(r, sm.subarray(32), n + 32);
this.reduce(r);
this.scalarbase(p, r);
this.pack(sm, p);
- for (let i = 0; i < 32; i++)
- sm[i + 32] = pk[i];
+ for (let i = 0; i < 32; i++) sm[i + 32] = pk[i];
this.crypto_hash(h, sm, n + 64);
this.reduce(h);
- for (let i = 0; i < 64; i++)
- x[i] = 0;
- for (let i = 0; i < 32; i++)
- x[i] = r[i];
+ for (let i = 0; i < 64; i++) x[i] = 0;
+ for (let i = 0; i < 32; i++) x[i] = r[i];
for (let i = 0; i < 32; i++) {
for (let j = 0; j < 32; j++) {
x[i + j] += h[i] * d[j];
this.M(r[0], t, den);
this.S(chk, r[0]);
this.M(chk, chk, den);
- if (this.neq25519(chk, num))
- this.M(r[0], r[0], this.I);
+ if (this.neq25519(chk, num)) this.M(r[0], r[0], this.I);
this.S(chk, r[0]);
this.M(chk, chk, den);
- if (this.neq25519(chk, num))
- return -1;
- if (this.par25519(r[0]) === p[31] >> 7)
- this.Z(r[0], this.gf0, r[0]);
+ if (this.neq25519(chk, num)) return -1;
+ if (this.par25519(r[0]) === p[31] >> 7) this.Z(r[0], this.gf0, r[0]);
this.M(r[3], r[0], r[1]);
return 0;
}
const h = new Uint8Array(64);
const p = [this.gf(), this.gf(), this.gf(), this.gf()];
const q = [this.gf(), this.gf(), this.gf(), this.gf()];
- if (n < 64)
- return -1;
- if (this.unpackneg(q, pk))
- return -1;
- for (let i = 0; i < n; i++)
- m[i] = sm[i];
- for (let i = 0; i < 32; i++)
- m[i + 32] = pk[i];
+ if (n < 64) return -1;
+ if (this.unpackneg(q, pk)) return -1;
+ for (let i = 0; i < n; i++) m[i] = sm[i];
+ for (let i = 0; i < 32; i++) m[i + 32] = pk[i];
this.crypto_hash(h, m, n);
this.reduce(h);
this.scalarmult(p, q, h);
this.pack(t, p);
n -= 64;
if (this.crypto_verify_32(sm, 0, t, 0)) {
- for (let i = 0; i < n; i++)
- m[i] = 0;
+ for (let i = 0; i < n; i++) m[i] = 0;
return -1;
}
- for (let i = 0; i < n; i++)
- m[i] = sm[i + 64];
+ for (let i = 0; i < n; i++) m[i] = sm[i + 64];
return n;
}
static crypto_sign_BYTES = 64;
}
}
static parseHex(hex2) {
- if (hex2.length % 2 === 1)
- hex2 = `0${hex2}`;
+ if (hex2.length % 2 === 1) hex2 = `0${hex2}`;
const arr = hex2.match(/.{1,2}/g)?.map((byte) => parseInt(byte, 16));
return Uint8Array.from(arr ?? []);
}
throw new Error("bad public key size");
const tmp = new Uint8Array(signedMsg.length);
var mlen = this.crypto_sign_open(tmp, signedMsg, signedMsg.length, publicKey);
- if (mlen < 0)
- return new Uint8Array(0);
+ if (mlen < 0) return new Uint8Array(0);
var m = new Uint8Array(mlen);
- for (var i = 0; i < m.length; i++)
- m[i] = tmp[i];
+ for (var i = 0; i < m.length; i++) m[i] = tmp[i];
return m;
}
static detached(msg, secretKey) {
var signedMsg = this.sign(msg, secretKey);
var sig = new Uint8Array(this.crypto_sign_BYTES);
- for (var i = 0; i < sig.length; i++)
- sig[i] = signedMsg[i];
+ for (var i = 0; i < sig.length; i++) sig[i] = signedMsg[i];
return this.hexify(sig).toUpperCase();
}
static verify(msg, sig, publicKey) {
throw new Error("bad public key size");
const sm = new Uint8Array(this.crypto_sign_BYTES + msg.length);
const m = new Uint8Array(this.crypto_sign_BYTES + msg.length);
- for (let i = 0; i < this.crypto_sign_BYTES; i++)
- sm[i] = sig[i];
- for (let i = 0; i < msg.length; i++)
- sm[i + this.crypto_sign_BYTES] = msg[i];
+ for (let i = 0; i < this.crypto_sign_BYTES; i++) sm[i] = sig[i];
+ for (let i = 0; i < msg.length; i++) sm[i + this.crypto_sign_BYTES] = msg[i];
return this.crypto_sign_open(m, sm, sm.length, publicKey) >= 0;
}
static convert(seed) {
- if (typeof seed === "string")
- seed = this.parseHex(seed);
+ if (typeof seed === "string") seed = this.parseHex(seed);
this.checkArrayTypes(seed);
if (seed.length !== this.crypto_sign_SEEDBYTES)
throw new Error("bad seed size");
const pk = new Uint8Array(this.crypto_sign_PUBLICKEYBYTES);
const p = [this.gf(), this.gf(), this.gf(), this.gf()];
- const hash2 = new Blake2b(64).update(seed).digest();
+ const hash2 = new Blake2b2(64).update(seed).digest();
hash2[0] &= 248;
hash2[31] &= 127;
hash2[31] |= 64;
}
};
nano_nacl_default = `
- const Blake2b = ${Blake2b}
+ const Blake2b = ${Blake2b2}
const WorkerInterface = ${WorkerInterface}
const NanoNaCl = ${NanoNaCl}
`;
const encodedChecksum = bytes.toBase32(checksumBytes);
return `${PREFIX}${encodedPublicKey}${encodedChecksum}`;
}
- static #validateKey(key) {
- if (key === void 0) {
- throw new TypeError(`Key is undefined`);
+ static #validateKey(key) {
+ if (key === void 0) {
+ throw new TypeError(`Key is undefined`);
+ }
+ if (typeof key !== "string") {
+ throw new TypeError(`Key must be a string`);
+ }
+ if (key.length !== ACCOUNT_KEY_LENGTH) {
+ throw new TypeError(`Key must be ${ACCOUNT_KEY_LENGTH} characters`);
+ }
+ if (!/^[0-9a-fA-F]+$/i.test(key)) {
+ throw new RangeError("Key is not a valid hexadecimal value");
+ }
+ }
+ };
+ }
+});
+
+// dist/lib/pool.js
+var Pool2;
+var init_pool2 = __esm({
+ "dist/lib/pool.js"() {
+ "use strict";
+ Pool2 = class _Pool {
+ static #cores = Math.max(1, navigator.hardwareConcurrency - 1);
+ #queue = [];
+ #threads = [];
+ #url;
+ get threadsBusy() {
+ let n = 0;
+ for (const thread of this.#threads) {
+ n += +(thread.job != null);
+ }
+ return n;
+ }
+ get threadsIdle() {
+ let n = 0;
+ for (const thread of this.#threads) {
+ n += +(thread.job == null);
+ }
+ return n;
+ }
+ async assign(data) {
+ if (!(data instanceof ArrayBuffer || Array.isArray(data)))
+ data = [data];
+ return new Promise((resolve, reject) => {
+ const job = {
+ id: performance.now(),
+ results: [],
+ data,
+ resolve,
+ reject
+ };
+ if (this.#queue.length > 0) {
+ this.#queue.push(job);
+ } else {
+ for (const thread of this.#threads)
+ this.#assign(thread, job);
+ }
+ });
+ }
+ /**
+ *
+ * @param {string} worker - Stringified worker class
+ * @param {number} [count=1] - Integer between 1 and CPU thread count shared among all Pools
+ */
+ constructor(worker, count = 1) {
+ count = Math.min(_Pool.#cores, Math.max(1, Math.floor(Math.abs(count))));
+ this.#url = URL.createObjectURL(new Blob([worker], { type: "text/javascript" }));
+ for (let i = 0; i < count; i++) {
+ const thread = {
+ worker: new Worker(this.#url, { type: "module" }),
+ job: null
+ };
+ thread.worker.addEventListener("message", (message) => {
+ let result = JSON.parse(new TextDecoder().decode(message.data) || "[]");
+ if (!Array.isArray(result))
+ result = [result];
+ this.#report(thread, result);
+ });
+ this.#threads.push(thread);
+ _Pool.#cores = Math.max(1, _Pool.#cores - this.#threads.length);
+ }
+ }
+ #assign(thread, job) {
+ if (job.data instanceof ArrayBuffer) {
+ if (job.data.byteLength > 0) {
+ thread.job = job;
+ thread.worker.postMessage({ buffer: job.data }, [job.data]);
+ }
+ } else {
+ const chunk = 1 + job.data.length / this.threadsIdle;
+ const next = job.data.slice(0, chunk);
+ job.data = job.data.slice(chunk);
+ if (job.data.length === 0)
+ this.#queue.shift();
+ if (next?.length > 0) {
+ const buffer2 = new TextEncoder().encode(JSON.stringify(next)).buffer;
+ thread.job = job;
+ thread.worker.postMessage({ buffer: buffer2 }, [buffer2]);
+ }
+ }
+ }
+ #isJobDone(jobId) {
+ for (const thread of this.#threads) {
+ if (thread.job?.id === jobId)
+ return false;
+ }
+ return true;
+ }
+ #report(thread, results) {
+ if (thread.job == null) {
+ throw new Error("Thread returned results but had nowhere to report it.");
+ }
+ const job = thread.job;
+ if (this.#queue.length > 0) {
+ this.#assign(thread, this.#queue[0]);
+ } else {
+ thread.job = null;
+ }
+ if (results.length > 0) {
+ job.results.push(...results);
+ }
+ if (this.#isJobDone(job.id)) {
+ job.resolve(job.results);
+ }
+ }
+ };
+ }
+});
+
+// src/lib/workers/bip44-ckd.ts
+var Bip44Ckd, bip44_ckd_default;
+var init_bip44_ckd = __esm({
+ "src/lib/workers/bip44-ckd.ts"() {
+ "use strict";
+ init_pool();
+ Bip44Ckd = class _Bip44Ckd extends WorkerInterface {
+ static BIP44_COIN_NANO = 165;
+ static BIP44_PURPOSE = 44;
+ static HARDENED_OFFSET = 2147483648;
+ static SLIP10_ED25519 = "ed25519 seed";
+ static {
+ _Bip44Ckd.listen();
+ }
+ static async work(data) {
+ for (const d of data) {
+ if (d.coin != null && d.coin !== this.BIP44_PURPOSE) {
+ d.privateKey = await this.ckd(d.seed, d.coin, d.index);
+ } else {
+ d.privateKey = await this.nanoCKD(d.seed, d.index);
+ }
+ }
+ return data;
+ }
+ /**
+ * Derives a private child key following the BIP-32 and BIP-44 derivation path
+ * registered to the Nano block lattice. Only hardened child keys are defined.
+ *
+ * @param {string} seed - Hexadecimal seed derived from mnemonic phrase
+ * @param {number} index - Account number between 0 and 2^31-1
+ * @returns {Promise<string>} Private child key for the account
+ */
+ static async nanoCKD(seed, index) {
+ if (!Number.isSafeInteger(index) || index < 0 || index > 2147483647) {
+ throw new RangeError(`Invalid child key index 0x${index.toString(16)}`);
+ }
+ return await this.ckd(seed, this.BIP44_COIN_NANO, index);
+ }
+ /**
+ * Derives a private child key for a coin by following the specified BIP-32 and
+ * BIP-44 derivation path. Purpose is always 44'. Only hardened child keys are
+ * defined.
+ *
+ * @param {string} seed - Hexadecimal seed derived from mnemonic phrase
+ * @param {number} coin - Number registered to a specific coin in SLIP-044
+ * @param {number} index - Account number between 0 and 2^31-1
+ * @returns {Promise<string>} Private child key for the account
+ */
+ static async ckd(seed, coin, index) {
+ if (seed.length < 32 || seed.length > 128) {
+ throw new RangeError(`Invalid seed length`);
+ }
+ if (!Number.isSafeInteger(index) || index < 0 || index > 2147483647) {
+ throw new RangeError(`Invalid child key index 0x${index.toString(16)}`);
+ }
+ const masterKey = await this.slip10(this.SLIP10_ED25519, seed);
+ const purposeKey = await this.CKDpriv(masterKey, this.BIP44_PURPOSE + this.HARDENED_OFFSET);
+ const coinKey = await this.CKDpriv(purposeKey, coin + this.HARDENED_OFFSET);
+ const accountKey = await this.CKDpriv(coinKey, index + this.HARDENED_OFFSET);
+ const privateKey = new Uint8Array(accountKey.privateKey.buffer);
+ let hex2 = "";
+ for (let i = 0; i < privateKey.length; i++) {
+ hex2 += privateKey[i].toString(16).padStart(2, "0");
+ }
+ return hex2;
+ }
+ static async slip10(curve, S) {
+ const key = new TextEncoder().encode(curve);
+ const data = new Uint8Array(64);
+ data.set(S.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)));
+ const I = await this.hmac(key, data);
+ 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 };
+ }
+ static async CKDpriv({ privateKey, chainCode }, index) {
+ const key = new Uint8Array(chainCode.buffer);
+ const data = new Uint8Array(37);
+ data.set([0]);
+ data.set(this.ser256(privateKey), 1);
+ data.set(this.ser32(index), 33);
+ const I = await this.hmac(key, data);
+ 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 };
+ }
+ static ser32(integer) {
+ if (typeof integer !== "number") {
+ throw new TypeError(`Expected a number, received ${typeof integer}`);
}
- if (typeof key !== "string") {
- throw new TypeError(`Key must be a string`);
+ if (integer > 4294967295) {
+ throw new RangeError(`Expected 32-bit integer, received ${integer.toString(2).length}-bit value: ${integer}`);
}
- if (key.length !== ACCOUNT_KEY_LENGTH) {
- throw new TypeError(`Key must be ${ACCOUNT_KEY_LENGTH} characters`);
+ const view = new DataView(new ArrayBuffer(4));
+ view.setUint32(0, integer, false);
+ return new Uint8Array(view.buffer);
+ }
+ static ser256(integer) {
+ if (integer.constructor !== DataView) {
+ throw new TypeError(`Expected DataView, received ${typeof integer}`);
}
- if (!/^[0-9a-fA-F]+$/i.test(key)) {
- throw new RangeError("Key is not a valid hexadecimal value");
+ if (integer.byteLength > 32) {
+ throw new RangeError(`Expected 32-byte integer, received ${integer.byteLength}-byte value: ${integer}`);
}
+ return new Uint8Array(integer.buffer);
+ }
+ static async hmac(key, data) {
+ const { subtle: subtle3 } = globalThis.crypto;
+ const pk = await subtle3.importKey("raw", key, { name: "HMAC", hash: "SHA-512" }, false, ["sign"]);
+ const signature = await subtle3.sign("HMAC", pk, data);
+ return new Uint8Array(signature);
}
};
+ bip44_ckd_default = `
+ const WorkerInterface = ${WorkerInterface}
+ const Bip44Ckd = ${Bip44Ckd}
+`;
}
});
-// dist/lib/workers/bip44-ckd.js
-var Bip44Ckd, bip44_ckd_default;
-var init_bip44_ckd = __esm({
- "dist/lib/workers/bip44-ckd.js"() {
- "use strict";
- init_pool();
- Bip44Ckd = class _Bip44Ckd extends WorkerInterface {
- static BIP44_COIN_NANO = 165;
- static BIP44_PURPOSE = 44;
- static HARDENED_OFFSET = 2147483648;
- static SLIP10_ED25519 = "ed25519 seed";
- static {
- _Bip44Ckd.listen();
- }
- static async work(data) {
- for (const d of data) {
- if (d.coin != null && d.coin !== this.BIP44_PURPOSE) {
- d.privateKey = await this.ckd(d.seed, d.coin, d.index);
- } else {
- d.privateKey = await this.nanoCKD(d.seed, d.index);
- }
- }
- return data;
- }
- /**
- * Derives a private child key following the BIP-32 and BIP-44 derivation path
- * registered to the Nano block lattice. Only hardened child keys are defined.
- *
- * @param {string} seed - Hexadecimal seed derived from mnemonic phrase
- * @param {number} index - Account number between 0 and 2^31-1
- * @returns {Promise<string>} Private child key for the account
- */
- static async nanoCKD(seed, index) {
- if (!Number.isSafeInteger(index) || index < 0 || index > 2147483647) {
- throw new RangeError(`Invalid child key index 0x${index.toString(16)}`);
- }
- return await this.ckd(seed, this.BIP44_COIN_NANO, index);
- }
- /**
- * Derives a private child key for a coin by following the specified BIP-32 and
- * BIP-44 derivation path. Purpose is always 44'. Only hardened child keys are
- * defined.
- *
- * @param {string} seed - Hexadecimal seed derived from mnemonic phrase
- * @param {number} coin - Number registered to a specific coin in SLIP-044
- * @param {number} index - Account number between 0 and 2^31-1
- * @returns {Promise<string>} Private child key for the account
- */
- static async ckd(seed, coin, index) {
- if (seed.length < 32 || seed.length > 128) {
- throw new RangeError(`Invalid seed length`);
- }
- if (!Number.isSafeInteger(index) || index < 0 || index > 2147483647) {
- throw new RangeError(`Invalid child key index 0x${index.toString(16)}`);
- }
- const masterKey = await this.slip10(this.SLIP10_ED25519, seed);
- const purposeKey = await this.CKDpriv(masterKey, this.BIP44_PURPOSE + this.HARDENED_OFFSET);
- const coinKey = await this.CKDpriv(purposeKey, coin + this.HARDENED_OFFSET);
- const accountKey = await this.CKDpriv(coinKey, index + this.HARDENED_OFFSET);
- const privateKey = new Uint8Array(accountKey.privateKey.buffer);
- let hex2 = "";
- for (let i = 0; i < privateKey.length; i++) {
- hex2 += privateKey[i].toString(16).padStart(2, "0");
- }
- return hex2;
- }
- static async slip10(curve, S) {
- const key = new TextEncoder().encode(curve);
- const data = new Uint8Array(64);
- data.set(S.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)));
- const I = await this.hmac(key, data);
- 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 };
- }
- static async CKDpriv({ privateKey, chainCode }, index) {
- const key = new Uint8Array(chainCode.buffer);
- const data = new Uint8Array(37);
- data.set([0]);
- data.set(this.ser256(privateKey), 1);
- data.set(this.ser32(index), 33);
- const I = await this.hmac(key, data);
- 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 };
- }
- static ser32(integer) {
- if (typeof integer !== "number") {
- throw new TypeError(`Expected a number, received ${typeof integer}`);
- }
- if (integer > 4294967295) {
- throw new RangeError(`Expected 32-bit integer, received ${integer.toString(2).length}-bit value: ${integer}`);
- }
- const view = new DataView(new ArrayBuffer(4));
- view.setUint32(0, integer, false);
- return new Uint8Array(view.buffer);
- }
- static ser256(integer) {
- if (integer.constructor !== DataView) {
- throw new TypeError(`Expected DataView, received ${typeof integer}`);
- }
- if (integer.byteLength > 32) {
- throw new RangeError(`Expected 32-byte integer, received ${integer.byteLength}-byte value: ${integer}`);
- }
- return new Uint8Array(integer.buffer);
- }
- static async hmac(key, data) {
- const { subtle: subtle3 } = globalThis.crypto;
- const pk = await subtle3.importKey("raw", key, { name: "HMAC", hash: "SHA-512" }, false, ["sign"]);
- const signature = await subtle3.sign("HMAC", pk, data);
- return new Uint8Array(signature);
- }
- };
- bip44_ckd_default = `
- const WorkerInterface = ${WorkerInterface}
- const Bip44Ckd = ${Bip44Ckd}
+// src/lib/nano-pow/shaders/gpu-compute.ts
+var NanoPowGpuComputeShader;
+var init_gpu_compute = __esm({
+ "src/lib/nano-pow/shaders/gpu-compute.ts"() {
+ "use strict";
+ {
+ }
+ NanoPowGpuComputeShader = `
+struct UBO {
+ blockhash: array<vec4<u32>, 2>,
+ random: u32,
+ threshold: u32
+};
+@group(0) @binding(0) var<uniform> ubo: UBO;
+
+struct WORK {
+ nonce: vec2<u32>,
+ found: atomic<u32>
+};
+@group(0) @binding(1) var<storage, read_write> work: WORK;
+
+/**
+* Defined separately from uint v[32] below as the original value is required
+* to calculate the second uint32 of the digest for threshold comparison
+*/
+const BLAKE2B_IV32_1: u32 = 0x6A09E667u;
+
+
+/**
+* G Mixing function
+*/
+fn G (
+ va0: ptr<function, u32>, va1: ptr<function, u32>,
+ vb0: ptr<function, u32>, vb1: ptr<function, u32>,
+ vc0: ptr<function, u32>, vc1: ptr<function, u32>,
+ vd0: ptr<function, u32>, vd1: ptr<function, u32>,
+ mx0: u32, mx1: u32, my0: u32, my1: u32
+) {
+ var o0: u32;
+ var o1: u32;
+ var xor0: u32;
+ var xor1: u32;
+
+ // a = a + b;
+ o0 = *va0 + *vb0;
+ o1 = *va1 + *vb1;
+ if (*va0 > 0xFFFFFFFFu - *vb0) {
+ o1 = o1 + 1u;
+ }
+ *va0 = o0;
+ *va1 = o1;
+
+ // a = a + m[sigma[r][2*i+0]];
+ o0 = *va0 + mx0;
+ o1 = *va1 + mx1;
+ if (*va0 > 0xFFFFFFFFu - mx0) {
+ o1 = o1 + 1u;
+ }
+ *va0 = o0;
+ *va1 = o1;
+
+ // d = rotr64(d ^ a, 32);
+ xor0 = *vd0 ^ *va0;
+ xor1 = *vd1 ^ *va1;
+ *vd0 = xor1;
+ *vd1 = xor0;
+
+ // c = c + d;
+ o0 = *vc0 + *vd0;
+ o1 = *vc1 + *vd1;
+ if (*vc0 > 0xFFFFFFFFu - *vd0) {
+ o1 = o1 + 1u;
+ }
+ *vc0 = o0;
+ *vc1 = o1;
+
+ // b = rotr64(b ^ c, 24);
+ xor0 = *vb0 ^ *vc0;
+ xor1 = *vb1 ^ *vc1;
+ *vb0 = (xor0 >> 24u) ^ (xor1 << 8u);
+ *vb1 = (xor1 >> 24u) ^ (xor0 << 8u);
+
+ // a = a + b;
+ o0 = *va0 + *vb0;
+ o1 = *va1 + *vb1;
+ if (*va0 > 0xFFFFFFFFu - *vb0) {
+ o1 = o1 + 1u;
+ }
+ *va0 = o0;
+ *va1 = o1;
+
+ // a = a + m[sigma[r][2*i+1]];
+ o0 = *va0 + my0;
+ o1 = *va1 + my1;
+ if (*va0 > 0xFFFFFFFFu - my0) {
+ o1 = o1 + 1u;
+ }
+ *va0 = o0;
+ *va1 = o1;
+
+ // d = rotr64(d ^ a, 16)
+ xor0 = *vd0 ^ *va0;
+ xor1 = *vd1 ^ *va1;
+ *vd0 = (xor0 >> 16u) ^ (xor1 << 16u);
+ *vd1 = (xor1 >> 16u) ^ (xor0 << 16u);
+
+ // c = c + d;
+ o0 = *vc0 + *vd0;
+ o1 = *vc1 + *vd1;
+ if (*vc0 > 0xFFFFFFFFu - *vd0) {
+ o1 = o1 + 1u;
+ }
+ *vc0 = o0;
+ *vc1 = o1;
+
+ // b = rotr64(b ^ c, 63)
+ xor0 = *vb0 ^ *vc0;
+ xor1 = *vb1 ^ *vc1;
+ *vb0 = (xor1 >> 31u) ^ (xor0 << 1u);
+ *vb1 = (xor0 >> 31u) ^ (xor1 << 1u);
+}
+
+/**
+* Main compute function
+* 8-byte work is split into two 4-byte u32. Low 4 bytes are random u32 from
+* UBO. High 4 bytes are the random value XOR'd with index of each thread.
+*/
+@compute @workgroup_size(64)
+fn main(
+ @builtin(workgroup_id) workgroup_id: vec3<u32>,
+ @builtin(local_invocation_id) local_id: vec3<u32>
+) {
+ if (atomicLoad(&work.found) != 0u) { return; }
+
+ let threshold: u32 = ubo.threshold;
+
+ /**
+ * Flatten 3D workgroup and local identifiers into u32 for each thread
+ */
+ var id: u32 = ((workgroup_id.x & 0xFFu) << 24u) |
+ ((workgroup_id.y & 0xFFu) << 16u) |
+ ((workgroup_id.z & 0xFFu) << 8u) |
+ (local_id.x & 0xFFu);
+
+ /**
+ * Initialize (nonce||blockhash) concatenation
+ */
+ var m0: u32 = ubo.random;
+ var m1: u32 = ubo.random ^ id;
+ var m2: u32 = ubo.blockhash[0u].x;
+ var m3: u32 = ubo.blockhash[0u].y;
+ var m4: u32 = ubo.blockhash[0u].z;
+ var m5: u32 = ubo.blockhash[0u].w;
+ var m6: u32 = ubo.blockhash[1u].x;
+ var m7: u32 = ubo.blockhash[1u].y;
+ var m8: u32 = ubo.blockhash[1u].z;
+ var m9: u32 = ubo.blockhash[1u].w;
+
+ /**
+ * Compression buffer intialized to 2 instances of initialization vector
+ * The following values have been modified from the BLAKE2B_IV:
+ * OUTLEN is constant 8 bytes
+ * v[0u] ^= 0x01010000u ^ uint(OUTLEN);
+ * INLEN is constant 40 bytes: work value (8) + block hash (32)
+ * v[24u] ^= uint(INLEN);
+ * It is always the "last" compression at this INLEN
+ * v[28u] = ~v[28u];
+ * v[29u] = ~v[29u];
+ */
+ var v0: u32 = 0xF2BDC900u;
+ var v1: u32 = 0x6A09E667u;
+ var v2: u32 = 0x84CAA73Bu;
+ var v3: u32 = 0xBB67AE85u;
+ var v4: u32 = 0xFE94F82Bu;
+ var v5: u32 = 0x3C6EF372u;
+ var v6: u32 = 0x5F1D36F1u;
+ var v7: u32 = 0xA54FF53Au;
+ var v8: u32 = 0xADE682D1u;
+ var v9: u32 = 0x510E527Fu;
+ var v10: u32 = 0x2B3E6C1Fu;
+ var v11: u32 = 0x9B05688Cu;
+ var v12: u32 = 0xFB41BD6Bu;
+ var v13: u32 = 0x1F83D9ABu;
+ var v14: u32 = 0x137E2179u;
+ var v15: u32 = 0x5BE0CD19u;
+ var v16: u32 = 0xF3BCC908u;
+ var v17: u32 = 0x6A09E667u;
+ var v18: u32 = 0x84CAA73Bu;
+ var v19: u32 = 0xBB67AE85u;
+ var v20: u32 = 0xFE94F82Bu;
+ var v21: u32 = 0x3C6EF372u;
+ var v22: u32 = 0x5F1D36F1u;
+ var v23: u32 = 0xA54FF53Au;
+ var v24: u32 = 0xADE682F9u;
+ var v25: u32 = 0x510E527Fu;
+ var v26: u32 = 0x2B3E6C1Fu;
+ var v27: u32 = 0x9B05688Cu;
+ var v28: u32 = 0x04BE4294u;
+ var v29: u32 = 0xE07C2654u;
+ var v30: u32 = 0x137E2179u;
+ var v31: u32 = 0x5BE0CD19u;
+
+ /**
+ * Twelve rounds of G mixing as part of BLAKE2b compression step.
+ * Each sigma r index correlates with the reference implementation, but each
+ * sigma i index, and each v index, is doubled due to using two u32 array
+ * elements to represent one uint64_t.
+ */
+ var o0: u32;
+ var o1: u32;
+ var xor0: u32;
+ var xor1: u32;
+
+ /****************************************************************************
+ * ROUND(0) *
+ ****************************************************************************/
+
+ /**
+ * r=0, i=0(x2), a=v[0-1], b=v[8-9], c=v[16-17], d=v[24-25]
+ */
+
+ // a = a + b;
+ o0 = v0 + v8;
+ o1 = v1 + v9;
+ if (v0 > 0xFFFFFFFFu - v8) {
+ o1 = o1 + 1u;
+ }
+ v0 = o0;
+ v1 = o1;
+
+ // a = a + m[sigma[r][2*i+0]];
+ o0 = v0 + m0;
+ o1 = v1 + m1;
+ if (v0 > 0xFFFFFFFFu - m0) {
+ o1 = o1 + 1u;
+ }
+ v0 = o0;
+ v1 = o1;
+
+ // d = rotr64(d ^ a, 32);
+ xor0 = v24 ^ v0;
+ xor1 = v25 ^ v1;
+ v24 = xor1;
+ v25 = xor0;
+
+ // c = c + d;
+ o0 = v16 + v24;
+ o1 = v17 + v25;
+ if (v16 > 0xFFFFFFFFu - v24) {
+ o1 = o1 + 1u;
+ }
+ v16 = o0;
+ v17 = o1;
+
+ // b = rotr64(b ^ c, 24);
+ xor0 = v8 ^ v16;
+ xor1 = v9 ^ v17;
+ v8 = (xor0 >> 24u) ^ (xor1 << 8u);
+ v9 = (xor1 >> 24u) ^ (xor0 << 8u);
+
+ // a = a + b;
+ o0 = v0 + v8;
+ o1 = v1 + v9;
+ if (v0 > 0xFFFFFFFFu - v8) {
+ o1 = o1 + 1u;
+ }
+ v0 = o0;
+ v1 = o1;
+
+ // a = a + m[sigma[r][2*i+1]];
+ o0 = v0 + m2;
+ o1 = v1 + m3;
+ if (v0 > 0xFFFFFFFFu - m2) {
+ o1 = o1 + 1u;
+ }
+ v0 = o0;
+ v1 = o1;
+
+ // d = rotr64(d ^ a, 16)
+ xor0 = v24 ^ v0;
+ xor1 = v25 ^ v1;
+ v24 = (xor0 >> 16u) ^ (xor1 << 16u);
+ v25 = (xor1 >> 16u) ^ (xor0 << 16u);
+
+ // c = c + d;
+ o0 = v16 + v24;
+ o1 = v17 + v25;
+ if (v16 > 0xFFFFFFFFu - v24) {
+ o1 = o1 + 1u;
+ }
+ v16 = o0;
+ v17 = o1;
+
+ // b = rotr64(b ^ c, 63)
+ xor0 = v8 ^ v16;
+ xor1 = v9 ^ v17;
+ v8 = (xor1 >> 31u) ^ (xor0 << 1u);
+ v9 = (xor0 >> 31u) ^ (xor1 << 1u);
+
+
+
+
+
+ /**
+ * r=0, i=1(x2), a=v[2-3], b=v[10-11], c=v[18-19], d=v[26-27]
+ */
+
+ // a = a + b;
+ o0 = v2 + v10;
+ o1 = v3 + v11;
+ if (v2 > 0xFFFFFFFFu - v10) {
+ o1 = o1 + 1u;
+ }
+ v2 = o0;
+ v3 = o1;
+
+ // a = a + m[sigma[r][2*i+0]];
+ o0 = v2 + m4;
+ o1 = v3 + m5;
+ if (v2 > 0xFFFFFFFFu - m4) {
+ o1 = o1 + 1u;
+ }
+ v2 = o0;
+ v3 = o1;
+
+ // d = rotr64(d ^ a, 32);
+ xor0 = v26 ^ v2;
+ xor1 = v27 ^ v3;
+ v26 = xor1;
+ v27 = xor0;
+
+ // c = c + d;
+ o0 = v18 + v26;
+ o1 = v19 + v27;
+ if (v18 > 0xFFFFFFFFu - v26) {
+ o1 = o1 + 1u;
+ }
+ v18 = o0;
+ v19 = o1;
+
+ // b = rotr64(b ^ c, 24);
+ xor0 = v10 ^ v18;
+ xor1 = v11 ^ v19;
+ v10 = (xor0 >> 24u) ^ (xor1 << 8u);
+ v11 = (xor1 >> 24u) ^ (xor0 << 8u);
+
+ // a = a + b;
+ o0 = v2 + v10;
+ o1 = v3 + v11;
+ if (v2 > 0xFFFFFFFFu - v10) {
+ o1 = o1 + 1u;
+ }
+ v2 = o0;
+ v3 = o1;
+
+ // a = a + m[sigma[r][2*i+1]];
+ o0 = v2 + m6;
+ o1 = v3 + m7;
+ if (v2 > 0xFFFFFFFFu - m6) {
+ o1 = o1 + 1u;
+ }
+ v2 = o0;
+ v3 = o1;
+
+ // d = rotr64(d ^ a, 16)
+ xor0 = v26 ^ v2;
+ xor1 = v27 ^ v3;
+ v26 = (xor0 >> 16u) ^ (xor1 << 16u);
+ v27 = (xor1 >> 16u) ^ (xor0 << 16u);
+
+ // c = c + d;
+ o0 = v18 + v26;
+ o1 = v19 + v27;
+ if (v18 > 0xFFFFFFFFu - v26) {
+ o1 = o1 + 1u;
+ }
+ v18 = o0;
+ v19 = o1;
+
+ // b = rotr64(b ^ c, 63)
+ xor0 = v10 ^ v18;
+ xor1 = v11 ^ v19;
+ v10 = (xor1 >> 31u) ^ (xor0 << 1u);
+ v11 = (xor0 >> 31u) ^ (xor1 << 1u);
+
+
+
+
+
+ /**
+ * r=0, i=2(x2), a=v[2-3], b=v[10-11], c=v[18-19], d=v[26-27]
+ */
+
+ // a = a + b
+ o0 = v4 + v12;
+ o1 = v5 + v13;
+ if (v4 > 0xFFFFFFFFu - v12) {
+ o1 = o1 + 1u;
+ }
+ v4 = o0;
+ v5 = o1;
+
+ // a = a + m[sigma[r][2*i+0]]
+ o0 = v4 + m8;
+ o1 = v5 + m9;
+ if (v4 > 0xFFFFFFFFu - m8) {
+ o1 = o1 + 1u;
+ }
+ v4 = o0;
+ v5 = o1;
+
+ // d = rotr64(d ^ a, 32)
+ xor0 = v28 ^ v4;
+ xor1 = v29 ^ v5;
+ v28 = xor1;
+ v29 = xor0;
+
+ // c = c + d
+ o0 = v20 + v28;
+ o1 = v21 + v29;
+ if (v20 > 0xFFFFFFFFu - v28) {
+ o1 = o1 + 1u;
+ }
+ v20 = o0;
+ v21 = o1;
+
+ // b = rotr64(b ^ c, 24)
+ xor0 = v12 ^ v20;
+ xor1 = v13 ^ v21;
+ v12 = (xor0 >> 24u) ^ (xor1 << 8u);
+ v13 = (xor1 >> 24u) ^ (xor0 << 8u);
+
+ // a = a + b
+ o0 = v4 + v12;
+ o1 = v5 + v13;
+ if (v4 > 0xFFFFFFFFu - v12) {
+ o1 = o1 + 1u;
+ }
+ v4 = o0;
+ v5 = o1;
+
+ // // a = a + m[sigma[r][2*i+1]]
+ // // skip since adding 0u does nothing
+ // o0 = v4 + 0u;
+ // o1 = v5 + 0u;
+ // if (v4 > 0xFFFFFFFFu - 0u) {
+ // o1 = o1 + 1u;
+ // }
+ // v4 = o0;
+ // v5 = o1;
+
+ // d = rotr64(d ^ a, 16)
+ xor0 = v28 ^ v4;
+ xor1 = v29 ^ v5;
+ v28 = (xor0 >> 16u) ^ (xor1 << 16u);
+ v29 = (xor1 >> 16u) ^ (xor0 << 16u);
+
+ // c = c + d
+ o0 = v20 + v28;
+ o1 = v21 + v29;
+ if (v20 > 0xFFFFFFFFu - v28) {
+ o1 = o1 + 1u;
+ }
+ v20 = o0;
+ v21 = o1;
+
+ // b = rotr64(b ^ c, 63)
+ xor0 = v12 ^ v20;
+ xor1 = v13 ^ v21;
+ v12 = (xor1 >> 31u) ^ (xor0 << 1u);
+ v13 = (xor0 >> 31u) ^ (xor1 << 1u);
+
+
+
+
+
+ /**
+ * r=0, i=3(x2), a=v[6-7], b=v[14-15], c=v[22-23], d=v[30-31]
+ */
+
+ // a = a + b
+ o0 = v6 + v14;
+ o1 = v7 + v15;
+ if (v6 > 0xFFFFFFFFu - v14) {
+ o1 = o1 + 1u;
+ }
+ v6 = o0;
+ v7 = o1;
+
+ // // a = a + m[sigma[r][2*i+0]]
+ // // skip since adding 0u does nothing
+ // o0 = v6 + 0u;
+ // o1 = v7 + 0u;
+ // if (v6 > 0xFFFFFFFFu - 0u) {
+ // o1 = o1 + 1u;
+ // }
+ // v6 = o0;
+ // v7 = o1;
+
+ // d = rotr64(d ^ a, 32)
+ xor0 = v30 ^ v6;
+ xor1 = v31 ^ v7;
+ v30 = xor1;
+ v31 = xor0;
+
+ // c = c + d
+ o0 = v22 + v30;
+ o1 = v23 + v31;
+ if (v22 > 0xFFFFFFFFu - v30) {
+ o1 = o1 + 1u;
+ }
+ v22 = o0;
+ v23 = o1;
+
+ // b = rotr64(b ^ c, 24)
+ xor0 = v14 ^ v22;
+ xor1 = v15 ^ v23;
+ v14 = (xor0 >> 24u) ^ (xor1 << 8u);
+ v15 = (xor1 >> 24u) ^ (xor0 << 8u);
+
+ // a = a + b
+ o0 = v6 + v14;
+ o1 = v7 + v15;
+ if (v6 > 0xFFFFFFFFu - v14) {
+ o1 = o1 + 1u;
+ }
+ v6 = o0;
+ v7 = o1;
+
+ // // a = a + m[sigma[r][2*i+1]]
+ // // skip since adding 0u does nothing
+ // o0 = v6 + 0u;
+ // o1 = v7 + 0u;
+ // if (v6 > 0xFFFFFFFFu - 0u) {
+ // o1 = o1 + 1u;
+ // }
+ // v6 = o0;
+ // v7 = o1;
+
+ // d = rotr64(d ^ a, 16)
+ xor0 = v30 ^ v6;
+ xor1 = v31 ^ v7;
+ v30 = (xor0 >> 16u) ^ (xor1 << 16u);
+ v31 = (xor1 >> 16u) ^ (xor0 << 16u);
+
+ // c = c + d
+ o0 = v22 + v30;
+ o1 = v23 + v31;
+ if (v22 > 0xFFFFFFFFu - v30) {
+ o1 = o1 + 1u;
+ }
+ v22 = o0;
+ v23 = o1;
+
+ // b = rotr64(b ^ c, 63)
+ xor0 = v14 ^ v22;
+ xor1 = v15 ^ v23;
+ v14 = (xor1 >> 31u) ^ (xor0 << 1u);
+ v15 = (xor0 >> 31u) ^ (xor1 << 1u);
+
+
+
+
+
+ /**
+ * r=0, i=4(x2), a=v[0-1], b=v[10-11], c=v[20-21], d=v[30-31]
+ */
+
+ // a = a + b
+ o0 = v0 + v10;
+ o1 = v1 + v11;
+ if (v0 > 0xFFFFFFFFu - v10) {
+ o1 = o1 + 1u;
+ }
+ v0 = o0;
+ v1 = o1;
+
+ // // a = a + m[sigma[r][2*i+0]]
+ // // skip since adding 0u does nothing
+ // o0 = v0 + 0u;
+ // o1 = v1 + 0u;
+ // if (v0 > 0xFFFFFFFFu - 0u) {
+ // o1 = o1 + 1u;
+ // }
+ // v0 = o0;
+ // v1 = o1;
+
+ // d = rotr64(d ^ a, 32)
+ xor0 = v30 ^ v0;
+ xor1 = v31 ^ v1;
+ v30 = xor1;
+ v31 = xor0;
+
+ // c = c + d
+ o0 = v20 + v30;
+ o1 = v21 + v31;
+ if (v20 > 0xFFFFFFFFu - v30) {
+ o1 = o1 + 1u;
+ }
+ v20 = o0;
+ v21 = o1;
+
+ // b = rotr64(b ^ c, 24)
+ xor0 = v10 ^ v20;
+ xor1 = v11 ^ v21;
+ v10 = (xor0 >> 24u) ^ (xor1 << 8u);
+ v11 = (xor1 >> 24u) ^ (xor0 << 8u);
+
+ // a = a + b
+ o0 = v0 + v10;
+ o1 = v1 + v11;
+ if (v0 > 0xFFFFFFFFu - v10) {
+ o1 = o1 + 1u;
+ }
+ v0 = o0;
+ v1 = o1;
+
+ // // a = a + m[sigma[r][2*i+1]]
+ // // skip since adding 0u does nothing
+ // o0 = v0 + 0u;
+ // o1 = v1 + 0u;
+ // if (v0 > 0xFFFFFFFFu - 0u) {
+ // o1 = o1 + 1u;
+ // }
+ // v0 = o0;
+ // v1 = o1;
+
+ // d = rotr64(d ^ a, 16)
+ xor0 = v30 ^ v0;
+ xor1 = v31 ^ v1;
+ v30 = (xor0 >> 16u) ^ (xor1 << 16u);
+ v31 = (xor1 >> 16u) ^ (xor0 << 16u);
+
+ // c = c + d
+ o0 = v20 + v30;
+ o1 = v21 + v31;
+ if (v20 > 0xFFFFFFFFu - v30) {
+ o1 = o1 + 1u;
+ }
+ v20 = o0;
+ v21 = o1;
+
+ // b = rotr64(b ^ c, 63)
+ xor0 = v10 ^ v20;
+ xor1 = v11 ^ v21;
+ v10 = (xor1 >> 31u) ^ (xor0 << 1u);
+ v11 = (xor0 >> 31u) ^ (xor1 << 1u);
+
+
+
+
+
+ /**
+ * r=0, i=5(x2), a=v[2-3], b=v[12-13], c=v[22-23], d=v[24-25]
+ */
+
+ // a = a + b
+ o0 = v2 + v12;
+ o1 = v3 + v13;
+ if (v2 > 0xFFFFFFFFu - v12) {
+ o1 = o1 + 1u;
+ }
+ v2 = o0;
+ v3 = o1;
+
+ // // a = a + m[sigma[r][2*i+0]]
+ // // skip since adding 0u does nothing
+ // o0 = v2 + 0u;
+ // o1 = v3 + 0u;
+ // if (v2 > 0xFFFFFFFFu - 0u) {
+ // o1 = o1 + 1u;
+ // }
+ // v2 = o0;
+ // v3 = o1;
+
+ // d = rotr64(d ^ a, 32)
+ xor0 = v24 ^ v2;
+ xor1 = v25 ^ v3;
+ v24 = xor1;
+ v25 = xor0;
+
+ // c = c + d
+ o0 = v22 + v24;
+ o1 = v23 + v25;
+ if (v22 > 0xFFFFFFFFu - v24) {
+ o1 = o1 + 1u;
+ }
+ v22 = o0;
+ v23 = o1;
+
+ // b = rotr64(b ^ c, 24)
+ xor0 = v12 ^ v22;
+ xor1 = v13 ^ v23;
+ v12 = (xor0 >> 24u) ^ (xor1 << 8u);
+ v13 = (xor1 >> 24u) ^ (xor0 << 8u);
+
+ // a = a + b
+ o0 = v2 + v12;
+ o1 = v3 + v13;
+ if (v2 > 0xFFFFFFFFu - v12) {
+ o1 = o1 + 1u;
+ }
+ v2 = o0;
+ v3 = o1;
+
+ // // a = a + m[sigma[r][2*i+1]]
+ // // skip since adding 0u does nothing
+ // o0 = v2 + 0u;
+ // o1 = v3 + 0u;
+ // if (v2 > 0xFFFFFFFFu - 0u) {
+ // o1 = o1 + 1u;
+ // }
+ // v2 = o0;
+ // v3 = o1;
+
+ // d = rotr64(d ^ a, 16)
+ xor0 = v24 ^ v2;
+ xor1 = v25 ^ v3;
+ v24 = (xor0 >> 16u) ^ (xor1 << 16u);
+ v25 = (xor1 >> 16u) ^ (xor0 << 16u);
+
+ // c = c + d
+ o0 = v22 + v24;
+ o1 = v23 + v25;
+ if (v22 > 0xFFFFFFFFu - v24) {
+ o1 = o1 + 1u;
+ }
+ v22 = o0;
+ v23 = o1;
+
+ // b = rotr64(b ^ c, 63)
+ xor0 = v12 ^ v22;
+ xor1 = v13 ^ v23;
+ v12 = (xor1 >> 31u) ^ (xor0 << 1u);
+ v13 = (xor0 >> 31u) ^ (xor1 << 1u);
+
+
+
+
+
+ /**
+ * r=0, i=6(x2), a=v[4-6], b=v[14-15], c=v[16-17], d=v[26-27]
+ */
+
+ // a = a + b
+ o0 = v4 + v14;
+ o1 = v5 + v15;
+ if (v4 > 0xFFFFFFFFu - v14) {
+ o1 = o1 + 1u;
+ }
+ v4 = o0;
+ v5 = o1;
+
+ // // a = a + m[sigma[r][2*i+0]]
+ // // skip since adding 0u does nothing
+ // o0 = v4 + 0u;
+ // o1 = v5 + 0u;
+ // if (v4 > 0xFFFFFFFFu - 0u) {
+ // o1 = o1 + 1u;
+ // }
+ // v4 = o0;
+ // v5 = o1;
+
+ // d = rotr64(d ^ a, 32)
+ xor0 = v26 ^ v4;
+ xor1 = v27 ^ v5;
+ v26 = xor1;
+ v27 = xor0;
+
+ // c = c + d
+ o0 = v16 + v26;
+ o1 = v17 + v27;
+ if (v16 > 0xFFFFFFFFu - v26) {
+ o1 = o1 + 1u;
+ }
+ v16 = o0;
+ v17 = o1;
+
+ // b = rotr64(b ^ c, 24)
+ xor0 = v14 ^ v16;
+ xor1 = v15 ^ v17;
+ v14 = (xor0 >> 24u) ^ (xor1 << 8u);
+ v15 = (xor1 >> 24u) ^ (xor0 << 8u);
+
+ // a = a + b
+ o0 = v4 + v14;
+ o1 = v5 + v15;
+ if (v4 > 0xFFFFFFFFu - v14) {
+ o1 = o1 + 1u;
+ }
+ v4 = o0;
+ v5 = o1;
+
+ // // a = a + m[sigma[r][2*i+1]]
+ // // skip since adding 0u does nothing
+ // o0 = v4 + 0u;
+ // o1 = v5 + 0u;
+ // if (v4 > 0xFFFFFFFFu - 0u) {
+ // o1 = o1 + 1u;
+ // }
+ // v4 = o0;
+ // v5 = o1;
+
+ // d = rotr64(d ^ a, 16)
+ xor0 = v26 ^ v4;
+ xor1 = v27 ^ v5;
+ v26 = (xor0 >> 16u) ^ (xor1 << 16u);
+ v27 = (xor1 >> 16u) ^ (xor0 << 16u);
+
+ // c = c + d
+ o0 = v16 + v26;
+ o1 = v17 + v27;
+ if (v16 > 0xFFFFFFFFu - v26) {
+ o1 = o1 + 1u;
+ }
+ v16 = o0;
+ v17 = o1;
+
+ // b = rotr64(b ^ c, 63)
+ xor0 = v14 ^ v16;
+ xor1 = v15 ^ v17;
+ v14 = (xor1 >> 31u) ^ (xor0 << 1u);
+ v15 = (xor0 >> 31u) ^ (xor1 << 1u);
+
+
+
+
+
+ /**
+ * r=0, i=7(x2), a=v[6-7], b=v[8-9], c=v[18-19], d=v[28-29]
+ */
+
+ // a = a + b
+ o0 = v6 + v8;
+ o1 = v7 + v9;
+ if (v6 > 0xFFFFFFFFu - v8) {
+ o1 = o1 + 1u;
+ }
+ v6 = o0;
+ v7 = o1;
+
+ // // a = a + m[sigma[r][2*i+0]]
+ // // skip since adding 0u does nothing
+ // o0 = v6 + 0u;
+ // o1 = v7 + 0u;
+ // if (v6 > 0xFFFFFFFFu - 0u) {
+ // o1 = o1 + 1u;
+ // }
+ // v6 = o0;
+ // v7 = o1;
+
+ // d = rotr64(d ^ a, 32)
+ xor0 = v28 ^ v6;
+ xor1 = v29 ^ v7;
+ v28 = xor1;
+ v29 = xor0;
+
+ // c = c + d
+ o0 = v18 + v28;
+ o1 = v19 + v29;
+ if (v18 > 0xFFFFFFFFu - v28) {
+ o1 = o1 + 1u;
+ }
+ v18 = o0;
+ v19 = o1;
+
+ // b = rotr64(b ^ c, 24)
+ xor0 = v8 ^ v18;
+ xor1 = v9 ^ v19;
+ v8 = (xor0 >> 24u) ^ (xor1 << 8u);
+ v9 = (xor1 >> 24u) ^ (xor0 << 8u);
+
+ // a = a + b
+ o0 = v6 + v8;
+ o1 = v7 + v9;
+ if (v6 > 0xFFFFFFFFu - v8) {
+ o1 = o1 + 1u;
+ }
+ v6 = o0;
+ v7 = o1;
+
+ // // a = a + m[sigma[r][2*i+1]]
+ // // skip since adding 0u does nothing
+ // o0 = v6 + 0u;
+ // o1 = v7 + 0u;
+ // if (v6 > 0xFFFFFFFFu - 0u) {
+ // o1 = o1 + 1u;
+ // }
+ // v6 = o0;
+ // v7 = o1;
+
+ // d = rotr64(d ^ a, 16)
+ xor0 = v28 ^ v6;
+ xor1 = v29 ^ v7;
+ v28 = (xor0 >> 16u) ^ (xor1 << 16u);
+ v29 = (xor1 >> 16u) ^ (xor0 << 16u);
+
+ // c = c + d
+ o0 = v18 + v28;
+ o1 = v19 + v29;
+ if (v18 > 0xFFFFFFFFu - v28) {
+ o1 = o1 + 1u;
+ }
+ v18 = o0;
+ v19 = o1;
+
+ // b = rotr64(b ^ c, 63)
+ xor0 = v8 ^ v18;
+ xor1 = v9 ^ v19;
+ v8 = (xor1 >> 31u) ^ (xor0 << 1u);
+ v9 = (xor0 >> 31u) ^ (xor1 << 1u);
+
+
+
+
+
+ /****************************************************************************
+ * ROUND(1) *
+ ****************************************************************************/
+
+ G(&v0, &v1, &v8, &v9, &v16, &v17, &v24, &v25, 0u, 0u, 0u, 0u);
+ G(&v2, &v3, &v10, &v11, &v18, &v19, &v26, &v27, m8, m9, 0u, 0u);
+ G(&v4, &v5, &v12, &v13, &v20, &v21, &v28, &v29, 0u, 0u, 0u, 0u);
+ G(&v6, &v7, &v14, &v15, &v22, &v23, &v30, &v31, 0u, 0u, 0u, 0u);
+ G(&v0, &v1, &v10, &v11, &v20, &v21, &v30, &v31, m2, m3, 0u, 0u);
+ G(&v2, &v3, &v12, &v13, &v22, &v23, &v24, &v25, m0, m1, m4, m5);
+ G(&v4, &v5, &v14, &v15, &v16, &v17, &v26, &v27, 0u, 0u, 0u, 0u);
+ G(&v6, &v7, &v8, &v9, &v18, &v19, &v28, &v29, 0u, 0u, m6, m7);
+
+
+
+ /****************************************************************************
+ * ROUND(2) *
+ ****************************************************************************/
+
+ G(&v0, &v1, &v8, &v9, &v16, &v17, &v24, &v25, 0u, 0u, 0u, 0u);
+ G(&v2, &v3, &v10, &v11, &v18, &v19, &v26, &v27, 0u, 0u, m0, m1);
+ G(&v4, &v5, &v12, &v13, &v20, &v21, &v28, &v29, 0u, 0u, m4, m5);
+ G(&v6, &v7, &v14, &v15, &v22, &v23, &v30, &v31, 0u, 0u, 0u, 0u);
+ G(&v0, &v1, &v10, &v11, &v20, &v21, &v30, &v31, 0u, 0u, 0u, 0u);
+ G(&v2, &v3, &v12, &v13, &v22, &v23, &v24, &v25, m6, m7, 0u, 0u);
+ G(&v4, &v5, &v14, &v15, &v16, &v17, &v26, &v27, 0u, 0u, m2, m3);
+ G(&v6, &v7, &v8, &v9, &v18, &v19, &v28, &v29, 0u, 0u, m8, m9);
+
+
+
+ /****************************************************************************
+ * ROUND(3) *
+ ****************************************************************************/
+
+ G(&v0, &v1, &v8, &v9, &v16, &v17, &v24, &v25, 0u, 0u, 0u, 0u);
+ G(&v2, &v3, &v10, &v11, &v18, &v19, &v26, &v27, m6, m7, m2, m3);
+ G(&v4, &v5, &v12, &v13, &v20, &v21, &v28, &v29, 0u, 0u, 0u, 0u);
+ G(&v6, &v7, &v14, &v15, &v22, &v23, &v30, &v31, 0u, 0u, 0u, 0u);
+ G(&v0, &v1, &v10, &v11, &v20, &v21, &v30, &v31, m4, m5, 0u, 0u);
+ G(&v2, &v3, &v12, &v13, &v22, &v23, &v24, &v25, 0u, 0u, 0u, 0u);
+ G(&v4, &v5, &v14, &v15, &v16, &v17, &v26, &v27, m8, m9, m0, m1);
+ G(&v6, &v7, &v8, &v9, &v18, &v19, &v28, &v29, 0u, 0u, 0u, 0u);
+
+
+
+ /****************************************************************************
+ * ROUND(4) *
+ ****************************************************************************/
+
+ G(&v0, &v1, &v8, &v9, &v16, &v17, &v24, &v25, 0u, 0u, m0, m1);
+ G(&v2, &v3, &v10, &v11, &v18, &v19, &v26, &v27, 0u, 0u, 0u, 0u);
+ G(&v4, &v5, &v12, &v13, &v20, &v21, &v28, &v29, m4, m5, m8, m9);
+ G(&v6, &v7, &v14, &v15, &v22, &v23, &v30, &v31, 0u, 0u, 0u, 0u);
+ G(&v0, &v1, &v10, &v11, &v20, &v21, &v30, &v31, 0u, 0u, m2, m3);
+ G(&v2, &v3, &v12, &v13, &v22, &v23, &v24, &v25, 0u, 0u, 0u, 0u);
+ G(&v4, &v5, &v14, &v15, &v16, &v17, &v26, &v27, 0u, 0u, 0u, 0u);
+ G(&v6, &v7, &v8, &v9, &v18, &v19, &v28, &v29, m6, m7, 0u, 0u);
+
+
+
+ /****************************************************************************
+ * ROUND(5) *
+ ****************************************************************************/
+
+ G(&v0, &v1, &v8, &v9, &v16, &v17, &v24, &v25, m4, m5, 0u, 0u);
+ G(&v2, &v3, &v10, &v11, &v18, &v19, &v26, &v27, 0u, 0u, 0u, 0u);
+ G(&v4, &v5, &v12, &v13, &v20, &v21, &v28, &v29, m0, m1, 0u, 0u);
+ G(&v6, &v7, &v14, &v15, &v22, &v23, &v30, &v31, 0u, 0u, m6, m7);
+ G(&v0, &v1, &v10, &v11, &v20, &v21, &v30, &v31, m8, m9, 0u, 0u);
+ G(&v2, &v3, &v12, &v13, &v22, &v23, &v24, &v25, 0u, 0u, 0u, 0u);
+ G(&v4, &v5, &v14, &v15, &v16, &v17, &v26, &v27, 0u, 0u, 0u, 0u);
+ G(&v6, &v7, &v8, &v9, &v18, &v19, &v28, &v29, m2, m3, 0u, 0u);
+
+
+
+ /****************************************************************************
+ * ROUND(6) *
+ ****************************************************************************/
+
+ G(&v0, &v1, &v8, &v9, &v16, &v17, &v24, &v25, 0u, 0u, 0u, 0u);
+ G(&v2, &v3, &v10, &v11, &v18, &v19, &v26, &v27, m2, m3, 0u, 0u);
+ G(&v4, &v5, &v12, &v13, &v20, &v21, &v28, &v29, 0u, 0u, 0u, 0u);
+ G(&v6, &v7, &v14, &v15, &v22, &v23, &v30, &v31, m8, m9, 0u, 0u);
+ G(&v0, &v1, &v10, &v11, &v20, &v21, &v30, &v31, m0, m1, 0u, 0u);
+ G(&v2, &v3, &v12, &v13, &v22, &v23, &v24, &v25, 0u, 0u, m6, m7);
+ G(&v4, &v5, &v14, &v15, &v16, &v17, &v26, &v27, 0u, 0u, m4, m5);
+ G(&v6, &v7, &v8, &v9, &v18, &v19, &v28, &v29, 0u, 0u, 0u, 0u);
+
+
+
+ /****************************************************************************
+ * ROUND(7) *
+ ****************************************************************************/
+
+ G(&v0, &v1, &v8, &v9, &v16, &v17, &v24, &v25, 0u, 0u, 0u, 0u);
+ G(&v2, &v3, &v10, &v11, &v18, &v19, &v26, &v27, 0u, 0u, 0u, 0u);
+ G(&v4, &v5, &v12, &v13, &v20, &v21, &v28, &v29, 0u, 0u, m2, m3);
+ G(&v6, &v7, &v14, &v15, &v22, &v23, &v30, &v31, m6, m7, 0u, 0u);
+ G(&v0, &v1, &v10, &v11, &v20, &v21, &v30, &v31, 0u, 0u, m0, m1);
+ G(&v2, &v3, &v12, &v13, &v22, &v23, &v24, &v25, 0u, 0u, m8, m9);
+ G(&v4, &v5, &v14, &v15, &v16, &v17, &v26, &v27, 0u, 0u, 0u, 0u);
+ G(&v6, &v7, &v8, &v9, &v18, &v19, &v28, &v29, m4, m5, 0u, 0u);
+
+
+
+ /****************************************************************************
+ * ROUND(8) *
+ ****************************************************************************/
+
+ G(&v0, &v1, &v8, &v9, &v16, &v17, &v24, &v25, 0u, 0u, 0u, 0u);
+ G(&v2, &v3, &v10, &v11, &v18, &v19, &v26, &v27, 0u, 0u, 0u, 0u);
+ G(&v4, &v5, &v12, &v13, &v20, &v21, &v28, &v29, 0u, 0u, m6, m7);
+ G(&v6, &v7, &v14, &v15, &v22, &v23, &v30, &v31, m0, m1, 0u, 0u);
+ G(&v0, &v1, &v10, &v11, &v20, &v21, &v30, &v31, 0u, 0u, m4, m5);
+ G(&v2, &v3, &v12, &v13, &v22, &v23, &v24, &v25, 0u, 0u, 0u, 0u);
+ G(&v4, &v5, &v14, &v15, &v16, &v17, &v26, &v27, m2, m3, m8, m9);
+ G(&v6, &v7, &v8, &v9, &v18, &v19, &v28, &v29, 0u, 0u, 0u, 0u);
+
+
+
+ /****************************************************************************
+ * ROUND(9) *
+ ****************************************************************************/
+
+ G(&v0, &v1, &v8, &v9, &v16, &v17, &v24, &v25, 0u, 0u, m4, m5);
+ G(&v2, &v3, &v10, &v11, &v18, &v19, &v26, &v27, 0u, 0u, m8, m9);
+ G(&v4, &v5, &v12, &v13, &v20, &v21, &v28, &v29, 0u, 0u, 0u, 0u);
+ G(&v6, &v7, &v14, &v15, &v22, &v23, &v30, &v31, m2, m3, 0u, 0u);
+ G(&v0, &v1, &v10, &v11, &v20, &v21, &v30, &v31, 0u, 0u, 0u, 0u);
+ G(&v2, &v3, &v12, &v13, &v22, &v23, &v24, &v25, 0u, 0u, 0u, 0u);
+ G(&v4, &v5, &v14, &v15, &v16, &v17, &v26, &v27, m6, m7, 0u, 0u);
+ G(&v6, &v7, &v8, &v9, &v18, &v19, &v28, &v29, 0u, 0u, m0, m1);
+
+
+
+ /****************************************************************************
+ * ROUND(10) *
+ ****************************************************************************/
+
+ G(&v0, &v1, &v8, &v9, &v16, &v17, &v24, &v25, m0, m1, m2, m3);
+ G(&v2, &v3, &v10, &v11, &v18, &v19, &v26, &v27, m4, m5, m6, m7);
+ G(&v4, &v5, &v12, &v13, &v20, &v21, &v28, &v29, m8, m9, 0u, 0u);
+ G(&v6, &v7, &v14, &v15, &v22, &v23, &v30, &v31, 0u, 0u, 0u, 0u);
+ G(&v0, &v1, &v10, &v11, &v20, &v21, &v30, &v31, 0u, 0u, 0u, 0u);
+ G(&v2, &v3, &v12, &v13, &v22, &v23, &v24, &v25, 0u, 0u, 0u, 0u);
+ G(&v4, &v5, &v14, &v15, &v16, &v17, &v26, &v27, 0u, 0u, 0u, 0u);
+ G(&v6, &v7, &v8, &v9, &v18, &v19, &v28, &v29, 0u, 0u, 0u, 0u);
+
+
+
+ /****************************************************************************
+ * ROUND(11) *
+ ****************************************************************************/
+
+ G(&v0, &v1, &v8, &v9, &v16, &v17, &v24, &v25, 0u, 0u, 0u, 0u);
+ G(&v2, &v3, &v10, &v11, &v18, &v19, &v26, &v27, m8, m9, 0u, 0u);
+ G(&v4, &v5, &v12, &v13, &v20, &v21, &v28, &v29, 0u, 0u, 0u, 0u);
+ G(&v6, &v7, &v14, &v15, &v22, &v23, &v30, &v31, 0u, 0u, 0u, 0u);
+ G(&v0, &v1, &v10, &v11, &v20, &v21, &v30, &v31, m2, m3, 0u, 0u);
+ G(&v2, &v3, &v12, &v13, &v22, &v23, &v24, &v25, m0, m1, m4, m5);
+ G(&v4, &v5, &v14, &v15, &v16, &v17, &v26, &v27, 0u, 0u, 0u, 0u);
+ G(&v6, &v7, &v8, &v9, &v18, &v19, &v28, &v29, 0u, 0u, m6, m7);
+
+
+
+ /****************************************************************************
+ * NONCE CHECK *
+ ****************************************************************************/
+
+ /**
+ * Set nonce if it passes the threshold and no other thread has set it
+ */
+ if ((BLAKE2B_IV32_1 ^ v1 ^ v17) > threshold && atomicLoad(&work.found) == 0u) {
+ atomicStore(&work.found, 1u);
+ work.nonce.x = m0;
+ work.nonce.y = m1;
+ }
+ return;
+}
`;
}
});
-// dist/lib/workers/powgl.js
-var PowGl, powgl_default;
-var init_powgl = __esm({
- "dist/lib/workers/powgl.js"() {
+// src/lib/nano-pow/shaders/gl-fragment.ts
+var NanoPowGlFragmentShader;
+var init_gl_fragment = __esm({
+ "src/lib/nano-pow/shaders/gl-fragment.ts"() {
"use strict";
- init_pool();
- PowGl = class _PowGl extends WorkerInterface {
- static {
- _PowGl.listen();
- }
- /**
- * Calculates proof-of-work as described by the Nano cryptocurrency protocol.
- *
- * @param {any[]} data - Array of hashes and minimum thresholds
- * @returns Promise for proof-of-work attached to original array objects
- */
- static async work(data) {
- return new Promise(async (resolve, reject) => {
- for (const d of data) {
- try {
- d.work = await this.search(d.hash, d.threshold);
- } catch (err) {
- reject(err);
- }
- }
- resolve(data);
- });
- }
- // Vertex Shader
- static #vsSource = `#version 300 es
-#pragma vscode_glsllint_stage: vert
-precision highp float;
-layout (location=0) in vec4 position;
-layout (location=1) in vec2 uv;
-
-out vec2 uv_pos;
-
-void main() {
- uv_pos = uv;
- gl_Position = position;
-}`;
- // Fragment shader
- static #fsSource = `#version 300 es
+ NanoPowGlFragmentShader = `#version 300 es
#pragma vscode_glsllint_stage: frag
precision highp float;
precision highp int;
} else {
discard;
}
-}`;
+}
+`;
+ }
+});
+
+// src/lib/nano-pow/shaders/gl-vertex.ts
+var NanoPowGlVertexShader;
+var init_gl_vertex = __esm({
+ "src/lib/nano-pow/shaders/gl-vertex.ts"() {
+ "use strict";
+ NanoPowGlVertexShader = `#version 300 es
+#pragma vscode_glsllint_stage: vert
+precision highp float;
+layout (location=0) in vec4 position;
+layout (location=1) in vec2 uv;
+
+out vec2 uv_pos;
+
+void main() {
+ uv_pos = uv;
+ gl_Position = position;
+}
+`;
+ }
+});
+
+// src/lib/nano-pow/shaders/index.ts
+var init_shaders = __esm({
+ "src/lib/nano-pow/shaders/index.ts"() {
+ "use strict";
+ init_gpu_compute();
+ init_gl_fragment();
+ init_gl_vertex();
+ }
+});
+
+// src/lib/nano-pow/classes/gl.ts
+var NanoPowGl, gl_default;
+var init_gl = __esm({
+ "src/lib/nano-pow/classes/gl.ts"() {
+ "use strict";
+ init_shaders();
+ NanoPowGl = class _NanoPowGl {
/** Used to set canvas size. Must be a multiple of 256. */
static #WORKLOAD = 256 * Math.max(1, Math.floor(navigator.hardwareConcurrency));
static #hexify(arr) {
static #workBuffer;
static #query;
static #pixels;
- // Vertex Positions, 2 triangles
+ /**Vertex Positions, 2 triangles */
static #positions = new Float32Array([
-1,
-1,
-1,
0
]);
- // Texture Positions
+ /** Texture Positions */
static #uvPosArray = new Float32Array([
1,
1,
]);
static {
this.#gl = new OffscreenCanvas(this.#WORKLOAD, this.#WORKLOAD).getContext("webgl2");
- if (this.#gl == null)
- throw new Error("WebGL 2 is required");
+ if (this.#gl == null) throw new Error("WebGL 2 is required");
this.#gl.clearColor(0, 0, 0, 1);
this.#program = this.#gl.createProgram();
- if (this.#program == null)
- throw new Error("Failed to create shader program");
+ if (this.#program == null) throw new Error("Failed to create shader program");
this.#vertexShader = this.#gl.createShader(this.#gl.VERTEX_SHADER);
- if (this.#vertexShader == null)
- throw new Error("Failed to create vertex shader");
- this.#gl.shaderSource(this.#vertexShader, this.#vsSource);
+ if (this.#vertexShader == null) throw new Error("Failed to create vertex shader");
+ this.#gl.shaderSource(this.#vertexShader, NanoPowGlVertexShader);
this.#gl.compileShader(this.#vertexShader);
if (!this.#gl.getShaderParameter(this.#vertexShader, this.#gl.COMPILE_STATUS))
throw new Error(this.#gl.getShaderInfoLog(this.#vertexShader) ?? `Failed to compile vertex shader`);
this.#fragmentShader = this.#gl.createShader(this.#gl.FRAGMENT_SHADER);
- if (this.#fragmentShader == null)
- throw new Error("Failed to create fragment shader");
- this.#gl.shaderSource(this.#fragmentShader, this.#fsSource);
+ if (this.#fragmentShader == null) throw new Error("Failed to create fragment shader");
+ this.#gl.shaderSource(this.#fragmentShader, NanoPowGlFragmentShader);
this.#gl.compileShader(this.#fragmentShader);
if (!this.#gl.getShaderParameter(this.#fragmentShader, this.#gl.COMPILE_STATUS))
throw new Error(this.#gl.getShaderInfoLog(this.#fragmentShader) ?? `Failed to compile fragment shader`);
* @param {number} [threshold=0xfffffff8] - Difficulty of proof-of-work calculation
*/
static async search(hash2, threshold = 4294967288) {
- if (_PowGl.#gl == null)
- throw new Error("WebGL 2 is required");
- if (!/^[A-F-a-f0-9]{64}$/.test(hash2))
- throw new Error(`invalid_hash ${hash2}`);
- if (typeof threshold !== "number")
- throw new TypeError(`Invalid threshold ${threshold}`);
- if (this.#gl == null)
- throw new Error("WebGL 2 is required");
+ if (_NanoPowGl.#gl == null) throw new Error("WebGL 2 is required");
+ if (!/^[A-F-a-f0-9]{64}$/.test(hash2)) throw new Error(`invalid_hash ${hash2}`);
+ if (typeof threshold !== "number") throw new TypeError(`Invalid threshold ${threshold}`);
+ if (this.#gl == null) throw new Error("WebGL 2 is required");
const uboView = new DataView(new ArrayBuffer(144));
for (let i = 0; i < 64; i += 8) {
const uint32 = hash2.slice(i, i + 8);
uboView.setUint32(i * 2, parseInt(uint32, 16));
}
uboView.setUint32(128, threshold, true);
- uboView.setFloat32(132, _PowGl.#WORKLOAD - 1, true);
- _PowGl.#gl.bindBuffer(_PowGl.#gl.UNIFORM_BUFFER, _PowGl.#uboBuffer);
- _PowGl.#gl.bufferSubData(_PowGl.#gl.UNIFORM_BUFFER, 0, uboView);
- _PowGl.#gl.bindBuffer(_PowGl.#gl.UNIFORM_BUFFER, null);
+ uboView.setFloat32(132, _NanoPowGl.#WORKLOAD - 1, true);
+ _NanoPowGl.#gl.bindBuffer(_NanoPowGl.#gl.UNIFORM_BUFFER, _NanoPowGl.#uboBuffer);
+ _NanoPowGl.#gl.bufferSubData(_NanoPowGl.#gl.UNIFORM_BUFFER, 0, uboView);
+ _NanoPowGl.#gl.bindBuffer(_NanoPowGl.#gl.UNIFORM_BUFFER, null);
let nonce = null;
const work = new Uint8Array(8);
while (nonce == null) {
return nonce;
}
static draw(work) {
- if (this.#gl == null || this.#query == null)
- throw new Error("WebGL 2 is required to draw and query pixels");
- if (this.#workBuffer == null)
- throw new Error("Work buffer is required to draw");
+ if (this.#gl == null || this.#query == null) throw new Error("WebGL 2 is required to draw and query pixels");
+ if (this.#workBuffer == null) throw new Error("Work buffer is required to draw");
this.#gl.clear(this.#gl.COLOR_BUFFER_BIT);
crypto.getRandomValues(work);
this.#gl.bindBuffer(this.#gl.UNIFORM_BUFFER, this.#workBuffer);
this.#gl.endQuery(this.#gl.ANY_SAMPLES_PASSED_CONSERVATIVE);
}
static async checkQueryResult() {
- if (this.#gl == null || this.#query == null)
- throw new Error("WebGL 2 is required to check query results");
+ if (this.#gl == null || this.#query == null) throw new Error("WebGL 2 is required to check query results");
if (this.#gl.getQueryParameter(this.#query, this.#gl.QUERY_RESULT_AVAILABLE)) {
return this.#gl.getQueryParameter(this.#query, this.#gl.QUERY_RESULT);
}
return new Promise((resolve, reject) => {
try {
requestAnimationFrame(async () => {
- const result = await _PowGl.checkQueryResult();
+ const result = await _NanoPowGl.checkQueryResult();
resolve(result);
});
} catch (err) {
* @returns Nonce as an 8-byte (16-char) hexadecimal string
*/
static readResult(work) {
- if (this.#gl == null)
- throw new Error("WebGL 2 is required to read pixels");
+ if (this.#gl == null) throw new Error("WebGL 2 is required to read pixels");
this.#gl.readPixels(0, 0, this.#gl.drawingBufferWidth, this.#gl.drawingBufferHeight, this.#gl.RGBA, this.#gl.UNSIGNED_BYTE, this.#pixels);
for (let i = 0; i < this.#pixels.length; i += 4) {
if (this.#pixels[i] !== 0) {
- const hex2 = this.#hexify(work.subarray(4, 8)) + this.#hexify([
- this.#pixels[i + 2],
- this.#pixels[i + 3],
- work[2] ^ this.#pixels[i] - 1,
- work[3] ^ this.#pixels[i + 1] - 1
- ]);
- return hex2;
- }
- }
- throw new Error("Query reported result but nonce value not found");
- }
- };
- powgl_default = `
- const WorkerInterface = ${WorkerInterface}
- const PowGl = ${PowGl}
-`;
- }
-});
-
-// dist/lib/workers/powgpu.js
-var PowGpu, powgpu_default;
-var init_powgpu = __esm({
- "dist/lib/workers/powgpu.js"() {
- "use strict";
- init_pool();
- PowGpu = class _PowGpu extends WorkerInterface {
- static {
- _PowGpu.listen();
- }
- /**
- * Calculates proof-of-work as described by the Nano cryptocurrency protocol.
- *
- * @param {any[]} data - Array of hashes and minimum thresholds
- * @returns Promise for proof-of-work attached to original array objects
- */
- static async work(data) {
- return new Promise(async (resolve, reject) => {
- for (const d of data) {
- try {
- d.work = await this.search(d.hash, d.threshold);
- } catch (err) {
- reject(err);
- }
+ const hex2 = this.#hexify(work.subarray(4, 8)) + this.#hexify([
+ this.#pixels[i + 2],
+ this.#pixels[i + 3],
+ work[2] ^ this.#pixels[i] - 1,
+ work[3] ^ this.#pixels[i + 1] - 1
+ ]);
+ return hex2;
}
- resolve(data);
- });
+ }
+ throw new Error("Query reported result but nonce value not found");
}
- // WebGPU Compute Shader
- static shader = `
- struct UBO {
- blockhash: array<vec4<u32>, 2>,
- random: u32,
- threshold: u32
- };
- @group(0) @binding(0) var<uniform> ubo: UBO;
-
- struct WORK {
- nonce: vec2<u32>,
- found: atomic<u32>
- };
- @group(0) @binding(1) var<storage, read_write> work: WORK;
-
- /**
- * Defined separately from uint v[32] below as the original value is required
- * to calculate the second uint32 of the digest for threshold comparison
- */
- const BLAKE2B_IV32_1: u32 = 0x6A09E667u;
-
- /**
- * These are offsets into the input data buffer for each mixing step.
- * They are multiplied by 2 from the original SIGMA values in
- * the C reference implementation, which refered to uint64s.
- *
- * const SIGMA82: array<u32, 192> = array<u32, 192>(
- * 0u,2u,4u,6u,8u,10u,12u,14u,16u,18u,20u,22u,24u,26u,28u,30u,
- * 28u,20u,8u,16u,18u,30u,26u,12u,2u,24u,0u,4u,22u,14u,10u,6u,
- * 22u,16u,24u,0u,10u,4u,30u,26u,20u,28u,6u,12u,14u,2u,18u,8u,
- * 14u,18u,6u,2u,26u,24u,22u,28u,4u,12u,10u,20u,8u,0u,30u,16u,
- * 18u,0u,10u,14u,4u,8u,20u,30u,28u,2u,22u,24u,12u,16u,6u,26u,
- * 4u,24u,12u,20u,0u,22u,16u,6u,8u,26u,14u,10u,30u,28u,2u,18u,
- * 24u,10u,2u,30u,28u,26u,8u,20u,0u,14u,12u,6u,18u,4u,16u,22u,
- * 26u,22u,14u,28u,24u,2u,6u,18u,10u,0u,30u,8u,16u,12u,4u,20u,
- * 12u,30u,28u,18u,22u,6u,0u,16u,24u,4u,26u,14u,2u,8u,20u,10u,
- * 20u,4u,16u,8u,14u,12u,2u,10u,30u,22u,18u,28u,6u,24u,26u,0u,
- * 0u,2u,4u,6u,8u,10u,12u,14u,16u,18u,20u,22u,24u,26u,28u,30u,
- * 28u,20u,8u,16u,18u,30u,26u,12u,2u,24u,0u,4u,22u,14u,10u,6u
- * );
- */
-
- /**
- * G Mixing function
- */
- fn G (
- va0: ptr<function, u32>, va1: ptr<function, u32>,
- vb0: ptr<function, u32>, vb1: ptr<function, u32>,
- vc0: ptr<function, u32>, vc1: ptr<function, u32>,
- vd0: ptr<function, u32>, vd1: ptr<function, u32>,
- mx0: u32, mx1: u32, my0: u32, my1: u32
- ) {
- var o0: u32;
- var o1: u32;
- var xor0: u32;
- var xor1: u32;
-
- // a = a + b;
- o0 = *va0 + *vb0;
- o1 = *va1 + *vb1;
- if (*va0 > 0xFFFFFFFFu - *vb0) {
- o1 = o1 + 1u;
- }
- *va0 = o0;
- *va1 = o1;
-
- // a = a + m[sigma[r][2*i+0]];
- o0 = *va0 + mx0;
- o1 = *va1 + mx1;
- if (*va0 > 0xFFFFFFFFu - mx0) {
- o1 = o1 + 1u;
- }
- *va0 = o0;
- *va1 = o1;
-
- // d = rotr64(d ^ a, 32);
- xor0 = *vd0 ^ *va0;
- xor1 = *vd1 ^ *va1;
- *vd0 = xor1;
- *vd1 = xor0;
-
- // c = c + d;
- o0 = *vc0 + *vd0;
- o1 = *vc1 + *vd1;
- if (*vc0 > 0xFFFFFFFFu - *vd0) {
- o1 = o1 + 1u;
- }
- *vc0 = o0;
- *vc1 = o1;
-
- // b = rotr64(b ^ c, 24);
- xor0 = *vb0 ^ *vc0;
- xor1 = *vb1 ^ *vc1;
- *vb0 = (xor0 >> 24u) ^ (xor1 << 8u);
- *vb1 = (xor1 >> 24u) ^ (xor0 << 8u);
-
- // a = a + b;
- o0 = *va0 + *vb0;
- o1 = *va1 + *vb1;
- if (*va0 > 0xFFFFFFFFu - *vb0) {
- o1 = o1 + 1u;
- }
- *va0 = o0;
- *va1 = o1;
-
- // a = a + m[sigma[r][2*i+1]];
- o0 = *va0 + my0;
- o1 = *va1 + my1;
- if (*va0 > 0xFFFFFFFFu - my0) {
- o1 = o1 + 1u;
- }
- *va0 = o0;
- *va1 = o1;
-
- // d = rotr64(d ^ a, 16)
- xor0 = *vd0 ^ *va0;
- xor1 = *vd1 ^ *va1;
- *vd0 = (xor0 >> 16u) ^ (xor1 << 16u);
- *vd1 = (xor1 >> 16u) ^ (xor0 << 16u);
-
- // c = c + d;
- o0 = *vc0 + *vd0;
- o1 = *vc1 + *vd1;
- if (*vc0 > 0xFFFFFFFFu - *vd0) {
- o1 = o1 + 1u;
- }
- *vc0 = o0;
- *vc1 = o1;
-
- // b = rotr64(b ^ c, 63)
- xor0 = *vb0 ^ *vc0;
- xor1 = *vb1 ^ *vc1;
- *vb0 = (xor1 >> 31u) ^ (xor0 << 1u);
- *vb1 = (xor0 >> 31u) ^ (xor1 << 1u);
- }
-
- /**
- * Main compute function
- * 8-byte work is split into two 4-byte u32. Low 4 bytes are random u32 from
- * UBO. High 4 bytes are the random value XOR'd with index of each thread.
- */
- @compute @workgroup_size(64)
- fn main(
- @builtin(workgroup_id) workgroup_id: vec3<u32>,
- @builtin(local_invocation_id) local_id: vec3<u32>
- ) {
- if (atomicLoad(&work.found) != 0u) { return; }
-
- let threshold: u32 = ubo.threshold;
-
- /**
- * Flatten 3D workgroup and local identifiers into u32 for each thread
- */
- var id: u32 = ((workgroup_id.x & 0xff) << 24) |
- ((workgroup_id.y & 0xff) << 16) |
- ((workgroup_id.z & 0xff) << 8) |
- (local_id.x & 0xff);
-
- /**
- * Initialize (nonce||blockhash) concatenation
- */
- var m0: u32 = ubo.random;
- var m1: u32 = ubo.random ^ id;
- var m2: u32 = ubo.blockhash[0u].x;
- var m3: u32 = ubo.blockhash[0u].y;
- var m4: u32 = ubo.blockhash[0u].z;
- var m5: u32 = ubo.blockhash[0u].w;
- var m6: u32 = ubo.blockhash[1u].x;
- var m7: u32 = ubo.blockhash[1u].y;
- var m8: u32 = ubo.blockhash[1u].z;
- var m9: u32 = ubo.blockhash[1u].w;
-
- /**
- * Compression buffer intialized to 2 instances of initialization vector
- * The following values have been modified from the BLAKE2B_IV:
- * OUTLEN is constant 8 bytes
- * v[0u] ^= 0x01010000u ^ uint(OUTLEN);
- * INLEN is constant 40 bytes: work value (8) + block hash (32)
- * v[24u] ^= uint(INLEN);
- * It is always the "last" compression at this INLEN
- * v[28u] = ~v[28u];
- * v[29u] = ~v[29u];
- */
- var v0: u32 = 0xF2BDC900u;
- var v1: u32 = 0x6A09E667u;
- var v2: u32 = 0x84CAA73Bu;
- var v3: u32 = 0xBB67AE85u;
- var v4: u32 = 0xFE94F82Bu;
- var v5: u32 = 0x3C6EF372u;
- var v6: u32 = 0x5F1D36F1u;
- var v7: u32 = 0xA54FF53Au;
- var v8: u32 = 0xADE682D1u;
- var v9: u32 = 0x510E527Fu;
- var v10: u32 = 0x2B3E6C1Fu;
- var v11: u32 = 0x9B05688Cu;
- var v12: u32 = 0xFB41BD6Bu;
- var v13: u32 = 0x1F83D9ABu;
- var v14: u32 = 0x137E2179u;
- var v15: u32 = 0x5BE0CD19u;
- var v16: u32 = 0xF3BCC908u;
- var v17: u32 = 0x6A09E667u;
- var v18: u32 = 0x84CAA73Bu;
- var v19: u32 = 0xBB67AE85u;
- var v20: u32 = 0xFE94F82Bu;
- var v21: u32 = 0x3C6EF372u;
- var v22: u32 = 0x5F1D36F1u;
- var v23: u32 = 0xA54FF53Au;
- var v24: u32 = 0xADE682F9u;
- var v25: u32 = 0x510E527Fu;
- var v26: u32 = 0x2B3E6C1Fu;
- var v27: u32 = 0x9B05688Cu;
- var v28: u32 = 0x04BE4294u;
- var v29: u32 = 0xE07C2654u;
- var v30: u32 = 0x137E2179u;
- var v31: u32 = 0x5BE0CD19u;
-
- /**
- * Twelve rounds of mixing as part of BLAKE2b compression step
- */
- // ROUND(0)
- G(&v0, &v1, &v8, &v9, &v16, &v17, &v24, &v25, m0, m1, m2, m3);
- G(&v2, &v3, &v10, &v11, &v18, &v19, &v26, &v27, m4, m5, m6, m7);
- G(&v4, &v5, &v12, &v13, &v20, &v21, &v28, &v29, m8, m9, 0u, 0u);
- G(&v6, &v7, &v14, &v15, &v22, &v23, &v30, &v31, 0u, 0u, 0u, 0u);
- G(&v0, &v1, &v10, &v11, &v20, &v21, &v30, &v31, 0u, 0u, 0u, 0u);
- G(&v2, &v3, &v12, &v13, &v22, &v23, &v24, &v25, 0u, 0u, 0u, 0u);
- G(&v4, &v5, &v14, &v15, &v16, &v17, &v26, &v27, 0u, 0u, 0u, 0u);
- G(&v6, &v7, &v8, &v9, &v18, &v19, &v28, &v29, 0u, 0u, 0u, 0u);
-
- // ROUND(1)
- G(&v0, &v1, &v8, &v9, &v16, &v17, &v24, &v25, 0u, 0u, 0u, 0u);
- G(&v2, &v3, &v10, &v11, &v18, &v19, &v26, &v27, m8, m9, 0u, 0u);
- G(&v4, &v5, &v12, &v13, &v20, &v21, &v28, &v29, 0u, 0u, 0u, 0u);
- G(&v6, &v7, &v14, &v15, &v22, &v23, &v30, &v31, 0u, 0u, 0u, 0u);
- G(&v0, &v1, &v10, &v11, &v20, &v21, &v30, &v31, m2, m3, 0u, 0u);
- G(&v2, &v3, &v12, &v13, &v22, &v23, &v24, &v25, m0, m1, m4, m5);
- G(&v4, &v5, &v14, &v15, &v16, &v17, &v26, &v27, 0u, 0u, 0u, 0u);
- G(&v6, &v7, &v8, &v9, &v18, &v19, &v28, &v29, 0u, 0u, m6, m7);
-
- // ROUND(2)
- G(&v0, &v1, &v8, &v9, &v16, &v17, &v24, &v25, 0u, 0u, 0u, 0u);
- G(&v2, &v3, &v10, &v11, &v18, &v19, &v26, &v27, 0u, 0u, m0, m1);
- G(&v4, &v5, &v12, &v13, &v20, &v21, &v28, &v29, 0u, 0u, m4, m5);
- G(&v6, &v7, &v14, &v15, &v22, &v23, &v30, &v31, 0u, 0u, 0u, 0u);
- G(&v0, &v1, &v10, &v11, &v20, &v21, &v30, &v31, 0u, 0u, 0u, 0u);
- G(&v2, &v3, &v12, &v13, &v22, &v23, &v24, &v25, m6, m7, 0u, 0u);
- G(&v4, &v5, &v14, &v15, &v16, &v17, &v26, &v27, 0u, 0u, m2, m3);
- G(&v6, &v7, &v8, &v9, &v18, &v19, &v28, &v29, 0u, 0u, m8, m9);
-
- // ROUND(3)
- G(&v0, &v1, &v8, &v9, &v16, &v17, &v24, &v25, 0u, 0u, 0u, 0u);
- G(&v2, &v3, &v10, &v11, &v18, &v19, &v26, &v27, m6, m7, m2, m3);
- G(&v4, &v5, &v12, &v13, &v20, &v21, &v28, &v29, 0u, 0u, 0u, 0u);
- G(&v6, &v7, &v14, &v15, &v22, &v23, &v30, &v31, 0u, 0u, 0u, 0u);
- G(&v0, &v1, &v10, &v11, &v20, &v21, &v30, &v31, m4, m5, 0u, 0u);
- G(&v2, &v3, &v12, &v13, &v22, &v23, &v24, &v25, 0u, 0u, 0u, 0u);
- G(&v4, &v5, &v14, &v15, &v16, &v17, &v26, &v27, m8, m9, m0, m1);
- G(&v6, &v7, &v8, &v9, &v18, &v19, &v28, &v29, 0u, 0u, 0u, 0u);
-
- // ROUND(4)
- G(&v0, &v1, &v8, &v9, &v16, &v17, &v24, &v25, 0u, 0u, m0, m1);
- G(&v2, &v3, &v10, &v11, &v18, &v19, &v26, &v27, 0u, 0u, 0u, 0u);
- G(&v4, &v5, &v12, &v13, &v20, &v21, &v28, &v29, m4, m5, m8, m9);
- G(&v6, &v7, &v14, &v15, &v22, &v23, &v30, &v31, 0u, 0u, 0u, 0u);
- G(&v0, &v1, &v10, &v11, &v20, &v21, &v30, &v31, 0u, 0u, m2, m3);
- G(&v2, &v3, &v12, &v13, &v22, &v23, &v24, &v25, 0u, 0u, 0u, 0u);
- G(&v4, &v5, &v14, &v15, &v16, &v17, &v26, &v27, 0u, 0u, 0u, 0u);
- G(&v6, &v7, &v8, &v9, &v18, &v19, &v28, &v29, m6, m7, 0u, 0u);
-
- // ROUND(5)
- G(&v0, &v1, &v8, &v9, &v16, &v17, &v24, &v25, m4, m5, 0u, 0u);
- G(&v2, &v3, &v10, &v11, &v18, &v19, &v26, &v27, 0u, 0u, 0u, 0u);
- G(&v4, &v5, &v12, &v13, &v20, &v21, &v28, &v29, m0, m1, 0u, 0u);
- G(&v6, &v7, &v14, &v15, &v22, &v23, &v30, &v31, 0u, 0u, m6, m7);
- G(&v0, &v1, &v10, &v11, &v20, &v21, &v30, &v31, m8, m9, 0u, 0u);
- G(&v2, &v3, &v12, &v13, &v22, &v23, &v24, &v25, 0u, 0u, 0u, 0u);
- G(&v4, &v5, &v14, &v15, &v16, &v17, &v26, &v27, 0u, 0u, 0u, 0u);
- G(&v6, &v7, &v8, &v9, &v18, &v19, &v28, &v29, m2, m3, 0u, 0u);
-
- // ROUND(6)
- G(&v0, &v1, &v8, &v9, &v16, &v17, &v24, &v25, 0u, 0u, 0u, 0u);
- G(&v2, &v3, &v10, &v11, &v18, &v19, &v26, &v27, m2, m3, 0u, 0u);
- G(&v4, &v5, &v12, &v13, &v20, &v21, &v28, &v29, 0u, 0u, 0u, 0u);
- G(&v6, &v7, &v14, &v15, &v22, &v23, &v30, &v31, m8, m9, 0u, 0u);
- G(&v0, &v1, &v10, &v11, &v20, &v21, &v30, &v31, m0, m1, 0u, 0u);
- G(&v2, &v3, &v12, &v13, &v22, &v23, &v24, &v25, 0u, 0u, m6, m7);
- G(&v4, &v5, &v14, &v15, &v16, &v17, &v26, &v27, 0u, 0u, m4, m5);
- G(&v6, &v7, &v8, &v9, &v18, &v19, &v28, &v29, 0u, 0u, 0u, 0u);
-
- // ROUND(7)
- G(&v0, &v1, &v8, &v9, &v16, &v17, &v24, &v25, 0u, 0u, 0u, 0u);
- G(&v2, &v3, &v10, &v11, &v18, &v19, &v26, &v27, 0u, 0u, 0u, 0u);
- G(&v4, &v5, &v12, &v13, &v20, &v21, &v28, &v29, 0u, 0u, m2, m3);
- G(&v6, &v7, &v14, &v15, &v22, &v23, &v30, &v31, m6, m7, 0u, 0u);
- G(&v0, &v1, &v10, &v11, &v20, &v21, &v30, &v31, 0u, 0u, m0, m1);
- G(&v2, &v3, &v12, &v13, &v22, &v23, &v24, &v25, 0u, 0u, m8, m9);
- G(&v4, &v5, &v14, &v15, &v16, &v17, &v26, &v27, 0u, 0u, 0u, 0u);
- G(&v6, &v7, &v8, &v9, &v18, &v19, &v28, &v29, m4, m5, 0u, 0u);
-
- // ROUND(8)
- G(&v0, &v1, &v8, &v9, &v16, &v17, &v24, &v25, 0u, 0u, 0u, 0u);
- G(&v2, &v3, &v10, &v11, &v18, &v19, &v26, &v27, 0u, 0u, 0u, 0u);
- G(&v4, &v5, &v12, &v13, &v20, &v21, &v28, &v29, 0u, 0u, m6, m7);
- G(&v6, &v7, &v14, &v15, &v22, &v23, &v30, &v31, m0, m1, 0u, 0u);
- G(&v0, &v1, &v10, &v11, &v20, &v21, &v30, &v31, 0u, 0u, m4, m5);
- G(&v2, &v3, &v12, &v13, &v22, &v23, &v24, &v25, 0u, 0u, 0u, 0u);
- G(&v4, &v5, &v14, &v15, &v16, &v17, &v26, &v27, m2, m3, m8, m9);
- G(&v6, &v7, &v8, &v9, &v18, &v19, &v28, &v29, 0u, 0u, 0u, 0u);
-
- // ROUND(9)
- G(&v0, &v1, &v8, &v9, &v16, &v17, &v24, &v25, 0u, 0u, m4, m5);
- G(&v2, &v3, &v10, &v11, &v18, &v19, &v26, &v27, 0u, 0u, m8, m9);
- G(&v4, &v5, &v12, &v13, &v20, &v21, &v28, &v29, 0u, 0u, 0u, 0u);
- G(&v6, &v7, &v14, &v15, &v22, &v23, &v30, &v31, m2, m3, 0u, 0u);
- G(&v0, &v1, &v10, &v11, &v20, &v21, &v30, &v31, 0u, 0u, 0u, 0u);
- G(&v2, &v3, &v12, &v13, &v22, &v23, &v24, &v25, 0u, 0u, 0u, 0u);
- G(&v4, &v5, &v14, &v15, &v16, &v17, &v26, &v27, m6, m7, 0u, 0u);
- G(&v6, &v7, &v8, &v9, &v18, &v19, &v28, &v29, 0u, 0u, m0, m1);
-
- // ROUND(10)
- G(&v0, &v1, &v8, &v9, &v16, &v17, &v24, &v25, m0, m1, m2, m3);
- G(&v2, &v3, &v10, &v11, &v18, &v19, &v26, &v27, m4, m5, m6, m7);
- G(&v4, &v5, &v12, &v13, &v20, &v21, &v28, &v29, m8, m9, 0u, 0u);
- G(&v6, &v7, &v14, &v15, &v22, &v23, &v30, &v31, 0u, 0u, 0u, 0u);
- G(&v0, &v1, &v10, &v11, &v20, &v21, &v30, &v31, 0u, 0u, 0u, 0u);
- G(&v2, &v3, &v12, &v13, &v22, &v23, &v24, &v25, 0u, 0u, 0u, 0u);
- G(&v4, &v5, &v14, &v15, &v16, &v17, &v26, &v27, 0u, 0u, 0u, 0u);
- G(&v6, &v7, &v8, &v9, &v18, &v19, &v28, &v29, 0u, 0u, 0u, 0u);
-
- // ROUND(11)
- G(&v0, &v1, &v8, &v9, &v16, &v17, &v24, &v25, 0u, 0u, 0u, 0u);
- G(&v2, &v3, &v10, &v11, &v18, &v19, &v26, &v27, m8, m9, 0u, 0u);
- G(&v4, &v5, &v12, &v13, &v20, &v21, &v28, &v29, 0u, 0u, 0u, 0u);
- G(&v6, &v7, &v14, &v15, &v22, &v23, &v30, &v31, 0u, 0u, 0u, 0u);
- G(&v0, &v1, &v10, &v11, &v20, &v21, &v30, &v31, m2, m3, 0u, 0u);
- G(&v2, &v3, &v12, &v13, &v22, &v23, &v24, &v25, m0, m1, m4, m5);
- G(&v4, &v5, &v14, &v15, &v16, &v17, &v26, &v27, 0u, 0u, 0u, 0u);
- G(&v6, &v7, &v8, &v9, &v18, &v19, &v28, &v29, 0u, 0u, m6, m7);
-
- /**
- * Set nonce if it passes the threshold and no other thread has set it
- */
- if ((BLAKE2B_IV32_1 ^ v1 ^ v17) > threshold && atomicLoad(&work.found) == 0u) {
- atomicStore(&work.found, 1u);
- work.nonce.x = m0;
- work.nonce.y = m1;
- }
- return;
- }
- `;
+ };
+ gl_default = `
+ const NanoPowGlFragmentShader = \`${NanoPowGlFragmentShader}\`
+ const NanoPowGlVertexShader = \`${NanoPowGlVertexShader}\`
+ const PowGl = ${NanoPowGl}
+`;
+ }
+});
+
+// src/lib/nano-pow/classes/gpu.ts
+var NanoPowGpu, gpu_default;
+var init_gpu = __esm({
+ "src/lib/nano-pow/classes/gpu.ts"() {
+ "use strict";
+ init_shaders();
+ NanoPowGpu = class {
// Initialize WebGPU
static #device = null;
static #uboBuffer;
compute: {
entryPoint: "main",
module: this.#device.createShaderModule({
- code: this.shader
+ code: NanoPowGpuComputeShader
})
}
});
* @param {number} [threshold=0xfffffff8] - Difficulty of proof-of-work calculation
*/
static async search(hash2, threshold = 4294967288) {
- if (!/^[A-Fa-f0-9]{64}$/.test(hash2))
- throw new TypeError(`Invalid hash ${hash2}`);
- if (typeof threshold !== "number")
- throw new TypeError(`Invalid threshold ${threshold}`);
+ if (!/^[A-Fa-f0-9]{64}$/.test(hash2)) throw new TypeError(`Invalid hash ${hash2}`);
+ if (typeof threshold !== "number") throw new TypeError(`Invalid threshold ${threshold}`);
while (this.#device == null && performance.now() < 8e3) {
await new Promise((resolve) => {
setTimeout(resolve, 500);
});
}
- if (this.#device == null)
- throw new Error(`WebGPU device failed to load.`);
+ if (this.#device == null) throw new Error(`WebGPU device failed to load.`);
const uboView = new DataView(new ArrayBuffer(48));
for (let i = 0; i < 64; i += 8) {
const uint32 = hash2.slice(i, i + 8);
passEncoder.setBindGroup(0, bindGroup);
passEncoder.dispatchWorkgroups(256, 256, 256);
passEncoder.end();
- commandEncoder.copyBufferToBuffer(this.#gpuBuffer, 0, this.#cpuBuffer, 0, 12);
+ commandEncoder.copyBufferToBuffer(
+ this.#gpuBuffer,
+ 0,
+ this.#cpuBuffer,
+ 0,
+ 12
+ );
this.#device.queue.submit([commandEncoder.finish()]);
try {
await this.#cpuBuffer.mapAsync(GPUMapMode.READ);
}
}
};
- powgpu_default = `
+ gpu_default = `
+ const NanoPowGpuComputeShader = \`${NanoPowGpuComputeShader}\`
+ const NanoPowGpu = ${NanoPowGpu}
+`;
+ }
+});
+
+// src/lib/nano-pow/classes/index.ts
+var init_classes = __esm({
+ "src/lib/nano-pow/classes/index.ts"() {
+ "use strict";
+ init_gl();
+ init_gpu();
+ }
+});
+
+// src/lib/workers/nano-pow.ts
+var NanoPow, nano_pow_default;
+var init_nano_pow = __esm({
+ "src/lib/workers/nano-pow.ts"() {
+ "use strict";
+ init_pool();
+ init_shaders();
+ init_classes();
+ NanoPow = class _NanoPow extends WorkerInterface {
+ static {
+ _NanoPow.listen();
+ }
+ /**
+ * Calculates proof-of-work as described by the Nano cryptocurrency protocol.
+ *
+ * @param {any[]} data - Array of hashes and minimum thresholds
+ * @returns Promise for proof-of-work attached to original array objects
+ */
+ static async work(data) {
+ return new Promise(async (resolve, reject) => {
+ for (const d of data) {
+ try {
+ d.work = await NanoPowGpu.search(d.hash, d.threshold);
+ } catch (err) {
+ reject(err);
+ }
+ }
+ resolve(data);
+ });
+ }
+ };
+ nano_pow_default = `
+ const NanoPowGpuComputeShader = \`${NanoPowGpuComputeShader}\`
+ const NanoPowGlFragmentShader = \`${NanoPowGlFragmentShader}\`
+ const NanoPowGlVertexShader = \`${NanoPowGlVertexShader}\`
+ const NanoPowGl = ${NanoPowGl}
+ const NanoPowGpu = ${NanoPowGpu}
const WorkerInterface = ${WorkerInterface}
- const PowGpu = ${PowGpu}
+ const NanoPow = ${NanoPow}
`;
}
});
-// dist/lib/workers.js
+// src/lib/workers/index.ts
var init_workers = __esm({
- "dist/lib/workers.js"() {
+ "src/lib/workers/index.ts"() {
"use strict";
init_bip44_ckd();
init_nano_nacl();
- init_powgl();
- init_powgpu();
+ init_nano_pow();
}
});
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
- configurationValue = 1;
- endpointNumber = 3;
- TransportWebUSB = class _TransportWebUSB extends Transport_default {
- constructor(device, interfaceNumber) {
+ configurationValue = 1;
+ endpointNumber = 3;
+ TransportWebUSB = class _TransportWebUSB extends Transport_default {
+ constructor(device, interfaceNumber) {
+ super();
+ this.channel = Math.floor(Math.random() * 65535);
+ this.packetSize = 64;
+ this._disconnectEmitted = false;
+ this._emitDisconnect = (e) => {
+ if (this._disconnectEmitted)
+ return;
+ this._disconnectEmitted = true;
+ this.emit("disconnect", e);
+ };
+ this.device = device;
+ this.interfaceNumber = interfaceNumber;
+ this.deviceModel = identifyUSBProductId(device.productId);
+ }
+ /**
+ * Similar to create() except it will always display the device permission (even if some devices are already accepted).
+ */
+ static request() {
+ return __awaiter6(this, void 0, void 0, function* () {
+ const device = yield requestLedgerDevice();
+ return _TransportWebUSB.open(device);
+ });
+ }
+ /**
+ * Similar to create() except it will never display the device permission (it returns a Promise<?Transport>, null if it fails to find a device).
+ */
+ static openConnected() {
+ return __awaiter6(this, void 0, void 0, function* () {
+ const devices2 = yield getLedgerDevices();
+ if (devices2.length === 0)
+ return null;
+ return _TransportWebUSB.open(devices2[0]);
+ });
+ }
+ /**
+ * Create a Ledger transport with a USBDevice
+ */
+ static open(device) {
+ return __awaiter6(this, void 0, void 0, function* () {
+ yield device.open();
+ if (device.configuration === null) {
+ yield device.selectConfiguration(configurationValue);
+ }
+ yield gracefullyResetDevice(device);
+ const iface = device.configurations[0].interfaces.find(({ alternates }) => alternates.some((a) => a.interfaceClass === 255));
+ if (!iface) {
+ throw new TransportInterfaceNotAvailable("No WebUSB interface found for your Ledger device. Please upgrade firmware or contact techsupport.");
+ }
+ const interfaceNumber = iface.interfaceNumber;
+ try {
+ yield device.claimInterface(interfaceNumber);
+ } catch (e) {
+ yield device.close();
+ throw new TransportInterfaceNotAvailable(e.message);
+ }
+ const transport = new _TransportWebUSB(device, interfaceNumber);
+ const onDisconnect = (e) => {
+ if (device === e.device) {
+ navigator.usb.removeEventListener("disconnect", onDisconnect);
+ transport._emitDisconnect(new DisconnectedDevice());
+ }
+ };
+ navigator.usb.addEventListener("disconnect", onDisconnect);
+ return transport;
+ });
+ }
+ /**
+ * Release the transport device
+ */
+ close() {
+ return __awaiter6(this, void 0, void 0, function* () {
+ yield this.exchangeBusyPromise;
+ yield this.device.releaseInterface(this.interfaceNumber);
+ yield gracefullyResetDevice(this.device);
+ yield this.device.close();
+ });
+ }
+ /**
+ * Exchange with the device using APDU protocol.
+ * @param apdu
+ * @returns a promise of apdu response
+ */
+ exchange(apdu) {
+ return __awaiter6(this, void 0, void 0, function* () {
+ const b = yield this.exchangeAtomicImpl(() => __awaiter6(this, void 0, void 0, function* () {
+ const { channel, packetSize } = this;
+ log("apdu", "=> " + apdu.toString("hex"));
+ const framing = hid_framing_default(channel, packetSize);
+ const blocks = framing.makeBlocks(apdu);
+ for (let i = 0; i < blocks.length; i++) {
+ yield this.device.transferOut(endpointNumber, blocks[i]);
+ }
+ let result;
+ let acc;
+ while (!(result = framing.getReducedResult(acc))) {
+ const r = yield this.device.transferIn(endpointNumber, packetSize);
+ const buffer2 = Buffer.from(r.data.buffer);
+ acc = framing.reduceResponse(acc, buffer2);
+ }
+ log("apdu", "<= " + result.toString("hex"));
+ return result;
+ })).catch((e) => {
+ if (e && e.message && e.message.includes("disconnected")) {
+ this._emitDisconnect(e);
+ throw new DisconnectedDeviceDuringOperation(e.message);
+ }
+ throw e;
+ });
+ return b;
+ });
+ }
+ setScrambleKey() {
+ }
+ };
+ TransportWebUSB.isSupported = isSupported;
+ TransportWebUSB.list = getLedgerDevices;
+ TransportWebUSB.listen = (observer) => {
+ let unsubscribed = false;
+ getFirstLedgerDevice().then((device) => {
+ if (!unsubscribed) {
+ const deviceModel = identifyUSBProductId(device.productId);
+ observer.next({
+ type: "add",
+ descriptor: device,
+ deviceModel
+ });
+ observer.complete();
+ }
+ }, (error) => {
+ if (window.DOMException && error instanceof window.DOMException && error.code === 18) {
+ observer.error(new TransportWebUSBGestureRequired(error.message));
+ } else {
+ observer.error(new TransportOpenUserCancelled(error.message));
+ }
+ });
+ function unsubscribe() {
+ unsubscribed = true;
+ }
+ return {
+ unsubscribe
+ };
+ };
+ TransportWebUSB_default = TransportWebUSB;
+ }
+});
+
+// node_modules/@ledgerhq/hw-transport-webhid/lib-es/TransportWebHID.js
+function requestLedgerDevices() {
+ return __awaiter7(this, void 0, void 0, function* () {
+ const device = yield getHID().requestDevice({
+ filters: ledgerDevices2
+ });
+ if (Array.isArray(device))
+ return device;
+ return [device];
+ });
+}
+function getLedgerDevices2() {
+ return __awaiter7(this, void 0, void 0, function* () {
+ const devices2 = yield getHID().getDevices();
+ return devices2.filter((d) => d.vendorId === ledgerUSBVendorId);
+ });
+}
+function getFirstLedgerDevice2() {
+ return __awaiter7(this, void 0, void 0, function* () {
+ const existingDevices = yield getLedgerDevices2();
+ if (existingDevices.length > 0)
+ return existingDevices[0];
+ const devices2 = yield requestLedgerDevices();
+ return devices2[0];
+ });
+}
+var __awaiter7, ledgerDevices2, isSupported2, getHID, TransportWebHID, TransportWebHID_default;
+var init_TransportWebHID = __esm({
+ "node_modules/@ledgerhq/hw-transport-webhid/lib-es/TransportWebHID.js"() {
+ init_Transport();
+ init_hid_framing();
+ init_lib_es3();
+ init_lib_es2();
+ init_lib_es();
+ __awaiter7 = function(thisArg, _arguments, P, generator) {
+ function adopt(value) {
+ return value instanceof P ? value : new P(function(resolve) {
+ resolve(value);
+ });
+ }
+ return new (P || (P = Promise))(function(resolve, reject) {
+ function fulfilled(value) {
+ try {
+ step(generator.next(value));
+ } catch (e) {
+ reject(e);
+ }
+ }
+ function rejected(value) {
+ try {
+ step(generator["throw"](value));
+ } catch (e) {
+ reject(e);
+ }
+ }
+ function step(result) {
+ result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
+ }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+ };
+ ledgerDevices2 = [
+ {
+ vendorId: ledgerUSBVendorId
+ }
+ ];
+ isSupported2 = () => Promise.resolve(!!(window.navigator && window.navigator.hid));
+ getHID = () => {
+ const { hid } = navigator;
+ if (!hid)
+ throw new TransportError("navigator.hid is not supported", "HIDNotSupported");
+ return hid;
+ };
+ TransportWebHID = class _TransportWebHID extends Transport_default {
+ constructor(device) {
super();
this.channel = Math.floor(Math.random() * 65535);
this.packetSize = 64;
+ this.inputs = [];
+ this.read = () => {
+ if (this.inputs.length) {
+ return Promise.resolve(this.inputs.shift());
+ }
+ return new Promise((success) => {
+ this.inputCallback = success;
+ });
+ };
+ this.onInputReport = (e) => {
+ const buffer2 = Buffer.from(e.data.buffer);
+ if (this.inputCallback) {
+ this.inputCallback(buffer2);
+ this.inputCallback = null;
+ } else {
+ this.inputs.push(buffer2);
+ }
+ };
this._disconnectEmitted = false;
this._emitDisconnect = (e) => {
if (this._disconnectEmitted)
this._disconnectEmitted = true;
this.emit("disconnect", e);
};
+ this.exchange = (apdu) => __awaiter7(this, void 0, void 0, function* () {
+ const b = yield this.exchangeAtomicImpl(() => __awaiter7(this, void 0, void 0, function* () {
+ const { channel, packetSize } = this;
+ log("apdu", "=> " + apdu.toString("hex"));
+ const framing = hid_framing_default(channel, packetSize);
+ const blocks = framing.makeBlocks(apdu);
+ for (let i = 0; i < blocks.length; i++) {
+ yield this.device.sendReport(0, blocks[i]);
+ }
+ let result;
+ let acc;
+ while (!(result = framing.getReducedResult(acc))) {
+ const buffer2 = yield this.read();
+ acc = framing.reduceResponse(acc, buffer2);
+ }
+ log("apdu", "<= " + result.toString("hex"));
+ return result;
+ })).catch((e) => {
+ if (e && e.message && e.message.includes("write")) {
+ this._emitDisconnect(e);
+ throw new DisconnectedDeviceDuringOperation(e.message);
+ }
+ throw e;
+ });
+ return b;
+ });
this.device = device;
- this.interfaceNumber = interfaceNumber;
- this.deviceModel = identifyUSBProductId(device.productId);
+ this.deviceModel = typeof device.productId === "number" ? identifyUSBProductId(device.productId) : void 0;
+ device.addEventListener("inputreport", this.onInputReport);
}
/**
* Similar to create() except it will always display the device permission (even if some devices are already accepted).
*/
static request() {
- return __awaiter6(this, void 0, void 0, function* () {
- const device = yield requestLedgerDevice();
- return _TransportWebUSB.open(device);
+ return __awaiter7(this, void 0, void 0, function* () {
+ const [device] = yield requestLedgerDevices();
+ return _TransportWebHID.open(device);
});
}
/**
* Similar to create() except it will never display the device permission (it returns a Promise<?Transport>, null if it fails to find a device).
*/
static openConnected() {
- return __awaiter6(this, void 0, void 0, function* () {
- const devices2 = yield getLedgerDevices();
+ return __awaiter7(this, void 0, void 0, function* () {
+ const devices2 = yield getLedgerDevices2();
if (devices2.length === 0)
return null;
- return _TransportWebUSB.open(devices2[0]);
+ return _TransportWebHID.open(devices2[0]);
+ });
+ }
+ /**
+ * Create a Ledger transport with a HIDDevice
+ */
+ static open(device) {
+ return __awaiter7(this, void 0, void 0, function* () {
+ yield device.open();
+ const transport = new _TransportWebHID(device);
+ const onDisconnect = (e) => {
+ if (device === e.device) {
+ getHID().removeEventListener("disconnect", onDisconnect);
+ transport._emitDisconnect(new DisconnectedDevice());
+ }
+ };
+ getHID().addEventListener("disconnect", onDisconnect);
+ return transport;
+ });
+ }
+ /**
+ * Release the transport device
+ */
+ close() {
+ return __awaiter7(this, void 0, void 0, function* () {
+ yield this.exchangeBusyPromise;
+ this.device.removeEventListener("inputreport", this.onInputReport);
+ yield this.device.close();
});
}
+ setScrambleKey() {
+ }
+ };
+ TransportWebHID.isSupported = isSupported2;
+ TransportWebHID.list = getLedgerDevices2;
+ TransportWebHID.listen = (observer) => {
+ let unsubscribed = false;
+ getFirstLedgerDevice2().then((device) => {
+ if (!device) {
+ observer.error(new TransportOpenUserCancelled("Access denied to use Ledger device"));
+ } else if (!unsubscribed) {
+ const deviceModel = typeof device.productId === "number" ? identifyUSBProductId(device.productId) : void 0;
+ observer.next({
+ type: "add",
+ descriptor: device,
+ deviceModel
+ });
+ observer.complete();
+ }
+ }, (error) => {
+ observer.error(new TransportOpenUserCancelled(error.message));
+ });
+ function unsubscribe() {
+ unsubscribed = true;
+ }
+ return {
+ unsubscribe
+ };
+ };
+ TransportWebHID_default = TransportWebHID;
+ }
+});
+
+// dist/lib/ledger.js
+var ledger_exports = {};
+__export(ledger_exports, {
+ Ledger: () => Ledger
+});
+var Ledger;
+var init_ledger = __esm({
+ "dist/lib/ledger.js"() {
+ "use strict";
+ init_TransportWebBLE();
+ init_TransportWebUSB();
+ init_TransportWebHID();
+ init_constants();
+ init_convert();
+ init_rpc();
+ init_block();
+ Ledger = class _Ledger {
+ static #isInternal = false;
+ #status = "DISCONNECTED";
+ get status() {
+ return this.#status;
+ }
+ openTimeout = 3e3;
+ listenTimeout = 3e4;
+ transport = null;
+ DynamicTransport = TransportWebHID_default;
+ constructor() {
+ if (!_Ledger.#isInternal) {
+ throw new Error("Ledger cannot be instantiated directly. Use Ledger.init()");
+ }
+ _Ledger.#isInternal = false;
+ }
+ static async init() {
+ _Ledger.#isInternal = true;
+ const self = new this();
+ await self.checkBrowserSupport();
+ await self.listen();
+ return self;
+ }
+ /**
+ * Check which transport protocols are supported by the browser and set the
+ * transport type according to the following priorities: Bluetooth, USB, HID.
+ */
+ async checkBrowserSupport() {
+ console.log("Checking browser Ledger support...");
+ const supports = {
+ ble: await TransportWebBLE_default.isSupported(),
+ usb: await TransportWebUSB_default.isSupported(),
+ hid: await TransportWebHID_default.isSupported()
+ };
+ console.log(`ble: ${supports.ble}; usb: ${supports.usb}; hid: ${supports.hid}`);
+ if (supports.ble) {
+ this.DynamicTransport = TransportWebBLE_default;
+ } else if (supports.usb) {
+ this.DynamicTransport = TransportWebUSB_default;
+ } else if (supports.hid) {
+ this.DynamicTransport = TransportWebHID_default;
+ } else {
+ throw new Error("Unsupported browser");
+ }
+ }
+ async listen() {
+ const { usb } = globalThis.navigator;
+ if (usb) {
+ usb.addEventListener("connect", console.log.bind(console));
+ usb.addEventListener("disconnect", console.log.bind(console));
+ }
+ }
+ async connect() {
+ const { usb } = globalThis.navigator;
+ if (usb) {
+ usb.removeEventListener("disconnect", this.onDisconnectUsb.bind(this));
+ usb.addEventListener("disconnect", this.onDisconnectUsb.bind(this));
+ }
+ const version = await this.version();
+ if (version.status === "OK") {
+ if (version.name === "Nano") {
+ const account = await this.account();
+ if (account.status === "OK") {
+ this.#status = "CONNECTED";
+ } else if (account.status === "SECURITY_STATUS_NOT_SATISFIED") {
+ this.#status = "LOCKED";
+ } else {
+ this.#status = "DISCONNECTED";
+ }
+ } else if (version.name === "BOLOS") {
+ const open2 = await this.open();
+ this.#status = open2.status === "OK" ? "CONNECTED" : "DISCONNECTED";
+ } else {
+ this.#status = "BUSY";
+ }
+ } else {
+ this.#status = "DISCONNECTED";
+ }
+ return this.status;
+ }
+ async onDisconnectUsb(e) {
+ if (e.device?.manufacturerName === "Ledger") {
+ const { usb } = globalThis.navigator;
+ usb.removeEventListener("disconnect", this.onDisconnectUsb);
+ this.#status = "DISCONNECTED";
+ }
+ }
+ /**
+ * Open Nano app by launching user flow.
+ *
+ * https://developers.ledger.com/docs/connectivity/ledgerJS/open-close-info-on-apps#open-application
+ *
+ * This command resets the internal USB connection of the device which can
+ * cause subsequent commands to fail if called too quickly. A one-second delay
+ * is implemented in this method to mitigate the issue.
+ *
+ * https://github.com/LedgerHQ/ledger-live/issues/4964#issuecomment-1878361157
+ *
+ * @returns Status of command
+ */
+ async open() {
+ const name = new TextEncoder().encode("Nano");
+ const transport = await this.DynamicTransport.create(this.openTimeout, this.listenTimeout);
+ const response = await transport.send(224, 216, 0, 0, name).then((res) => bytes.toDec(res)).catch((err) => err.statusCode);
+ return new Promise((resolve) => setTimeout(resolve, 1e3, { status: LEDGER_STATUS_CODES[response] }));
+ }
/**
- * Create a Ledger transport with a USBDevice
- */
- static open(device) {
- return __awaiter6(this, void 0, void 0, function* () {
- yield device.open();
- if (device.configuration === null) {
- yield device.selectConfiguration(configurationValue);
- }
- yield gracefullyResetDevice(device);
- const iface = device.configurations[0].interfaces.find(({ alternates }) => alternates.some((a) => a.interfaceClass === 255));
- if (!iface) {
- throw new TransportInterfaceNotAvailable("No WebUSB interface found for your Ledger device. Please upgrade firmware or contact techsupport.");
- }
- const interfaceNumber = iface.interfaceNumber;
- try {
- yield device.claimInterface(interfaceNumber);
- } catch (e) {
- yield device.close();
- throw new TransportInterfaceNotAvailable(e.message);
- }
- const transport = new _TransportWebUSB(device, interfaceNumber);
- const onDisconnect = (e) => {
- if (device === e.device) {
- navigator.usb.removeEventListener("disconnect", onDisconnect);
- transport._emitDisconnect(new DisconnectedDevice());
- }
- };
- navigator.usb.addEventListener("disconnect", onDisconnect);
- return transport;
- });
+ * Close the currently running app.
+ *
+ * https://developers.ledger.com/docs/connectivity/ledgerJS/open-close-info-on-apps#quit-application
+ *
+ * This command resets the internal USB connection of the device which can
+ * cause subsequent commands to fail if called too quickly. A one-second delay
+ * is implemented in this method to mitigate the issue.
+ *
+ * https://github.com/LedgerHQ/ledger-live/issues/4964#issuecomment-1878361157
+ *
+ * @returns Status of command
+ */
+ async close() {
+ const transport = await this.DynamicTransport.create(this.openTimeout, this.listenTimeout);
+ const response = await transport.send(176, 167, 0, 0).then((res) => bytes.toDec(res)).catch((err) => err.statusCode);
+ return new Promise((resolve) => setTimeout(resolve, 1e3, { status: LEDGER_STATUS_CODES[response] }));
}
/**
- * Release the transport device
- */
- close() {
- return __awaiter6(this, void 0, void 0, function* () {
- yield this.exchangeBusyPromise;
- yield this.device.releaseInterface(this.interfaceNumber);
- yield gracefullyResetDevice(this.device);
- yield this.device.close();
- });
+ * Get the version of the current process. If a specific app is running, get
+ * the app version. Otherwise, get the Ledger BOLOS version instead.
+ *
+ * https://developers.ledger.com/docs/connectivity/ledgerJS/open-close-info-on-apps#get-information
+ *
+ * @returns Status, process name, and version
+ */
+ async version() {
+ const transport = await this.DynamicTransport.create(this.openTimeout, this.listenTimeout);
+ const response = await transport.send(176, 1, 0, 0).catch((err) => dec.toBytes(err.statusCode));
+ await transport.close();
+ if (response.length === 2) {
+ const statusCode2 = bytes.toDec(response);
+ const status2 = LEDGER_STATUS_CODES[statusCode2] ?? "UNKNOWN_ERROR";
+ return { status: status2, name: null, version: null };
+ }
+ const nameLength = response[1];
+ const name = response.slice(2, 2 + nameLength).toString();
+ const versionLength = response[2 + nameLength];
+ const version = response.slice(2 + nameLength + 1, 2 + nameLength + 1 + versionLength).toString();
+ const statusCode = bytes.toDec(response.slice(-2));
+ const status = LEDGER_STATUS_CODES[statusCode];
+ return { status, name, version };
}
/**
- * Exchange with the device using APDU protocol.
- * @param apdu
- * @returns a promise of apdu response
- */
- exchange(apdu) {
- return __awaiter6(this, void 0, void 0, function* () {
- const b = yield this.exchangeAtomicImpl(() => __awaiter6(this, void 0, void 0, function* () {
- const { channel, packetSize } = this;
- log("apdu", "=> " + apdu.toString("hex"));
- const framing = hid_framing_default(channel, packetSize);
- const blocks = framing.makeBlocks(apdu);
- for (let i = 0; i < blocks.length; i++) {
- yield this.device.transferOut(endpointNumber, blocks[i]);
- }
- let result;
- let acc;
- while (!(result = framing.getReducedResult(acc))) {
- const r = yield this.device.transferIn(endpointNumber, packetSize);
- const buffer2 = Buffer.from(r.data.buffer);
- acc = framing.reduceResponse(acc, buffer2);
- }
- log("apdu", "<= " + result.toString("hex"));
- return result;
- })).catch((e) => {
- if (e && e.message && e.message.includes("disconnected")) {
- this._emitDisconnect(e);
- throw new DisconnectedDeviceDuringOperation(e.message);
- }
- throw e;
- });
- return b;
- });
+ * Get an account at a specific BIP-44 index.
+ *
+ * @returns Response object containing command status, public key, and address
+ */
+ async account(index = 0, show = false) {
+ if (typeof index !== "number" || index < 0 || index >= HARDENED_OFFSET) {
+ throw new TypeError("Invalid account index");
+ }
+ const purpose = dec.toBytes(BIP44_PURPOSE + HARDENED_OFFSET, 4);
+ const coin = dec.toBytes(BIP44_COIN_NANO + HARDENED_OFFSET, 4);
+ const account = dec.toBytes(index + HARDENED_OFFSET, 4);
+ const data = new Uint8Array([3, ...purpose, ...coin, ...account]);
+ const transport = await this.DynamicTransport.create(this.openTimeout, this.listenTimeout);
+ const response = await transport.send(161, 2, show ? 1 : 0, 0, data).catch((err) => dec.toBytes(err.statusCode));
+ await transport.close();
+ if (response.length === 2) {
+ const statusCode = bytes.toDec(response);
+ const status = LEDGER_STATUS_CODES[statusCode] ?? "UNKNOWN_ERROR";
+ return { status, publicKey: null, address: null };
+ }
+ try {
+ const publicKey = bytes.toHex(response.slice(0, 32));
+ const addressLength = response[32];
+ const address = response.slice(33, 33 + addressLength).toString();
+ const statusCode = bytes.toDec(response.slice(33 + addressLength));
+ const status = LEDGER_STATUS_CODES[statusCode];
+ return { status, publicKey, address };
+ } catch (err) {
+ return { status: "ERROR_PARSING_ACCOUNT", publicKey: null, address: null };
+ }
}
- setScrambleKey() {
+ /**
+ * Cache frontier block in device memory.
+ *
+ * @param {number} index - Account number
+ * @param {any} block - Block data to cache
+ * @returns Status of command
+ */
+ async cacheBlock(index = 0, block) {
+ if (typeof index !== "number" || index < 0 || index >= HARDENED_OFFSET) {
+ throw new TypeError("Invalid account index");
+ }
+ if (!(block instanceof SendBlock) && !(block instanceof ReceiveBlock) && !(block instanceof ChangeBlock)) {
+ throw new TypeError("Invalid block format");
+ }
+ if (!block.signature) {
+ throw new ReferenceError("Cannot cache unsigned block");
+ }
+ const purpose = dec.toBytes(BIP44_PURPOSE + HARDENED_OFFSET, 4);
+ const coin = dec.toBytes(BIP44_COIN_NANO + HARDENED_OFFSET, 4);
+ const account = dec.toBytes(index + HARDENED_OFFSET, 4);
+ const previous = hex.toBytes(block.previous);
+ const link = hex.toBytes(block.link);
+ const representative = hex.toBytes(block.representative.publicKey);
+ const balance = hex.toBytes(BigInt(block.balance).toString(16), 16);
+ const signature = hex.toBytes(block.signature);
+ const data = new Uint8Array([3, ...purpose, ...coin, ...account, ...previous, ...link, ...representative, ...balance, ...signature]);
+ const transport = await this.DynamicTransport.create(this.openTimeout, this.listenTimeout);
+ const response = await transport.send(161, 3, 0, 0, data).then((res) => bytes.toDec(res)).catch((err) => err.statusCode);
+ await transport.close();
+ return { status: LEDGER_STATUS_CODES[response] };
}
- };
- TransportWebUSB.isSupported = isSupported;
- TransportWebUSB.list = getLedgerDevices;
- TransportWebUSB.listen = (observer) => {
- let unsubscribed = false;
- getFirstLedgerDevice().then((device) => {
- if (!unsubscribed) {
- const deviceModel = identifyUSBProductId(device.productId);
- observer.next({
- type: "add",
- descriptor: device,
- deviceModel
- });
- observer.complete();
+ async sign(index = 0, input) {
+ if (typeof index !== "number" || index < 0 || index >= HARDENED_OFFSET) {
+ throw new TypeError("Invalid account index");
}
- }, (error) => {
- if (window.DOMException && error instanceof window.DOMException && error.code === 18) {
- observer.error(new TransportWebUSBGestureRequired(error.message));
+ const purpose = dec.toBytes(BIP44_PURPOSE + HARDENED_OFFSET, 4);
+ const coin = dec.toBytes(BIP44_COIN_NANO + HARDENED_OFFSET, 4);
+ const account = dec.toBytes(index + HARDENED_OFFSET, 4);
+ const transport = await this.DynamicTransport.create(this.openTimeout, this.listenTimeout);
+ if (typeof input === "string") {
+ const nonce = utf8.toBytes(input);
+ if (nonce.length !== 16) {
+ throw new RangeError("Nonce must be 16-byte string");
+ }
+ const data = new Uint8Array([3, ...purpose, ...coin, ...account, ...nonce]);
+ const response = await transport.send(161, 5, 0, 0, data).catch((err) => dec.toBytes(err.statusCode));
+ await transport.close();
+ if (response.length === 2) {
+ const statusCode2 = bytes.toDec(response);
+ const status2 = LEDGER_STATUS_CODES[statusCode2] ?? "UNKNOWN_ERROR";
+ return { status: status2, signature: null };
+ }
+ const signature = bytes.toHex(response.slice(0, 64));
+ const statusCode = bytes.toDec(response.slice(-2));
+ const status = LEDGER_STATUS_CODES[statusCode];
+ return { status, signature };
} else {
- observer.error(new TransportOpenUserCancelled(error.message));
+ const previous = hex.toBytes(input.previous);
+ const link = hex.toBytes(input.link);
+ const representative = hex.toBytes(input.representative.publicKey);
+ const balance = hex.toBytes(BigInt(input.balance).toString(16), 16);
+ const data = new Uint8Array([3, ...purpose, ...coin, ...account, ...previous, ...link, ...representative, ...balance]);
+ const response = await transport.send(161, 4, 0, 0, data).catch((err) => dec.toBytes(err.statusCode));
+ await transport.close();
+ if (response.length === 2) {
+ const statusCode2 = bytes.toDec(response);
+ const status2 = LEDGER_STATUS_CODES[statusCode2] ?? "UNKNOWN_ERROR";
+ return { status: status2, signature: null, hash: null };
+ }
+ const hash2 = bytes.toHex(response.slice(0, 32));
+ const signature = bytes.toHex(response.slice(32, 96));
+ const statusCode = bytes.toDec(response.slice(-2));
+ const status = LEDGER_STATUS_CODES[statusCode];
+ return { status, signature, hash: hash2 };
}
- });
- function unsubscribe() {
- unsubscribed = true;
}
- return {
- unsubscribe
- };
+ async updateCache(index, input, node) {
+ if (typeof input === "string" && node?.constructor === Rpc) {
+ const data = {
+ "json_block": "true",
+ "hash": input
+ };
+ const res = await node.call("block_info", data);
+ if (!res || res.ok === false) {
+ throw new Error(`Unable to fetch block info`, res);
+ }
+ input = res.contents;
+ }
+ return this.cacheBlock(index, input);
+ }
};
- TransportWebUSB_default = TransportWebUSB;
}
});
-// node_modules/@ledgerhq/hw-transport-webhid/lib-es/TransportWebHID.js
-function requestLedgerDevices() {
- return __awaiter7(this, void 0, void 0, function* () {
- const device = yield getHID().requestDevice({
- filters: ledgerDevices2
- });
- if (Array.isArray(device))
- return device;
- return [device];
- });
-}
-function getLedgerDevices2() {
- return __awaiter7(this, void 0, void 0, function* () {
- const devices2 = yield getHID().getDevices();
- return devices2.filter((d) => d.vendorId === ledgerUSBVendorId);
- });
-}
-function getFirstLedgerDevice2() {
- return __awaiter7(this, void 0, void 0, function* () {
- const existingDevices = yield getLedgerDevices2();
- if (existingDevices.length > 0)
- return existingDevices[0];
- const devices2 = yield requestLedgerDevices();
- return devices2[0];
- });
-}
-var __awaiter7, ledgerDevices2, isSupported2, getHID, TransportWebHID, TransportWebHID_default;
-var init_TransportWebHID = __esm({
- "node_modules/@ledgerhq/hw-transport-webhid/lib-es/TransportWebHID.js"() {
- init_Transport();
- init_hid_framing();
- init_lib_es3();
- init_lib_es2();
- init_lib_es();
- __awaiter7 = function(thisArg, _arguments, P, generator) {
- function adopt(value) {
- return value instanceof P ? value : new P(function(resolve) {
- resolve(value);
- });
+// dist/lib/block.js
+function validate(block) {
+ if (block.account == null) {
+ throw new Error("Account missing");
+ }
+ if (block.previous == null || block.previous === "") {
+ throw new Error("Frontier missing");
+ }
+ if (block.representative == null) {
+ throw new Error("Representative missing");
+ }
+ if (block.balance == null) {
+ throw new Error("Balance missing");
+ }
+ if (block.balance < 0) {
+ throw new Error("Negative balance");
+ }
+ switch (block.constructor) {
+ case SendBlock: {
+ if (block.link == null || block.link === "") {
+ throw new Error("Recipient missing");
}
- return new (P || (P = Promise))(function(resolve, reject) {
- function fulfilled(value) {
- try {
- step(generator.next(value));
- } catch (e) {
- reject(e);
- }
- }
- function rejected(value) {
- try {
- step(generator["throw"](value));
- } catch (e) {
- reject(e);
- }
+ break;
+ }
+ case ReceiveBlock: {
+ if (block.link == null) {
+ throw new Error("Origin send block hash missing");
+ }
+ break;
+ }
+ case ChangeBlock: {
+ if (block.link == null) {
+ throw new Error("Change block link missing");
+ }
+ if (+block.link !== 0) {
+ throw new Error("Invalid change block link");
+ }
+ break;
+ }
+ }
+}
+var Block, SendBlock, ReceiveBlock, ChangeBlock;
+var init_block = __esm({
+ "dist/lib/block.js"() {
+ "use strict";
+ init_constants();
+ init_account();
+ init_blake2b();
+ init_convert();
+ init_nano_nacl();
+ init_pool2();
+ init_workers();
+ Block = class _Block {
+ static #pool = new Pool2(nano_pow_default);
+ account;
+ type = "state";
+ constructor(account) {
+ if (this.constructor === _Block) {
+ throw new Error("Block is an abstract class and cannot be instantiated directly.");
}
- function step(result) {
- result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
+ if (account.constructor === Account) {
+ this.account = account;
+ } else if (typeof account === "string") {
+ this.account = Account.fromAddress(account);
+ } else {
+ throw new TypeError("Invalid account");
}
- step((generator = generator.apply(thisArg, _arguments || [])).next());
- });
- };
- ledgerDevices2 = [
- {
- vendorId: ledgerUSBVendorId
}
- ];
- isSupported2 = () => Promise.resolve(!!(window.navigator && window.navigator.hid));
- getHID = () => {
- const { hid } = navigator;
- if (!hid)
- throw new TransportError("navigator.hid is not supported", "HIDNotSupported");
- return hid;
- };
- TransportWebHID = class _TransportWebHID extends Transport_default {
- constructor(device) {
- super();
- this.channel = Math.floor(Math.random() * 65535);
- this.packetSize = 64;
- this.inputs = [];
- this.read = () => {
- if (this.inputs.length) {
- return Promise.resolve(this.inputs.shift());
- }
- return new Promise((success) => {
- this.inputCallback = success;
- });
- };
- this.onInputReport = (e) => {
- const buffer2 = Buffer.from(e.data.buffer);
- if (this.inputCallback) {
- this.inputCallback(buffer2);
- this.inputCallback = null;
- } else {
- this.inputs.push(buffer2);
- }
- };
- this._disconnectEmitted = false;
- this._emitDisconnect = (e) => {
- if (this._disconnectEmitted)
- return;
- this._disconnectEmitted = true;
- this.emit("disconnect", e);
+ /**
+ * Converts the block to JSON format as expected by the `process` RPC.
+ *
+ * @returns {string} JSON representation of the block
+ */
+ json() {
+ return {
+ "type": this.type,
+ "account": this.account.address,
+ "previous": this.previous,
+ "representative": this.representative.address,
+ "balance": this.balance.toString(),
+ "link": this.link,
+ "signature": this.signature ?? "",
+ "work": this.work ?? ""
};
- this.exchange = (apdu) => __awaiter7(this, void 0, void 0, function* () {
- const b = yield this.exchangeAtomicImpl(() => __awaiter7(this, void 0, void 0, function* () {
- const { channel, packetSize } = this;
- log("apdu", "=> " + apdu.toString("hex"));
- const framing = hid_framing_default(channel, packetSize);
- const blocks = framing.makeBlocks(apdu);
- for (let i = 0; i < blocks.length; i++) {
- yield this.device.sendReport(0, blocks[i]);
- }
- let result;
- let acc;
- while (!(result = framing.getReducedResult(acc))) {
- const buffer2 = yield this.read();
- acc = framing.reduceResponse(acc, buffer2);
- }
- log("apdu", "<= " + result.toString("hex"));
- return result;
- })).catch((e) => {
- if (e && e.message && e.message.includes("write")) {
- this._emitDisconnect(e);
- throw new DisconnectedDeviceDuringOperation(e.message);
- }
- throw e;
- });
- return b;
- });
- this.device = device;
- this.deviceModel = typeof device.productId === "number" ? identifyUSBProductId(device.productId) : void 0;
- device.addEventListener("inputreport", this.onInputReport);
}
/**
- * Similar to create() except it will always display the device permission (even if some devices are already accepted).
- */
- static request() {
- return __awaiter7(this, void 0, void 0, function* () {
- const [device] = yield requestLedgerDevices();
- return _TransportWebHID.open(device);
- });
+ * Hashes the block using Blake2b.
+ *
+ * @returns {Promise<string>} Block data hashed to a byte array
+ */
+ async hash() {
+ const data = [
+ PREAMBLE,
+ this.account.publicKey,
+ this.previous,
+ this.representative.publicKey,
+ dec.toHex(this.balance, 32),
+ this.link
+ ];
+ const hash2 = new Blake2b(32);
+ data.forEach((str) => hash2.update(hex.toBytes(str)));
+ return hash2.digest("hex").toUpperCase();
+ }
+ /**
+ * Calculates proof-of-work using a pool of WebGL workers.
+ *
+ * A successful response sets the `work` property.
+ */
+ async pow() {
+ const data = {
+ "hash": this.previous,
+ "threshold": this instanceof SendBlock || this instanceof ChangeBlock ? THRESHOLD_SEND : THRESHOLD_RECEIVE
+ };
+ const [{ work }] = await _Block.#pool.assign([data]);
+ this.work = work;
+ }
+ async sign(input, block) {
+ if (typeof input === "number") {
+ const index = input;
+ const { Ledger: Ledger2 } = await Promise.resolve().then(() => (init_ledger(), ledger_exports));
+ const ledger = await Ledger2.init();
+ await ledger.open();
+ if (block) {
+ try {
+ await ledger.updateCache(index, block);
+ } catch (err) {
+ console.warn("Error updating Ledger cache of previous block, attempting signature anyway", err);
+ }
+ }
+ const result = await ledger.sign(index, this);
+ if (result.status !== "OK") {
+ throw new Error(result.status);
+ }
+ this.signature = result.signature;
+ } else {
+ const key = input ?? this.account.privateKey;
+ if (key == null) {
+ throw new Error("No valid key found to sign block");
+ }
+ const account = await Account.fromPrivateKey(key);
+ try {
+ const signature = NanoNaCl.detached(hex.toBytes(await this.hash()), hex.toBytes(`${account.privateKey}`));
+ this.signature = signature;
+ } catch (err) {
+ throw new Error(`Failed to sign block with key ${key}: ${err}`);
+ }
+ }
}
/**
- * Similar to create() except it will never display the device permission (it returns a Promise<?Transport>, null if it fails to find a device).
- */
- static openConnected() {
- return __awaiter7(this, void 0, void 0, function* () {
- const devices2 = yield getLedgerDevices2();
- if (devices2.length === 0)
- return null;
- return _TransportWebHID.open(devices2[0]);
- });
+ * Sends the block to a node for processing on the network.
+ *
+ * The block must already be signed (see `sign()` for more information).
+ * The block must also have a `work` value.
+ *
+ * @param {Rpc|string|URL} rpc - RPC node information required to call `process`
+ * @returns {Promise<string>} Hash of the processed block
+ */
+ async process(rpc) {
+ if (!this.signature) {
+ throw new Error("Block is missing signature. Use sign() and try again.");
+ }
+ if (!this.work == null) {
+ throw new Error("Block is missing proof-of-work. Generate PoW and try again.");
+ }
+ const data = {
+ "subtype": this.subtype,
+ "json_block": "true",
+ "block": this.json()
+ };
+ const res = await rpc.call("process", data);
+ if (res.hash == null) {
+ throw new Error("Block could not be processed", res);
+ }
+ return res.hash;
}
/**
- * Create a Ledger transport with a HIDDevice
- */
- static open(device) {
- return __awaiter7(this, void 0, void 0, function* () {
- yield device.open();
- const transport = new _TransportWebHID(device);
- const onDisconnect = (e) => {
- if (device === e.device) {
- getHID().removeEventListener("disconnect", onDisconnect);
- transport._emitDisconnect(new DisconnectedDevice());
- }
- };
- getHID().addEventListener("disconnect", onDisconnect);
- return transport;
- });
+ * Verifies the signature of the block. If a key is not provided, the public
+ * key of the block's account will be used if it exists.
+ *
+ * @param {string} [key] - Hexadecimal-formatted public key to use for verification
+ * @returns {boolean} True if block was signed by the matching private key
+ */
+ async verify(key) {
+ key ??= this.account.publicKey;
+ if (!key) {
+ throw new Error("Provide a key for block signature verification.");
+ }
+ const data = [
+ PREAMBLE,
+ this.account.publicKey,
+ this.previous,
+ this.representative.publicKey,
+ dec.toHex(this.balance, 32),
+ this.link
+ ];
+ const hash2 = new Blake2b(32);
+ data.forEach((str) => hash2.update(hex.toBytes(str)));
+ const blockHash = hash2.digest("hex").toUpperCase();
+ return NanoNaCl.verify(hex.toBytes(blockHash), hex.toBytes(this.signature ?? ""), hex.toBytes(key));
}
- /**
- * Release the transport device
- */
- close() {
- return __awaiter7(this, void 0, void 0, function* () {
- yield this.exchangeBusyPromise;
- this.device.removeEventListener("inputreport", this.onInputReport);
- yield this.device.close();
- });
+ };
+ SendBlock = class extends Block {
+ type = "state";
+ subtype = "send";
+ previous;
+ representative;
+ balance;
+ link;
+ signature;
+ work;
+ constructor(sender, balance, recipient, amount, representative, frontier, work) {
+ super(sender);
+ this.previous = frontier;
+ this.representative = Account.fromAddress(representative);
+ this.link = Account.fromAddress(recipient).publicKey;
+ this.work = work ?? "";
+ const bigBalance = BigInt(balance);
+ const bigAmount = BigInt(amount);
+ this.balance = bigBalance - bigAmount;
+ validate(this);
}
- setScrambleKey() {
+ };
+ ReceiveBlock = class extends Block {
+ type = "state";
+ subtype = "receive";
+ previous;
+ representative;
+ balance;
+ link;
+ signature;
+ work;
+ constructor(recipient, balance, origin, amount, representative, frontier, work) {
+ super(recipient);
+ this.previous = frontier ?? Account.fromAddress(recipient).publicKey;
+ this.representative = Account.fromAddress(representative);
+ this.link = origin;
+ this.work = work ?? "";
+ const bigBalance = BigInt(balance);
+ const bigAmount = BigInt(amount);
+ this.balance = bigBalance + bigAmount;
+ validate(this);
}
};
- TransportWebHID.isSupported = isSupported2;
- TransportWebHID.list = getLedgerDevices2;
- TransportWebHID.listen = (observer) => {
- let unsubscribed = false;
- getFirstLedgerDevice2().then((device) => {
- if (!device) {
- observer.error(new TransportOpenUserCancelled("Access denied to use Ledger device"));
- } else if (!unsubscribed) {
- const deviceModel = typeof device.productId === "number" ? identifyUSBProductId(device.productId) : void 0;
- observer.next({
- type: "add",
- descriptor: device,
- deviceModel
- });
- observer.complete();
- }
- }, (error) => {
- observer.error(new TransportOpenUserCancelled(error.message));
- });
- function unsubscribe() {
- unsubscribed = true;
+ ChangeBlock = class extends Block {
+ type = "state";
+ subtype = "change";
+ previous;
+ representative;
+ balance;
+ link = Account.fromAddress(BURN_ADDRESS).publicKey;
+ signature;
+ work;
+ constructor(account, balance, representative, frontier, work) {
+ super(account);
+ this.previous = frontier;
+ this.representative = Account.fromAddress(representative);
+ this.balance = BigInt(balance);
+ this.work = work ?? "";
+ validate(this);
}
- return {
- unsubscribe
- };
};
- TransportWebHID_default = TransportWebHID;
}
});
-// dist/lib/ledger.js
-var ledger_exports = {};
-__export(ledger_exports, {
- Ledger: () => Ledger
-});
-var Ledger;
-var init_ledger = __esm({
- "dist/lib/ledger.js"() {
+// dist/lib/workers/nano-nacl.js
+var NanoNaCl2, nano_nacl_default2;
+var init_nano_nacl2 = __esm({
+ "dist/lib/workers/nano-nacl.js"() {
"use strict";
- init_TransportWebBLE();
- init_TransportWebUSB();
- init_TransportWebHID();
- init_constants();
- init_convert();
- init_rpc();
- init_block();
- Ledger = class _Ledger {
- static #isInternal = false;
- #status = "DISCONNECTED";
- get status() {
- return this.#status;
+ init_blake2b();
+ init_pool();
+ NanoNaCl2 = class _NanoNaCl extends WorkerInterface {
+ static {
+ _NanoNaCl.listen();
}
- openTimeout = 3e3;
- listenTimeout = 3e4;
- transport = null;
- DynamicTransport = TransportWebHID_default;
- constructor() {
- if (!_Ledger.#isInternal) {
- throw new Error("Ledger cannot be instantiated directly. Use Ledger.init()");
- }
- _Ledger.#isInternal = false;
+ static async work(data) {
+ return new Promise(async (resolve, reject) => {
+ for (let d of data) {
+ try {
+ d.publicKey = await this.convert(d.privateKey);
+ } catch (err) {
+ reject(err);
+ }
+ }
+ resolve(data);
+ });
}
- static async init() {
- _Ledger.#isInternal = true;
- const self = new this();
- await self.checkBrowserSupport();
- await self.listen();
- return self;
+ static gf = function(init) {
+ const r = new Float64Array(16);
+ if (init)
+ for (let i = 0; i < init.length; i++)
+ r[i] = init[i];
+ return r;
+ };
+ static gf0 = this.gf();
+ static gf1 = this.gf([1]);
+ static D = this.gf([30883, 4953, 19914, 30187, 55467, 16705, 2637, 112, 59544, 30585, 16505, 36039, 65139, 11119, 27886, 20995]);
+ static D2 = this.gf([61785, 9906, 39828, 60374, 45398, 33411, 5274, 224, 53552, 61171, 33010, 6542, 64743, 22239, 55772, 9222]);
+ static X = this.gf([54554, 36645, 11616, 51542, 42930, 38181, 51040, 26924, 56412, 64982, 57905, 49316, 21502, 52590, 14035, 8553]);
+ static Y = this.gf([26200, 26214, 26214, 26214, 26214, 26214, 26214, 26214, 26214, 26214, 26214, 26214, 26214, 26214, 26214, 26214]);
+ static I = this.gf([41136, 18958, 6951, 50414, 58488, 44335, 6150, 12099, 55207, 15867, 153, 11085, 57099, 20417, 9344, 11139]);
+ static vn(x, xi, y, yi, n) {
+ let d = 0;
+ for (let i = 0; i < n; i++)
+ d |= x[xi + i] ^ y[yi + i];
+ return (1 & d - 1 >>> 8) - 1;
+ }
+ static crypto_verify_32(x, xi, y, yi) {
+ return this.vn(x, xi, y, yi, 32);
+ }
+ static set25519(r, a) {
+ for (let i = 0; i < 16; i++)
+ r[i] = a[i] | 0;
}
- /**
- * Check which transport protocols are supported by the browser and set the
- * transport type according to the following priorities: Bluetooth, USB, HID.
- */
- async checkBrowserSupport() {
- console.log("Checking browser Ledger support...");
- const supports = {
- ble: await TransportWebBLE_default.isSupported(),
- usb: await TransportWebUSB_default.isSupported(),
- hid: await TransportWebHID_default.isSupported()
- };
- console.log(`ble: ${supports.ble}; usb: ${supports.usb}; hid: ${supports.hid}`);
- if (supports.ble) {
- this.DynamicTransport = TransportWebBLE_default;
- } else if (supports.usb) {
- this.DynamicTransport = TransportWebUSB_default;
- } else if (supports.hid) {
- this.DynamicTransport = TransportWebHID_default;
- } else {
- throw new Error("Unsupported browser");
+ static car25519(o) {
+ let v, c = 1;
+ for (let i = 0; i < 16; i++) {
+ v = o[i] + c + 65535;
+ c = Math.floor(v / 65536);
+ o[i] = v - c * 65536;
}
+ o[0] += c - 1 + 37 * (c - 1);
}
- async listen() {
- const { usb } = globalThis.navigator;
- if (usb) {
- usb.addEventListener("connect", console.log.bind(console));
- usb.addEventListener("disconnect", console.log.bind(console));
+ static sel25519(p, q, b) {
+ let t;
+ const c = ~(b - 1);
+ for (let i = 0; i < 16; i++) {
+ t = c & (p[i] ^ q[i]);
+ p[i] ^= t;
+ q[i] ^= t;
}
}
- async connect() {
- const { usb } = globalThis.navigator;
- if (usb) {
- usb.removeEventListener("disconnect", this.onDisconnectUsb.bind(this));
- usb.addEventListener("disconnect", this.onDisconnectUsb.bind(this));
- }
- const version = await this.version();
- if (version.status === "OK") {
- if (version.name === "Nano") {
- const account = await this.account();
- if (account.status === "OK") {
- this.#status = "CONNECTED";
- } else if (account.status === "SECURITY_STATUS_NOT_SATISFIED") {
- this.#status = "LOCKED";
- } else {
- this.#status = "DISCONNECTED";
- }
- } else if (version.name === "BOLOS") {
- const open2 = await this.open();
- this.#status = open2.status === "OK" ? "CONNECTED" : "DISCONNECTED";
- } else {
- this.#status = "BUSY";
+ static pack25519(o, n) {
+ let b;
+ const m = this.gf();
+ const t = this.gf();
+ for (let i = 0; i < 16; i++)
+ t[i] = n[i];
+ this.car25519(t);
+ this.car25519(t);
+ this.car25519(t);
+ for (let j = 0; j < 2; j++) {
+ m[0] = t[0] - 65517;
+ for (let i = 1; i < 15; i++) {
+ m[i] = t[i] - 65535 - (m[i - 1] >> 16 & 1);
+ m[i - 1] &= 65535;
}
- } else {
- this.#status = "DISCONNECTED";
+ m[15] = t[15] - 32767 - (m[14] >> 16 & 1);
+ b = m[15] >> 16 & 1;
+ m[14] &= 65535;
+ this.sel25519(t, m, 1 - b);
}
- return this.status;
- }
- async onDisconnectUsb(e) {
- if (e.device?.manufacturerName === "Ledger") {
- const { usb } = globalThis.navigator;
- usb.removeEventListener("disconnect", this.onDisconnectUsb);
- this.#status = "DISCONNECTED";
+ for (let i = 0; i < 16; i++) {
+ o[2 * i] = t[i] & 255;
+ o[2 * i + 1] = t[i] >> 8;
}
}
- /**
- * Open Nano app by launching user flow.
- *
- * https://developers.ledger.com/docs/connectivity/ledgerJS/open-close-info-on-apps#open-application
- *
- * This command resets the internal USB connection of the device which can
- * cause subsequent commands to fail if called too quickly. A one-second delay
- * is implemented in this method to mitigate the issue.
- *
- * https://github.com/LedgerHQ/ledger-live/issues/4964#issuecomment-1878361157
- *
- * @returns Status of command
- */
- async open() {
- const name = new TextEncoder().encode("Nano");
- const transport = await this.DynamicTransport.create(this.openTimeout, this.listenTimeout);
- const response = await transport.send(224, 216, 0, 0, name).then((res) => bytes.toDec(res)).catch((err) => err.statusCode);
- return new Promise((resolve) => setTimeout(resolve, 1e3, { status: LEDGER_STATUS_CODES[response] }));
+ static neq25519(a, b) {
+ const c = new Uint8Array(32);
+ const d = new Uint8Array(32);
+ this.pack25519(c, a);
+ this.pack25519(d, b);
+ return this.crypto_verify_32(c, 0, d, 0);
}
- /**
- * Close the currently running app.
- *
- * https://developers.ledger.com/docs/connectivity/ledgerJS/open-close-info-on-apps#quit-application
- *
- * This command resets the internal USB connection of the device which can
- * cause subsequent commands to fail if called too quickly. A one-second delay
- * is implemented in this method to mitigate the issue.
- *
- * https://github.com/LedgerHQ/ledger-live/issues/4964#issuecomment-1878361157
- *
- * @returns Status of command
- */
- async close() {
- const transport = await this.DynamicTransport.create(this.openTimeout, this.listenTimeout);
- const response = await transport.send(176, 167, 0, 0).then((res) => bytes.toDec(res)).catch((err) => err.statusCode);
- return new Promise((resolve) => setTimeout(resolve, 1e3, { status: LEDGER_STATUS_CODES[response] }));
+ static par25519(a) {
+ var d = new Uint8Array(32);
+ this.pack25519(d, a);
+ return d[0] & 1;
}
- /**
- * Get the version of the current process. If a specific app is running, get
- * the app version. Otherwise, get the Ledger BOLOS version instead.
- *
- * https://developers.ledger.com/docs/connectivity/ledgerJS/open-close-info-on-apps#get-information
- *
- * @returns Status, process name, and version
- */
- async version() {
- const transport = await this.DynamicTransport.create(this.openTimeout, this.listenTimeout);
- const response = await transport.send(176, 1, 0, 0).catch((err) => dec.toBytes(err.statusCode));
- await transport.close();
- if (response.length === 2) {
- const statusCode2 = bytes.toDec(response);
- const status2 = LEDGER_STATUS_CODES[statusCode2] ?? "UNKNOWN_ERROR";
- return { status: status2, name: null, version: null };
- }
- const nameLength = response[1];
- const name = response.slice(2, 2 + nameLength).toString();
- const versionLength = response[2 + nameLength];
- const version = response.slice(2 + nameLength + 1, 2 + nameLength + 1 + versionLength).toString();
- const statusCode = bytes.toDec(response.slice(-2));
- const status = LEDGER_STATUS_CODES[statusCode];
- return { status, name, version };
+ static unpack25519(o, n) {
+ for (let i = 0; i < 16; i++)
+ o[i] = n[2 * i] + (n[2 * i + 1] << 8);
+ o[15] &= 32767;
+ }
+ static A(o, a, b) {
+ for (let i = 0; i < 16; i++)
+ o[i] = a[i] + b[i];
+ }
+ static Z(o, a, b) {
+ for (let i = 0; i < 16; i++)
+ o[i] = a[i] - b[i];
+ }
+ static M(o, a, b) {
+ let v, c, t0 = 0, t1 = 0, t2 = 0, t3 = 0, t4 = 0, t5 = 0, t6 = 0, t7 = 0, t8 = 0, t9 = 0, t10 = 0, t11 = 0, t12 = 0, t13 = 0, t14 = 0, t15 = 0, t16 = 0, t17 = 0, t18 = 0, t19 = 0, t20 = 0, t21 = 0, t22 = 0, t23 = 0, t24 = 0, t25 = 0, t26 = 0, t27 = 0, t28 = 0, t29 = 0, t30 = 0, b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5], b6 = b[6], b7 = b[7], b8 = b[8], b9 = b[9], b10 = b[10], b11 = b[11], b12 = b[12], b13 = b[13], b14 = b[14], b15 = b[15];
+ v = a[0];
+ t0 += v * b0;
+ t1 += v * b1;
+ t2 += v * b2;
+ t3 += v * b3;
+ t4 += v * b4;
+ t5 += v * b5;
+ t6 += v * b6;
+ t7 += v * b7;
+ t8 += v * b8;
+ t9 += v * b9;
+ t10 += v * b10;
+ t11 += v * b11;
+ t12 += v * b12;
+ t13 += v * b13;
+ t14 += v * b14;
+ t15 += v * b15;
+ v = a[1];
+ t1 += v * b0;
+ t2 += v * b1;
+ t3 += v * b2;
+ t4 += v * b3;
+ t5 += v * b4;
+ t6 += v * b5;
+ t7 += v * b6;
+ t8 += v * b7;
+ t9 += v * b8;
+ t10 += v * b9;
+ t11 += v * b10;
+ t12 += v * b11;
+ t13 += v * b12;
+ t14 += v * b13;
+ t15 += v * b14;
+ t16 += v * b15;
+ v = a[2];
+ t2 += v * b0;
+ t3 += v * b1;
+ t4 += v * b2;
+ t5 += v * b3;
+ t6 += v * b4;
+ t7 += v * b5;
+ t8 += v * b6;
+ t9 += v * b7;
+ t10 += v * b8;
+ t11 += v * b9;
+ t12 += v * b10;
+ t13 += v * b11;
+ t14 += v * b12;
+ t15 += v * b13;
+ t16 += v * b14;
+ t17 += v * b15;
+ v = a[3];
+ t3 += v * b0;
+ t4 += v * b1;
+ t5 += v * b2;
+ t6 += v * b3;
+ t7 += v * b4;
+ t8 += v * b5;
+ t9 += v * b6;
+ t10 += v * b7;
+ t11 += v * b8;
+ t12 += v * b9;
+ t13 += v * b10;
+ t14 += v * b11;
+ t15 += v * b12;
+ t16 += v * b13;
+ t17 += v * b14;
+ t18 += v * b15;
+ v = a[4];
+ t4 += v * b0;
+ t5 += v * b1;
+ t6 += v * b2;
+ t7 += v * b3;
+ t8 += v * b4;
+ t9 += v * b5;
+ t10 += v * b6;
+ t11 += v * b7;
+ t12 += v * b8;
+ t13 += v * b9;
+ t14 += v * b10;
+ t15 += v * b11;
+ t16 += v * b12;
+ t17 += v * b13;
+ t18 += v * b14;
+ t19 += v * b15;
+ v = a[5];
+ t5 += v * b0;
+ t6 += v * b1;
+ t7 += v * b2;
+ t8 += v * b3;
+ t9 += v * b4;
+ t10 += v * b5;
+ t11 += v * b6;
+ t12 += v * b7;
+ t13 += v * b8;
+ t14 += v * b9;
+ t15 += v * b10;
+ t16 += v * b11;
+ t17 += v * b12;
+ t18 += v * b13;
+ t19 += v * b14;
+ t20 += v * b15;
+ v = a[6];
+ t6 += v * b0;
+ t7 += v * b1;
+ t8 += v * b2;
+ t9 += v * b3;
+ t10 += v * b4;
+ t11 += v * b5;
+ t12 += v * b6;
+ t13 += v * b7;
+ t14 += v * b8;
+ t15 += v * b9;
+ t16 += v * b10;
+ t17 += v * b11;
+ t18 += v * b12;
+ t19 += v * b13;
+ t20 += v * b14;
+ t21 += v * b15;
+ v = a[7];
+ t7 += v * b0;
+ t8 += v * b1;
+ t9 += v * b2;
+ t10 += v * b3;
+ t11 += v * b4;
+ t12 += v * b5;
+ t13 += v * b6;
+ t14 += v * b7;
+ t15 += v * b8;
+ t16 += v * b9;
+ t17 += v * b10;
+ t18 += v * b11;
+ t19 += v * b12;
+ t20 += v * b13;
+ t21 += v * b14;
+ t22 += v * b15;
+ v = a[8];
+ t8 += v * b0;
+ t9 += v * b1;
+ t10 += v * b2;
+ t11 += v * b3;
+ t12 += v * b4;
+ t13 += v * b5;
+ t14 += v * b6;
+ t15 += v * b7;
+ t16 += v * b8;
+ t17 += v * b9;
+ t18 += v * b10;
+ t19 += v * b11;
+ t20 += v * b12;
+ t21 += v * b13;
+ t22 += v * b14;
+ t23 += v * b15;
+ v = a[9];
+ t9 += v * b0;
+ t10 += v * b1;
+ t11 += v * b2;
+ t12 += v * b3;
+ t13 += v * b4;
+ t14 += v * b5;
+ t15 += v * b6;
+ t16 += v * b7;
+ t17 += v * b8;
+ t18 += v * b9;
+ t19 += v * b10;
+ t20 += v * b11;
+ t21 += v * b12;
+ t22 += v * b13;
+ t23 += v * b14;
+ t24 += v * b15;
+ v = a[10];
+ t10 += v * b0;
+ t11 += v * b1;
+ t12 += v * b2;
+ t13 += v * b3;
+ t14 += v * b4;
+ t15 += v * b5;
+ t16 += v * b6;
+ t17 += v * b7;
+ t18 += v * b8;
+ t19 += v * b9;
+ t20 += v * b10;
+ t21 += v * b11;
+ t22 += v * b12;
+ t23 += v * b13;
+ t24 += v * b14;
+ t25 += v * b15;
+ v = a[11];
+ t11 += v * b0;
+ t12 += v * b1;
+ t13 += v * b2;
+ t14 += v * b3;
+ t15 += v * b4;
+ t16 += v * b5;
+ t17 += v * b6;
+ t18 += v * b7;
+ t19 += v * b8;
+ t20 += v * b9;
+ t21 += v * b10;
+ t22 += v * b11;
+ t23 += v * b12;
+ t24 += v * b13;
+ t25 += v * b14;
+ t26 += v * b15;
+ v = a[12];
+ t12 += v * b0;
+ t13 += v * b1;
+ t14 += v * b2;
+ t15 += v * b3;
+ t16 += v * b4;
+ t17 += v * b5;
+ t18 += v * b6;
+ t19 += v * b7;
+ t20 += v * b8;
+ t21 += v * b9;
+ t22 += v * b10;
+ t23 += v * b11;
+ t24 += v * b12;
+ t25 += v * b13;
+ t26 += v * b14;
+ t27 += v * b15;
+ v = a[13];
+ t13 += v * b0;
+ t14 += v * b1;
+ t15 += v * b2;
+ t16 += v * b3;
+ t17 += v * b4;
+ t18 += v * b5;
+ t19 += v * b6;
+ t20 += v * b7;
+ t21 += v * b8;
+ t22 += v * b9;
+ t23 += v * b10;
+ t24 += v * b11;
+ t25 += v * b12;
+ t26 += v * b13;
+ t27 += v * b14;
+ t28 += v * b15;
+ v = a[14];
+ t14 += v * b0;
+ t15 += v * b1;
+ t16 += v * b2;
+ t17 += v * b3;
+ t18 += v * b4;
+ t19 += v * b5;
+ t20 += v * b6;
+ t21 += v * b7;
+ t22 += v * b8;
+ t23 += v * b9;
+ t24 += v * b10;
+ t25 += v * b11;
+ t26 += v * b12;
+ t27 += v * b13;
+ t28 += v * b14;
+ t29 += v * b15;
+ v = a[15];
+ t15 += v * b0;
+ t16 += v * b1;
+ t17 += v * b2;
+ t18 += v * b3;
+ t19 += v * b4;
+ t20 += v * b5;
+ t21 += v * b6;
+ t22 += v * b7;
+ t23 += v * b8;
+ t24 += v * b9;
+ t25 += v * b10;
+ t26 += v * b11;
+ t27 += v * b12;
+ t28 += v * b13;
+ t29 += v * b14;
+ t30 += v * b15;
+ t0 += 38 * t16;
+ t1 += 38 * t17;
+ t2 += 38 * t18;
+ t3 += 38 * t19;
+ t4 += 38 * t20;
+ t5 += 38 * t21;
+ t6 += 38 * t22;
+ t7 += 38 * t23;
+ t8 += 38 * t24;
+ t9 += 38 * t25;
+ t10 += 38 * t26;
+ t11 += 38 * t27;
+ t12 += 38 * t28;
+ t13 += 38 * t29;
+ t14 += 38 * t30;
+ c = 1;
+ v = t0 + c + 65535;
+ c = Math.floor(v / 65536);
+ t0 = v - c * 65536;
+ v = t1 + c + 65535;
+ c = Math.floor(v / 65536);
+ t1 = v - c * 65536;
+ v = t2 + c + 65535;
+ c = Math.floor(v / 65536);
+ t2 = v - c * 65536;
+ v = t3 + c + 65535;
+ c = Math.floor(v / 65536);
+ t3 = v - c * 65536;
+ v = t4 + c + 65535;
+ c = Math.floor(v / 65536);
+ t4 = v - c * 65536;
+ v = t5 + c + 65535;
+ c = Math.floor(v / 65536);
+ t5 = v - c * 65536;
+ v = t6 + c + 65535;
+ c = Math.floor(v / 65536);
+ t6 = v - c * 65536;
+ v = t7 + c + 65535;
+ c = Math.floor(v / 65536);
+ t7 = v - c * 65536;
+ v = t8 + c + 65535;
+ c = Math.floor(v / 65536);
+ t8 = v - c * 65536;
+ v = t9 + c + 65535;
+ c = Math.floor(v / 65536);
+ t9 = v - c * 65536;
+ v = t10 + c + 65535;
+ c = Math.floor(v / 65536);
+ t10 = v - c * 65536;
+ v = t11 + c + 65535;
+ c = Math.floor(v / 65536);
+ t11 = v - c * 65536;
+ v = t12 + c + 65535;
+ c = Math.floor(v / 65536);
+ t12 = v - c * 65536;
+ v = t13 + c + 65535;
+ c = Math.floor(v / 65536);
+ t13 = v - c * 65536;
+ v = t14 + c + 65535;
+ c = Math.floor(v / 65536);
+ t14 = v - c * 65536;
+ v = t15 + c + 65535;
+ c = Math.floor(v / 65536);
+ t15 = v - c * 65536;
+ t0 += c - 1 + 37 * (c - 1);
+ c = 1;
+ v = t0 + c + 65535;
+ c = Math.floor(v / 65536);
+ t0 = v - c * 65536;
+ v = t1 + c + 65535;
+ c = Math.floor(v / 65536);
+ t1 = v - c * 65536;
+ v = t2 + c + 65535;
+ c = Math.floor(v / 65536);
+ t2 = v - c * 65536;
+ v = t3 + c + 65535;
+ c = Math.floor(v / 65536);
+ t3 = v - c * 65536;
+ v = t4 + c + 65535;
+ c = Math.floor(v / 65536);
+ t4 = v - c * 65536;
+ v = t5 + c + 65535;
+ c = Math.floor(v / 65536);
+ t5 = v - c * 65536;
+ v = t6 + c + 65535;
+ c = Math.floor(v / 65536);
+ t6 = v - c * 65536;
+ v = t7 + c + 65535;
+ c = Math.floor(v / 65536);
+ t7 = v - c * 65536;
+ v = t8 + c + 65535;
+ c = Math.floor(v / 65536);
+ t8 = v - c * 65536;
+ v = t9 + c + 65535;
+ c = Math.floor(v / 65536);
+ t9 = v - c * 65536;
+ v = t10 + c + 65535;
+ c = Math.floor(v / 65536);
+ t10 = v - c * 65536;
+ v = t11 + c + 65535;
+ c = Math.floor(v / 65536);
+ t11 = v - c * 65536;
+ v = t12 + c + 65535;
+ c = Math.floor(v / 65536);
+ t12 = v - c * 65536;
+ v = t13 + c + 65535;
+ c = Math.floor(v / 65536);
+ t13 = v - c * 65536;
+ v = t14 + c + 65535;
+ c = Math.floor(v / 65536);
+ t14 = v - c * 65536;
+ v = t15 + c + 65535;
+ c = Math.floor(v / 65536);
+ t15 = v - c * 65536;
+ t0 += c - 1 + 37 * (c - 1);
+ o[0] = t0;
+ o[1] = t1;
+ o[2] = t2;
+ o[3] = t3;
+ o[4] = t4;
+ o[5] = t5;
+ o[6] = t6;
+ o[7] = t7;
+ o[8] = t8;
+ o[9] = t9;
+ o[10] = t10;
+ o[11] = t11;
+ o[12] = t12;
+ o[13] = t13;
+ o[14] = t14;
+ o[15] = t15;
}
- /**
- * Get an account at a specific BIP-44 index.
- *
- * @returns Response object containing command status, public key, and address
- */
- async account(index = 0, show = false) {
- if (typeof index !== "number" || index < 0 || index >= HARDENED_OFFSET) {
- throw new TypeError("Invalid account index");
- }
- const purpose = dec.toBytes(BIP44_PURPOSE + HARDENED_OFFSET, 4);
- const coin = dec.toBytes(BIP44_COIN_NANO + HARDENED_OFFSET, 4);
- const account = dec.toBytes(index + HARDENED_OFFSET, 4);
- const data = new Uint8Array([3, ...purpose, ...coin, ...account]);
- const transport = await this.DynamicTransport.create(this.openTimeout, this.listenTimeout);
- const response = await transport.send(161, 2, show ? 1 : 0, 0, data).catch((err) => dec.toBytes(err.statusCode));
- await transport.close();
- if (response.length === 2) {
- const statusCode = bytes.toDec(response);
- const status = LEDGER_STATUS_CODES[statusCode] ?? "UNKNOWN_ERROR";
- return { status, publicKey: null, address: null };
- }
- try {
- const publicKey = bytes.toHex(response.slice(0, 32));
- const addressLength = response[32];
- const address = response.slice(33, 33 + addressLength).toString();
- const statusCode = bytes.toDec(response.slice(33 + addressLength));
- const status = LEDGER_STATUS_CODES[statusCode];
- return { status, publicKey, address };
- } catch (err) {
- return { status: "ERROR_PARSING_ACCOUNT", publicKey: null, address: null };
- }
+ static S(o, a) {
+ this.M(o, a, a);
}
- /**
- * Cache frontier block in device memory.
- *
- * @param {number} index - Account number
- * @param {any} block - Block data to cache
- * @returns Status of command
- */
- async cacheBlock(index = 0, block) {
- if (typeof index !== "number" || index < 0 || index >= HARDENED_OFFSET) {
- throw new TypeError("Invalid account index");
- }
- if (!(block instanceof SendBlock) && !(block instanceof ReceiveBlock) && !(block instanceof ChangeBlock)) {
- throw new TypeError("Invalid block format");
- }
- if (!block.signature) {
- throw new ReferenceError("Cannot cache unsigned block");
+ static inv25519(o, i) {
+ const c = this.gf();
+ for (let a = 0; a < 16; a++)
+ c[a] = i[a];
+ for (let a = 253; a >= 0; a--) {
+ this.S(c, c);
+ if (a !== 2 && a !== 4)
+ this.M(c, c, i);
}
- const purpose = dec.toBytes(BIP44_PURPOSE + HARDENED_OFFSET, 4);
- const coin = dec.toBytes(BIP44_COIN_NANO + HARDENED_OFFSET, 4);
- const account = dec.toBytes(index + HARDENED_OFFSET, 4);
- const previous = hex.toBytes(block.previous);
- const link = hex.toBytes(block.link);
- const representative = hex.toBytes(block.representative.publicKey);
- const balance = hex.toBytes(BigInt(block.balance).toString(16), 16);
- const signature = hex.toBytes(block.signature);
- const data = new Uint8Array([3, ...purpose, ...coin, ...account, ...previous, ...link, ...representative, ...balance, ...signature]);
- const transport = await this.DynamicTransport.create(this.openTimeout, this.listenTimeout);
- const response = await transport.send(161, 3, 0, 0, data).then((res) => bytes.toDec(res)).catch((err) => err.statusCode);
- await transport.close();
- return { status: LEDGER_STATUS_CODES[response] };
+ for (let a = 0; a < 16; a++)
+ o[a] = c[a];
}
- async sign(index = 0, input) {
- if (typeof index !== "number" || index < 0 || index >= HARDENED_OFFSET) {
- throw new TypeError("Invalid account index");
- }
- const purpose = dec.toBytes(BIP44_PURPOSE + HARDENED_OFFSET, 4);
- const coin = dec.toBytes(BIP44_COIN_NANO + HARDENED_OFFSET, 4);
- const account = dec.toBytes(index + HARDENED_OFFSET, 4);
- const transport = await this.DynamicTransport.create(this.openTimeout, this.listenTimeout);
- if (typeof input === "string") {
- const nonce = utf8.toBytes(input);
- if (nonce.length !== 16) {
- throw new RangeError("Nonce must be 16-byte string");
- }
- const data = new Uint8Array([3, ...purpose, ...coin, ...account, ...nonce]);
- const response = await transport.send(161, 5, 0, 0, data).catch((err) => dec.toBytes(err.statusCode));
- await transport.close();
- if (response.length === 2) {
- const statusCode2 = bytes.toDec(response);
- const status2 = LEDGER_STATUS_CODES[statusCode2] ?? "UNKNOWN_ERROR";
- return { status: status2, signature: null };
- }
- const signature = bytes.toHex(response.slice(0, 64));
- const statusCode = bytes.toDec(response.slice(-2));
- const status = LEDGER_STATUS_CODES[statusCode];
- return { status, signature };
- } else {
- const previous = hex.toBytes(input.previous);
- const link = hex.toBytes(input.link);
- const representative = hex.toBytes(input.representative.publicKey);
- const balance = hex.toBytes(BigInt(input.balance).toString(16), 16);
- const data = new Uint8Array([3, ...purpose, ...coin, ...account, ...previous, ...link, ...representative, ...balance]);
- const response = await transport.send(161, 4, 0, 0, data).catch((err) => dec.toBytes(err.statusCode));
- await transport.close();
- if (response.length === 2) {
- const statusCode2 = bytes.toDec(response);
- const status2 = LEDGER_STATUS_CODES[statusCode2] ?? "UNKNOWN_ERROR";
- return { status: status2, signature: null, hash: null };
- }
- const hash2 = bytes.toHex(response.slice(0, 32));
- const signature = bytes.toHex(response.slice(32, 96));
- const statusCode = bytes.toDec(response.slice(-2));
- const status = LEDGER_STATUS_CODES[statusCode];
- return { status, signature, hash: hash2 };
+ static pow2523(o, i) {
+ const c = this.gf();
+ for (let a = 0; a < 16; a++)
+ c[a] = i[a];
+ for (let a = 250; a >= 0; a--) {
+ this.S(c, c);
+ if (a !== 1)
+ this.M(c, c, i);
}
+ for (let a = 0; a < 16; a++)
+ o[a] = c[a];
}
- async updateCache(index, input, node) {
- if (typeof input === "string" && node?.constructor === Rpc) {
- const data = {
- "json_block": "true",
- "hash": input
- };
- const res = await node.call("block_info", data);
- if (!res || res.ok === false) {
- throw new Error(`Unable to fetch block info`, res);
- }
- input = res.contents;
- }
- return this.cacheBlock(index, input);
+ // Note: difference from TweetNaCl - BLAKE2b used to hash instead of SHA-512.
+ static crypto_hash(out, m, n) {
+ const input = new Uint8Array(n);
+ for (let i = 0; i < n; ++i)
+ input[i] = m[i];
+ const hash2 = new Blake2b(64).update(m).digest();
+ for (let i = 0; i < 64; ++i)
+ out[i] = hash2[i];
+ return 0;
}
- };
- }
-});
-
-// dist/lib/block.js
-function validate(block) {
- if (block.account == null) {
- throw new Error("Account missing");
- }
- if (block.previous == null || block.previous === "") {
- throw new Error("Frontier missing");
- }
- if (block.representative == null) {
- throw new Error("Representative missing");
- }
- if (block.balance == null) {
- throw new Error("Balance missing");
- }
- if (block.balance < 0) {
- throw new Error("Negative balance");
- }
- switch (block.constructor) {
- case SendBlock: {
- if (block.link == null || block.link === "") {
- throw new Error("Recipient missing");
+ static add(p, q) {
+ const a = this.gf();
+ const b = this.gf();
+ const c = this.gf();
+ const d = this.gf();
+ const e = this.gf();
+ const f = this.gf();
+ const g = this.gf();
+ const h = this.gf();
+ const t = this.gf();
+ this.Z(a, p[1], p[0]);
+ this.Z(t, q[1], q[0]);
+ this.M(a, a, t);
+ this.A(b, p[0], p[1]);
+ this.A(t, q[0], q[1]);
+ this.M(b, b, t);
+ this.M(c, p[3], q[3]);
+ this.M(c, c, this.D2);
+ this.M(d, p[2], q[2]);
+ this.A(d, d, d);
+ this.Z(e, b, a);
+ this.Z(f, d, c);
+ this.A(g, d, c);
+ this.A(h, b, a);
+ this.M(p[0], e, f);
+ this.M(p[1], h, g);
+ this.M(p[2], g, f);
+ this.M(p[3], e, h);
}
- break;
- }
- case ReceiveBlock: {
- if (block.link == null) {
- throw new Error("Origin send block hash missing");
+ static cswap(p, q, b) {
+ for (let i = 0; i < 4; i++) {
+ this.sel25519(p[i], q[i], b);
+ }
}
- break;
- }
- case ChangeBlock: {
- if (block.link == null) {
- throw new Error("Change block link missing");
+ static pack(r, p) {
+ const tx = this.gf();
+ const ty = this.gf();
+ const zi = this.gf();
+ this.inv25519(zi, p[2]);
+ this.M(tx, p[0], zi);
+ this.M(ty, p[1], zi);
+ this.pack25519(r, ty);
+ r[31] ^= this.par25519(tx) << 7;
}
- if (+block.link !== 0) {
- throw new Error("Invalid change block link");
+ static scalarmult(p, q, s) {
+ this.set25519(p[0], this.gf0);
+ this.set25519(p[1], this.gf1);
+ this.set25519(p[2], this.gf1);
+ this.set25519(p[3], this.gf0);
+ for (let i = 255; i >= 0; --i) {
+ const b = s[i / 8 | 0] >> (i & 7) & 1;
+ this.cswap(p, q, b);
+ this.add(q, p);
+ this.add(p, p);
+ this.cswap(p, q, b);
+ }
}
- break;
- }
- }
-}
-var Block, SendBlock, ReceiveBlock, ChangeBlock;
-var init_block = __esm({
- "dist/lib/block.js"() {
- "use strict";
- init_constants();
- init_account();
- init_blake2b();
- init_convert();
- init_nano_nacl();
- init_pool();
- init_workers();
- Block = class _Block {
- static #pool = new Pool(powgpu_default);
- account;
- type = "state";
- constructor(account) {
- if (this.constructor === _Block) {
- throw new Error("Block is an abstract class and cannot be instantiated directly.");
+ static scalarbase(p, s) {
+ const q = [this.gf(), this.gf(), this.gf(), this.gf()];
+ this.set25519(q[0], this.X);
+ this.set25519(q[1], this.Y);
+ this.set25519(q[2], this.gf1);
+ this.M(q[3], this.X, this.Y);
+ this.scalarmult(p, q, s);
+ }
+ static L = new Float64Array([
+ 237,
+ 211,
+ 245,
+ 92,
+ 26,
+ 99,
+ 18,
+ 88,
+ 214,
+ 156,
+ 247,
+ 162,
+ 222,
+ 249,
+ 222,
+ 20,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 16
+ ]);
+ static modL(r, x) {
+ let carry, i, j, k;
+ for (i = 63; i >= 32; --i) {
+ carry = 0;
+ for (j = i - 32, k = i - 12; j < k; ++j) {
+ x[j] += carry - 16 * x[i] * this.L[j - (i - 32)];
+ carry = Math.floor((x[j] + 128) / 256);
+ x[j] -= carry * 256;
+ }
+ x[j] += carry;
+ x[i] = 0;
}
- if (account.constructor === Account) {
- this.account = account;
- } else if (typeof account === "string") {
- this.account = Account.fromAddress(account);
- } else {
- throw new TypeError("Invalid account");
+ carry = 0;
+ for (j = 0; j < 32; j++) {
+ x[j] += carry - (x[31] >> 4) * this.L[j];
+ carry = x[j] >> 8;
+ x[j] &= 255;
+ }
+ for (j = 0; j < 32; j++)
+ x[j] -= carry * this.L[j];
+ for (i = 0; i < 32; i++) {
+ x[i + 1] += x[i] >> 8;
+ r[i] = x[i] & 255;
}
}
- /**
- * Converts the block to JSON format as expected by the `process` RPC.
- *
- * @returns {string} JSON representation of the block
- */
- json() {
- return {
- "type": this.type,
- "account": this.account.address,
- "previous": this.previous,
- "representative": this.representative.address,
- "balance": this.balance.toString(),
- "link": this.link,
- "signature": this.signature ?? "",
- "work": this.work ?? ""
- };
+ static reduce(r) {
+ let x = new Float64Array(64);
+ for (let i = 0; i < 64; i++)
+ x[i] = r[i];
+ for (let i = 0; i < 64; i++)
+ r[i] = 0;
+ this.modL(r, x);
}
- /**
- * Hashes the block using Blake2b.
- *
- * @returns {Promise<string>} Block data hashed to a byte array
- */
- async hash() {
- const data = [
- PREAMBLE,
- this.account.publicKey,
- this.previous,
- this.representative.publicKey,
- dec.toHex(this.balance, 32),
- this.link
- ];
- const hash2 = new Blake2b(32);
- data.forEach((str) => hash2.update(hex.toBytes(str)));
- return hash2.digest("hex").toUpperCase();
+ // Note: difference from C - smlen returned, not passed as argument.
+ static crypto_sign(sm, m, n, sk, pk) {
+ const d = new Uint8Array(64);
+ const h = new Uint8Array(64);
+ const r = new Uint8Array(64);
+ const x = new Float64Array(64);
+ const p = [this.gf(), this.gf(), this.gf(), this.gf()];
+ this.crypto_hash(d, sk, 32);
+ d[0] &= 248;
+ d[31] &= 127;
+ d[31] |= 64;
+ const smlen = n + 64;
+ for (let i = 0; i < n; i++)
+ sm[64 + i] = m[i];
+ for (let i = 0; i < 32; i++)
+ sm[32 + i] = d[32 + i];
+ this.crypto_hash(r, sm.subarray(32), n + 32);
+ this.reduce(r);
+ this.scalarbase(p, r);
+ this.pack(sm, p);
+ for (let i = 0; i < 32; i++)
+ sm[i + 32] = pk[i];
+ this.crypto_hash(h, sm, n + 64);
+ this.reduce(h);
+ for (let i = 0; i < 64; i++)
+ x[i] = 0;
+ for (let i = 0; i < 32; i++)
+ x[i] = r[i];
+ for (let i = 0; i < 32; i++) {
+ for (let j = 0; j < 32; j++) {
+ x[i + j] += h[i] * d[j];
+ }
+ }
+ this.modL(sm.subarray(32), x);
+ return smlen;
}
- /**
- * Calculates proof-of-work using a pool of WebGL workers.
- *
- * A successful response sets the `work` property.
- */
- async pow() {
- const data = {
- "hash": this.previous,
- "threshold": this instanceof SendBlock || this instanceof ChangeBlock ? THRESHOLD_SEND : THRESHOLD_RECEIVE
- };
- const [{ work }] = await _Block.#pool.assign([data]);
- this.work = work;
+ static unpackneg(r, p) {
+ const t = this.gf();
+ const chk = this.gf();
+ const num = this.gf();
+ const den = this.gf();
+ const den2 = this.gf();
+ const den4 = this.gf();
+ const den6 = this.gf();
+ this.set25519(r[2], this.gf1);
+ this.unpack25519(r[1], p);
+ this.S(num, r[1]);
+ this.M(den, num, this.D);
+ this.Z(num, num, r[2]);
+ this.A(den, r[2], den);
+ this.S(den2, den);
+ this.S(den4, den2);
+ this.M(den6, den4, den2);
+ this.M(t, den6, num);
+ this.M(t, t, den);
+ this.pow2523(t, t);
+ this.M(t, t, num);
+ this.M(t, t, den);
+ this.M(t, t, den);
+ this.M(r[0], t, den);
+ this.S(chk, r[0]);
+ this.M(chk, chk, den);
+ if (this.neq25519(chk, num))
+ this.M(r[0], r[0], this.I);
+ this.S(chk, r[0]);
+ this.M(chk, chk, den);
+ if (this.neq25519(chk, num))
+ return -1;
+ if (this.par25519(r[0]) === p[31] >> 7)
+ this.Z(r[0], this.gf0, r[0]);
+ this.M(r[3], r[0], r[1]);
+ return 0;
}
- async sign(input, block) {
- if (typeof input === "number") {
- const index = input;
- const { Ledger: Ledger2 } = await Promise.resolve().then(() => (init_ledger(), ledger_exports));
- const ledger = await Ledger2.init();
- await ledger.open();
- if (block) {
- try {
- await ledger.updateCache(index, block);
- } catch (err) {
- console.warn("Error updating Ledger cache of previous block, attempting signature anyway", err);
- }
- }
- const result = await ledger.sign(index, this);
- if (result.status !== "OK") {
- throw new Error(result.status);
- }
- this.signature = result.signature;
- } else {
- const key = input ?? this.account.privateKey;
- if (key == null) {
- throw new Error("No valid key found to sign block");
- }
- const account = await Account.fromPrivateKey(key);
- try {
- const signature = NanoNaCl.detached(hex.toBytes(await this.hash()), hex.toBytes(`${account.privateKey}`));
- this.signature = signature;
- } catch (err) {
- throw new Error(`Failed to sign block with key ${key}: ${err}`);
- }
+ static crypto_sign_open(m, sm, n, pk) {
+ const t = new Uint8Array(32);
+ const h = new Uint8Array(64);
+ const p = [this.gf(), this.gf(), this.gf(), this.gf()];
+ const q = [this.gf(), this.gf(), this.gf(), this.gf()];
+ if (n < 64)
+ return -1;
+ if (this.unpackneg(q, pk))
+ return -1;
+ for (let i = 0; i < n; i++)
+ m[i] = sm[i];
+ for (let i = 0; i < 32; i++)
+ m[i + 32] = pk[i];
+ this.crypto_hash(h, m, n);
+ this.reduce(h);
+ this.scalarmult(p, q, h);
+ this.scalarbase(q, sm.subarray(32));
+ this.add(p, q);
+ this.pack(t, p);
+ n -= 64;
+ if (this.crypto_verify_32(sm, 0, t, 0)) {
+ for (let i = 0; i < n; i++)
+ m[i] = 0;
+ return -1;
}
+ for (let i = 0; i < n; i++)
+ m[i] = sm[i + 64];
+ return n;
}
- /**
- * Sends the block to a node for processing on the network.
- *
- * The block must already be signed (see `sign()` for more information).
- * The block must also have a `work` value.
- *
- * @param {Rpc|string|URL} rpc - RPC node information required to call `process`
- * @returns {Promise<string>} Hash of the processed block
- */
- async process(rpc) {
- if (!this.signature) {
- throw new Error("Block is missing signature. Use sign() and try again.");
- }
- if (!this.work == null) {
- throw new Error("Block is missing proof-of-work. Generate PoW and try again.");
- }
- const data = {
- "subtype": this.subtype,
- "json_block": "true",
- "block": this.json()
- };
- const res = await rpc.call("process", data);
- if (res.hash == null) {
- throw new Error("Block could not be processed", res);
+ static crypto_sign_BYTES = 64;
+ static crypto_sign_PUBLICKEYBYTES = 32;
+ static crypto_sign_SECRETKEYBYTES = 32;
+ static crypto_sign_SEEDBYTES = 32;
+ /* High-level API */
+ static checkArrayTypes(...args) {
+ for (let i = 0; i < args.length; i++) {
+ if (!(args[i] instanceof Uint8Array))
+ throw new TypeError(`expected Uint8Array; received ${args[i].constructor?.name ?? typeof args[i]}`);
}
- return res.hash;
}
- /**
- * Verifies the signature of the block. If a key is not provided, the public
- * key of the block's account will be used if it exists.
- *
- * @param {string} [key] - Hexadecimal-formatted public key to use for verification
- * @returns {boolean} True if block was signed by the matching private key
- */
- async verify(key) {
- key ??= this.account.publicKey;
- if (!key) {
- throw new Error("Provide a key for block signature verification.");
+ static parseHex(hex2) {
+ if (hex2.length % 2 === 1)
+ hex2 = `0${hex2}`;
+ const arr = hex2.match(/.{1,2}/g)?.map((byte) => parseInt(byte, 16));
+ return Uint8Array.from(arr ?? []);
+ }
+ static hexify(buf) {
+ let str = "";
+ for (let i = 0; i < buf.length; i++) {
+ if (typeof buf[i] !== "number")
+ throw new TypeError(`expected number to convert to hex; received ${typeof buf[i]}`);
+ if (buf[i] < 0 || buf[i] > 255)
+ throw new RangeError(`expected byte value 0-255; received ${buf[i]}`);
+ str += buf[i].toString(16).padStart(2, "0");
}
- const data = [
- PREAMBLE,
- this.account.publicKey,
- this.previous,
- this.representative.publicKey,
- dec.toHex(this.balance, 32),
- this.link
- ];
- const hash2 = new Blake2b(32);
- data.forEach((str) => hash2.update(hex.toBytes(str)));
- const blockHash = hash2.digest("hex").toUpperCase();
- return NanoNaCl.verify(hex.toBytes(blockHash), hex.toBytes(this.signature ?? ""), hex.toBytes(key));
+ return str;
}
- };
- SendBlock = class extends Block {
- type = "state";
- subtype = "send";
- previous;
- representative;
- balance;
- link;
- signature;
- work;
- constructor(sender, balance, recipient, amount, representative, frontier, work) {
- super(sender);
- this.previous = frontier;
- this.representative = Account.fromAddress(representative);
- this.link = Account.fromAddress(recipient).publicKey;
- this.work = work ?? "";
- const bigBalance = BigInt(balance);
- const bigAmount = BigInt(amount);
- this.balance = bigBalance - bigAmount;
- validate(this);
+ static sign(msg, secretKey) {
+ this.checkArrayTypes(msg, secretKey);
+ if (secretKey.length !== this.crypto_sign_SECRETKEYBYTES)
+ throw new Error("bad secret key size");
+ var signedMsg = new Uint8Array(this.crypto_sign_BYTES + msg.length);
+ const publicKey = this.parseHex(this.convert(secretKey));
+ this.crypto_sign(signedMsg, msg, msg.length, secretKey, publicKey);
+ return signedMsg;
}
- };
- ReceiveBlock = class extends Block {
- type = "state";
- subtype = "receive";
- previous;
- representative;
- balance;
- link;
- signature;
- work;
- constructor(recipient, balance, origin, amount, representative, frontier, work) {
- super(recipient);
- this.previous = frontier ?? Account.fromAddress(recipient).publicKey;
- this.representative = Account.fromAddress(representative);
- this.link = origin;
- this.work = work ?? "";
- const bigBalance = BigInt(balance);
- const bigAmount = BigInt(amount);
- this.balance = bigBalance + bigAmount;
- validate(this);
+ static open(signedMsg, publicKey) {
+ this.checkArrayTypes(signedMsg, publicKey);
+ if (publicKey.length !== this.crypto_sign_PUBLICKEYBYTES)
+ throw new Error("bad public key size");
+ const tmp = new Uint8Array(signedMsg.length);
+ var mlen = this.crypto_sign_open(tmp, signedMsg, signedMsg.length, publicKey);
+ if (mlen < 0)
+ return new Uint8Array(0);
+ var m = new Uint8Array(mlen);
+ for (var i = 0; i < m.length; i++)
+ m[i] = tmp[i];
+ return m;
}
- };
- ChangeBlock = class extends Block {
- type = "state";
- subtype = "change";
- previous;
- representative;
- balance;
- link = Account.fromAddress(BURN_ADDRESS).publicKey;
- signature;
- work;
- constructor(account, balance, representative, frontier, work) {
- super(account);
- this.previous = frontier;
- this.representative = Account.fromAddress(representative);
- this.balance = BigInt(balance);
- this.work = work ?? "";
- validate(this);
+ static detached(msg, secretKey) {
+ var signedMsg = this.sign(msg, secretKey);
+ var sig = new Uint8Array(this.crypto_sign_BYTES);
+ for (var i = 0; i < sig.length; i++)
+ sig[i] = signedMsg[i];
+ return this.hexify(sig).toUpperCase();
+ }
+ static verify(msg, sig, publicKey) {
+ this.checkArrayTypes(msg, sig, publicKey);
+ if (sig.length !== this.crypto_sign_BYTES)
+ throw new Error("bad signature size");
+ if (publicKey.length !== this.crypto_sign_PUBLICKEYBYTES)
+ throw new Error("bad public key size");
+ const sm = new Uint8Array(this.crypto_sign_BYTES + msg.length);
+ const m = new Uint8Array(this.crypto_sign_BYTES + msg.length);
+ for (let i = 0; i < this.crypto_sign_BYTES; i++)
+ sm[i] = sig[i];
+ for (let i = 0; i < msg.length; i++)
+ sm[i + this.crypto_sign_BYTES] = msg[i];
+ return this.crypto_sign_open(m, sm, sm.length, publicKey) >= 0;
+ }
+ static convert(seed) {
+ if (typeof seed === "string")
+ seed = this.parseHex(seed);
+ this.checkArrayTypes(seed);
+ if (seed.length !== this.crypto_sign_SEEDBYTES)
+ throw new Error("bad seed size");
+ const pk = new Uint8Array(this.crypto_sign_PUBLICKEYBYTES);
+ const p = [this.gf(), this.gf(), this.gf(), this.gf()];
+ const hash2 = new Blake2b(64).update(seed).digest();
+ hash2[0] &= 248;
+ hash2[31] &= 127;
+ hash2[31] |= 64;
+ this.scalarbase(p, hash2);
+ this.pack(pk, p);
+ return this.hexify(pk).toUpperCase();
}
};
+ nano_nacl_default2 = `
+ const Blake2b = ${Blake2b}
+ const WorkerInterface = ${WorkerInterface}
+ const NanoNaCl = ${NanoNaCl2}
+`;
}
});
async function sign(key, ...input) {
const account = await Account.fromPrivateKey(key);
const data = hash(input);
- const signature = NanoNaCl.detached(hex.toBytes(data), hex.toBytes(`${account.privateKey}`));
+ const signature = NanoNaCl2.detached(hex.toBytes(data), hex.toBytes(`${account.privateKey}`));
return signature;
}
async function sweep(rpc, wallet, recipient, from2 = 0, to = from2) {
async function verify(key, signature, ...input) {
const data = hash(input);
try {
- return await NanoNaCl.verify(hex.toBytes(data), hex.toBytes(signature), hex.toBytes(key));
+ return await NanoNaCl2.verify(hex.toBytes(data), hex.toBytes(signature), hex.toBytes(key));
} catch (err) {
console.error(err);
return false;
init_convert();
init_rpc();
init_block();
- init_nano_nacl();
+ init_nano_nacl2();
Tools = { convert, sign, sweep, verify };
}
});
Blake2bWallet: () => Blake2bWallet,
ChangeBlock: () => ChangeBlock,
LedgerWallet: () => LedgerWallet,
- PowGl: () => PowGl,
- PowGpu: () => PowGpu,
+ NanoPowGpu: () => NanoPowGpu,
+ PowGl: () => NanoPowGl,
ReceiveBlock: () => ReceiveBlock,
Rolodex: () => Rolodex,
Rpc: () => Rpc,
init_account();
init_blake2b();
init_block();
-init_powgl();
-init_powgpu();
+
+// src/lib/nano-pow/index.ts
+init_shaders();
+init_classes();
+
+// dist/main.js
init_rpc();
// dist/lib/rolodex.js
// dist/lib/wallet.js
init_constants();
init_entropy();
-init_pool();
+init_pool2();
init_rpc();
init_safe();
init_workers();
this.#accounts = [];
this.#id = id2;
this.#mnemonic = mnemonic ?? null;
- this.#poolNanoNacl = new Pool(nano_nacl_default);
+ this.#poolNanoNacl = new Pool2(nano_nacl_default);
this.#safe = new Safe();
this.#seed = seed ?? null;
}
};
var Bip44Wallet = class _Bip44Wallet extends Wallet {
static #isInternal = false;
- static #poolBip44Ckd = new Pool(bip44_ckd_default);
+ static #poolBip44Ckd = new Pool2(bip44_ckd_default);
constructor(id2, seed, mnemonic) {
if (!_Bip44Wallet.#isInternal) {
throw new Error(`Bip44Wallet cannot be instantiated directly. Use 'await Bip44Wallet.create()' instead.`);