igneum/site/lc/verify-receipt.js

5322 lines
174 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
// Igneum payment receipt verifier, one file, offline. Source: tools/reference-apps/receipt/verify-receipt.src.mjs and site/lc/core.js
// (the same checks the browser page runs), bundled with @noble/hashes 2.4.0 and @noble/curves 2.4.0 (MIT). Usage: node verify-receipt.js receipt.json [--tamper]
// tools/reference-apps/receipt/verify-receipt.src.mjs
var import_node_fs = require("node:fs");
// tools/reference-apps/light-service/node_modules/@noble/hashes/utils.js
function isBytes(a) {
return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array" && "BYTES_PER_ELEMENT" in a && a.BYTES_PER_ELEMENT === 1;
}
var atitle = (title) => title ? `"${title}" ` : "";
function anumber(n, title = "") {
if (typeof n !== "number")
throw new TypeError(atitle(title) + "expected number, got " + typeof n);
if (!Number.isSafeInteger(n) || n < 0)
throw new RangeError(atitle(title) + "expected integer >= 0, got " + n);
return n;
}
function abool(value, title = "") {
if (typeof value !== "boolean")
throw new TypeError(atitle(title) + "expected boolean, got type=" + typeof value);
return value;
}
function abytes(value, length, title = "") {
if (isBytes(value) && (length === void 0 || value.length === length))
return value;
if (length !== void 0)
anumber(length, "length");
const bytes = isBytes(value);
const ofLen = length !== void 0 ? ` of length ${length}` : "";
const got = bytes ? `length=${value.length}` : `type=${typeof value}`;
const message = atitle(title) + "expected Uint8Array" + ofLen + ", got " + got;
if (!bytes)
throw new TypeError(message);
throw new RangeError(message);
}
function copyBytes(bytes) {
return Uint8Array.from(abytes(bytes));
}
var aobject = (value, label) => {
if (value === null || typeof value !== "object" || Array.isArray(value))
throw new TypeError((label === "object" ? "" : `"${label}" `) + "expected object, got type=" + typeof value);
};
var aopts = (value, label) => {
aobject(value, label);
const proto = Object.getPrototypeOf(value);
if (proto !== Object.prototype && proto !== null)
throw new TypeError(`"${label}" expected plain object`);
if (Object.hasOwn(value, "__proto__"))
throw new TypeError(`"${label}.__proto__" is not allowed`);
};
function aexists(instance, checkFinished = true) {
if (instance.destroyed)
throw new Error("hash was destroyed");
if (checkFinished && instance.finished)
throw new Error("digest() was already called");
}
function aoutput(out, instance) {
abytes(out, void 0, "output");
const min = instance.outputLen;
if (!(out.length >= min)) {
throw new RangeError('"output" expected length >= ' + min);
}
}
function u32(arr) {
return new Uint32Array(arr.buffer, arr.byteOffset, Math.floor(arr.byteLength / 4));
}
function clean(...arrays) {
for (let i = 0; i < arrays.length; i++) {
arrays[i].fill(0);
}
}
function createView(arr) {
return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
}
function rotr(word, shift) {
return word << 32 - shift | word >>> shift;
}
var isLE = /* @__PURE__ */ (() => new Uint8Array(new Uint32Array([287454020]).buffer)[0] === 68)();
function byteSwap(word) {
return word << 24 & 4278190080 | word << 8 & 16711680 | word >>> 8 & 65280 | word >>> 24 & 255;
}
var swap8IfBE = isLE ? (n) => n : (n) => byteSwap(n) >>> 0;
function byteSwap32(arr) {
for (let i = 0; i < arr.length; i++) {
arr[i] = byteSwap(arr[i]);
}
return arr;
}
var swap32IfBE = isLE ? (u) => u : byteSwap32;
var hasHexBuiltin = /* @__PURE__ */ (() => (
// @ts-ignore
typeof Uint8Array.from([]).toHex === "function" && typeof Uint8Array.fromHex === "function"
))();
var hexes = /* @__PURE__ */ Array.from({ length: 256 }, (_, i) => i.toString(16).padStart(2, "0"));
function bytesToHex(bytes) {
abytes(bytes);
if (hasHexBuiltin)
return bytes.toHex();
let hex = "";
for (let i = 0; i < bytes.length; i++) {
hex += hexes[bytes[i]];
}
return hex;
}
function asciiToBase16(ch) {
return ch >= 48 && ch <= 57 ? ch - 48 : ch >= 65 && ch <= 70 ? ch - (65 - 10) : ch >= 97 && ch <= 102 ? ch - (97 - 10) : void 0;
}
function hexToBytes(hex) {
if (typeof hex !== "string")
throw new TypeError("hex string expected, got " + typeof hex);
if (hasHexBuiltin) {
try {
return Uint8Array.fromHex(hex);
} catch (error) {
if (error instanceof SyntaxError)
throw new RangeError(error.message);
throw error;
}
}
const hl = hex.length;
const al = hl / 2;
if (hl % 2)
throw new RangeError("hex string expected, got unpadded hex of length " + hl);
const array = new Uint8Array(al);
for (let ai = 0, hi = 0; ai < al; ai++, hi += 2) {
const n1 = asciiToBase16(hex.charCodeAt(hi));
const n2 = asciiToBase16(hex.charCodeAt(hi + 1));
if (n1 === void 0 || n2 === void 0) {
const char = hex[hi] + hex[hi + 1];
throw new RangeError('hex string expected, got non-hex character "' + char + '" at index ' + hi);
}
array[ai] = n1 * 16 + n2;
}
return array;
}
function concatBytes(...arrays) {
let sum = 0;
for (let i = 0; i < arrays.length; i++) {
const a = arrays[i];
abytes(a);
sum += a.length;
}
const res = new Uint8Array(sum);
for (let i = 0, pad = 0; i < arrays.length; i++) {
const a = arrays[i];
res.set(a, pad);
pad += a.length;
}
return res;
}
function checkOpts(defaults, opts, title = "opts") {
aopts(defaults, "defaults");
if (opts !== void 0)
aopts(opts, title);
const merged = Object.assign(/* @__PURE__ */ Object.create(null), defaults, opts);
return merged;
}
function createHasher(hashCons, info = {}) {
if (typeof hashCons !== "function")
throw new TypeError('"hashCons" expected function, got type=' + typeof hashCons);
info = checkOpts({}, info, "info");
const hashC = (msg, opts) => hashCons(opts).update(msg).digest();
const tmp = hashCons(void 0);
hashC.outputLen = tmp.outputLen;
hashC.blockLen = tmp.blockLen;
hashC.canXOF = tmp.canXOF;
hashC.create = (opts) => hashCons(opts);
Object.assign(hashC, info);
return Object.freeze(hashC);
}
function randomBytes(bytesLength = 32) {
anumber(bytesLength, "bytesLength");
const cr = typeof globalThis === "object" ? globalThis.crypto : null;
if (typeof cr?.getRandomValues !== "function")
throw new Error("crypto.getRandomValues must be defined");
if (bytesLength > 65536)
throw new RangeError(`"bytesLength" expected <= 65536, got ${bytesLength}`);
return cr.getRandomValues(new Uint8Array(bytesLength));
}
var oidNist = (suffix) => ({
// Current NIST hashAlgs suffixes used here fit in one DER subidentifier octet.
// Larger suffix values would need base-128 OID encoding and a different length byte.
oid: Uint8Array.from([6, 9, 96, 134, 72, 1, 101, 3, 4, 2, suffix])
});
// tools/reference-apps/light-service/node_modules/@noble/hashes/_blake.js
var BSIGMA = /* @__PURE__ */ Uint8Array.from([
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,
// Blake1, unused in others
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
]);
// tools/reference-apps/light-service/node_modules/@noble/hashes/_u64.js
var U32_MASK64 = /* @__PURE__ */ (() => BigInt(2 ** 32 - 1))();
var _32n = /* @__PURE__ */ BigInt(32);
function fromBig(n, le = false) {
if (le)
return { h: Number(n & U32_MASK64), l: Number(n >> _32n & U32_MASK64) };
return { h: Number(n >> _32n & U32_MASK64) | 0, l: Number(n & U32_MASK64) | 0 };
}
function split(lst, le = false) {
const len = lst.length;
let Ah = new Uint32Array(len);
let Al = new Uint32Array(len);
for (let i = 0; i < len; i++) {
const { h, l } = fromBig(lst[i], le);
[Ah[i], Al[i]] = [h, l];
}
return [Ah, Al];
}
var fromNumH = (n) => n / 2 ** 32 | 0;
var fromNumL = (n) => n >>> 0;
function setU64FromNum(view, byteOffset, n, isLE2) {
const h = fromNumH(n);
const l = fromNumL(n);
view.setUint32(byteOffset, isLE2 ? l : h, isLE2);
view.setUint32(byteOffset + 4, isLE2 ? h : l, isLE2);
}
var rotrSH = (h, l, s) => h >>> s | l << 32 - s;
var rotrSL = (h, l, s) => h << 32 - s | l >>> s;
var rotrBH = (h, l, s) => h << 64 - s | l >>> s - 32;
var rotrBL = (h, l, s) => h >>> s - 32 | l << 64 - s;
var rotr32H = (_h, l) => l;
var rotr32L = (h, _l) => h;
function add(Ah, Al, Bh, Bl) {
const l = (Al >>> 0) + (Bl >>> 0);
return { h: Ah + Bh + (l / 2 ** 32 | 0) | 0, l: l | 0 };
}
var add3L = (Al, Bl, Cl) => (Al >>> 0) + (Bl >>> 0) + (Cl >>> 0);
var add3H = (low, Ah, Bh, Ch) => Ah + Bh + Ch + (low / 2 ** 32 | 0) | 0;
// tools/reference-apps/light-service/node_modules/@noble/hashes/_md.js
function Chi(a, b, c) {
return a & b ^ ~a & c;
}
function Maj(a, b, c) {
return a & b ^ a & c ^ b & c;
}
var HashMD = class {
blockLen;
outputLen;
canXOF = false;
padOffset;
isLE;
// For partial updates less than block size
buffer;
view;
finished = false;
length = 0;
pos = 0;
destroyed = false;
constructor(blockLen, outputLen, padOffset, isLE2) {
this.blockLen = blockLen;
this.outputLen = outputLen;
this.padOffset = padOffset;
this.isLE = isLE2;
this.buffer = new Uint8Array(blockLen);
this.view = createView(this.buffer);
}
update(data) {
aexists(this);
abytes(data);
const { view, buffer, blockLen } = this;
const len = data.length;
let processed = false;
for (let pos = 0; pos < len; ) {
const take = Math.min(blockLen - this.pos, len - pos);
if (take === blockLen) {
const dataView = createView(data);
for (; blockLen <= len - pos; pos += blockLen)
this.process(dataView, pos);
processed = true;
continue;
}
buffer.set(pos === 0 && take === len ? data : data.subarray(pos, pos + take), this.pos);
this.pos += take;
pos += take;
if (this.pos === blockLen) {
this.process(view, 0);
this.pos = 0;
processed = true;
}
}
this.length += data.length;
if (processed)
this.roundClean();
return this;
}
digestInto(out) {
aexists(this);
aoutput(out, this);
this.finished = true;
const { buffer, view, blockLen, isLE: isLE2 } = this;
let { pos } = this;
buffer[pos++] = 128;
buffer.fill(0, pos);
if (this.padOffset > blockLen - pos) {
this.process(view, 0);
buffer.fill(0);
}
setU64FromNum(view, blockLen - 8, this.length * 8, isLE2);
this.process(view, 0);
this.roundClean();
const oview = out === buffer ? view : createView(out);
const len = this.outputLen;
const outLen = len / 4;
const state = this.get();
if (len % 4 || outLen > state.length)
throw new Error("invalid outputLen");
for (let i = 0; i < outLen; i++)
oview.setUint32(4 * i, state[i], isLE2);
}
digest() {
const { buffer, outputLen } = this;
this.digestInto(buffer);
const res = buffer.slice(0, outputLen);
this.destroy();
return res;
}
_cloneIntoMeta(to) {
const { buffer, length, finished, destroyed, pos } = this;
to.destroyed = destroyed;
to.finished = finished;
to.length = length;
to.pos = pos;
if (pos)
to.buffer.set(buffer);
return to;
}
clone() {
return this._cloneInto();
}
};
var SHA256_IV = /* @__PURE__ */ Uint32Array.from([
1779033703,
3144134277,
1013904242,
2773480762,
1359893119,
2600822924,
528734635,
1541459225
]);
// tools/reference-apps/light-service/node_modules/@noble/hashes/blake2.js
var B2B_IV = /* @__PURE__ */ Uint32Array.from([
4089235720,
1779033703,
2227873595,
3144134277,
4271175723,
1013904242,
1595750129,
2773480762,
2917565137,
1359893119,
725511199,
2600822924,
4215389547,
528734635,
327033209,
1541459225
]);
var BBUF = /* @__PURE__ */ new Uint32Array(32);
function G1b(a, b, c, d, msg, x) {
const Xl = msg[x], Xh = msg[x + 1];
let Al = BBUF[2 * a], Ah = BBUF[2 * a + 1];
let Bl = BBUF[2 * b], Bh = BBUF[2 * b + 1];
let Cl = BBUF[2 * c], Ch = BBUF[2 * c + 1];
let Dl = BBUF[2 * d], Dh = BBUF[2 * d + 1];
const ll = add3L(Al, Bl, Xl);
Ah = add3H(ll, Ah, Bh, Xh);
Al = ll | 0;
let xh = Dh ^ Ah, xl = Dl ^ Al;
Dh = rotr32H(xh, xl);
Dl = rotr32L(xh, xl);
({ h: Ch, l: Cl } = add(Ch, Cl, Dh, Dl));
xh = Bh ^ Ch;
xl = Bl ^ Cl;
Bh = rotrSH(xh, xl, 24);
Bl = rotrSL(xh, xl, 24);
BBUF[2 * a] = Al;
BBUF[2 * a + 1] = Ah;
BBUF[2 * b] = Bl;
BBUF[2 * b + 1] = Bh;
BBUF[2 * c] = Cl;
BBUF[2 * c + 1] = Ch;
BBUF[2 * d] = Dl;
BBUF[2 * d + 1] = Dh;
}
function G2b(a, b, c, d, msg, x) {
const Xl = msg[x], Xh = msg[x + 1];
let Al = BBUF[2 * a], Ah = BBUF[2 * a + 1];
let Bl = BBUF[2 * b], Bh = BBUF[2 * b + 1];
let Cl = BBUF[2 * c], Ch = BBUF[2 * c + 1];
let Dl = BBUF[2 * d], Dh = BBUF[2 * d + 1];
const ll = add3L(Al, Bl, Xl);
Ah = add3H(ll, Ah, Bh, Xh);
Al = ll | 0;
let xh = Dh ^ Ah, xl = Dl ^ Al;
Dh = rotrSH(xh, xl, 16);
Dl = rotrSL(xh, xl, 16);
({ h: Ch, l: Cl } = add(Ch, Cl, Dh, Dl));
xh = Bh ^ Ch;
xl = Bl ^ Cl;
Bh = rotrBH(xh, xl, 63);
Bl = rotrBL(xh, xl, 63);
BBUF[2 * a] = Al;
BBUF[2 * a + 1] = Ah;
BBUF[2 * b] = Bl;
BBUF[2 * b + 1] = Bh;
BBUF[2 * c] = Cl;
BBUF[2 * c + 1] = Ch;
BBUF[2 * d] = Dl;
BBUF[2 * d + 1] = Dh;
}
function checkBlake2Opts(outputLen, opts = {}, keyLen, saltLen, persLen) {
anumber(keyLen);
if (outputLen <= 0 || outputLen > keyLen)
throw new Error('"dkLen" must be 1..' + keyLen + ", got " + outputLen);
const { key, salt, personalization } = opts;
if (key !== void 0 && (key.length < 1 || key.length > keyLen))
throw new Error('"key" expected to be undefined or of length=1..' + keyLen);
if (salt !== void 0)
abytes(salt, saltLen, "salt");
if (personalization !== void 0)
abytes(personalization, persLen, "personalization");
}
var _BLAKE2 = class {
buffer;
buffer32;
finished = false;
destroyed = false;
length = 0;
pos = 0;
blockLen;
outputLen;
canXOF = false;
constructor(blockLen, outputLen) {
anumber(blockLen);
anumber(outputLen);
this.blockLen = blockLen;
this.outputLen = outputLen;
this.buffer = new Uint8Array(blockLen);
this.buffer32 = u32(this.buffer);
}
update(data) {
aexists(this);
abytes(data);
const { blockLen, buffer, buffer32 } = this;
const len = data.length;
const offset = data.byteOffset;
const buf = data.buffer;
for (let pos = 0; pos < len; ) {
if (this.pos === blockLen) {
swap32IfBE(buffer32);
this.compress(buffer32, 0, false);
swap32IfBE(buffer32);
this.pos = 0;
}
const take = Math.min(blockLen - this.pos, len - pos);
const dataOffset = offset + pos;
if (take === blockLen && !(dataOffset % 4) && pos + take < len) {
const data32 = new Uint32Array(buf, dataOffset, Math.floor((len - pos) / 4));
swap32IfBE(data32);
for (let pos32 = 0; pos + blockLen < len; pos32 += buffer32.length, pos += blockLen) {
this.length += blockLen;
this.compress(data32, pos32, false);
}
swap32IfBE(data32);
continue;
}
buffer.set(pos === 0 && take === len ? data : data.subarray(pos, pos + take), this.pos);
this.pos += take;
this.length += take;
pos += take;
}
return this;
}
digestInto(out) {
aexists(this);
aoutput(out, this);
if (out.byteOffset & 3)
throw new RangeError('"output" expected 4-byte aligned byteOffset, got ' + out.byteOffset);
const { pos, buffer32 } = this;
this.finished = true;
this.buffer.fill(0, pos);
swap32IfBE(buffer32);
this.compress(buffer32, 0, true);
swap32IfBE(buffer32);
const state = this.get();
const out32 = out === this.buffer ? buffer32 : u32(out);
const full = Math.floor(this.outputLen / 4);
for (let i = 0; i < full; i++)
out32[i] = swap8IfBE(state[i]);
const tail = this.outputLen % 4;
if (!tail)
return;
const off = full * 4;
const word = state[full];
for (let i = 0; i < tail; i++)
out[off + i] = word >>> 8 * i;
}
digest() {
const { buffer, outputLen } = this;
this.digestInto(buffer);
const res = buffer.slice(0, outputLen);
this.destroy();
return res;
}
_cloneInto(to) {
const { buffer, length, finished, destroyed, outputLen, pos } = this;
to ||= new this.constructor({ dkLen: outputLen });
to.set(...this.get());
to.buffer.set(buffer);
to.destroyed = destroyed;
to.finished = finished;
to.length = length;
to.pos = pos;
to.outputLen = outputLen;
return to;
}
clone() {
return this._cloneInto();
}
};
var _BLAKE2b = class extends _BLAKE2 {
// Same IV words as SHA-512 / BLAKE2b, encoded as LE u32 low/high halves.
v0l = B2B_IV[0] | 0;
v0h = B2B_IV[1] | 0;
v1l = B2B_IV[2] | 0;
v1h = B2B_IV[3] | 0;
v2l = B2B_IV[4] | 0;
v2h = B2B_IV[5] | 0;
v3l = B2B_IV[6] | 0;
v3h = B2B_IV[7] | 0;
v4l = B2B_IV[8] | 0;
v4h = B2B_IV[9] | 0;
v5l = B2B_IV[10] | 0;
v5h = B2B_IV[11] | 0;
v6l = B2B_IV[12] | 0;
v6h = B2B_IV[13] | 0;
v7l = B2B_IV[14] | 0;
v7h = B2B_IV[15] | 0;
constructor(opts = {}) {
opts = checkOpts({}, opts);
const olen = opts.dkLen === void 0 ? 64 : opts.dkLen;
super(128, olen);
checkBlake2Opts(olen, opts, 64, 16, 16);
let { key, personalization, salt } = opts;
let keyLength = 0;
if (key !== void 0) {
abytes(key, void 0, "key");
keyLength = key.length;
}
this.v0l ^= this.outputLen | keyLength << 8 | 1 << 16 | 1 << 24;
if (salt !== void 0) {
abytes(salt, void 0, "salt");
const slt = u32(copyBytes(salt));
this.v4l ^= swap8IfBE(slt[0]);
this.v4h ^= swap8IfBE(slt[1]);
this.v5l ^= swap8IfBE(slt[2]);
this.v5h ^= swap8IfBE(slt[3]);
}
if (personalization !== void 0) {
abytes(personalization, void 0, "personalization");
const pers = u32(copyBytes(personalization));
this.v6l ^= swap8IfBE(pers[0]);
this.v6h ^= swap8IfBE(pers[1]);
this.v7l ^= swap8IfBE(pers[2]);
this.v7h ^= swap8IfBE(pers[3]);
}
if (key !== void 0) {
const tmp = new Uint8Array(this.blockLen);
tmp.set(key);
this.update(tmp);
clean(tmp);
}
}
// prettier-ignore
get() {
let { v0l, v0h, v1l, v1h, v2l, v2h, v3l, v3h, v4l, v4h, v5l, v5h, v6l, v6h, v7l, v7h } = this;
return [v0l, v0h, v1l, v1h, v2l, v2h, v3l, v3h, v4l, v4h, v5l, v5h, v6l, v6h, v7l, v7h];
}
// prettier-ignore
set(v0l, v0h, v1l, v1h, v2l, v2h, v3l, v3h, v4l, v4h, v5l, v5h, v6l, v6h, v7l, v7h) {
this.v0l = v0l | 0;
this.v0h = v0h | 0;
this.v1l = v1l | 0;
this.v1h = v1h | 0;
this.v2l = v2l | 0;
this.v2h = v2h | 0;
this.v3l = v3l | 0;
this.v3h = v3h | 0;
this.v4l = v4l | 0;
this.v4h = v4h | 0;
this.v5l = v5l | 0;
this.v5h = v5h | 0;
this.v6l = v6l | 0;
this.v6h = v6h | 0;
this.v7l = v7l | 0;
this.v7h = v7h | 0;
}
compress(msg, offset, isLast) {
const { v0l, v0h, v1l, v1h, v2l, v2h, v3l, v3h, v4l, v4h, v5l, v5h, v6l, v6h, v7l, v7h } = this;
{
BBUF[0] = v0l;
BBUF[1] = v0h;
BBUF[2] = v1l;
BBUF[3] = v1h;
BBUF[4] = v2l;
BBUF[5] = v2h;
BBUF[6] = v3l;
BBUF[7] = v3h;
BBUF[8] = v4l;
BBUF[9] = v4h;
BBUF[10] = v5l;
BBUF[11] = v5h;
BBUF[12] = v6l;
BBUF[13] = v6h;
BBUF[14] = v7l;
BBUF[15] = v7h;
}
BBUF.set(B2B_IV, 16);
const l = fromNumL(this.length);
const h = fromNumH(this.length);
BBUF[24] = B2B_IV[8] ^ l;
BBUF[25] = B2B_IV[9] ^ h;
if (isLast) {
BBUF[28] = ~BBUF[28];
BBUF[29] = ~BBUF[29];
}
let j = 0;
const s = BSIGMA;
for (let i = 0; i < 12; i++) {
G1b(0, 4, 8, 12, msg, offset + 2 * s[j++]);
G2b(0, 4, 8, 12, msg, offset + 2 * s[j++]);
G1b(1, 5, 9, 13, msg, offset + 2 * s[j++]);
G2b(1, 5, 9, 13, msg, offset + 2 * s[j++]);
G1b(2, 6, 10, 14, msg, offset + 2 * s[j++]);
G2b(2, 6, 10, 14, msg, offset + 2 * s[j++]);
G1b(3, 7, 11, 15, msg, offset + 2 * s[j++]);
G2b(3, 7, 11, 15, msg, offset + 2 * s[j++]);
G1b(0, 5, 10, 15, msg, offset + 2 * s[j++]);
G2b(0, 5, 10, 15, msg, offset + 2 * s[j++]);
G1b(1, 6, 11, 12, msg, offset + 2 * s[j++]);
G2b(1, 6, 11, 12, msg, offset + 2 * s[j++]);
G1b(2, 7, 8, 13, msg, offset + 2 * s[j++]);
G2b(2, 7, 8, 13, msg, offset + 2 * s[j++]);
G1b(3, 4, 9, 14, msg, offset + 2 * s[j++]);
G2b(3, 4, 9, 14, msg, offset + 2 * s[j++]);
}
this.v0l ^= BBUF[0] ^ BBUF[16];
this.v0h ^= BBUF[1] ^ BBUF[17];
this.v1l ^= BBUF[2] ^ BBUF[18];
this.v1h ^= BBUF[3] ^ BBUF[19];
this.v2l ^= BBUF[4] ^ BBUF[20];
this.v2h ^= BBUF[5] ^ BBUF[21];
this.v3l ^= BBUF[6] ^ BBUF[22];
this.v3h ^= BBUF[7] ^ BBUF[23];
this.v4l ^= BBUF[8] ^ BBUF[24];
this.v4h ^= BBUF[9] ^ BBUF[25];
this.v5l ^= BBUF[10] ^ BBUF[26];
this.v5h ^= BBUF[11] ^ BBUF[27];
this.v6l ^= BBUF[12] ^ BBUF[28];
this.v6h ^= BBUF[13] ^ BBUF[29];
this.v7l ^= BBUF[14] ^ BBUF[30];
this.v7h ^= BBUF[15] ^ BBUF[31];
clean(BBUF);
}
destroy() {
this.destroyed = true;
clean(this.buffer32);
this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
};
var blake2b = /* @__PURE__ */ createHasher((opts) => new _BLAKE2b(opts));
// tools/reference-apps/light-service/node_modules/@noble/hashes/sha3.js
var _0n = BigInt(0);
var _1n = BigInt(1);
var _2n = BigInt(2);
var _7n = BigInt(7);
var _256n = BigInt(256);
var _0x71n = BigInt(113);
var SHA3_PI = [];
var SHA3_ROTL = [];
var _SHA3_IOTA = [];
for (let round = 0, R = _1n, x = 1, y = 0; round < 24; round++) {
[x, y] = [y, (2 * x + 3 * y) % 5];
SHA3_PI.push(2 * (5 * y + x));
SHA3_ROTL.push((round + 1) * (round + 2) / 2 % 64);
let t2 = _0n;
for (let j = 0; j < 7; j++) {
R = (R << _1n ^ (R >> _7n) * _0x71n) % _256n;
if (R & _2n)
t2 ^= _1n << (_1n << BigInt(j)) - _1n;
}
_SHA3_IOTA.push(t2);
}
var IOTAS = split(_SHA3_IOTA, true);
var SHA3_IOTA_H = IOTAS[0];
var SHA3_IOTA_L = IOTAS[1];
var rotlSH = (h, l, s) => h << s | l >>> 32 - s;
var rotlSL = (h, l, s) => l << s | h >>> 32 - s;
var rotlBH = (h, l, s) => l << s - 32 | h >>> 64 - s;
var rotlBL = (h, l, s) => h << s - 32 | l >>> 64 - s;
var rotlH = (h, l, s) => s > 32 ? rotlBH(h, l, s) : rotlSH(h, l, s);
var rotlL = (h, l, s) => s > 32 ? rotlBL(h, l, s) : rotlSL(h, l, s);
var B = new Uint32Array(5 * 2);
function keccakP(s, rounds = 24) {
if (!(s instanceof Uint32Array))
throw new TypeError('"s" expected Uint32Array(50), got type=' + typeof s);
if (s.length !== 50)
throw new RangeError('"s" expected Uint32Array(50), got length=' + s.length);
anumber(rounds, "rounds");
if (rounds < 1 || rounds > 24)
throw new Error('"rounds" expected integer 1..24');
for (let round = 24 - rounds; round < 24; round++) {
for (let x = 0; x < 10; x++)
B[x] = s[x] ^ s[x + 10] ^ s[x + 20] ^ s[x + 30] ^ s[x + 40];
for (let x = 0; x < 10; x += 2) {
const idx1 = (x + 8) % 10;
const idx0 = (x + 2) % 10;
const B0 = B[idx0];
const B1 = B[idx0 + 1];
const Th = rotlH(B0, B1, 1) ^ B[idx1];
const Tl = rotlL(B0, B1, 1) ^ B[idx1 + 1];
for (let y = 0; y < 50; y += 10) {
s[x + y] ^= Th;
s[x + y + 1] ^= Tl;
}
}
let curH = s[2];
let curL = s[3];
for (let t2 = 0; t2 < 24; t2++) {
const shift = SHA3_ROTL[t2];
const Th = rotlH(curH, curL, shift);
const Tl = rotlL(curH, curL, shift);
const PI = SHA3_PI[t2];
curH = s[PI];
curL = s[PI + 1];
s[PI] = Th;
s[PI + 1] = Tl;
}
for (let y = 0; y < 50; y += 10) {
const b0 = s[y], b1 = s[y + 1], b2 = s[y + 2], b3 = s[y + 3];
s[y] ^= ~s[y + 2] & s[y + 4];
s[y + 1] ^= ~s[y + 3] & s[y + 5];
s[y + 2] ^= ~s[y + 4] & s[y + 6];
s[y + 3] ^= ~s[y + 5] & s[y + 7];
s[y + 4] ^= ~s[y + 6] & s[y + 8];
s[y + 5] ^= ~s[y + 7] & s[y + 9];
s[y + 6] ^= ~s[y + 8] & b0;
s[y + 7] ^= ~s[y + 9] & b1;
s[y + 8] ^= ~b0 & b2;
s[y + 9] ^= ~b1 & b3;
}
s[0] ^= SHA3_IOTA_H[round];
s[1] ^= SHA3_IOTA_L[round];
}
clean(B);
}
var Keccak = class _Keccak {
state;
pos = 0;
posOut = 0;
finished = false;
state32;
destroyed = false;
blockLen;
suffix;
outputLen;
canXOF;
enableXOF = false;
rounds;
// NOTE: we accept arguments in bytes instead of bits here.
constructor(blockLen, suffix, outputLen, enableXOF = false, rounds = 24) {
anumber(blockLen, "blockLen");
anumber(suffix, "suffix");
anumber(rounds, "rounds");
abool(enableXOF, "enableXOF");
this.blockLen = blockLen;
this.suffix = suffix;
this.outputLen = outputLen;
this.enableXOF = enableXOF;
this.canXOF = enableXOF;
this.rounds = rounds;
anumber(outputLen, "outputLen");
if (!(0 < blockLen && blockLen < 200))
throw new Error('"blockLen" must be 1..199');
this.state = new Uint8Array(200);
this.state32 = u32(this.state);
}
clone() {
return this._cloneInto();
}
keccak() {
swap32IfBE(this.state32);
keccakP(this.state32, this.rounds);
swap32IfBE(this.state32);
this.posOut = 0;
this.pos = 0;
}
update(data) {
aexists(this);
abytes(data);
const { blockLen, state, state32 } = this;
const len = data.length;
const canUseU32 = blockLen % 4 === 0 && data.byteOffset % 4 === 0;
const blockLen32 = blockLen / 4;
const data32 = canUseU32 && len >= blockLen ? u32(data) : void 0;
for (let pos = 0; pos < len; ) {
if (data32 !== void 0 && this.pos === 0 && pos % 4 === 0 && len - pos >= blockLen) {
for (let i = 0, o = pos / 4; i < blockLen32; i++)
state32[i] ^= data32[o + i];
pos += blockLen;
this.pos = blockLen;
this.keccak();
continue;
}
const take = Math.min(blockLen - this.pos, len - pos);
for (let i = 0; i < take; i++)
state[this.pos++] ^= data[pos++];
if (this.pos === blockLen)
this.keccak();
}
return this;
}
finish() {
if (this.finished)
return;
this.finished = true;
const { state, suffix, pos, blockLen } = this;
state[pos] ^= suffix;
if ((suffix & 128) !== 0 && pos === blockLen - 1)
this.keccak();
state[blockLen - 1] ^= 128;
this.keccak();
}
writeInto(out) {
aexists(this, false);
abytes(out);
this.finish();
const bufferOut = this.state;
const { blockLen } = this;
for (let pos = 0, len = out.length; pos < len; ) {
if (this.posOut >= blockLen)
this.keccak();
const take = Math.min(blockLen - this.posOut, len - pos);
out.set(bufferOut.subarray(this.posOut, this.posOut + take), pos);
this.posOut += take;
pos += take;
}
return out;
}
xofInto(out) {
if (!this.enableXOF)
throw new Error("XOF is not enabled");
return this.writeInto(out);
}
xof(bytes) {
anumber(bytes);
return this.xofInto(new Uint8Array(bytes));
}
digestInto(out) {
aoutput(out, this);
if (this.finished)
throw new Error("digest() was already called");
this.writeInto(out.length === this.outputLen ? out : out.subarray(0, this.outputLen));
this.destroy();
}
digest() {
const out = new Uint8Array(this.outputLen);
this.digestInto(out);
return out;
}
destroy() {
this.destroyed = true;
clean(this.state);
}
_cloneInto(to) {
const { blockLen, suffix, outputLen, rounds, enableXOF } = this;
to ||= new _Keccak(blockLen, suffix, outputLen, enableXOF, rounds);
to.blockLen = blockLen;
to.state32.set(this.state32);
to.pos = this.pos;
to.posOut = this.posOut;
to.finished = this.finished;
to.rounds = rounds;
to.suffix = suffix;
to.outputLen = outputLen;
to.enableXOF = enableXOF;
to.canXOF = this.canXOF;
to.destroyed = this.destroyed;
return to;
}
};
var genKeccak = (suffix, blockLen, outputLen, info = {}) => createHasher(() => new Keccak(blockLen, suffix, outputLen), info);
var keccak_256 = /* @__PURE__ */ genKeccak(1, 136, 32);
// tools/reference-apps/light-service/node_modules/@noble/hashes/sha2.js
var SHA256_K = /* @__PURE__ */ Uint32Array.from([
1116352408,
1899447441,
3049323471,
3921009573,
961987163,
1508970993,
2453635748,
2870763221,
3624381080,
310598401,
607225278,
1426881987,
1925078388,
2162078206,
2614888103,
3248222580,
3835390401,
4022224774,
264347078,
604807628,
770255983,
1249150122,
1555081692,
1996064986,
2554220882,
2821834349,
2952996808,
3210313671,
3336571891,
3584528711,
113926993,
338241895,
666307205,
773529912,
1294757372,
1396182291,
1695183700,
1986661051,
2177026350,
2456956037,
2730485921,
2820302411,
3259730800,
3345764771,
3516065817,
3600352804,
4094571909,
275423344,
430227734,
506948616,
659060556,
883997877,
958139571,
1322822218,
1537002063,
1747873779,
1955562222,
2024104815,
2227730452,
2361852424,
2428436474,
2756734187,
3204031479,
3329325298
]);
var SHA256_W = /* @__PURE__ */ new Uint32Array(64);
var SHA2_32B = class extends HashMD {
// We cannot use array here since array allows indexing by variable
// which means optimizer/compiler cannot use registers.
// Numeric initializers matter: starting the fields as `undefined` changes
// V8's field representation and makes sha256 3x slower (measured).
A = 0;
B = 0;
C = 0;
D = 0;
E = 0;
F = 0;
G = 0;
H = 0;
constructor(outputLen, IV) {
super(64, outputLen, 8, false);
this.A = IV[0] | 0;
this.B = IV[1] | 0;
this.C = IV[2] | 0;
this.D = IV[3] | 0;
this.E = IV[4] | 0;
this.F = IV[5] | 0;
this.G = IV[6] | 0;
this.H = IV[7] | 0;
}
get() {
const { A, B: B2, C, D, E, F, G, H } = this;
return [A, B2, C, D, E, F, G, H];
}
// prettier-ignore
set(A, B2, C, D, E, F, G, H) {
this.A = A | 0;
this.B = B2 | 0;
this.C = C | 0;
this.D = D | 0;
this.E = E | 0;
this.F = F | 0;
this.G = G | 0;
this.H = H | 0;
}
_cloneInto(to) {
(to ||= new this.constructor()).set(...this.get());
return this._cloneIntoMeta(to);
}
process(view, offset) {
for (let i = 0; i < 16; i++, offset += 4)
SHA256_W[i] = view.getUint32(offset, false);
for (let i = 16; i < 64; i++) {
const W15 = SHA256_W[i - 15];
const W2 = SHA256_W[i - 2];
const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3;
const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10;
SHA256_W[i] = s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16] | 0;
}
let { A, B: B2, C, D, E, F, G, H } = this;
for (let i = 0; i < 64; i++) {
const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
const T1 = H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i] | 0;
const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);
const T2 = sigma0 + Maj(A, B2, C) | 0;
H = G;
G = F;
F = E;
E = D + T1 | 0;
D = C;
C = B2;
B2 = A;
A = T1 + T2 | 0;
}
A = A + this.A | 0;
B2 = B2 + this.B | 0;
C = C + this.C | 0;
D = D + this.D | 0;
E = E + this.E | 0;
F = F + this.F | 0;
G = G + this.G | 0;
H = H + this.H | 0;
this.set(A, B2, C, D, E, F, G, H);
}
roundClean() {
clean(SHA256_W);
}
destroy() {
this.destroyed = true;
this.set(0, 0, 0, 0, 0, 0, 0, 0);
clean(this.buffer);
}
};
var _SHA256 = class extends SHA2_32B {
constructor() {
super(32, SHA256_IV);
}
};
var sha256 = /* @__PURE__ */ createHasher(
() => new _SHA256(),
/* @__PURE__ */ oidNist(1)
);
// tools/reference-apps/light-service/node_modules/@noble/curves/utils.js
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
function aarray(item, title, inner = () => {
}) {
if (!Array.isArray(item))
throw new TypeError(`"${title}" expected array, got type=${typeof item}`);
for (let i = 0; i < item.length; i++)
inner(item[i], `${title}[${i}]`);
return item;
}
var abytes2 = (value, length, title) => abytes(value, length, title);
var anumber2 = anumber;
function aobject2(value, title = "object") {
if (value === null || typeof value !== "object" || Array.isArray(value))
throw new TypeError(title === "object" ? "expected valid options object" : `"${title}" expected object, got type=${typeof value}`);
return value;
}
function afunction(value, title) {
if (typeof value !== "function")
throw new TypeError(`"${title}" is invalid: expected function, got ${typeof value}`);
return value;
}
var bytesToHex2 = bytesToHex;
var concatBytes2 = (...arrays) => concatBytes(...arrays);
var hexToBytes2 = (hex) => hexToBytes(hex);
var isBytes2 = isBytes;
var randomBytes2 = (bytesLength) => randomBytes(bytesLength);
var _0n2 = /* @__PURE__ */ BigInt(0);
var _1n2 = /* @__PURE__ */ BigInt(1);
var atitle2 = (title) => title ? `"${title}" ` : "";
function abool2(value, title = "") {
if (typeof value !== "boolean")
throw new TypeError(atitle2(title) + "expected boolean, got type=" + typeof value);
return value;
}
function abignumber(n) {
if (typeof n === "bigint") {
if (!isPosBig(n))
throw new RangeError("positive bigint expected, got " + n);
} else
anumber2(n);
return n;
}
function asafenumber(value, title = "") {
if (typeof value !== "number") {
const prefix = title && `"${title}" `;
throw new TypeError(prefix + "expected number, got type=" + typeof value);
}
if (!Number.isSafeInteger(value)) {
const prefix = title && `"${title}" `;
throw new RangeError(prefix + "expected safe integer, got " + value);
}
}
function hexToNumber(hex) {
if (typeof hex !== "string")
throw new TypeError("hex string expected, got " + typeof hex);
return hex === "" ? _0n2 : BigInt("0x" + hex);
}
function bytesToNumberBE(bytes) {
return hexToNumber(bytesToHex(bytes));
}
function bytesToNumberLE(bytes) {
return hexToNumber(bytesToHex(copyBytes2(abytes(bytes)).reverse()));
}
function numberToBytesBE(n, len) {
anumber(len);
if (len === 0)
throw new Error("zero output length is invalid");
n = abignumber(n);
const expectedLen = len * 2;
const hex = n.toString(16);
if (hex.length > expectedLen)
throw new RangeError("number is too large");
return hexToBytes(hex.padStart(expectedLen, "0"));
}
function numberToBytesLE(n, len) {
return numberToBytesBE(n, len).reverse();
}
function copyBytes2(bytes) {
return Uint8Array.from(abytes2(bytes));
}
function asciiToBytes(ascii) {
if (typeof ascii !== "string")
throw new TypeError("ascii string expected, got " + typeof ascii);
return Uint8Array.from(ascii, (c, i) => {
const charCode = c.charCodeAt(0);
if (c.length !== 1 || charCode > 127) {
throw new RangeError(`string contains non-ASCII character "${ascii[i]}" with code ${charCode} at position ${i}`);
}
return charCode;
});
}
function isPosBig(n) {
return typeof n === "bigint" && _0n2 <= n;
}
function inRange(n, min, max) {
return isPosBig(n) && isPosBig(min) && isPosBig(max) && min <= n && n < max;
}
function aInRange(title, n, min, max) {
if (!inRange(n, min, max))
throw new RangeError("expected valid " + title + ": " + min + " <= n < " + max + ", got " + n);
}
function bitLen(n) {
if (n < _0n2)
throw new Error("expected non-negative bigint, got " + n);
return n === _0n2 ? 0 : n.toString(2).length;
}
function bitGet(n, pos) {
if (typeof n !== "bigint")
throw new TypeError('"n" expected bigint, got type=' + typeof n);
asafenumber(pos, "pos");
return n >> BigInt(pos) & _1n2;
}
var bitMask = (n) => {
asafenumber(n, "n");
return (_1n2 << BigInt(n)) - _1n2;
};
function validateObject(object, fields2 = {}, optFields = {}, title = "object") {
aobject2(object, title);
aobject2(fields2, "fields");
aobject2(optFields, "optFields");
function checkField(fieldName, expectedType, isOpt) {
const label = title === "object" ? `param "${String(fieldName)}"` : `"${title}.${String(fieldName)}"`;
const val = object[fieldName];
if (!Object.hasOwn(object, fieldName) && (isOpt ? val !== void 0 : expectedType !== "function")) {
throw new TypeError(`${label} is invalid: expected own property`);
}
if (isOpt && val === void 0)
return;
const current = typeof val;
if (current !== expectedType || val === null)
throw new TypeError(`${label} is invalid: expected ${expectedType}, got ${current}`);
}
const iter = (f, isOpt) => Object.entries(f).forEach(([k, v]) => checkField(k, v, isOpt));
iter(fields2, false);
iter(optFields, true);
}
var notImplemented = () => {
throw new Error("not implemented");
};
// tools/reference-apps/light-service/node_modules/@noble/curves/abstract/modular.js
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
var _0n3 = /* @__PURE__ */ BigInt(0);
var _1n3 = /* @__PURE__ */ BigInt(1);
var _2n2 = /* @__PURE__ */ BigInt(2);
var _3n = /* @__PURE__ */ BigInt(3);
var _4n = /* @__PURE__ */ BigInt(4);
var _5n = /* @__PURE__ */ BigInt(5);
var _7n2 = /* @__PURE__ */ BigInt(7);
var _8n = /* @__PURE__ */ BigInt(8);
var _9n = /* @__PURE__ */ BigInt(9);
var _15n = /* @__PURE__ */ BigInt(15);
var _16n = /* @__PURE__ */ BigInt(16);
var POW_WINDOWED_MIN = /* @__PURE__ */ BigInt("0x10000000000000000");
function mod(a, b) {
if (b <= _0n3)
throw new Error("mod: expected positive modulus, got " + b);
const result = a % b;
return result >= _0n3 ? result : b + result;
}
function pow(num, power, modulo) {
if (modulo <= _1n3)
throw new Error("pow: expected modulus > 1, got " + modulo);
if (typeof power !== "bigint")
throw new TypeError("invalid exponent: expected bigint, got " + typeof power);
if (power < _0n3)
throw new Error("invalid exponent, negatives unsupported");
if (power === _0n3)
return _1n3;
if (power === _1n3)
return num;
let d = num % modulo;
if (d < _0n3)
d += modulo;
if (power < POW_WINDOWED_MIN) {
let p2 = _1n3;
while (power > _0n3) {
if (power & _1n3)
p2 = p2 * d % modulo;
d = d * d % modulo;
power >>= _1n3;
}
return p2;
}
const digits = [];
while (power > _0n3) {
digits.push(Number(power & _15n));
power >>= _4n;
}
const table = new Array(16);
table[0] = _1n3;
table[1] = d;
for (let i = 2; i < 16; i++)
table[i] = table[i - 1] * d % modulo;
let p = table[digits[digits.length - 1]];
for (let w = digits.length - 2; w >= 0; w--) {
p = p * p % modulo;
p = p * p % modulo;
p = p * p % modulo;
p = p * p % modulo;
const digit = digits[w];
if (digit !== 0)
p = p * table[digit] % modulo;
}
return p;
}
function invert(number, modulo) {
if (number === _0n3)
throw new Error("invert: expected non-zero number");
if (modulo <= _1n3)
throw new Error("invert: expected modulus > 1, got " + modulo);
let a = mod(number, modulo);
let b = modulo;
let x = _0n3, u = _1n3;
while (a !== _0n3) {
const q = b / a;
const r2 = b - a * q;
const m = x - u * q;
b = a, a = r2, x = u, u = m;
}
const gcd = b;
if (gcd !== _1n3)
throw new Error("invert: does not exist");
return mod(x, modulo);
}
function assertIsSquare(Fp3, root, n) {
const F = Fp3;
if (!F.eql(F.sqr(root), n))
throw new Error("Cannot find square root");
}
function aoddModulus(order, fnName) {
if ((order & _1n3) === _0n3)
throw new Error(fnName + ": expected odd modulus, got " + order);
}
function sqrt3mod4(Fp3, n) {
const F = Fp3;
const p1div4 = (F.ORDER + _1n3) / _4n;
const root = F.pow(n, p1div4);
assertIsSquare(F, root, n);
return root;
}
function sqrt5mod8(Fp3, n) {
const F = Fp3;
const p5div8 = (F.ORDER - _5n) / _8n;
const n2 = F.mul(n, _2n2);
const v = F.pow(n2, p5div8);
const nv = F.mul(n, v);
const i = F.mul(F.mul(nv, _2n2), v);
const root = F.mul(nv, F.sub(i, F.ONE));
assertIsSquare(F, root, n);
return root;
}
function sqrt9mod16(P) {
const Fp_ = Field(P);
const tn = tonelliShanks(P);
const c1 = tn(Fp_, Fp_.neg(Fp_.ONE));
const c2 = tn(Fp_, c1);
const c3 = tn(Fp_, Fp_.neg(c1));
const c4 = (P + _7n2) / _16n;
return (Fp3, n) => {
const F = Fp3;
let tv1 = F.pow(n, c4);
let tv2 = F.mul(tv1, c1);
const tv3 = F.mul(tv1, c2);
const tv4 = F.mul(tv1, c3);
const e1 = F.eql(F.sqr(tv2), n);
const e2 = F.eql(F.sqr(tv3), n);
tv1 = F.cmov(tv1, tv2, e1);
tv2 = F.cmov(tv4, tv3, e2);
const e3 = F.eql(F.sqr(tv2), n);
const root = F.cmov(tv1, tv2, e3);
assertIsSquare(F, root, n);
return root;
};
}
function tonelliShanks(P) {
if (P < _3n)
throw new Error("sqrt is not defined for small field");
aoddModulus(P, "tonelliShanks");
let Q = P - _1n3;
let S = 0;
while (Q % _2n2 === _0n3) {
Q /= _2n2;
S++;
}
let Z = _2n2;
const _Fp = Field(P);
while (FpLegendre(_Fp, Z) === 1) {
if (Z++ > 1e3)
throw new Error("Cannot find square root: probably non-prime P");
}
if (S === 1)
return sqrt3mod4;
let cc = _Fp.pow(Z, Q);
const Q1div2 = (Q + _1n3) / _2n2;
return function tonelliSlow(Fp3, n) {
const F = Fp3;
if (F.is0(n))
return n;
if (FpLegendre(F, n) !== 1)
throw new Error("Cannot find square root");
let M = S;
let c = F.mul(F.ONE, cc);
let t2 = F.pow(n, Q);
let R = F.pow(n, Q1div2);
while (!F.eql(t2, F.ONE)) {
if (F.is0(t2))
throw new Error("Cannot find square root: probably non-prime P");
let i = 1;
let t_tmp = F.sqr(t2);
while (!F.eql(t_tmp, F.ONE)) {
i++;
t_tmp = F.sqr(t_tmp);
if (i === M)
throw new Error("Cannot find square root");
}
const exponent = _1n3 << BigInt(M - i - 1);
const b = F.pow(c, exponent);
M = i;
c = F.sqr(b);
t2 = F.mul(t2, c);
R = F.mul(R, b);
}
return R;
};
}
function FpSqrt(P) {
aoddModulus(P, "Fp.sqrt");
if (P % _4n === _3n)
return sqrt3mod4;
if (P % _8n === _5n)
return sqrt5mod8;
if (P % _16n === _9n)
return sqrt9mod16(P);
return tonelliShanks(P);
}
var FIELD_FIELDS = [
"create",
"isValid",
"is0",
"neg",
"inv",
"sqrt",
"sqr",
"eql",
"add",
"sub",
"mul",
"pow",
"div",
"addN",
"subN",
"mulN",
"sqrN"
];
function validateField(field) {
aobject2(field, "field");
if (typeof field.ORDER !== "bigint")
throw new TypeError('param "ORDER" is invalid: expected bigint, got ' + typeof field.ORDER);
asafenumber(field.BYTES, "BYTES");
asafenumber(field.BITS, "BITS");
for (const name of FIELD_FIELDS)
afunction(field[name], "field." + name);
if (field.BYTES < 1 || field.BITS < 1)
throw new Error("invalid field: expected BYTES/BITS > 0");
if (field.ORDER <= _1n3)
throw new Error("invalid field: expected ORDER > 1, got " + field.ORDER);
return field;
}
function FpPow(Fp3, num, power) {
validateField(Fp3);
const F = Fp3;
if (typeof power !== "bigint")
throw new TypeError("invalid exponent: expected bigint, got " + typeof power);
if (power < _0n3)
throw new Error("invalid exponent, negatives unsupported");
if (power === _0n3)
return F.ONE;
if (power === _1n3)
return num;
if (power < POW_WINDOWED_MIN) {
let p2 = F.ONE;
let d = num;
while (power > _0n3) {
if (power & _1n3)
p2 = F.mul(p2, d);
d = F.sqr(d);
power >>= _1n3;
}
return p2;
}
const digits = [];
while (power > _0n3) {
digits.push(Number(power & _15n));
power >>= _4n;
}
const table = new Array(16);
table[0] = F.ONE;
table[1] = num;
for (let i = 2; i < 16; i++)
table[i] = F.mul(table[i - 1], num);
let p = table[digits[digits.length - 1]];
for (let w = digits.length - 2; w >= 0; w--) {
p = F.sqr(F.sqr(F.sqr(F.sqr(p))));
const digit = digits[w];
if (digit !== 0)
p = F.mul(p, table[digit]);
}
return p;
}
function FpInvertBatch(Fp3, nums, passZero = false) {
validateField(Fp3);
aarray(nums, "nums");
abool2(passZero, "passZero");
const F = Fp3;
const inverted = new Array(nums.length).fill(passZero ? F.ZERO : void 0);
const multipliedAcc = nums.reduce((acc, num, i) => {
if (F.is0(num))
return acc;
inverted[i] = acc;
return F.mul(acc, num);
}, F.ONE);
const invertedAcc = F.inv(multipliedAcc);
nums.reduceRight((acc, num, i) => {
if (F.is0(num))
return acc;
inverted[i] = F.mul(acc, inverted[i]);
return F.mul(acc, num);
}, invertedAcc);
return inverted;
}
function FpLegendre(Fp3, n) {
validateField(Fp3);
const F = Fp3;
aoddModulus(F.ORDER, "FpLegendre");
const p1mod2 = (F.ORDER - _1n3) / _2n2;
const powered = F.pow(n, p1mod2);
const yes = F.eql(powered, F.ONE);
const zero = F.eql(powered, F.ZERO);
const no = F.eql(powered, F.neg(F.ONE));
if (!yes && !zero && !no)
throw new Error("invalid Legendre symbol result");
return yes ? 1 : zero ? 0 : -1;
}
function FpIsSquare(Fp3, n) {
const l = FpLegendre(Fp3, n);
return l !== -1;
}
function nLength(n, nBitLength) {
if (nBitLength !== void 0)
anumber2(nBitLength);
if (n <= _0n3)
throw new Error("invalid n length: expected positive n, got " + n);
if (nBitLength !== void 0 && nBitLength < 1)
throw new Error("invalid n length: expected positive bit length, got " + nBitLength);
const bits = bitLen(n);
if (nBitLength !== void 0 && nBitLength < bits)
throw new Error(`invalid n length: expected nBitLength (${nBitLength}) >= bitLen(n) (${bits})`);
const _nBitLength = nBitLength !== void 0 ? nBitLength : bits;
const nByteLength = Math.ceil(_nBitLength / 8);
return { nBitLength: _nBitLength, nByteLength };
}
var FIELD_SQRT = /* @__PURE__ */ new WeakMap();
var _Field = class {
ORDER;
BITS;
BYTES;
isLE;
ZERO = _0n3;
ONE = _1n3;
_lengths;
_mod;
constructor(ORDER, opts = {}) {
if (ORDER <= _1n3)
throw new Error("invalid field: expected ORDER > 1, got " + ORDER);
let _nbitLength = void 0;
this.isLE = false;
if (opts != null && typeof opts === "object") {
if (typeof opts.BITS === "number")
_nbitLength = opts.BITS;
if (typeof opts.sqrt === "function")
Object.defineProperty(this, "sqrt", { value: opts.sqrt, enumerable: true });
if (typeof opts.isLE === "boolean")
this.isLE = opts.isLE;
if (opts.allowedLengths)
this._lengths = Object.freeze(opts.allowedLengths.slice());
if (typeof opts.modFromBytes === "boolean")
this._mod = opts.modFromBytes;
}
const { nBitLength, nByteLength } = nLength(ORDER, _nbitLength);
if (nByteLength > 2048)
throw new Error("invalid field: expected ORDER of <= 2048 bytes");
this.ORDER = ORDER;
this.BITS = nBitLength;
this.BYTES = nByteLength;
Object.freeze(this);
}
create(num) {
return mod(num, this.ORDER);
}
isValid(num) {
if (typeof num !== "bigint")
throw new TypeError("invalid field element: expected bigint, got " + typeof num);
return _0n3 <= num && num < this.ORDER;
}
is0(num) {
return num === _0n3;
}
// is valid and invertible
isValidNot0(num) {
return !this.is0(num) && this.isValid(num);
}
isOdd(num) {
return (num & _1n3) === _1n3;
}
neg(num) {
return mod(-num, this.ORDER);
}
eql(lhs, rhs) {
return lhs === rhs;
}
sqr(num) {
return mod(num * num, this.ORDER);
}
add(lhs, rhs) {
return mod(lhs + rhs, this.ORDER);
}
sub(lhs, rhs) {
return mod(lhs - rhs, this.ORDER);
}
mul(lhs, rhs) {
return mod(lhs * rhs, this.ORDER);
}
pow(num, power) {
return pow(num, power, this.ORDER);
}
div(lhs, rhs) {
return mod(lhs * invert(rhs, this.ORDER), this.ORDER);
}
// Same as above, but doesn't normalize
sqrN(num) {
return num * num;
}
addN(lhs, rhs) {
return lhs + rhs;
}
subN(lhs, rhs) {
return lhs - rhs;
}
mulN(lhs, rhs) {
return lhs * rhs;
}
inv(num) {
return invert(num, this.ORDER);
}
sqrt(num) {
let sqrt = FIELD_SQRT.get(this);
if (!sqrt)
FIELD_SQRT.set(this, sqrt = FpSqrt(this.ORDER));
return sqrt(this, num);
}
toBytes(num) {
return this.isLE ? numberToBytesLE(num, this.BYTES) : numberToBytesBE(num, this.BYTES);
}
fromBytes(bytes, skipValidation = false) {
abytes2(bytes);
const { _lengths: allowedLengths, BYTES, isLE: isLE2, ORDER, _mod: modFromBytes } = this;
if (allowedLengths) {
if (bytes.length < 1 || !allowedLengths.includes(bytes.length) || bytes.length > BYTES) {
throw new Error("Field.fromBytes: expected " + allowedLengths + " bytes, got " + bytes.length);
}
const padded = new Uint8Array(BYTES);
padded.set(bytes, isLE2 ? 0 : padded.length - bytes.length);
bytes = padded;
}
if (bytes.length !== BYTES)
throw new Error("Field.fromBytes: expected " + BYTES + " bytes, got " + bytes.length);
let scalar = isLE2 ? bytesToNumberLE(bytes) : bytesToNumberBE(bytes);
if (modFromBytes)
scalar = mod(scalar, ORDER);
if (!skipValidation) {
if (!this.isValid(scalar))
throw new Error("invalid field element: outside of range 0..ORDER");
}
return scalar;
}
// TODO: we don't need it here, move out to separate fn
invertBatch(lst) {
return FpInvertBatch(this, lst, true);
}
// We can't move this out because Fp6, Fp12 implement it
// and it's unclear what to return in there.
cmov(a, b, condition) {
abool2(condition, "condition");
return condition ? b : a;
}
};
function Field(ORDER, opts = {}) {
Object.freeze(_Field.prototype);
return new _Field(ORDER, opts);
}
function getFieldBytesLength(fieldOrder) {
if (typeof fieldOrder !== "bigint")
throw new Error("field order must be bigint");
if (fieldOrder <= _1n3)
throw new Error("field order must be greater than 1");
const bitLength = bitLen(fieldOrder - _1n3);
return Math.ceil(bitLength / 8);
}
function getMinHashLength(fieldOrder) {
const length = getFieldBytesLength(fieldOrder);
return length + Math.ceil(length / 2);
}
function mapHashToField(key, fieldOrder, isLE2 = false) {
abytes2(key);
const len = key.length;
const fieldLen = getFieldBytesLength(fieldOrder);
const minLen = Math.max(getMinHashLength(fieldOrder), 16);
if (len < minLen || len > 1024)
throw new Error("expected " + minLen + "-1024 bytes of input, got " + len);
const num = isLE2 ? bytesToNumberLE(key) : bytesToNumberBE(key);
const reduced = mod(num, fieldOrder - _1n3) + _1n3;
return isLE2 ? numberToBytesLE(reduced, fieldLen) : numberToBytesBE(reduced, fieldLen);
}
// tools/reference-apps/light-service/node_modules/@noble/curves/abstract/curve.js
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
var _0n4 = /* @__PURE__ */ BigInt(0);
var _1n4 = /* @__PURE__ */ BigInt(1);
var _4n2 = /* @__PURE__ */ BigInt(4);
var BLIND_BYTES = 16;
var BLIND_BITS = 128;
var FW_WINDOW = 5;
var TABLE_BYTES_MAX = /* @__PURE__ */ (() => 2 ** 31)();
function validatePointCons(Point) {
const pc = Point;
if (typeof pc !== "function")
throw new TypeError('"Point" expected constructor, got type=' + typeof Point);
afunction(pc.fromAffine, "Point.fromAffine");
afunction(pc.fromBytes, "Point.fromBytes");
afunction(pc.fromHex, "Point.fromHex");
aobject2(pc.BASE, "Point.BASE");
aobject2(pc.ZERO, "Point.ZERO");
validateField(pc.Fp);
validateField(pc.Fn);
}
function normalizeZ(c, points) {
validatePointCons(c);
validateMSMPoints(points, c);
const invertedZs = FpInvertBatch(c.Fp, points.map((p) => p.Z));
return points.map((p, i) => c.fromAffine(p.toAffine(invertedZs[i])));
}
function validateW(W, bits, min = 1) {
if (!Number.isSafeInteger(W) || W < min || W > bits)
throw new Error("invalid window size, expected [" + min + ".." + bits + "], got W=" + W);
}
function validateTableBytes(numPoints, fpBytes) {
const bytes = numPoints * (4 * fpBytes + 128);
if (bytes > TABLE_BYTES_MAX)
throw new Error("invalid window size: table would need ~" + Math.ceil(bytes / 2 ** 20) + " MiB, max " + TABLE_BYTES_MAX / 2 ** 20 + " MiB");
}
function probeRandomBytes(randomBytes3, length) {
if (randomBytes3 === void 0)
return void 0;
afunction(randomBytes3, "randomBytes");
try {
const probe = randomBytes3(length);
if (!isBytes2(probe) || probe.length !== length)
return void 0;
} catch {
return void 0;
}
return randomBytes3;
}
function validateMSMPoints(points, c) {
aarray(points, "points");
points.forEach((p, i) => {
if (!(p instanceof c))
throw new Error("invalid point at index " + i);
});
}
function validateMSMScalars(scalars, field, maxScalar) {
if (!Array.isArray(scalars))
throw new Error("array of scalars expected");
scalars.forEach((s, i) => {
const ok = maxScalar === void 0 ? field.isValid(s) : isPosBig(s) && s < maxScalar;
if (!ok)
throw new Error("invalid scalar at index " + i);
});
}
var pointWindowSizes = /* @__PURE__ */ new WeakMap();
function getWindowSize(P) {
return pointWindowSizes.get(P) || 1;
}
function oddMultiples(p, size) {
const dbl = p.double();
const t2 = [p];
for (let j = 1; j < size; j++)
t2.push(t2[j - 1].add(dbl));
return t2;
}
function wnafDigits(n, W) {
const size = 2 ** W;
const half = size / 2;
const mask = BigInt(size - 1);
const d = [];
while (n > _0n4) {
let w = 0;
if (n & _1n4) {
w = Number(n & mask);
if (w >= half)
w -= size;
n -= BigInt(w);
}
d.push(w);
n >>= _1n4;
}
return d;
}
function signedWindowDigits(n, W, windows) {
const size = 2 ** W;
const half = size / 2;
const mask = BigInt(size - 1);
const shiftBy = BigInt(W);
const d = [];
for (let w = 0; w < windows; w++) {
let v = Number(n & mask);
n >>= shiftBy;
if (v > half) {
v -= size;
n += _1n4;
}
d.push(v);
}
if (n !== _0n4)
throw new Error("invalid wnaf");
return d;
}
function wnafWalk(zero, tables, digits) {
let max = 0;
for (const d of digits)
max = Math.max(max, d.length);
let acc = zero;
for (let bit = max - 1; bit >= 0; bit--) {
if (bit !== max - 1)
acc = acc.double();
for (let i = 0; i < digits.length; i++) {
const w = digits[i][bit];
if (w) {
const item = tables[i][Math.abs(w) - 1 >> 1];
acc = acc.add(w < 0 ? item.negate() : item);
}
}
}
return acc;
}
var ScalarMultiplier = class {
Point;
BASE;
ZERO;
randomBytes;
wnafPrecomputes = /* @__PURE__ */ new WeakMap();
baseCanBeBlinded;
bits;
// Parametrized with a given Point class (not individual point)
constructor(Point, randomBytes3) {
validatePointCons(Point);
this.randomBytes = probeRandomBytes(randomBytes3, BLIND_BYTES);
this.Point = Point;
this.BASE = Point.BASE;
this.ZERO = Point.ZERO;
this.bits = Point.Fn.BITS;
}
/**
* Creates a signed fixed-window wNAF precomputation table: for every window w, the
* multiples `[1..2^(W−1)]⋅2^(w⋅W)⋅P`, flattened. All doublings are baked into the table,
* so cached multiplication is additions-only. `windows = ceil(bits/W) + 1`: the extra
* window absorbs the final carry of signed-digit recoding.
* For a 256-bit curve and W=6, the table is 44⋅32 = 1408 points.
* @param point - Point instance
* @param W - window size
* @param bits - scalar bitlength the table must cover
*/
buildWnafTable(point, W, bits) {
const windows = Math.ceil(bits / W) + 1;
const half = 2 ** (W - 1);
const comp = [];
let base = point;
for (let w = 0; w < windows; w++) {
let acc = base;
for (let i = 0; i < half; i++) {
comp.push(acc);
acc = acc.add(base);
}
base = comp[comp.length - 1].double();
}
return { W, bits, windows, comp };
}
/**
* Implements ec multiplication using precomputed signed fixed-window wNAF tables.
* Constant-time: fixed window count with one table addition per window — zero digits feed
* the fake accumulator — and no doublings; the lookup scans the whole window slice.
* Scalar bounds are validated by the public entry points ({@link ScalarMultiplier.mulCT},
* {@link ScalarMultiplier.mulCTBlinded}, {@link ScalarMultiplier.mulUnsafe});
* signedWindowDigits throws if `n` exceeds the table.
* @returns real and fake (for const-time) points
*/
wnafCachedCT(precomputes, n) {
const { W, windows, comp } = precomputes;
const half = 2 ** (W - 1);
const digits = signedWindowDigits(n, W, windows);
let p = this.ZERO;
let f = this.BASE;
for (let w = 0; w < windows; w++) {
const digit = digits[w];
const start = w * half;
const idx = Math.abs(digit) - 1;
let sel = comp[start];
for (let i = 1; i < half; i++)
sel = i === idx ? comp[start + i] : sel;
const neg = sel.negate();
if (digit === 0)
f = f.add(comp[start]);
else
p = p.add(digit < 0 ? neg : sel);
}
return { p, f };
}
// Cache key is point identity plus (W, bits); at most two entries exist per point (public-width
// `Fn.BITS` and blinded `Fn.BITS + BLIND_BITS`). Callers must not reuse the same point with
// incompatible `transform(...)` layouts and expect a separate cache entry.
getWnafPrecomputes(W, point, bits, transform) {
let entries = this.wnafPrecomputes.get(point);
let comp = entries?.find((entry) => entry.W === W && entry.bits === bits);
if (!comp) {
comp = this.buildWnafTable(point, W, bits);
if (typeof transform === "function")
comp = { ...comp, comp: transform(comp.comp) };
if (!entries) {
entries = [];
this.wnafPrecomputes.set(point, entries);
}
entries.push(comp);
}
return comp;
}
assertPoint(point) {
if (!(point instanceof this.Point))
throw new TypeError('"point" expected Point instance, got type=' + typeof point);
}
// Shared prologue of the constant-time entry points. Rejects scalar 0: in key/signature-style
// callers a zero scalar means broken upstream plumbing, and concrete Points already reject it.
// Uses inRange instead of Fn.isValidNot0: validateField() only certifies the arithmetic subset.
validateMulInput(point, scalar) {
this.assertPoint(point);
if (!inRange(scalar, _1n4, this.Point.Fn.ORDER))
throw new Error("invalid scalar");
}
// Constant-time dispatch shared by mulCT / mulCTBlinded. Un-precomputed points (W===1, e.g.
// ECDH peer keys) skip building a throwaway cached table in favor of a small fixed-window
// multiply. `n` must be < 2^bits.
runCT(point, n, bits, transform) {
const W = getWindowSize(point);
if (W === 1)
return this.fixedWindowCT(point, n, bits);
return this.wnafCachedCT(this.getWnafPrecomputes(W, point, bits, transform), n);
}
mulCT(point, scalar, transform) {
this.validateMulInput(point, scalar);
return this.runCT(point, scalar, this.bits, transform);
}
mulCTBlinded(point, scalar, transform) {
this.validateMulInput(point, scalar);
if (this.randomBytes === void 0)
throw new Error("randomBytes is required for scalar blinding");
const bits = this.Point.Fn.BITS + BLIND_BITS;
const blind = this.randomBytes(BLIND_BYTES);
if (!isBytes2(blind) || blind.length !== BLIND_BYTES)
throw new Error("randomBytes returned invalid byte array");
blind[0] = blind[0] & 63 | 128;
const n = scalar + bytesToNumberBE(blind) * this.Point.Fn.ORDER;
return this.runCT(point, n, bits, transform);
}
/**
* Constant-time multiplication `n*point` for an un-precomputed point, via a small fixed window.
* A cached wNAF table only pays off when reused; a flat 2^FW_WINDOW table (`size-1` adds) is
* far cheaper to build for a single use. The point-operation sequence is independent of `n`:
* build the table, then per window exactly FW_WINDOW doublings, a data-oblivious scan over
* every table entry, and one addition (adds the identity when the window digit is 0 — never
* skipped).
*
* `n` must be `< 2^bits`. Assumes complete addition (adding the identity costs the same as any
* add), which holds for the Weierstrass/Edwards point types used here. The table is left in
* projective form (no normalizeZ): normalizing this small a table costs more than the
* mixed-add savings it would buy for a single multiply.
* @returns real point `p`; `f` duplicates it only to match {@link wnafCachedCT}'s return shape
* (this path needs no fake accumulator — its op-count is already scalar-independent).
*/
fixedWindowCT(point, n, bits) {
const W = FW_WINDOW;
const size = 1 << W;
const mask = bitMask(W);
const table = new Array(size);
table[0] = this.ZERO;
for (let i = 1; i < size; i++)
table[i] = table[i - 1].add(point);
const windows = Math.ceil(bits / W);
let acc = this.ZERO;
for (let window = windows - 1; window >= 0; window--) {
if (window !== windows - 1)
for (let d = 0; d < W; d++)
acc = acc.double();
const digit = Number(n >> BigInt(window * W) & mask);
let sel = table[0];
for (let i = 1; i < size; i++)
sel = i === digit ? table[i] : sel;
acc = acc.add(sel);
}
return { p: acc, f: acc };
}
shouldBlind(point, cofactor) {
if (this.randomBytes === void 0)
return false;
if (cofactor === _1n4)
return true;
if (point !== this.BASE)
return false;
if (this.baseCanBeBlinded === void 0)
this.baseCanBeBlinded = this.mulUnsafe(this.BASE, this.Point.Fn.ORDER).is0();
return this.baseCanBeBlinded;
}
mulSecret(point, scalar, cofactor, transform) {
return this.shouldBlind(point, cofactor) ? this.mulCTBlinded(point, scalar, transform) : this.mulCT(point, scalar, transform);
}
mulUnsafe(point, scalar, transform) {
this.assertPoint(point);
if (!isPosBig(scalar))
throw new Error("invalid scalar");
const W = getWindowSize(point);
if (W === 1 || scalar >= this.Point.Fn.ORDER)
return mulAddUnsafe(this.Point, [point], [scalar], true);
const precomputes = this.getWnafPrecomputes(W, point, this.bits, transform);
return this.wnafCachedCT(precomputes, scalar).p;
}
// Remembers the window size used for precomputed wNAF multiplication of the given point
// and drops any previously built tables. Usually only the base point is precomputed.
// W=1 resets the point to the un-precomputed (table-less) paths.
// W is additionally capped so tables stay under ~2 GiB ({@link TABLE_BYTES_MAX}).
setWindowSize(point, W) {
this.assertPoint(point);
validateW(W, this.bits);
const windows = Math.ceil((this.bits + BLIND_BITS) / W) + 1;
validateTableBytes(windows * 2 ** (W - 1), this.Point.Fp.BYTES);
pointWindowSizes.set(point, W);
this.wnafPrecomputes.delete(point);
}
// True when a window size is set: tables themselves are built lazily on first multiply.
hasWindowSize(point) {
return getWindowSize(point) !== 1;
}
};
function mulAddUnsafe(c, points, scalars, allowOversized = false) {
validatePointCons(c);
validateMSMPoints(points, c);
abool2(allowOversized, "allowOversized");
validateMSMScalars(scalars, c.Fn, allowOversized ? c.Fn.ORDER ** _4n2 : void 0);
if (points.length !== scalars.length)
throw new Error("arrays of points and scalars must have equal length");
const tables = points.map((p) => oddMultiples(p, 4));
const digits = scalars.map((n) => wnafDigits(n, 4));
return wnafWalk(c.ZERO, tables, digits);
}
function createField(order, field, isLE2) {
if (field) {
if (field.ORDER !== order)
throw new Error("Field.ORDER must match order: Fp == p, Fn == n");
validateField(field);
return field;
} else {
return Field(order, { isLE: isLE2 });
}
}
function createCurveFields(type, CURVE, curveOpts = {}, FpFnLE) {
if (type !== "weierstrass" && type !== "edwards")
throw new Error('expected curve type "weierstrass" or "edwards"');
if (FpFnLE === void 0)
FpFnLE = type === "edwards";
if (!CURVE || typeof CURVE !== "object")
throw new Error(`expected valid ${type} CURVE object`);
validateObject(curveOpts);
for (const p of ["p", "n", "h"]) {
const val = CURVE[p];
if (!(isPosBig(val) && val !== _0n4))
throw new Error(`CURVE.${p} must be positive bigint`);
}
const Fp3 = createField(CURVE.p, curveOpts.Fp, FpFnLE);
const Fn = createField(CURVE.n, curveOpts.Fn, FpFnLE);
const _b = type === "weierstrass" ? "b" : "d";
const params = ["Gx", "Gy", "a", _b];
for (const p of params) {
if (!Fp3.isValid(CURVE[p]))
throw new Error(`CURVE.${p} must be valid field element of CURVE.Fp`);
}
CURVE = Object.freeze(Object.assign({}, CURVE));
return { CURVE, Fp: Fp3, Fn };
}
// tools/reference-apps/light-service/node_modules/@noble/curves/abstract/hash-to-curve.js
var _0n5 = /* @__PURE__ */ BigInt(0);
var _1n5 = /* @__PURE__ */ BigInt(1);
var _2n3 = /* @__PURE__ */ BigInt(2);
var _3n2 = /* @__PURE__ */ BigInt(3);
var _4n3 = /* @__PURE__ */ BigInt(4);
var os2ip = bytesToNumberBE;
function i2osp(value, length) {
asafenumber(value);
asafenumber(length);
if (length < 0 || length > 4)
throw new Error("invalid I2OSP length: " + length);
if (value < 0 || value > 2 ** (8 * length) - 1)
throw new Error("invalid I2OSP input: " + value);
const res = Array.from({ length }).fill(0);
for (let i = length - 1; i >= 0; i--) {
res[i] = value & 255;
value >>>= 8;
}
return new Uint8Array(res);
}
function strxor(a, b) {
const arr = new Uint8Array(a.length);
for (let i = 0; i < a.length; i++) {
arr[i] = a[i] ^ b[i];
}
return arr;
}
function normDST(DST) {
if (!isBytes2(DST) && typeof DST !== "string")
throw new Error("DST must be Uint8Array or ascii string");
const dst = typeof DST === "string" ? asciiToBytes(DST) : DST;
if (dst.length === 0)
throw new Error("DST must be non-empty");
return dst;
}
function expand_message_xmd(msg, DST, lenInBytes, H) {
abytes2(msg);
asafenumber(lenInBytes);
if (typeof H !== "function")
throw new Error("expand_message_xmd: expected hash function");
asafenumber(H.outputLen, "hash.outputLen");
asafenumber(H.blockLen, "hash.blockLen");
DST = normDST(DST);
if (DST.length > 255)
DST = H(concatBytes2(asciiToBytes("H2C-OVERSIZE-DST-"), DST));
const { outputLen: b_in_bytes, blockLen: r_in_bytes } = H;
const ell = Math.ceil(lenInBytes / b_in_bytes);
if (lenInBytes > 65535 || ell > 255)
throw new Error("expand_message_xmd: invalid lenInBytes");
const DST_prime = concatBytes2(DST, i2osp(DST.length, 1));
const Z_pad = new Uint8Array(r_in_bytes);
const l_i_b_str = i2osp(lenInBytes, 2);
const b = new Array(ell);
const b_0 = H(concatBytes2(Z_pad, msg, l_i_b_str, i2osp(0, 1), DST_prime));
b[0] = H(concatBytes2(b_0, i2osp(1, 1), DST_prime));
for (let i = 1; i < ell; i++) {
const args2 = [strxor(b_0, b[i - 1]), i2osp(i + 1, 1), DST_prime];
b[i] = H(concatBytes2(...args2));
}
const pseudo_random_bytes = concatBytes2(...b);
return pseudo_random_bytes.slice(0, lenInBytes);
}
function expand_message_xof(msg, DST, lenInBytes, k, H) {
abytes2(msg);
asafenumber(lenInBytes);
asafenumber(k, "k");
if (k < 0)
throw new Error("expand_message_xof: invalid k");
if (typeof H !== "function")
throw new Error("expand_message_xof: expected XOF function");
if (typeof H.create !== "function")
throw new Error("expand_message_xof: expected XOF create");
DST = normDST(DST);
if (lenInBytes < 0 || lenInBytes > 65535)
throw new Error("expand_message_xof: invalid lenInBytes");
if (DST.length > 255) {
const dkLen = Math.ceil(2 * k / 8);
DST = H.create({ dkLen }).update(asciiToBytes("H2C-OVERSIZE-DST-")).update(DST).digest();
}
if (DST.length > 255)
throw new Error("expand_message_xof: invalid DST");
return H.create({ dkLen: lenInBytes }).update(msg).update(i2osp(lenInBytes, 2)).update(DST).update(i2osp(DST.length, 1)).digest();
}
function hash_to_field(msg, count, options) {
validateObject(options, {
p: "bigint",
m: "number",
k: "number",
hash: "function"
});
const { p, k, m, hash, expand, DST } = options;
asafenumber(hash.outputLen, "valid hash");
abytes2(msg);
asafenumber(count);
asafenumber(m, "m");
asafenumber(k, "k");
if (p <= BigInt(1))
throw new Error("hash_to_field: expected valid field characteristic");
if (count < 1)
throw new Error("hash_to_field: expected count >= 1");
if (m < 1)
throw new Error("hash_to_field: expected m >= 1");
if (k < 0)
throw new Error("hash_to_field: invalid k");
const log2p = p.toString(2).length;
const L = Math.ceil((log2p + k) / 8);
const len_in_bytes = count * m * L;
let prb;
if (expand === "xmd") {
prb = expand_message_xmd(msg, DST, len_in_bytes, hash);
} else if (expand === "xof") {
prb = expand_message_xof(msg, DST, len_in_bytes, k, hash);
} else if (expand === "_internal_pass") {
prb = msg;
} else {
throw new Error('expand must be "xmd" or "xof"');
}
const u = new Array(count);
for (let i = 0; i < count; i++) {
const e = new Array(m);
for (let j = 0; j < m; j++) {
const elm_offset = L * (j + i * m);
const tv = prb.subarray(elm_offset, elm_offset + L);
e[j] = mod(os2ip(tv), p);
}
u[i] = e;
}
return u;
}
function isogenyMap(field, map) {
validateField(field);
aarray(map, "map");
const coeff = map.map((i, row) => {
aarray(i, "map[" + row + "]");
if (i.length < 1)
throw new Error("isogenyMap: expected non-empty coefficients");
return Array.from(i).reverse();
});
return (x, y) => {
const [xn, xd, yn, yd] = coeff.map((val) => val.reduce((acc, i) => field.add(field.mul(acc, x), i)));
const isZero = field.is0(xd) || field.is0(yd);
const [xd_inv, yd_inv] = FpInvertBatch(field, [xd, yd], true);
x = field.mul(xn, xd_inv);
y = field.mul(y, field.mul(yn, yd_inv));
return isZero ? { x: field.ZERO, y: field.ZERO } : { x, y };
};
}
var _DST_scalar = "HashToScalar-";
function createHasher2(Point, mapToCurve, defaults) {
if (typeof mapToCurve !== "function")
throw new Error("mapToCurve() must be defined");
validateObject(defaults);
const snapshot = (src) => Object.freeze({
...src,
DST: isBytes2(src.DST) ? copyBytes2(src.DST) : src.DST,
...src.encodeDST === void 0 ? {} : { encodeDST: isBytes2(src.encodeDST) ? copyBytes2(src.encodeDST) : src.encodeDST }
});
const safeDefaults = snapshot(defaults);
const dstOverride = (options) => options && options.DST !== void 0 ? { DST: options.DST } : void 0;
function map(num) {
return Point.fromAffine(mapToCurve(num));
}
function clear(initial) {
const P = initial.clearCofactor();
if (P.equals(Point.ZERO))
return Point.ZERO;
P.assertValidity();
return P;
}
return Object.freeze({
get defaults() {
return snapshot(safeDefaults);
},
Point,
hashToCurve(msg, options) {
const opts = Object.assign({}, safeDefaults, dstOverride(options));
const u = hash_to_field(msg, 2, opts);
const u0 = map(u[0]);
const u1 = map(u[1]);
return clear(u0.add(u1));
},
encodeToCurve(msg, options) {
const optsDst = safeDefaults.encodeDST === void 0 ? {} : { DST: safeDefaults.encodeDST };
const opts = Object.assign({}, safeDefaults, optsDst, dstOverride(options));
const u = hash_to_field(msg, 1, opts);
const u0 = map(u[0]);
return clear(u0);
},
/** See {@link H2CHasher} */
mapToCurve(scalars) {
if (safeDefaults.m === 1) {
if (typeof scalars !== "bigint")
throw new Error("expected bigint (m=1)");
return clear(map([scalars]));
}
if (!Array.isArray(scalars))
throw new Error("expected array of bigints");
if (scalars.length !== safeDefaults.m)
throw new Error(`expected array of ${safeDefaults.m} bigints`);
for (const i of scalars)
if (typeof i !== "bigint")
throw new Error("expected array of bigints");
return clear(map(scalars));
},
// hash_to_scalar can produce 0: https://www.rfc-editor.org/errata/eid8393
// RFC 9380, draft-irtf-cfrg-bbs-signatures-08. Default scalar DST is the shared generic
// `HashToScalar-` prefix above unless the caller overrides it per invocation.
hashToScalar(msg, options) {
const N = Point.Fn.ORDER;
const opts = Object.assign({}, safeDefaults, { DST: _DST_scalar }, dstOverride(options), {
p: N,
m: 1
});
return hash_to_field(msg, 1, opts)[0][0];
}
});
}
function SWUFpSqrtRatio(Fp3, Z) {
const F = validateField(Fp3);
const q = F.ORDER;
let l = _0n5;
for (let o = q - _1n5; o % _2n3 === _0n5; o /= _2n3)
l += _1n5;
const c1 = l;
const _2n_pow_c1_1 = _2n3 << c1 - _1n5 - _1n5;
const _2n_pow_c1 = _2n_pow_c1_1 * _2n3;
const c2 = (q - _1n5) / _2n_pow_c1;
const c3 = (c2 - _1n5) / _2n3;
const c4 = _2n_pow_c1 - _1n5;
const c5 = _2n_pow_c1_1;
const c6 = F.pow(Z, c2);
const c7 = F.pow(Z, (c2 + _1n5) / _2n3);
let sqrtRatio = (u, v) => {
let tv1 = c6;
let tv2 = F.pow(v, c4);
let tv3 = F.sqr(tv2);
tv3 = F.mul(tv3, v);
let tv5 = F.mul(u, tv3);
tv5 = F.pow(tv5, c3);
tv5 = F.mul(tv5, tv2);
tv2 = F.mul(tv5, v);
tv3 = F.mul(tv5, u);
let tv4 = F.mul(tv3, tv2);
tv5 = F.pow(tv4, c5);
let isQR = F.eql(tv5, F.ONE);
tv2 = F.mul(tv3, c7);
tv5 = F.mul(tv4, tv1);
tv3 = F.cmov(tv2, tv3, isQR);
tv4 = F.cmov(tv5, tv4, isQR);
for (let i = c1; i > _1n5; i--) {
let tv52 = i - _2n3;
tv52 = _2n3 << tv52 - _1n5;
let tvv5 = F.pow(tv4, tv52);
const e1 = F.eql(tvv5, F.ONE);
tv2 = F.mul(tv3, tv1);
tv1 = F.mul(tv1, tv1);
tvv5 = F.mul(tv4, tv1);
tv3 = F.cmov(tv2, tv3, e1);
tv4 = F.cmov(tvv5, tv4, e1);
}
return { isValid: !F.is0(v) && (isQR || F.is0(u)), value: tv3 };
};
if (F.ORDER % _4n3 === _3n2) {
const c12 = (F.ORDER - _3n2) / _4n3;
const c22 = F.sqrt(F.neg(Z));
sqrtRatio = (u, v) => {
let tv1 = F.sqr(v);
const tv2 = F.mul(u, v);
tv1 = F.mul(tv1, tv2);
let y1 = F.pow(tv1, c12);
y1 = F.mul(y1, tv2);
const y2 = F.mul(y1, c22);
const tv3 = F.mul(F.sqr(y1), v);
const isQR = F.eql(tv3, u);
let y = F.cmov(y2, y1, isQR);
return { isValid: !F.is0(v) && isQR, value: y };
};
}
return sqrtRatio;
}
function mapToCurveSimpleSWU(Fp3, opts) {
const F = validateField(Fp3);
validateObject(opts, {}, {}, "opts");
const { A, B: B2, Z } = opts;
if (!F.isValidNot0(A) || !F.isValidNot0(B2) || !F.isValid(Z))
throw new Error("mapToCurveSimpleSWU: invalid opts");
if (F.eql(Z, F.neg(F.ONE)) || FpIsSquare(F, Z))
throw new Error("mapToCurveSimpleSWU: invalid opts");
const x = F.mul(B2, F.inv(F.mul(Z, A)));
const gx = F.add(F.add(F.mul(F.sqr(x), x), F.mul(A, x)), B2);
if (!FpIsSquare(F, gx))
throw new Error("mapToCurveSimpleSWU: invalid opts");
const sqrtRatio = SWUFpSqrtRatio(F, Z);
if (!F.isOdd)
throw new Error("Field does not have .isOdd()");
return (u) => {
let tv1, tv2, tv3, tv4, tv5, tv6, x2, y;
tv1 = F.sqr(u);
tv1 = F.mul(tv1, Z);
tv2 = F.sqr(tv1);
tv2 = F.add(tv2, tv1);
tv3 = F.add(tv2, F.ONE);
tv3 = F.mul(tv3, B2);
tv4 = F.cmov(Z, F.neg(tv2), !F.eql(tv2, F.ZERO));
tv4 = F.mul(tv4, A);
tv2 = F.sqr(tv3);
tv6 = F.sqr(tv4);
tv5 = F.mul(tv6, A);
tv2 = F.add(tv2, tv5);
tv2 = F.mul(tv2, tv3);
tv6 = F.mul(tv6, tv4);
tv5 = F.mul(tv6, B2);
tv2 = F.add(tv2, tv5);
x2 = F.mul(tv1, tv3);
const { isValid, value } = sqrtRatio(tv2, tv6);
y = F.mul(tv1, u);
y = F.mul(y, value);
x2 = F.cmov(x2, tv3, isValid);
y = F.cmov(y, value, isValid);
const e1 = F.isOdd(u) === F.isOdd(y);
y = F.cmov(F.neg(y), y, e1);
const tv4_inv = FpInvertBatch(F, [tv4], true)[0];
x2 = F.mul(x2, tv4_inv);
return { x: x2, y };
};
}
// tools/reference-apps/light-service/node_modules/@noble/curves/abstract/weierstrass.js
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
var divNearest = (num, den) => (num + (num >= 0 ? den : -den) / _2n4) / den;
function _splitEndoScalar(k, basis, n) {
aInRange("scalar", k, _0n6, n);
const [[a1, b1], [a2, b2]] = basis;
const c1 = divNearest(b2 * k, n);
const c2 = divNearest(-b1 * k, n);
let k1 = k - c1 * a1 - c2 * a2;
let k2 = -c1 * b1 - c2 * b2;
const k1neg = k1 < _0n6;
const k2neg = k2 < _0n6;
if (k1neg)
k1 = -k1;
if (k2neg)
k2 = -k2;
const MAX_NUM = bitMask(Math.ceil(bitLen(n) / 2)) + _1n6;
if (k1 < _0n6 || k1 >= MAX_NUM || k2 < _0n6 || k2 >= MAX_NUM) {
throw new Error("splitScalar (endomorphism): failed for k");
}
return { k1neg, k1, k2neg, k2 };
}
var _0n6 = /* @__PURE__ */ BigInt(0);
var _1n6 = /* @__PURE__ */ BigInt(1);
var _2n4 = /* @__PURE__ */ BigInt(2);
var _3n3 = /* @__PURE__ */ BigInt(3);
var _4n4 = /* @__PURE__ */ BigInt(4);
function weierstrass(params, extraOpts = {}) {
const validated = createCurveFields("weierstrass", params, extraOpts);
const Fp3 = validated.Fp;
const Fn = validated.Fn;
let CURVE = validated.CURVE;
const { h: cofactor, n: CURVE_ORDER } = CURVE;
validateObject(extraOpts, {}, {
allowInfinityPoint: "boolean",
clearCofactor: "function",
isTorsionFree: "function",
fromBytes: "function",
toBytes: "function",
endo: "object",
randomBytes: "function"
});
const { endo: endoOpts, allowInfinityPoint, clearCofactor, isTorsionFree, fromBytes, toBytes } = extraOpts;
const randomBytes3 = extraOpts.randomBytes === void 0 ? randomBytes2 : extraOpts.randomBytes;
if (endoOpts) {
if (!Fp3.is0(CURVE.a) || typeof endoOpts.beta !== "bigint" || !Array.isArray(endoOpts.basises)) {
throw new Error('invalid endo: expected "beta": bigint and "basises": array');
}
}
const endo = endoOpts ? {
beta: endoOpts.beta,
basises: endoOpts.basises.map((basis) => [...basis])
} : void 0;
const lengths = getWLengths(Fp3, Fn);
function assertCompressionIsSupported() {
if (!Fp3.isOdd)
throw new Error("compression is not supported: Field does not have .isOdd()");
}
function pointToBytes(_c, point, isCompressed) {
if (point.is0()) {
if (!allowInfinityPoint)
throw new Error("bad point: ZERO");
return Uint8Array.of(0);
}
const { x, y } = point.toAffine();
const bx = Fp3.toBytes(x);
abool2(isCompressed, "isCompressed");
if (isCompressed) {
assertCompressionIsSupported();
const hasEvenY = !Fp3.isOdd(y);
return concatBytes2(pprefix(hasEvenY), bx);
} else {
return concatBytes2(Uint8Array.of(4), bx, Fp3.toBytes(y));
}
}
function pointFromBytes(bytes) {
abytes2(bytes, void 0, "Point");
const { publicKey: comp, publicKeyUncompressed: uncomp } = lengths;
const length = bytes.length;
const head = bytes[0];
const tail = bytes.subarray(1);
if (allowInfinityPoint && length === 1 && head === 0)
return { x: Fp3.ZERO, y: Fp3.ZERO };
if (length === comp && (head === 2 || head === 3)) {
const x = Fp3.fromBytes(tail);
if (!Fp3.isValid(x))
throw new Error("bad point: is not on curve, wrong x");
const y2 = weierstrassEquation(x);
let y;
try {
y = Fp3.sqrt(y2);
} catch (sqrtError) {
const err = sqrtError instanceof Error ? ": " + sqrtError.message : "";
throw new Error("bad point: is not on curve, sqrt error" + err);
}
assertCompressionIsSupported();
const evenY = Fp3.isOdd(y);
const evenH = (head & 1) === 1;
if (evenH !== evenY)
y = Fp3.neg(y);
return { x, y };
} else if (length === uncomp && head === 4) {
const L = Fp3.BYTES;
const x = Fp3.fromBytes(tail.subarray(0, L));
const y = Fp3.fromBytes(tail.subarray(L, L * 2));
if (!isValidXY(x, y))
throw new Error("bad point: is not on curve");
return { x, y };
} else {
throw new Error(`bad point: got length ${length}, expected compressed=${comp} or uncompressed=${uncomp}`);
}
}
const encodePoint = toBytes === void 0 ? pointToBytes : toBytes;
const decodePoint = fromBytes === void 0 ? pointFromBytes : fromBytes;
const b3 = Fp3.mul(CURVE.b, _3n3);
const mulA = Fp3.is0(CURVE.a) ? (_) => Fp3.ZERO : (x) => Fp3.mul(CURVE.a, x);
function weierstrassEquation(x) {
const x2 = Fp3.sqr(x);
const x3 = Fp3.mul(x2, x);
return Fp3.add(Fp3.add(x3, Fp3.mul(x, CURVE.a)), CURVE.b);
}
function isValidXY(x, y) {
const left = Fp3.sqr(y);
const right = weierstrassEquation(x);
return Fp3.eql(left, right);
}
if (!isValidXY(CURVE.Gx, CURVE.Gy))
throw new Error("bad curve params: generator point");
const _4a3 = Fp3.mul(Fp3.pow(CURVE.a, _3n3), _4n4);
const _27b2 = Fp3.mul(Fp3.sqr(CURVE.b), BigInt(27));
if (Fp3.is0(Fp3.add(_4a3, _27b2)))
throw new Error("bad curve params: a or b");
function acoord(title, n, banZero = false) {
if (!Fp3.isValid(n) || banZero && Fp3.is0(n))
throw new Error(`bad point coordinate ${title}`);
return typeof n === "object" && n !== null ? Fp3.create(n) : n;
}
function aprjpoint(other) {
if (!(other instanceof Point))
throw new Error("Weierstrass Point expected");
}
function splitEndoScalarN(k) {
if (!endo || !endo.basises)
throw new Error("no endo");
return _splitEndoScalar(k, endo.basises, Fn.ORDER);
}
function pushWnafPair(points, scalars, p, k) {
if (!Fn.isValid(k))
throw new RangeError("invalid scalar: out of range");
if (endo) {
const { k1neg, k1, k2neg, k2 } = splitEndoScalarN(k);
const psi = new Point(Fp3.mul(p.X, endo.beta), p.Y, p.Z);
points.push(k1neg ? p.negate() : p, k2neg ? psi.negate() : psi);
scalars.push(k1, k2);
} else {
points.push(p);
scalars.push(k);
}
}
const validityCache = /* @__PURE__ */ new WeakSet();
class Point {
static BASE = new Point(CURVE.Gx, CURVE.Gy, Fp3.ONE);
static ZERO = new Point(Fp3.ZERO, Fp3.ONE, Fp3.ZERO);
static Fp = Fp3;
static Fn = Fn;
X;
Y;
Z;
/** Does NOT validate if the point is valid. Use `.assertValidity()`. */
constructor(X, Y, Z) {
this.X = acoord("x", X);
this.Y = acoord("y", Y, true);
this.Z = acoord("z", Z);
Object.freeze(this);
}
static CURVE() {
return CURVE;
}
/** Does NOT validate if the point is valid. Use `.assertValidity()`. */
static fromAffine(p) {
const { x, y } = p || {};
if (!p || !Fp3.isValid(x) || !Fp3.isValid(y))
throw new Error("invalid affine point");
if (p instanceof Point)
throw new Error("projective point not allowed");
if (Fp3.is0(x) && Fp3.is0(y))
return Point.ZERO;
return new Point(x, y, Fp3.ONE);
}
static fromBytes(bytes) {
const P = Point.fromAffine(decodePoint(abytes2(bytes, void 0, "point")));
P.assertValidity();
return P;
}
static fromHex(hex) {
return Point.fromBytes(hexToBytes2(hex));
}
get x() {
return this.toAffine().x;
}
get y() {
return this.toAffine().y;
}
/**
* @param isLazy - true will defer table computation until the first multiplication
*/
precompute(windowSize = 6, isLazy = true) {
wnaf.setWindowSize(this, windowSize);
if (!isLazy)
this.multiply(_3n3);
return this;
}
// TODO: return `this`
/** A point on curve is valid if it conforms to equation. */
assertValidity() {
const p = this;
if (p.is0()) {
if (allowInfinityPoint && Fp3.is0(p.X) && Fp3.eql(p.Y, Fp3.ONE) && Fp3.is0(p.Z))
return;
throw new Error("bad point: ZERO");
}
if (validityCache.has(p))
return;
const { x, y } = p.toAffine();
if (!Fp3.isValid(x) || !Fp3.isValid(y))
throw new Error("bad point: x or y not field elements");
if (!isValidXY(x, y))
throw new Error("bad point: equation left != right");
if (!p.isTorsionFree())
throw new Error("bad point: not in prime-order subgroup");
validityCache.add(p);
}
hasEvenY() {
const { y } = this.toAffine();
if (!Fp3.isOdd)
throw new Error("Field doesn't support isOdd");
return !Fp3.isOdd(y);
}
/** Compare one point to another. */
equals(other) {
aprjpoint(other);
const { X: X1, Y: Y1, Z: Z1 } = this;
const { X: X2, Y: Y2, Z: Z2 } = other;
const U1 = Fp3.eql(Fp3.mul(X1, Z2), Fp3.mul(X2, Z1));
const U2 = Fp3.eql(Fp3.mul(Y1, Z2), Fp3.mul(Y2, Z1));
return U1 && U2;
}
/** Flips point to one corresponding to (x, -y) in Affine coordinates. */
negate() {
return new Point(this.X, Fp3.neg(this.Y), this.Z);
}
// Renes-Costello-Batina exception-free doubling formula.
// There is 30% faster Jacobian formula, but it is not complete.
// https://eprint.iacr.org/2015/1060, algorithm 3
// Cost: 8M + 3S + 3*a + 2*b3 + 15add.
double() {
const { X: X1, Y: Y1, Z: Z1 } = this;
let X3 = Fp3.ZERO, Y3 = Fp3.ZERO, Z3 = Fp3.ZERO;
let t0 = Fp3.mul(X1, X1);
let t1 = Fp3.mul(Y1, Y1);
let t2 = Fp3.mul(Z1, Z1);
let t3 = Fp3.mul(X1, Y1);
t3 = Fp3.add(t3, t3);
Z3 = Fp3.mul(X1, Z1);
Z3 = Fp3.add(Z3, Z3);
X3 = mulA(Z3);
Y3 = Fp3.mul(b3, t2);
Y3 = Fp3.add(X3, Y3);
X3 = Fp3.sub(t1, Y3);
Y3 = Fp3.add(t1, Y3);
Y3 = Fp3.mul(X3, Y3);
X3 = Fp3.mul(t3, X3);
Z3 = Fp3.mul(b3, Z3);
t2 = mulA(t2);
t3 = Fp3.sub(t0, t2);
t3 = mulA(t3);
t3 = Fp3.add(t3, Z3);
Z3 = Fp3.add(t0, t0);
t0 = Fp3.add(Z3, t0);
t0 = Fp3.add(t0, t2);
t0 = Fp3.mul(t0, t3);
Y3 = Fp3.add(Y3, t0);
t2 = Fp3.mul(Y1, Z1);
t2 = Fp3.add(t2, t2);
t0 = Fp3.mul(t2, t3);
X3 = Fp3.sub(X3, t0);
Z3 = Fp3.mul(t2, t1);
Z3 = Fp3.add(Z3, Z3);
Z3 = Fp3.add(Z3, Z3);
return new Point(X3, Y3, Z3);
}
// Renes-Costello-Batina exception-free addition formula.
// There is 30% faster Jacobian formula, but it is not complete.
// https://eprint.iacr.org/2015/1060, algorithm 1
// Cost: 12M + 0S + 3*a + 3*b3 + 23add.
add(other) {
aprjpoint(other);
const { X: X1, Y: Y1, Z: Z1 } = this;
const { X: X2, Y: Y2, Z: Z2 } = other;
let X3 = Fp3.ZERO, Y3 = Fp3.ZERO, Z3 = Fp3.ZERO;
let t0 = Fp3.mul(X1, X2);
let t1 = Fp3.mul(Y1, Y2);
let t2 = Fp3.mul(Z1, Z2);
let t3 = Fp3.add(X1, Y1);
let t4 = Fp3.add(X2, Y2);
t3 = Fp3.mul(t3, t4);
t4 = Fp3.add(t0, t1);
t3 = Fp3.sub(t3, t4);
t4 = Fp3.add(X1, Z1);
let t5 = Fp3.add(X2, Z2);
t4 = Fp3.mul(t4, t5);
t5 = Fp3.add(t0, t2);
t4 = Fp3.sub(t4, t5);
t5 = Fp3.add(Y1, Z1);
X3 = Fp3.add(Y2, Z2);
t5 = Fp3.mul(t5, X3);
X3 = Fp3.add(t1, t2);
t5 = Fp3.sub(t5, X3);
Z3 = mulA(t4);
X3 = Fp3.mul(b3, t2);
Z3 = Fp3.add(X3, Z3);
X3 = Fp3.sub(t1, Z3);
Z3 = Fp3.add(t1, Z3);
Y3 = Fp3.mul(X3, Z3);
t1 = Fp3.add(t0, t0);
t1 = Fp3.add(t1, t0);
t2 = mulA(t2);
t4 = Fp3.mul(b3, t4);
t1 = Fp3.add(t1, t2);
t2 = Fp3.sub(t0, t2);
t2 = mulA(t2);
t4 = Fp3.add(t4, t2);
t0 = Fp3.mul(t1, t4);
Y3 = Fp3.add(Y3, t0);
t0 = Fp3.mul(t5, t4);
X3 = Fp3.mul(t3, X3);
X3 = Fp3.sub(X3, t0);
t0 = Fp3.mul(t3, t1);
Z3 = Fp3.mul(t5, Z3);
Z3 = Fp3.add(Z3, t0);
return new Point(X3, Y3, Z3);
}
subtract(other) {
aprjpoint(other);
return this.add(other.negate());
}
is0() {
return this.equals(Point.ZERO);
}
/**
* Constant time multiplication.
* Uses precomputed tables (signed fixed-window wNAF) when available.
* Uses scalar blinding and avoids endomorphism splitting in the secret-scalar path.
* @param scalar - by which the point would be multiplied
* @returns New point
*/
multiply(scalar) {
if (!Fn.isValidNot0(scalar))
throw new RangeError("invalid scalar: out of range");
const { p, f } = wnaf.mulSecret(this, scalar, cofactor, normalize);
return normalize([p, f])[0];
}
/**
* Non-constant-time multiplication. Uses width-4 wNAF with GLV endomorphism splitting
* when available (two half-width scalars sharing one halved doubling chain).
* It's faster, but should only be used when you don't care about
* an exposed secret key e.g. sig verification, which works over *public* keys.
*/
multiplyUnsafe(scalar) {
const p = this;
const sc = scalar;
if (!Fn.isValid(sc))
throw new RangeError("invalid scalar: out of range");
if (sc === _0n6 || p.is0())
return Point.ZERO;
if (sc === _1n6)
return p;
if (wnaf.hasWindowSize(this))
return wnaf.mulUnsafe(p, sc, normalize);
const points = [];
const scalars = [];
pushWnafPair(points, scalars, p, sc);
return mulAddUnsafe(Point, points, scalars);
}
/**
* Non-constant-time double-scalar multiplication `a⋅this + b⋅other` (Strauss–Shamir).
* Both walks share one doubling chain via {@link mulAddUnsafe}, and GLV endomorphism
* (when available) halves the chain again by splitting each scalar into two half-width
* parts. Used by ECDSA verification and public-key recovery for `R = u1⋅G + u2⋅P`.
* Only for public scalars.
*/
mulAddUnsafe(a, other, b) {
aprjpoint(other);
const points = [];
const scalars = [];
pushWnafPair(points, scalars, this, a);
pushWnafPair(points, scalars, other, b);
return mulAddUnsafe(Point, points, scalars);
}
/**
* Converts Projective point to affine (x, y) coordinates.
* (X, Y, Z) ∋ (x=X/Z, y=Y/Z).
* @param invertedZ - Z^-1 (inverted zero) - optional, precomputation is useful for invertBatch
*/
toAffine(invertedZ) {
const p = this;
let iz = invertedZ;
if (iz != null && !Fp3.isValid(iz))
throw new RangeError('"invertedZ" expected valid field element');
const { X, Y, Z } = p;
if (Fp3.eql(Z, Fp3.ONE))
return { x: X, y: Y };
const is0 = p.is0();
if (iz == null)
iz = is0 ? Fp3.ONE : Fp3.inv(Z);
const x = Fp3.mul(X, iz);
const y = Fp3.mul(Y, iz);
const zz = Fp3.mul(Z, iz);
if (is0)
return { x: Fp3.ZERO, y: Fp3.ZERO };
if (!Fp3.eql(zz, Fp3.ONE))
throw new Error("invZ was invalid");
return { x, y };
}
/**
* Checks whether Point is free of torsion elements (is in prime subgroup).
* Always torsion-free for cofactor=1 curves.
*/
isTorsionFree() {
if (cofactor === _1n6)
return true;
if (isTorsionFree)
return isTorsionFree(Point, this);
return wnaf.mulUnsafe(this, CURVE_ORDER).is0();
}
clearCofactor() {
if (cofactor === _1n6)
return this;
if (clearCofactor)
return clearCofactor(Point, this);
return this.multiplyUnsafe(cofactor);
}
isSmallOrder() {
if (cofactor === _1n6)
return this.is0();
return this.clearCofactor().is0();
}
toBytes(isCompressed = true) {
abool2(isCompressed, "isCompressed");
this.assertValidity();
return encodePoint(Point, this, isCompressed);
}
toHex(isCompressed = true) {
return bytesToHex2(this.toBytes(isCompressed));
}
toString() {
return `<Point ${this.is0() ? "ZERO" : this.toHex()}>`;
}
}
const normalize = (points) => normalizeZ(Point, points);
const wnaf = new ScalarMultiplier(Point, randomBytes3);
if (wnaf.bits >= 6)
Point.BASE.precompute(6);
Object.freeze(Point.prototype);
Object.freeze(Point);
return Point;
}
function pprefix(hasEvenY) {
return Uint8Array.of(hasEvenY ? 2 : 3);
}
function getWLengths(Fp3, Fn) {
return {
secretKey: Fn.BYTES,
publicKey: 1 + Fp3.BYTES,
publicKeyUncompressed: 1 + 2 * Fp3.BYTES,
publicKeyHasPrefix: true,
// Raw compact `(r || s)` signature width; DER and recovered signatures use
// different lengths outside this helper.
signature: 2 * Fn.BYTES
};
}
// tools/reference-apps/light-service/node_modules/@noble/curves/abstract/bls.js
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
var _0n7 = BigInt(0);
var _1n7 = BigInt(1);
var _2n5 = BigInt(2);
var _3n4 = BigInt(3);
function NAfDecomposition(a) {
const res = [];
for (; a > _1n7; a >>= _1n7) {
if ((a & _1n7) === _0n7)
res.unshift(0);
else if ((a & _3n4) === _3n4) {
res.unshift(-1);
a += _1n7;
} else
res.unshift(1);
}
return res;
}
function aNonEmpty(arr) {
if (!Array.isArray(arr) || arr.length === 0)
throw new Error("expected non-empty array");
}
function createBlsPairing(fields2, G1, G2, params) {
validateObject(fields2, { Fp: "object", Fr: "object", Fp2: "object", Fp12: "object" }, { Fp6: "object" }, "fields");
if (typeof G1 !== "function")
throw new TypeError('"G1_Point" expected point constructor, got type=' + typeof G1);
if (typeof G2 !== "function")
throw new TypeError('"G2_Point" expected point constructor, got type=' + typeof G2);
validateObject(params, { ateLoopSize: "bigint", xNegative: "boolean", twistType: "string" }, { randomBytes: "function", postPrecompute: "function" }, "params");
const { Fp: Fp3, Fr, Fp2: Fp22, Fp12: Fp122 } = fields2;
const { twistType, ateLoopSize, xNegative, postPrecompute } = params;
const fp22 = (c0, c1) => ({ c0, c1 });
const fp2f = ({ c0, c1 }) => Object.freeze({ c0, c1 });
const add2 = (a, b) => fp22(Fp3.add(a.c0, b.c0), Fp3.add(a.c1, b.c1));
const sub2 = (a, b) => fp22(Fp3.sub(a.c0, b.c0), Fp3.sub(a.c1, b.c1));
const mul2 = (a, b) => {
const t0 = Fp3.mul(a.c0, b.c0);
const t1 = Fp3.mul(a.c1, b.c1);
return fp22(Fp3.sub(t0, t1), Fp3.sub(Fp3.mul(Fp3.add(a.c0, a.c1), Fp3.add(b.c0, b.c1)), Fp3.add(t0, t1)));
};
const mul2ByFp = (a, rhs) => fp22(Fp3.mul(a.c0, rhs), Fp3.mul(a.c1, rhs));
const mul2ByNonresidue = (a) => Fp22.mulByNonresidue(a);
const mul014ByLine = ({ c0: f0, c1: f1 }, o0, l1, l4, Px, Py) => {
const o1 = mul2ByFp(l1, Px);
const o4 = mul2ByFp(l4, Py);
const { c0: a0, c1: a1, c2: a2 } = f0;
const { c0: b0, c1: b1, c2: b2 } = f1;
const t0_0 = mul2(a0, o0);
const t0_1 = mul2(a1, o1);
const t0_c0 = add2(mul2ByNonresidue(sub2(mul2(add2(a1, a2), o1), t0_1)), t0_0);
const t0_c1 = sub2(sub2(mul2(add2(o0, o1), add2(a0, a1)), t0_0), t0_1);
const t0_c2 = add2(sub2(mul2(add2(a0, a2), o0), t0_0), t0_1);
const t1_c0 = mul2ByNonresidue(mul2(b2, o4));
const t1_c1 = mul2(b0, o4);
const t1_c2 = mul2(b1, o4);
const s0 = add2(a0, b0);
const s1 = add2(a1, b1);
const s2 = add2(a2, b2);
const o14 = add2(o1, o4);
const t2_0 = mul2(s0, o0);
const t2_1 = mul2(s1, o14);
const t2_c0 = add2(mul2ByNonresidue(sub2(mul2(add2(s1, s2), o14), t2_1)), t2_0);
const t2_c1 = sub2(sub2(mul2(add2(o0, o14), add2(s0, s1)), t2_0), t2_1);
const t2_c2 = add2(sub2(mul2(add2(s0, s2), o0), t2_0), t2_1);
return Object.freeze({
c0: Object.freeze({
c0: fp2f(add2(mul2ByNonresidue(t1_c2), t0_c0)),
c1: fp2f(add2(t1_c0, t0_c1)),
c2: fp2f(add2(t1_c1, t0_c2))
}),
c1: Object.freeze({
c0: fp2f(sub2(sub2(t2_c0, t0_c0), t1_c0)),
c1: fp2f(sub2(sub2(t2_c1, t0_c1), t1_c1)),
c2: fp2f(sub2(sub2(t2_c2, t0_c2), t1_c2))
})
});
};
const mul034ByLine = ({ c0: f0, c1: f1 }, l0, l3, o4, Px, Py) => {
const o0 = mul2ByFp(l0, Py);
const o3 = mul2ByFp(l3, Px);
const { c0: a0, c1: a1, c2: a2 } = f0;
const { c0: b0, c1: b1, c2: b2 } = f1;
const a_c0 = mul2(a0, o0);
const a_c1 = mul2(a1, o0);
const a_c2 = mul2(a2, o0);
const b0m = mul2(b0, o3);
const b1m = mul2(b1, o4);
const b_c0 = add2(mul2ByNonresidue(sub2(mul2(add2(b1, b2), o4), b1m)), b0m);
const b_c1 = sub2(sub2(mul2(add2(o3, o4), add2(b0, b1)), b0m), b1m);
const b_c2 = add2(sub2(mul2(add2(b0, b2), o3), b0m), b1m);
const s0 = add2(a0, b0);
const s1 = add2(a1, b1);
const s2 = add2(a2, b2);
const o03 = add2(o0, o3);
const e0m = mul2(s0, o03);
const e1m = mul2(s1, o4);
const e_c0 = add2(mul2ByNonresidue(sub2(mul2(add2(s1, s2), o4), e1m)), e0m);
const e_c1 = sub2(sub2(mul2(add2(o03, o4), add2(s0, s1)), e0m), e1m);
const e_c2 = add2(sub2(mul2(add2(s0, s2), o03), e0m), e1m);
return Object.freeze({
c0: Object.freeze({
c0: fp2f(add2(mul2ByNonresidue(b_c2), a_c0)),
c1: fp2f(add2(b_c0, a_c1)),
c2: fp2f(add2(b_c1, a_c2))
}),
c1: Object.freeze({
c0: fp2f(sub2(sub2(e_c0, a_c0), b_c0)),
c1: fp2f(sub2(sub2(e_c1, a_c1), b_c1)),
c2: fp2f(sub2(sub2(e_c2, a_c2), b_c2))
})
});
};
let lineFunction;
if (twistType === "multiplicative") {
lineFunction = (c0, c1, c2, f, Px, Py) => mul014ByLine(f, c0, c1, c2, Px, Py);
} else if (twistType === "divisive") {
lineFunction = (c0, c1, c2, f, Px, Py) => mul034ByLine(f, c2, c1, c0, Px, Py);
} else
throw new Error("bls: unknown twist type");
const Fp2div2 = Fp22.div(Fp22.ONE, Fp22.mul(Fp22.ONE, _2n5));
function pointDouble(ell, Rx, Ry, Rz) {
const t0 = Fp22.sqr(Ry);
const t1 = Fp22.sqr(Rz);
const t2 = Fp22.mulByB(Fp22.mul(t1, _3n4));
const t3 = Fp22.mul(t2, _3n4);
const t4 = Fp22.sub(Fp22.sub(Fp22.sqr(Fp22.add(Ry, Rz)), t1), t0);
const c0 = Fp22.sub(t2, t0);
const c1 = Fp22.mul(Fp22.sqr(Rx), _3n4);
const c2 = Fp22.neg(t4);
ell.push([c0, c1, c2]);
Rx = Fp22.mul(Fp22.mul(Fp22.mul(Fp22.sub(t0, t3), Rx), Ry), Fp2div2);
Ry = Fp22.sub(Fp22.sqr(Fp22.mul(Fp22.add(t0, t3), Fp2div2)), Fp22.mul(Fp22.sqr(t2), _3n4));
Rz = Fp22.mul(t0, t4);
return { Rx, Ry, Rz };
}
function pointAdd(ell, Rx, Ry, Rz, Qx, Qy) {
const t0 = Fp22.sub(Ry, Fp22.mul(Qy, Rz));
const t1 = Fp22.sub(Rx, Fp22.mul(Qx, Rz));
const c0 = Fp22.sub(Fp22.mul(t0, Qx), Fp22.mul(t1, Qy));
const c1 = Fp22.neg(t0);
const c2 = t1;
ell.push([c0, c1, c2]);
const t2 = Fp22.sqr(t1);
const t3 = Fp22.mul(t2, t1);
const t4 = Fp22.mul(t2, Rx);
const t5 = Fp22.add(Fp22.sub(t3, Fp22.mul(t4, _2n5)), Fp22.mul(Fp22.sqr(t0), Rz));
Rx = Fp22.mul(t1, t5);
Ry = Fp22.sub(Fp22.mul(Fp22.sub(t4, t5), t0), Fp22.mul(t3, Ry));
Rz = Fp22.mul(Rz, t3);
return { Rx, Ry, Rz };
}
const ATE_NAF = NAfDecomposition(ateLoopSize);
const calcPairingPrecomputes = (point) => {
if (!(point instanceof G2))
throw new TypeError('"point" expected G2 point, got type=' + typeof point);
const p = point;
const { x, y } = p.toAffine();
const Qx = x, Qy = y, negQy = Fp22.neg(y);
let Rx = Qx, Ry = Qy, Rz = Fp22.ONE;
const ell = [];
for (const bit of ATE_NAF) {
const cur = [];
({ Rx, Ry, Rz } = pointDouble(cur, Rx, Ry, Rz));
if (bit)
({ Rx, Ry, Rz } = pointAdd(cur, Rx, Ry, Rz, Qx, bit === -1 ? negQy : Qy));
ell.push(cur);
}
if (postPrecompute) {
const last = ell[ell.length - 1];
postPrecompute(Rx, Ry, Rz, Qx, Qy, pointAdd.bind(null, last));
}
return ell;
};
function millerLoopBatch(pairs, withFinalExponent = false) {
aarray(pairs, "pairs", (pair, title) => {
aarray(pair, title);
if (pair.length !== 3)
throw new TypeError(`"${title}" expected precompute tuple`);
aarray(pair[0], title + "[0]");
});
let f12 = Fp122.ONE;
if (pairs.length) {
const ellLen = pairs[0][0].length;
for (let i = 0; i < ellLen; i++) {
if (i !== 0)
f12 = Fp122.sqr(f12);
for (const [ell, Px, Py] of pairs) {
for (const [c0, c1, c2] of ell[i])
f12 = lineFunction(c0, c1, c2, f12, Px, Py);
}
}
}
if (xNegative)
f12 = Fp122.conjugate(f12);
return withFinalExponent ? Fp122.finalExponentiate(f12) : f12;
}
function pairingBatch(pairs, withFinalExponent = true) {
aarray(pairs, "pairs");
const res = [];
for (let i = 0; i < pairs.length; i++) {
const pair = pairs[i];
validateObject(pair, { g1: "object", g2: "object" }, {}, "pairs[" + i + "]");
const { g1: g12, g2: g22 } = pair;
if (!(g12 instanceof G1))
throw new TypeError('"pairs[' + i + '].g1" expected G1 point, got type=' + typeof g12);
if (!(g22 instanceof G2))
throw new TypeError('"pairs[' + i + '].g2" expected G2 point, got type=' + typeof g22);
if (g12.is0() || g22.is0())
throw new Error("pairing is not available for ZERO point");
g12.assertValidity();
g22.assertValidity();
const Qa = g12.toAffine();
res.push([calcPairingPrecomputes(g22), Qa.x, Qa.y]);
}
return millerLoopBatch(res, withFinalExponent);
}
function pairing(Q, P, withFinalExponent = true) {
if (!(Q instanceof G1))
throw new TypeError('"Q" expected G1 point, got type=' + typeof Q);
if (!(P instanceof G2))
throw new TypeError('"P" expected G2 point, got type=' + typeof P);
return pairingBatch([{ g1: Q, g2: P }], withFinalExponent);
}
const lengths = {
seed: getMinHashLength(Fr.ORDER)
};
const rand = params.randomBytes === void 0 ? randomBytes2 : params.randomBytes;
const randomSecretKey = (seed) => {
seed = seed === void 0 ? rand(lengths.seed) : seed;
abytes2(seed, lengths.seed, "seed");
return mapHashToField(seed, Fr.ORDER);
};
Object.freeze(lengths);
return {
lengths,
Fr,
Fp12: Fp122,
// NOTE: we re-export Fp12 here because pairing results are Fp12!
millerLoopBatch,
pairing,
pairingBatch,
calcPairingPrecomputes,
randomSecretKey
};
}
function createBlsSig(blsPairing, PubPoint, SigPoint, isSigG1, hashToSigCurve, SignatureCoder) {
const { Fr, Fp12: Fp122, pairingBatch, randomSecretKey, lengths } = blsPairing;
if (!SignatureCoder) {
SignatureCoder = {
fromBytes: notImplemented,
fromHex: notImplemented,
toBytes: notImplemented,
toHex: notImplemented
};
}
const sigCoder = Object.freeze({ ...SignatureCoder });
function normPub(point) {
return point instanceof PubPoint ? point : PubPoint.fromBytes(point);
}
function normSig(point) {
return point instanceof SigPoint ? point : sigCoder.fromBytes(point);
}
function amsg(m) {
if (!(m instanceof SigPoint))
throw new Error(`expected valid message hashed to ${!isSigG1 ? "G2" : "G1"} curve`);
return m;
}
const pair = !isSigG1 ? (a, b) => ({ g1: a, g2: b }) : (a, b) => ({ g1: b, g2: a });
return Object.freeze({
lengths: Object.freeze({ ...lengths, secretKey: Fr.BYTES }),
keygen(seed) {
const secretKey = randomSecretKey(seed);
const publicKey = this.getPublicKey(secretKey);
return { secretKey, publicKey };
},
// P = pk x G
getPublicKey(secretKey) {
let sec;
try {
sec = PubPoint.Fn.fromBytes(secretKey);
} catch (error) {
throw new Error("invalid private key: " + typeof secretKey, { cause: error });
}
return PubPoint.BASE.multiply(sec);
},
// S = pk x H(m)
sign(message, secretKey, unusedArg) {
if (unusedArg != null)
throw new Error("sign() expects 2 arguments");
const sec = PubPoint.Fn.fromBytes(secretKey);
amsg(message).assertValidity();
return message.multiply(sec);
},
// Checks if pairing of public key & hash is equal to pairing of generator & signature.
// e(P, H(m)) == e(G, S)
// e(S, G) == e(H(m), P)
verify(signature, message, publicKey, unusedArg) {
if (unusedArg != null)
throw new Error("verify() expects 3 arguments");
signature = normSig(signature);
publicKey = normPub(publicKey);
const P = publicKey.negate();
const G = PubPoint.BASE;
const Hm = amsg(message);
const S = signature;
try {
const exp = pairingBatch([pair(P, Hm), pair(G, S)]);
return Fp122.eql(exp, Fp122.ONE);
} catch {
return false;
}
},
// https://ethresear.ch/t/fast-verification-of-multiple-bls-signatures/5407
// e(G, S) = e(G, SUM(n)(Si)) = MUL(n)(e(G, Si))
// TODO: maybe `{message: G2Hex, publicKey: G1Hex}[]` instead?
verifyBatch(signature, items) {
aNonEmpty(items);
const sig = normSig(signature);
const nMessages = items.map((i) => amsg(i.message));
const nPublicKeys = items.map((i) => normPub(i.publicKey));
const messagePubKeyMap = /* @__PURE__ */ new Map();
for (let i = 0; i < nPublicKeys.length; i++) {
const pub = nPublicKeys[i];
const msg = nMessages[i];
let keys = messagePubKeyMap.get(msg);
if (keys === void 0) {
keys = [];
messagePubKeyMap.set(msg, keys);
}
keys.push(pub);
}
const paired = [];
const G = PubPoint.BASE;
try {
for (const [msg, keys] of messagePubKeyMap) {
const groupPublicKey = keys.reduce((acc, msg2) => acc.add(msg2));
paired.push(pair(groupPublicKey, msg));
}
paired.push(pair(G.negate(), sig));
return Fp122.eql(pairingBatch(paired), Fp122.ONE);
} catch {
return false;
}
},
// Adds a bunch of public key points together.
// pk1 + pk2 + pk3 = pkA
aggregatePublicKeys(publicKeys) {
aNonEmpty(publicKeys);
publicKeys = publicKeys.map((pub) => normPub(pub));
const agg = publicKeys.reduce((sum, p) => sum.add(p), PubPoint.ZERO);
agg.assertValidity();
return agg;
},
// Adds a bunch of signature points together.
// pk1 + pk2 + pk3 = pkA
aggregateSignatures(signatures) {
aNonEmpty(signatures);
signatures = signatures.map((sig) => normSig(sig));
const agg = signatures.reduce((sum, s) => sum.add(s), SigPoint.ZERO);
agg.assertValidity();
return agg;
},
hash(messageBytes, DST) {
abytes2(messageBytes);
const opts = DST === void 0 ? void 0 : { DST };
return hashToSigCurve(messageBytes, opts);
},
Signature: Object.freeze({ ...sigCoder })
});
}
function blsBasic(fields2, G1_Point2, G2_Point2, params) {
const { Fp: Fp3, Fr, Fp2: Fp22, Fp6: Fp62, Fp12: Fp122 } = fields2;
const G1 = { Point: G1_Point2 };
const G2 = { Point: G2_Point2 };
const pairingRes = createBlsPairing(fields2, G1_Point2, G2_Point2, params);
const { millerLoopBatch, pairing, pairingBatch, calcPairingPrecomputes, randomSecretKey, lengths } = pairingRes;
G1.Point.BASE.precompute(4);
Object.freeze(G1);
Object.freeze(G2);
return Object.freeze({
lengths: Object.freeze(lengths),
millerLoopBatch,
pairing,
pairingBatch,
G1,
G2,
fields: Object.freeze({ Fr, Fp: Fp3, Fp2: Fp22, Fp6: Fp62, Fp12: Fp122 }),
params: Object.freeze({
ateLoopSize: params.ateLoopSize,
xNegative: params.xNegative,
twistType: params.twistType,
postPrecompute: params.postPrecompute
}),
utils: Object.freeze({
randomSecretKey,
calcPairingPrecomputes
})
});
}
function blsHashers(fields2, G1_Point2, G2_Point2, params, hasherParams) {
const base = blsBasic(fields2, G1_Point2, G2_Point2, params);
validateObject(hasherParams, { hasherOpts: "object", hasherOptsG1: "object", hasherOptsG2: "object" }, { mapToG1: "function", mapToG2: "function" }, "hasherParams");
const G1Hasher = createHasher2(G1_Point2, hasherParams.mapToG1 === void 0 ? notImplemented : hasherParams.mapToG1, {
...hasherParams.hasherOpts,
...hasherParams.hasherOptsG1
});
const G2Hasher = createHasher2(G2_Point2, hasherParams.mapToG2 === void 0 ? notImplemented : hasherParams.mapToG2, {
...hasherParams.hasherOpts,
...hasherParams.hasherOptsG2
});
return Object.freeze({ ...base, G1: G1Hasher, G2: G2Hasher });
}
function bls(fields2, G1_Point2, G2_Point2, params, hasherParams, signatureCoders2) {
const base = blsHashers(fields2, G1_Point2, G2_Point2, params, hasherParams);
const pairingRes = {
...base,
Fr: base.fields.Fr,
Fp12: base.fields.Fp12,
calcPairingPrecomputes: base.utils.calcPairingPrecomputes,
randomSecretKey: base.utils.randomSecretKey
};
const longSignatures = createBlsSig(pairingRes, G1_Point2, G2_Point2, false, base.G2.hashToCurve, signatureCoders2?.LongSignature);
const shortSignatures = createBlsSig(pairingRes, G2_Point2, G1_Point2, true, base.G1.hashToCurve, signatureCoders2?.ShortSignature);
return Object.freeze({ ...base, longSignatures, shortSignatures });
}
// tools/reference-apps/light-service/node_modules/@noble/curves/abstract/tower.js
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
var _0n8 = /* @__PURE__ */ BigInt(0);
var _1n8 = /* @__PURE__ */ BigInt(1);
var _2n6 = /* @__PURE__ */ BigInt(2);
var _3n5 = /* @__PURE__ */ BigInt(3);
var _6n = /* @__PURE__ */ BigInt(6);
var _12n = /* @__PURE__ */ BigInt(12);
var isObj = (value) => !!value && typeof value === "object";
function calcFrobeniusCoefficients(Fp3, nonResidue, modulus, degree, num = 1, divisor) {
asafenumber(num, "num");
asafenumber(degree, "degree");
const divisorN = divisor === void 0 ? degree : divisor;
asafenumber(divisorN, "divisor");
const F = Fp3;
if (typeof modulus !== "bigint" || modulus <= _1n8)
throw new Error("calcFrobeniusCoefficients: expected valid modulus, got " + modulus);
if (degree <= 0)
throw new Error("calcFrobeniusCoefficients: expected positive degree, got " + degree);
if (num <= 0)
throw new Error("calcFrobeniusCoefficients: expected positive row count, got " + num);
if (divisorN <= 0)
throw new Error("calcFrobeniusCoefficients: expected positive divisor, got " + divisorN);
const _divisor = BigInt(divisorN);
const towerModulus = modulus ** BigInt(degree);
const res = [];
for (let i = 0; i < num; i++) {
const a = BigInt(i + 1);
const powers = [];
for (let j = 0, qPower = _1n8; j < degree; j++) {
const numer = a * qPower - a;
if (numer % _divisor)
throw new Error("calcFrobeniusCoefficients: inexact tower exponent");
const power = numer / _divisor % towerModulus;
powers.push(F.pow(nonResidue, power));
qPower *= modulus;
}
res.push(powers);
}
return res;
}
function psiFrobenius(Fp3, Fp22, base) {
validateField(Fp3);
validateField(Fp22);
validateObject(Fp22, {
Fp: "object",
frobeniusMap: "function",
fromBigTuple: "function",
mulByB: "function",
mulByNonresidue: "function",
reim: "function",
Fp4Square: "function",
NONRESIDUE: "object"
}, {});
if (!isObj(base) || Array.isArray(base))
throw new TypeError('"base" expected Fp2 element, got type=' + typeof base);
if (!Fp22.isValid(base))
throw new RangeError('"base" expected valid Fp2 element');
const PSI_X = Fp22.pow(base, (Fp3.ORDER - _1n8) / _3n5);
const PSI_Y = Fp22.pow(base, (Fp3.ORDER - _1n8) / _2n6);
function psi(x, y) {
const x2 = Fp22.mul(Fp22.frobeniusMap(x, 1), PSI_X);
const y2 = Fp22.mul(Fp22.frobeniusMap(y, 1), PSI_Y);
return [x2, y2];
}
const PSI2_X = Fp22.pow(base, (Fp3.ORDER ** _2n6 - _1n8) / _3n5);
const PSI2_Y = Fp22.pow(base, (Fp3.ORDER ** _2n6 - _1n8) / _2n6);
if (!Fp22.eql(PSI2_Y, Fp22.neg(Fp22.ONE)))
throw new Error("psiFrobenius: PSI2_Y!==-1");
function psi2(x, y) {
return [Fp22.mul(x, PSI2_X), Fp22.neg(y)];
}
const mapAffine = (fn) => (c, P) => {
if (typeof c !== "function")
throw new TypeError('"c" expected point constructor, got type=' + typeof c);
validatePointCons(c);
if (!(P instanceof c))
throw new TypeError('"P" expected Point instance, got type=' + typeof P);
const affine = P.toAffine();
const p = fn(affine.x, affine.y);
return c.fromAffine({ x: p[0], y: p[1] });
};
const G2psi3 = mapAffine(psi);
const G2psi22 = mapAffine(psi2);
return { psi, psi2, G2psi: G2psi3, G2psi2: G2psi22, PSI_X, PSI_Y, PSI2_X, PSI2_Y };
}
var _Field2 = class {
ORDER;
BITS;
BYTES;
isLE;
ZERO;
ONE;
Fp;
NONRESIDUE;
mulByB;
Fp_NONRESIDUE;
Fp_div2;
constructor(Fp3, opts = {}) {
const { NONRESIDUE = BigInt(-1), FP2_NONRESIDUE, Fp2mulByB } = opts;
const ORDER = Fp3.ORDER;
const FP2_ORDER = ORDER * ORDER;
this.Fp = Fp3;
this.ORDER = FP2_ORDER;
this.BITS = bitLen(FP2_ORDER);
this.BYTES = Math.ceil(bitLen(FP2_ORDER) / 8);
this.isLE = Fp3.isLE;
this.ZERO = this.create({ c0: Fp3.ZERO, c1: Fp3.ZERO });
this.ONE = this.create({ c0: Fp3.ONE, c1: Fp3.ZERO });
this.Fp_NONRESIDUE = Fp3.create(NONRESIDUE);
this.Fp_div2 = Fp3.div(Fp3.ONE, _2n6);
this.NONRESIDUE = this.create({ c0: FP2_NONRESIDUE[0], c1: FP2_NONRESIDUE[1] });
this.mulByB = (num) => {
const { c0, c1 } = Fp2mulByB(num);
return Object.freeze({ c0, c1 });
};
Object.freeze(this);
}
fromBigTuple(tuple) {
if (!Array.isArray(tuple) || tuple.length !== 2)
throw new Error("invalid Fp2.fromBigTuple");
const [c0, c1] = tuple;
if (typeof c0 !== "bigint" || typeof c1 !== "bigint")
throw new Error("invalid Fp2.fromBigTuple");
return this.create({ c0, c1 });
}
create(num) {
const { Fp: Fp3 } = this;
const c0 = Fp3.create(num.c0);
const c1 = Fp3.create(num.c1);
return Object.freeze({ c0, c1 });
}
isValid(num) {
if (!isObj(num))
throw new TypeError("invalid field element: expected object, got " + typeof num);
const { c0, c1 } = num;
const { Fp: Fp3 } = this;
return Fp3.isValid(c0) && Fp3.isValid(c1);
}
is0(num) {
if (!isObj(num))
return false;
const { c0, c1 } = num;
const { Fp: Fp3 } = this;
return Fp3.is0(c0) && Fp3.is0(c1);
}
isValidNot0(num) {
return !this.is0(num) && this.isValid(num);
}
eql({ c0, c1 }, { c0: r0, c1: r1 }) {
const { Fp: Fp3 } = this;
return Fp3.eql(c0, r0) && Fp3.eql(c1, r1);
}
neg({ c0, c1 }) {
const { Fp: Fp3 } = this;
return Object.freeze({ c0: Fp3.neg(c0), c1: Fp3.neg(c1) });
}
pow(num, power) {
return FpPow(this, num, power);
}
invertBatch(nums) {
return FpInvertBatch(this, nums, true);
}
// Normalized
add(f1, f2) {
const { Fp: Fp3 } = this;
const { c0, c1 } = f1;
const { c0: r0, c1: r1 } = f2;
return Object.freeze({
c0: Fp3.add(c0, r0),
c1: Fp3.add(c1, r1)
});
}
sub({ c0, c1 }, { c0: r0, c1: r1 }) {
const { Fp: Fp3 } = this;
return Object.freeze({
c0: Fp3.sub(c0, r0),
c1: Fp3.sub(c1, r1)
});
}
mul({ c0, c1 }, rhs) {
const { Fp: Fp3 } = this;
if (typeof rhs === "bigint")
return Object.freeze({ c0: Fp3.mul(c0, rhs), c1: Fp3.mul(c1, rhs) });
const { c0: r0, c1: r1 } = rhs;
let t1 = Fp3.mul(c0, r0);
let t2 = Fp3.mul(c1, r1);
const o0 = Fp3.sub(t1, t2);
const o1 = Fp3.sub(Fp3.mul(Fp3.add(c0, c1), Fp3.add(r0, r1)), Fp3.add(t1, t2));
return Object.freeze({ c0: o0, c1: o1 });
}
sqr({ c0, c1 }) {
const { Fp: Fp3 } = this;
const a = Fp3.add(c0, c1);
const b = Fp3.sub(c0, c1);
const c = Fp3.add(c0, c0);
return Object.freeze({ c0: Fp3.mul(a, b), c1: Fp3.mul(c, c1) });
}
// NonNormalized stuff
addN(a, b) {
return this.add(a, b);
}
subN(a, b) {
return this.sub(a, b);
}
mulN(a, b) {
return this.mul(a, b);
}
sqrN(a) {
return this.sqr(a);
}
// Why inversion for bigint inside Fp instead of Fp2? it is even used in that context?
div(lhs, rhs) {
const { Fp: Fp3 } = this;
return this.mul(lhs, typeof rhs === "bigint" ? Fp3.inv(Fp3.create(rhs)) : this.inv(rhs));
}
inv({ c0: a, c1: b }) {
const { Fp: Fp3 } = this;
const factor = Fp3.inv(Fp3.create(a * a + b * b));
return Object.freeze({ c0: Fp3.mul(factor, Fp3.create(a)), c1: Fp3.mul(factor, Fp3.create(-b)) });
}
sqrt(num) {
const { Fp: Fp3 } = this;
const Fp22 = this;
const { c0, c1 } = num;
if (Fp3.is0(c1)) {
if (FpLegendre(Fp3, c0) === 1)
return Fp22.create({ c0: Fp3.sqrt(c0), c1: Fp3.ZERO });
else
return Fp22.create({ c0: Fp3.ZERO, c1: Fp3.sqrt(Fp3.div(c0, this.Fp_NONRESIDUE)) });
}
const a = Fp3.sqrt(Fp3.sub(Fp3.sqr(c0), Fp3.mul(Fp3.sqr(c1), this.Fp_NONRESIDUE)));
let d = Fp3.mul(Fp3.add(a, c0), this.Fp_div2);
const legendre = FpLegendre(Fp3, d);
if (legendre === -1)
d = Fp3.sub(d, a);
const a0 = Fp3.sqrt(d);
const candidateSqrt = Fp22.create({ c0: a0, c1: Fp3.div(Fp3.mul(c1, this.Fp_div2), a0) });
if (!Fp22.eql(Fp22.sqr(candidateSqrt), num))
throw new Error("Cannot find square root");
const x1 = candidateSqrt;
const x2 = Fp22.neg(x1);
const { re: re1, im: im1 } = Fp22.reim(x1);
const { re: re2, im: im2 } = Fp22.reim(x2);
if (im1 > im2 || im1 === im2 && re1 > re2)
return x1;
return x2;
}
// Same as sgn0_m_eq_2 in RFC 9380
isOdd(x) {
const { re: x0, im: x1 } = this.reim(x);
const sign_0 = x0 % _2n6;
const zero_0 = x0 === _0n8;
const sign_1 = x1 % _2n6;
return BigInt(sign_0 || zero_0 && sign_1) == _1n8;
}
// Bytes util
fromBytes(b) {
const { Fp: Fp3 } = this;
abytes2(b);
if (b.length !== this.BYTES)
throw new Error("fromBytes invalid length=" + b.length);
return this.create({
c0: Fp3.fromBytes(b.subarray(0, Fp3.BYTES)),
c1: Fp3.fromBytes(b.subarray(Fp3.BYTES))
});
}
toBytes({ c0, c1 }) {
return concatBytes2(this.Fp.toBytes(c0), this.Fp.toBytes(c1));
}
cmov({ c0, c1 }, { c0: r0, c1: r1 }, c) {
const { Fp: Fp3 } = this;
return this.create({
c0: Fp3.cmov(c0, r0, c),
c1: Fp3.cmov(c1, r1, c)
});
}
reim({ c0, c1 }) {
return { re: c0, im: c1 };
}
Fp4Square(a, b) {
const Fp22 = this;
const a2 = Fp22.sqr(a);
const b2 = Fp22.sqr(b);
return {
first: Fp22.add(Fp22.mulByNonresidue(b2), a2),
// b² * Nonresidue + a²
second: Fp22.sub(Fp22.sub(Fp22.sqr(Fp22.add(a, b)), a2), b2)
// (a + b)² - a² - b²
};
}
// multiply by u + 1
mulByNonresidue({ c0, c1 }) {
const { Fp: Fp3, NONRESIDUE: nr } = this;
if (nr.c0 === Fp3.ONE && nr.c1 === Fp3.ONE) {
return Object.freeze({ c0: Fp3.sub(c0, c1), c1: Fp3.add(c0, c1) });
}
if (nr.c1 === Fp3.ONE) {
return Object.freeze({
c0: Fp3.sub(Fp3.mul(c0, nr.c0), c1),
c1: Fp3.add(c0, Fp3.mul(c1, nr.c0))
});
}
return this.mul({ c0, c1 }, nr);
}
frobeniusMap(num, power) {
const { c0, c1 } = num;
const { Fp: Fp3 } = this;
return Object.freeze({ c0, c1: power % 2 === 0 ? c1 : Fp3.neg(c1) });
}
};
var _Field6 = class {
ORDER;
BITS;
BYTES;
isLE;
ZERO;
ONE;
Fp2;
constructor(Fp22) {
this.Fp2 = Fp22;
this.ORDER = Fp22.Fp.ORDER ** _6n;
this.BITS = 3 * Fp22.BITS;
this.BYTES = 3 * Fp22.BYTES;
this.isLE = Fp22.isLE;
this.ZERO = this.create({ c0: Fp22.ZERO, c1: Fp22.ZERO, c2: Fp22.ZERO });
this.ONE = this.create({ c0: Fp22.ONE, c1: Fp22.ZERO, c2: Fp22.ZERO });
Object.freeze(this);
}
// Most callers never touch Frobenius maps, so keep the sextic tables lazy:
// eagerly deriving them dominates `bls12-381.js` / `bn254.js` import time.
get FROBENIUS_COEFFICIENTS_1() {
const frob2 = _FROBENIUS_COEFFICIENTS_6.get(this);
if (frob2)
return frob2[0];
const { Fp2: Fp22 } = this;
const { Fp: Fp3 } = Fp22;
const rows = calcFrobeniusCoefficients(Fp22, Fp22.NONRESIDUE, Fp3.ORDER, 6, 2, 3);
const cache = [Object.freeze(rows[0]), Object.freeze(rows[1])];
_FROBENIUS_COEFFICIENTS_6.set(this, cache);
return cache[0];
}
get FROBENIUS_COEFFICIENTS_2() {
const frob2 = _FROBENIUS_COEFFICIENTS_6.get(this);
if (frob2)
return frob2[1];
void this.FROBENIUS_COEFFICIENTS_1;
return _FROBENIUS_COEFFICIENTS_6.get(this)[1];
}
add({ c0, c1, c2 }, { c0: r0, c1: r1, c2: r2 }) {
const { Fp2: Fp22 } = this;
return Object.freeze({
c0: Fp22.add(c0, r0),
c1: Fp22.add(c1, r1),
c2: Fp22.add(c2, r2)
});
}
sub({ c0, c1, c2 }, { c0: r0, c1: r1, c2: r2 }) {
const { Fp2: Fp22 } = this;
return Object.freeze({
c0: Fp22.sub(c0, r0),
c1: Fp22.sub(c1, r1),
c2: Fp22.sub(c2, r2)
});
}
mul({ c0, c1, c2 }, rhs) {
const { Fp2: Fp22 } = this;
if (typeof rhs === "bigint") {
return Object.freeze({
c0: Fp22.mul(c0, rhs),
c1: Fp22.mul(c1, rhs),
c2: Fp22.mul(c2, rhs)
});
}
const { c0: r0, c1: r1, c2: r2 } = rhs;
const t0 = Fp22.mul(c0, r0);
const t1 = Fp22.mul(c1, r1);
const t2 = Fp22.mul(c2, r2);
return Object.freeze({
// t0 + (c1 + c2) * (r1 * r2) - (T1 + T2) * (u + 1)
c0: Fp22.add(t0, Fp22.mulByNonresidue(Fp22.sub(Fp22.mul(Fp22.add(c1, c2), Fp22.add(r1, r2)), Fp22.add(t1, t2)))),
// (c0 + c1) * (r0 + r1) - (T0 + T1) + T2 * (u + 1)
c1: Fp22.add(Fp22.sub(Fp22.mul(Fp22.add(c0, c1), Fp22.add(r0, r1)), Fp22.add(t0, t1)), Fp22.mulByNonresidue(t2)),
// T1 + (c0 + c2) * (r0 + r2) - T0 + T2
c2: Fp22.sub(Fp22.add(t1, Fp22.mul(Fp22.add(c0, c2), Fp22.add(r0, r2))), Fp22.add(t0, t2))
});
}
sqr({ c0, c1, c2 }) {
const { Fp2: Fp22 } = this;
let t0 = Fp22.sqr(c0);
let t1 = Fp22.mul(Fp22.mul(c0, c1), _2n6);
let t3 = Fp22.mul(Fp22.mul(c1, c2), _2n6);
let t4 = Fp22.sqr(c2);
return Object.freeze({
c0: Fp22.add(Fp22.mulByNonresidue(t3), t0),
// T3 * (u + 1) + T0
c1: Fp22.add(Fp22.mulByNonresidue(t4), t1),
// T4 * (u + 1) + T1
// T1 + (c0 - c1 + c2)² + T3 - T0 - T4
c2: Fp22.sub(Fp22.sub(Fp22.add(Fp22.add(t1, Fp22.sqr(Fp22.add(Fp22.sub(c0, c1), c2))), t3), t0), t4)
});
}
addN(a, b) {
return this.add(a, b);
}
subN(a, b) {
return this.sub(a, b);
}
mulN(a, b) {
return this.mul(a, b);
}
sqrN(a) {
return this.sqr(a);
}
create(num) {
const { Fp2: Fp22 } = this;
const c0 = Fp22.create(num.c0);
const c1 = Fp22.create(num.c1);
const c2 = Fp22.create(num.c2);
return Object.freeze({ c0, c1, c2 });
}
isValid(num) {
if (!isObj(num))
throw new TypeError("invalid field element: expected object, got " + typeof num);
const { c0, c1, c2 } = num;
const { Fp2: Fp22 } = this;
return Fp22.isValid(c0) && Fp22.isValid(c1) && Fp22.isValid(c2);
}
is0(num) {
if (!isObj(num))
return false;
const { c0, c1, c2 } = num;
const { Fp2: Fp22 } = this;
return Fp22.is0(c0) && Fp22.is0(c1) && Fp22.is0(c2);
}
isValidNot0(num) {
return !this.is0(num) && this.isValid(num);
}
neg({ c0, c1, c2 }) {
const { Fp2: Fp22 } = this;
return Object.freeze({ c0: Fp22.neg(c0), c1: Fp22.neg(c1), c2: Fp22.neg(c2) });
}
eql({ c0, c1, c2 }, { c0: r0, c1: r1, c2: r2 }) {
const { Fp2: Fp22 } = this;
return Fp22.eql(c0, r0) && Fp22.eql(c1, r1) && Fp22.eql(c2, r2);
}
sqrt(_) {
return notImplemented();
}
// Do we need division by bigint at all? Should be done via order:
div(lhs, rhs) {
const { Fp2: Fp22 } = this;
const { Fp: Fp3 } = Fp22;
return this.mul(lhs, typeof rhs === "bigint" ? Fp3.inv(Fp3.create(rhs)) : this.inv(rhs));
}
pow(num, power) {
return FpPow(this, num, power);
}
invertBatch(nums) {
return FpInvertBatch(this, nums, true);
}
inv({ c0, c1, c2 }) {
const { Fp2: Fp22 } = this;
let t0 = Fp22.sub(Fp22.sqr(c0), Fp22.mulByNonresidue(Fp22.mul(c2, c1)));
let t1 = Fp22.sub(Fp22.mulByNonresidue(Fp22.sqr(c2)), Fp22.mul(c0, c1));
let t2 = Fp22.sub(Fp22.sqr(c1), Fp22.mul(c0, c2));
let t4 = Fp22.inv(Fp22.add(Fp22.mulByNonresidue(Fp22.add(Fp22.mul(c2, t1), Fp22.mul(c1, t2))), Fp22.mul(c0, t0)));
return Object.freeze({ c0: Fp22.mul(t4, t0), c1: Fp22.mul(t4, t1), c2: Fp22.mul(t4, t2) });
}
// Bytes utils
fromBytes(b) {
const { Fp2: Fp22 } = this;
abytes2(b);
if (b.length !== this.BYTES)
throw new Error("fromBytes invalid length=" + b.length);
const B2 = Fp22.BYTES;
return this.create({
c0: Fp22.fromBytes(b.subarray(0, B2)),
c1: Fp22.fromBytes(b.subarray(B2, B2 * 2)),
c2: Fp22.fromBytes(b.subarray(2 * B2))
});
}
toBytes({ c0, c1, c2 }) {
const { Fp2: Fp22 } = this;
return concatBytes2(Fp22.toBytes(c0), Fp22.toBytes(c1), Fp22.toBytes(c2));
}
cmov({ c0, c1, c2 }, { c0: r0, c1: r1, c2: r2 }, c) {
const { Fp2: Fp22 } = this;
return this.create({
c0: Fp22.cmov(c0, r0, c),
c1: Fp22.cmov(c1, r1, c),
c2: Fp22.cmov(c2, r2, c)
});
}
fromBigSix(tuple) {
const { Fp2: Fp22 } = this;
if (!Array.isArray(tuple) || tuple.length !== 6)
throw new Error("invalid Fp6.fromBigSix");
for (let i = 0; i < 6; i++)
if (typeof tuple[i] !== "bigint")
throw new Error("invalid Fp6.fromBigSix");
const t2 = tuple;
return this.create({
c0: Fp22.fromBigTuple(t2.slice(0, 2)),
c1: Fp22.fromBigTuple(t2.slice(2, 4)),
c2: Fp22.fromBigTuple(t2.slice(4, 6))
});
}
frobeniusMap(num, power) {
const { c0, c1, c2 } = num;
if (power % 6 === 0)
return Object.freeze({ c0, c1, c2 });
const { Fp2: Fp22 } = this;
return Object.freeze({
c0: Fp22.frobeniusMap(c0, power),
c1: Fp22.mul(Fp22.frobeniusMap(c1, power), this.FROBENIUS_COEFFICIENTS_1[power % 6]),
c2: Fp22.mul(Fp22.frobeniusMap(c2, power), this.FROBENIUS_COEFFICIENTS_2[power % 6])
});
}
mulByFp2({ c0, c1, c2 }, rhs) {
const { Fp2: Fp22 } = this;
return Object.freeze({
c0: Fp22.mul(c0, rhs),
c1: Fp22.mul(c1, rhs),
c2: Fp22.mul(c2, rhs)
});
}
mulByNonresidue({ c0, c1, c2 }) {
const { Fp2: Fp22 } = this;
return Object.freeze({ c0: Fp22.mulByNonresidue(c2), c1: c0, c2: c1 });
}
// Sparse multiplication
mul1({ c0, c1, c2 }, b1) {
const { Fp2: Fp22 } = this;
return Object.freeze({
c0: Fp22.mulByNonresidue(Fp22.mul(c2, b1)),
c1: Fp22.mul(c0, b1),
c2: Fp22.mul(c1, b1)
});
}
// Sparse multiplication
mul01({ c0, c1, c2 }, b0, b1) {
const { Fp2: Fp22 } = this;
let t0 = Fp22.mul(c0, b0);
let t1 = Fp22.mul(c1, b1);
return Object.freeze({
// ((c1 + c2) * b1 - T1) * (u + 1) + T0
c0: Fp22.add(Fp22.mulByNonresidue(Fp22.sub(Fp22.mul(Fp22.add(c1, c2), b1), t1)), t0),
// (b0 + b1) * (c0 + c1) - T0 - T1
c1: Fp22.sub(Fp22.sub(Fp22.mul(Fp22.add(b0, b1), Fp22.add(c0, c1)), t0), t1),
// (c0 + c2) * b0 - T0 + T1
c2: Fp22.add(Fp22.sub(Fp22.mul(Fp22.add(c0, c2), b0), t0), t1)
});
}
};
var _FROBENIUS_COEFFICIENTS_6 = /* @__PURE__ */ new WeakMap();
var _Field12 = class {
ORDER;
BITS;
BYTES;
isLE;
ZERO;
ONE;
Fp6;
X_LEN;
finalExponentiate;
constructor(Fp62, opts) {
const { X_LEN, Fp12finalExponentiate } = opts;
const { Fp2: Fp22 } = Fp62;
const { Fp: Fp3 } = Fp22;
this.Fp6 = Fp62;
this.ORDER = Fp3.ORDER ** _12n;
this.BITS = 2 * Fp62.BITS;
this.BYTES = 2 * Fp62.BYTES;
this.isLE = Fp62.isLE;
this.ZERO = this.create({ c0: Fp62.ZERO, c1: Fp62.ZERO });
this.ONE = this.create({ c0: Fp62.ONE, c1: Fp62.ZERO });
this.X_LEN = X_LEN;
this.finalExponentiate = (num) => {
const copy2 = ({ c0, c1 }) => Object.freeze({ c0, c1 });
const copy6 = ({ c0, c1, c2 }) => Object.freeze({ c0: copy2(c0), c1: copy2(c1), c2: copy2(c2) });
const res = Fp12finalExponentiate(num);
return Object.freeze({ c0: copy6(res.c0), c1: copy6(res.c1) });
};
Object.freeze(this);
}
// Keep the degree-12 Frobenius row lazy too; after the first lookup the cached
// array is reused exactly like the old eager table.
get FROBENIUS_COEFFICIENTS() {
const frob2 = _FROBENIUS_COEFFICIENTS_12.get(this);
if (frob2)
return frob2;
const { Fp2: Fp22 } = this.Fp6;
const { Fp: Fp3 } = Fp22;
const cache = Object.freeze(calcFrobeniusCoefficients(Fp22, Fp22.NONRESIDUE, Fp3.ORDER, 12, 1, 6)[0]);
_FROBENIUS_COEFFICIENTS_12.set(this, cache);
return cache;
}
create(num) {
const { Fp6: Fp62 } = this;
const c0 = Fp62.create(num.c0);
const c1 = Fp62.create(num.c1);
return Object.freeze({ c0, c1 });
}
isValid(num) {
if (!isObj(num))
throw new TypeError("invalid field element: expected object, got " + typeof num);
const { c0, c1 } = num;
const { Fp6: Fp62 } = this;
return Fp62.isValid(c0) && Fp62.isValid(c1);
}
is0(num) {
if (!isObj(num))
return false;
const { c0, c1 } = num;
const { Fp6: Fp62 } = this;
return Fp62.is0(c0) && Fp62.is0(c1);
}
isValidNot0(num) {
return !this.is0(num) && this.isValid(num);
}
neg({ c0, c1 }) {
const { Fp6: Fp62 } = this;
return Object.freeze({ c0: Fp62.neg(c0), c1: Fp62.neg(c1) });
}
eql({ c0, c1 }, { c0: r0, c1: r1 }) {
const { Fp6: Fp62 } = this;
return Fp62.eql(c0, r0) && Fp62.eql(c1, r1);
}
sqrt(_) {
return notImplemented();
}
inv({ c0, c1 }) {
const { Fp6: Fp62 } = this;
let t2 = Fp62.inv(Fp62.sub(Fp62.sqr(c0), Fp62.mulByNonresidue(Fp62.sqr(c1))));
return Object.freeze({ c0: Fp62.mul(c0, t2), c1: Fp62.neg(Fp62.mul(c1, t2)) });
}
div(lhs, rhs) {
const { Fp6: Fp62 } = this;
const { Fp2: Fp22 } = Fp62;
const { Fp: Fp3 } = Fp22;
return this.mul(lhs, typeof rhs === "bigint" ? Fp3.inv(Fp3.create(rhs)) : this.inv(rhs));
}
pow(num, power) {
return FpPow(this, num, power);
}
invertBatch(nums) {
return FpInvertBatch(this, nums, true);
}
// Normalized
add({ c0, c1 }, { c0: r0, c1: r1 }) {
const { Fp6: Fp62 } = this;
return Object.freeze({
c0: Fp62.add(c0, r0),
c1: Fp62.add(c1, r1)
});
}
sub({ c0, c1 }, { c0: r0, c1: r1 }) {
const { Fp6: Fp62 } = this;
return Object.freeze({
c0: Fp62.sub(c0, r0),
c1: Fp62.sub(c1, r1)
});
}
mul({ c0, c1 }, rhs) {
const { Fp6: Fp62 } = this;
if (typeof rhs === "bigint")
return Object.freeze({ c0: Fp62.mul(c0, rhs), c1: Fp62.mul(c1, rhs) });
let { c0: r0, c1: r1 } = rhs;
let t1 = Fp62.mul(c0, r0);
let t2 = Fp62.mul(c1, r1);
return Object.freeze({
c0: Fp62.add(t1, Fp62.mulByNonresidue(t2)),
// T1 + T2 * v
// (c0 + c1) * (r0 + r1) - (T1 + T2)
c1: Fp62.sub(Fp62.mul(Fp62.add(c0, c1), Fp62.add(r0, r1)), Fp62.add(t1, t2))
});
}
sqr({ c0, c1 }) {
const { Fp6: Fp62 } = this;
let ab = Fp62.mul(c0, c1);
return Object.freeze({
// (c1 * v + c0) * (c0 + c1) - AB - AB * v
c0: Fp62.sub(Fp62.sub(Fp62.mul(Fp62.add(Fp62.mulByNonresidue(c1), c0), Fp62.add(c0, c1)), ab), Fp62.mulByNonresidue(ab)),
c1: Fp62.add(ab, ab)
});
}
// NonNormalized stuff
addN(a, b) {
return this.add(a, b);
}
subN(a, b) {
return this.sub(a, b);
}
mulN(a, b) {
return this.mul(a, b);
}
sqrN(a) {
return this.sqr(a);
}
// Bytes utils
fromBytes(b) {
const { Fp6: Fp62 } = this;
abytes2(b);
if (b.length !== this.BYTES)
throw new Error("fromBytes invalid length=" + b.length);
return this.create({
c0: Fp62.fromBytes(b.subarray(0, Fp62.BYTES)),
c1: Fp62.fromBytes(b.subarray(Fp62.BYTES))
});
}
toBytes({ c0, c1 }) {
const { Fp6: Fp62 } = this;
return concatBytes2(Fp62.toBytes(c0), Fp62.toBytes(c1));
}
cmov({ c0, c1 }, { c0: r0, c1: r1 }, c) {
const { Fp6: Fp62 } = this;
return this.create({
c0: Fp62.cmov(c0, r0, c),
c1: Fp62.cmov(c1, r1, c)
});
}
// Utils
// toString() {
// return '' + 'Fp12(' + this.c0 + this.c1 + '* w');
// },
// fromTuple(c: [Fp6, Fp6]) {
// return new Fp12(...c);
// }
fromBigTwelve(tuple) {
const { Fp6: Fp62 } = this;
if (!Array.isArray(tuple) || tuple.length !== 12)
throw new Error("invalid Fp12.fromBigTwelve");
for (let i = 0; i < 12; i++)
if (typeof tuple[i] !== "bigint")
throw new Error("invalid Fp12.fromBigTwelve");
const t2 = tuple;
return this.create({
c0: Fp62.fromBigSix(t2.slice(0, 6)),
c1: Fp62.fromBigSix(t2.slice(6, 12))
});
}
// Raises to q**i -th power
frobeniusMap(lhs, power) {
const p = power % 12;
if (p === 0)
return Object.freeze({ c0: lhs.c0, c1: lhs.c1 });
if (p === 6)
return this.conjugate(lhs);
const { Fp6: Fp62 } = this;
const { Fp2: Fp22 } = Fp62;
const { c0, c1, c2 } = Fp62.frobeniusMap(lhs.c1, power);
const coeff = this.FROBENIUS_COEFFICIENTS[p];
return Object.freeze({
c0: Fp62.frobeniusMap(lhs.c0, power),
c1: Object.freeze({
c0: Fp22.mul(c0, coeff),
c1: Fp22.mul(c1, coeff),
c2: Fp22.mul(c2, coeff)
})
});
}
mulByFp2({ c0, c1 }, rhs) {
const { Fp6: Fp62 } = this;
return Object.freeze({
c0: Fp62.mulByFp2(c0, rhs),
c1: Fp62.mulByFp2(c1, rhs)
});
}
conjugate({ c0, c1 }) {
return Object.freeze({ c0, c1: this.Fp6.neg(c1) });
}
// A cyclotomic group is a subgroup of Fp^n defined by
// GΦₙ(p) = {α ∈ Fpⁿ : α^Φₙ(p) = 1}
// The result of any pairing is in a cyclotomic subgroup
// https://eprint.iacr.org/2009/565.pdf
// https://eprint.iacr.org/2010/354.pdf
_cyclotomicSquare({ c0, c1 }) {
const { Fp6: Fp62 } = this;
const { Fp2: Fp22 } = Fp62;
const { c0: c0c0, c1: c0c1, c2: c0c2 } = c0;
const { c0: c1c0, c1: c1c1, c2: c1c2 } = c1;
const { first: t3, second: t4 } = Fp22.Fp4Square(c0c0, c1c1);
const { first: t5, second: t6 } = Fp22.Fp4Square(c1c0, c0c2);
const { first: t7, second: t8 } = Fp22.Fp4Square(c0c1, c1c2);
const t9 = Fp22.mulByNonresidue(t8);
return Object.freeze({
c0: Object.freeze({
c0: Fp22.add(Fp22.mul(Fp22.sub(t3, c0c0), _2n6), t3),
// 2 * (T3 - c0c0) + T3
c1: Fp22.add(Fp22.mul(Fp22.sub(t5, c0c1), _2n6), t5),
// 2 * (T5 - c0c1) + T5
c2: Fp22.add(Fp22.mul(Fp22.sub(t7, c0c2), _2n6), t7)
}),
// 2 * (T7 - c0c2) + T7
c1: Object.freeze({
c0: Fp22.add(Fp22.mul(Fp22.add(t9, c1c0), _2n6), t9),
// 2 * (T9 + c1c0) + T9
c1: Fp22.add(Fp22.mul(Fp22.add(t4, c1c1), _2n6), t4),
// 2 * (T4 + c1c1) + T4
c2: Fp22.add(Fp22.mul(Fp22.add(t6, c1c2), _2n6), t6)
})
});
}
// https://eprint.iacr.org/2009/565.pdf
_cyclotomicExp(num, n) {
aInRange("cyclotomic exponent", n, _0n8, _1n8 << BigInt(this.X_LEN));
if (n === _0n8)
return this.ONE;
let z = num;
for (let i = bitLen(n) - 2; i >= 0; i--) {
z = this._cyclotomicSquare(z);
if (bitGet(n, i))
z = this.mul(z, num);
}
return z;
}
};
var _FROBENIUS_COEFFICIENTS_12 = /* @__PURE__ */ new WeakMap();
function tower12(opts) {
validateObject(opts, {
ORDER: "bigint",
X_LEN: "number",
FP2_NONRESIDUE: "object",
Fp2mulByB: "function",
Fp12finalExponentiate: "function"
}, { NONRESIDUE: "bigint" });
asafenumber(opts.X_LEN, "X_LEN");
if (opts.X_LEN < 1)
throw new Error("invalid X_LEN");
const nonresidue = opts.FP2_NONRESIDUE;
if (!Array.isArray(nonresidue) || nonresidue.length !== 2)
throw new Error("invalid FP2_NONRESIDUE");
if (typeof nonresidue[0] !== "bigint" || typeof nonresidue[1] !== "bigint")
throw new Error("invalid FP2_NONRESIDUE");
const Fp3 = Field(opts.ORDER);
const Fp22 = new _Field2(Fp3, opts);
const Fp62 = new _Field6(Fp22);
const Fp122 = new _Field12(Fp62, opts);
return { Fp: Fp3, Fp2: Fp22, Fp6: Fp62, Fp12: Fp122 };
}
// tools/reference-apps/light-service/node_modules/@noble/curves/bls12-381.js
/*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) */
var _0n9 = BigInt(0);
var _1n9 = BigInt(1);
var _2n7 = BigInt(2);
var _3n6 = BigInt(3);
var _4n5 = BigInt(4);
var BLS_X = BigInt("0xd201000000010000");
var BLS_X_LEN = bitLen(BLS_X);
var bls12_381_CURVE_G1 = {
p: BigInt("0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab"),
n: BigInt("0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001"),
h: BigInt("0x396c8c005555e1568c00aaab0000aaab"),
a: _0n9,
b: _4n5,
Gx: BigInt("0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb"),
Gy: BigInt("0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1")
};
var bls12_381_Fr = Field(bls12_381_CURVE_G1.n, {
modFromBytes: true
});
function bls12FromCompressed(g0, g12, { g2: g22, g3, g4, g5 }) {
return { c0: { c0: g0, c1: g4, c2: g3 }, c1: { c0: g22, c1: g12, c2: g5 } };
}
function bls12Compress({ c0, c1 }) {
return { g2: c1.c0, g3: c0.c2, g4: c0.c1, g5: c1.c2 };
}
function bls12CyclotomicSquareCompressed({ g2: g22, g3, g4, g5 }) {
const { first: h23c0, second: h23c1 } = Fp2.Fp4Square(g4, g5);
const { first: h45c0, second: h45c1 } = Fp2.Fp4Square(g22, g3);
const d2 = Fp2.add(g22, g22);
const d3 = Fp2.add(g3, g3);
const d4 = Fp2.add(g4, g4);
const d5 = Fp2.add(g5, g5);
return {
g2: Fp2.add(Fp2.mul(Fp2.mulByNonresidue(h23c1), _3n6), d2),
g3: Fp2.sub(Fp2.mul(h23c0, _3n6), d3),
g4: Fp2.sub(Fp2.mul(h45c0, _3n6), d4),
g5: Fp2.add(Fp2.mul(h45c1, _3n6), d5)
};
}
function bls12RecoverG1Ratio({ g2: g22, g3, g4, g5 }) {
if (Fp2.is0(g22))
return { num: Fp2.mul(Fp2.mul(g4, g5), _2n7), den: g3 };
return {
num: Fp2.add(Fp2.sub(Fp2.mul(Fp2.sqr(g4), _3n6), Fp2.mul(g3, _2n7)), Fp2.mulByNonresidue(Fp2.sqr(g5))),
den: Fp2.mul(g22, _4n5)
};
}
function bls12RecoverG0(g12, { g2: g22, g3, g4, g5 }) {
const g3g4 = Fp2.mul(g3, g4);
const t2 = Fp2.add(Fp2.sub(Fp2.mul(Fp2.sub(Fp2.sqr(g12), g3g4), _2n7), g3g4), Fp2.mul(g22, g5));
return Fp2.add(Fp2.mulByNonresidue(t2), Fp2.ONE);
}
function bls12CyclotomicExpCompressed(num, squarings) {
const gs = [];
let g = bls12Compress(num);
for (const count of squarings) {
for (let i = 0; i < count; i++)
g = bls12CyclotomicSquareCompressed(g);
gs.push(g);
}
const isOne = gs.map(({ g2: g22, g3 }) => Fp2.is0(g22) && Fp2.is0(g3));
const ratios = gs.map(bls12RecoverG1Ratio);
const invDens = Fp2.invertBatch(ratios.map(({ den }) => den));
const elems = gs.map((compressed, i) => {
if (isOne[i])
return Fp12.ONE;
const g12 = Fp2.mul(ratios[i].num, invDens[i]);
return bls12FromCompressed(bls12RecoverG0(g12, compressed), g12, compressed);
});
return { result: Fp12.mul(Fp12.mul(elems[0], elems[1]), elems[2]), last: elems[2] };
}
function bls12CyclotomicExpX(num) {
const { result, last } = bls12CyclotomicExpCompressed(num, [16, 32, 9]);
let r2 = result;
let s = last;
for (let i = 0; i < 3; i++)
s = Fp12._cyclotomicSquare(s);
r2 = Fp12.mul(r2, s);
for (let i = 0; i < 2; i++)
s = Fp12._cyclotomicSquare(s);
r2 = Fp12.mul(r2, s);
s = Fp12._cyclotomicSquare(s);
return Fp12.mul(r2, s);
}
var { Fp, Fp2, Fp6, Fp12 } = tower12({
ORDER: bls12_381_CURVE_G1.p,
X_LEN: BLS_X_LEN,
// Finite extension field over irreducible polynominal.
// Fp(u) / (u² - β) where β = -1
// Public `Fp2.NONRESIDUE` below is the sextic-tower value `(1, 1) = u + 1`;
// the quadratic non-residue for the base Fp2 construction is still `-1`.
FP2_NONRESIDUE: [_1n9, _1n9],
Fp2mulByB: ({ c0, c1 }) => {
const t0 = Fp.mul(c0, _4n5);
const t1 = Fp.mul(c1, _4n5);
return { c0: Fp.sub(t0, t1), c1: Fp.add(t0, t1) };
},
Fp12finalExponentiate: (num) => {
const powMinusX = (num2) => Fp12.conjugate(bls12CyclotomicExpX(num2));
const t0 = Fp12.div(Fp12.frobeniusMap(num, 6), num);
const t1 = Fp12.mul(Fp12.frobeniusMap(t0, 2), t0);
const t2 = powMinusX(t1);
const t3 = Fp12.mul(Fp12.conjugate(Fp12._cyclotomicSquare(t1)), t2);
const t4 = powMinusX(t3);
const t5 = powMinusX(t4);
const t6 = Fp12.mul(powMinusX(t5), Fp12._cyclotomicSquare(t2));
const t7 = powMinusX(t6);
const t2_t5_pow_q2 = Fp12.frobeniusMap(Fp12.mul(t2, t5), 2);
const t4_t1_pow_q3 = Fp12.frobeniusMap(Fp12.mul(t4, t1), 3);
const t6_t1c_pow_q1 = Fp12.frobeniusMap(Fp12.mul(t6, Fp12.conjugate(t1)), 1);
const t7_t3c_t1 = Fp12.mul(Fp12.mul(t7, Fp12.conjugate(t3)), t1);
return Fp12.mul(Fp12.mul(Fp12.mul(t2_t5_pow_q2, t4_t1_pow_q3), t6_t1c_pow_q1), t7_t3c_t1);
}
});
var frob;
var getFrob = () => frob || (frob = psiFrobenius(Fp, Fp2, Fp2.div(Fp2.ONE, Fp2.NONRESIDUE)));
var G2psi = (c, P) => {
const fn = getFrob().G2psi;
G2psi = fn;
return fn(c, P);
};
var G2psi2 = (c, P) => {
const fn = getFrob().G2psi2;
G2psi2 = fn;
return fn(c, P);
};
var hasher_opts = Object.freeze({
DST: "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_",
encodeDST: "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_",
p: Fp.ORDER,
m: 2,
k: 128,
expand: "xmd",
hash: sha256
});
var bls12_381_CURVE_G2 = {
p: Fp2.ORDER,
n: bls12_381_CURVE_G1.n,
h: BigInt("0x5d543a95414e7f1091d50792876a202cd91de4547085abaa68a205b2e5a7ddfa628f1cb4d9e82ef21537e293a6691ae1616ec6e786f0c70cf1c38e31c7238e5"),
a: Fp2.ZERO,
b: Fp2.fromBigTuple([_4n5, _4n5]),
Gx: Fp2.fromBigTuple([
BigInt("0x024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8"),
BigInt("0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e")
]),
Gy: Fp2.fromBigTuple([
BigInt("0x0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801"),
BigInt("0x0606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be")
])
};
var sortBit = (parts, p) => {
for (const part of parts) {
if (part !== _0n9)
return Boolean(part * _2n7 / p);
}
return false;
};
var fp2 = {
// Generic tower bytes use `c0 || c1`, but the BLS12-381 G2 point/signature wire encoding uses
// `c1 || c0`, so keep this local wrapper instead of changing generic field serialization.
encode({ c0, c1 }) {
const { BYTES: L } = Fp;
return concatBytes2(numberToBytesBE(c1, L), numberToBytesBE(c0, L));
},
decode(bytes) {
const { BYTES: L } = Fp;
return Fp2.create({
c0: decodeFp(bytes.subarray(L)),
c1: decodeFp(bytes.subarray(0, L))
});
}
};
var BaseFp = Fp;
function decodeFp(bytes) {
return Fp.fromBytes(bytes);
}
var coder = (name, Fp3, b, encode, decode, yparts) => {
const F = Fp3;
const enc = encode;
const dec = decode;
const W = F.BYTES;
return (allowUncompressed) => ({
encode(point, compressed = true) {
if (!compressed && !allowUncompressed)
throw new Error("invalid signature: expected compressed encoding");
const infinity = point.is0();
const { x, y } = point.toAffine();
const bytes = compressed ? enc(x) : concatBytes2(enc(x), enc(y));
let sort;
if (compressed && !infinity)
sort = sortBit(yparts(y), BaseFp.ORDER);
return setMask(bytes, { compressed, infinity, sort });
},
decode(bytes) {
const raw = allowUncompressed ? abytes2(bytes, void 0, "point") : abytes2(bytes, W, "signature");
const { compressed, infinity, sort, value } = parseMask(raw);
if (!allowUncompressed && !compressed)
throw new Error("invalid signature: expected compressed encoding");
const len = compressed ? W : 2 * W;
if (value.length !== len)
throw new Error(`invalid ${name} point: expected ${len} bytes`);
if (infinity) {
for (const b2 of value) {
if (b2)
throw new Error(`invalid ${name} point: non-canonical zero`);
}
return { x: F.ZERO, y: F.ZERO };
}
const x = dec(compressed ? value : value.subarray(0, W));
let y;
if (compressed) {
y = F.sqrt(F.add(F.pow(x, _3n6), b));
if (!y)
throw new Error(`invalid ${name} point: compressed`);
if (sortBit(yparts(y), BaseFp.ORDER) !== sort)
y = F.neg(y);
} else {
y = dec(value.subarray(W));
}
if (!compressed && F.is0(x) && F.is0(y))
throw new Error(`invalid ${name} point: uncompressed`);
return { x, y };
}
});
};
function validateMask({ compressed, infinity, sort }) {
if (!compressed && !infinity && sort || // 0010_0000 = 0x20
!compressed && infinity && sort || // 0110_0000 = 0x60
compressed && infinity && sort)
throw new Error("invalid encoding flag");
}
function parseMask(bytes) {
bytes = copyBytes2(bytes);
const mask = bytes[0] & 224;
const compressed = !!(mask >> 7 & 1);
const infinity = !!(mask >> 6 & 1);
const sort = !!(mask >> 5 & 1);
validateMask({ compressed, infinity, sort });
bytes[0] &= 31;
return { compressed, infinity, sort, value: bytes };
}
function setMask(bytes, mask) {
if (bytes[0] & 224)
throw new Error("setMask: non-empty mask");
validateMask({ compressed: !!mask.compressed, infinity: !!mask.infinity, sort: !!mask.sort });
if (mask.compressed)
bytes[0] |= 128;
if (mask.infinity)
bytes[0] |= 64;
if (mask.sort)
bytes[0] |= 32;
return bytes;
}
var g1coder = coder("G1", Fp, Fp.create(bls12_381_CURVE_G1.b), (x) => numberToBytesBE(x, Fp.BYTES), decodeFp, (y) => [y]);
var g1 = { point: g1coder(true), sig: g1coder(false) };
var signatureG1ToBytes = (point) => {
point.assertValidity();
return g1.sig.encode(point);
};
function signatureG1FromBytes(bytes) {
const Point = bls12_381.G1.Point;
const point = Point.fromAffine(g1.sig.decode(bytes));
point.assertValidity();
return point;
}
var g2coder = coder("G2", Fp2, bls12_381_CURVE_G2.b, fp2.encode, fp2.decode, (y) => [
y.c1,
y.c0
]);
var g2 = { point: g2coder(true), sig: g2coder(false) };
var signatureG2ToBytes = (point) => {
point.assertValidity();
return g2.sig.encode(point);
};
function signatureG2FromBytes(bytes) {
const Point = bls12_381.G2.Point;
const point = Point.fromAffine(g2.sig.decode(bytes));
point.assertValidity();
return point;
}
var signatureCoders = {
ShortSignature: {
fromBytes(bytes) {
return signatureG1FromBytes(abytes2(bytes));
},
fromHex(hex) {
return signatureG1FromBytes(hexToBytes2(hex));
},
toBytes(point) {
return signatureG1ToBytes(point);
},
// Historical alias: BLS signatures have a single compressed byte format here.
toRawBytes(point) {
return signatureG1ToBytes(point);
},
toHex(point) {
return bytesToHex2(signatureG1ToBytes(point));
}
},
LongSignature: {
fromBytes(bytes) {
return signatureG2FromBytes(abytes2(bytes));
},
fromHex(hex) {
return signatureG2FromBytes(hexToBytes2(hex));
},
toBytes(point) {
return signatureG2ToBytes(point);
},
// Historical alias: BLS signatures have a single compressed byte format here.
toRawBytes(point) {
return signatureG2ToBytes(point);
},
toHex(point) {
return bytesToHex2(signatureG2ToBytes(point));
}
}
};
var fields = {
Fp,
Fp2,
Fp6,
Fp12,
Fr: bls12_381_Fr
};
var G1_Point = weierstrass(bls12_381_CURVE_G1, {
// Public point APIs still accept infinity, even though the Zcash proof
// encoding rules cited above only define nonzero point encodings.
allowInfinityPoint: true,
Fn: bls12_381_Fr,
fromBytes: g1.point.decode,
toBytes: (_c, point, isComp) => g1.point.encode(point, isComp),
// Checks is the point resides in prime-order subgroup.
// point.isTorsionFree() should return true for valid points
// It returns false for shitty points.
// https://eprint.iacr.org/2021/1130.pdf
isTorsionFree: (c, point) => {
const beta = BigInt("0x5f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe");
const phi = new c(Fp.mul(point.X, beta), point.Y, point.Z);
const xP = point.multiplyUnsafe(BLS_X).negate();
const u2P = xP.multiplyUnsafe(BLS_X);
return u2P.equals(phi);
},
// Clear cofactor of G1
// https://eprint.iacr.org/2019/403
clearCofactor: (_c, point) => {
return point.multiplyUnsafe(BLS_X).add(point);
}
});
var G2_Point = weierstrass(bls12_381_CURVE_G2, {
Fp: Fp2,
// Public point APIs still accept infinity, even though the Zcash proof
// encoding rules cited above only define nonzero point encodings.
allowInfinityPoint: true,
Fn: bls12_381_Fr,
fromBytes: g2.point.decode,
toBytes: (_c, point, isComp) => g2.point.encode(point, isComp),
// https://eprint.iacr.org/2021/1130.pdf
// Older version: https://eprint.iacr.org/2019/814.pdf
isTorsionFree: (c, P) => {
return P.multiplyUnsafe(BLS_X).negate().equals(G2psi(c, P));
},
// clear_cofactor_bls12381_g2 from RFC 9380.
// https://eprint.iacr.org/2017/419.pdf
// prettier-ignore
clearCofactor: (c, P) => {
const x = BLS_X;
let t1 = P.multiplyUnsafe(x).negate();
let t2 = G2psi(c, P);
let t3 = P.double();
t3 = G2psi2(c, t3);
t3 = t3.subtract(t2);
t2 = t1.add(t2);
t2 = t2.multiplyUnsafe(x).negate();
t3 = t3.add(t2);
t3 = t3.subtract(t1);
const Q = t3.subtract(P);
return Q;
}
});
var bls12_hasher_opts = {
mapToG1,
mapToG2,
hasherOpts: hasher_opts,
// RFC 9380 Appendix J defines distinct G1/G2 RO and NU suite IDs, and
// draft-irtf-cfrg-bls-signature-06 §4.2.1 gives separate G1/G2 `_NUL_` DSTs.
// Keep G1 encode-to-curve on the G1 domain instead of inheriting G2's `encodeDST`.
hasherOptsG1: {
...hasher_opts,
m: 1,
DST: "BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_",
encodeDST: "BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_"
},
hasherOptsG2: { ...hasher_opts }
};
var bls12_params = {
ateLoopSize: BLS_X,
// The BLS parameter x for BLS12-381
xNegative: true,
twistType: "multiplicative",
randomBytes: randomBytes2
};
var bls12_381 = bls(fields, G1_Point, G2_Point, bls12_params, bls12_hasher_opts, signatureCoders);
var isogenyMapG2 = isogenyMap(Fp2, [
// xNum
[
[
"0x5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97d6",
"0x5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97d6"
],
[
"0x0",
"0x11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71a"
],
[
"0x11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71e",
"0x8ab05f8bdd54cde190937e76bc3e447cc27c3d6fbd7063fcd104635a790520c0a395554e5c6aaaa9354ffffffffe38d"
],
[
"0x171d6541fa38ccfaed6dea691f5fb614cb14b4e7f4e810aa22d6108f142b85757098e38d0f671c7188e2aaaaaaaa5ed1",
"0x0"
]
],
// xDen
[
[
"0x0",
"0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa63"
],
[
"0xc",
"0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa9f"
],
["0x1", "0x0"]
// LAST 1
],
// yNum
[
[
"0x1530477c7ab4113b59a4c18b076d11930f7da5d4a07f649bf54439d87d27e500fc8c25ebf8c92f6812cfc71c71c6d706",
"0x1530477c7ab4113b59a4c18b076d11930f7da5d4a07f649bf54439d87d27e500fc8c25ebf8c92f6812cfc71c71c6d706"
],
[
"0x0",
"0x5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97be"
],
[
"0x11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71c",
"0x8ab05f8bdd54cde190937e76bc3e447cc27c3d6fbd7063fcd104635a790520c0a395554e5c6aaaa9354ffffffffe38f"
],
[
"0x124c9ad43b6cf79bfbf7043de3811ad0761b0f37a1e26286b0e977c69aa274524e79097a56dc4bd9e1b371c71c718b10",
"0x0"
]
],
// yDen
[
[
"0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa8fb",
"0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa8fb"
],
[
"0x0",
"0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa9d3"
],
[
"0x12",
"0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa99"
],
["0x1", "0x0"]
// LAST 1
]
].map((i) => i.map((pair) => Fp2.fromBigTuple(pair.map(BigInt)))));
var isogenyMapG1 = isogenyMap(Fp, [
// xNum
[
"0x11a05f2b1e833340b809101dd99815856b303e88a2d7005ff2627b56cdb4e2c85610c2d5f2e62d6eaeac1662734649b7",
"0x17294ed3e943ab2f0588bab22147a81c7c17e75b2f6a8417f565e33c70d1e86b4838f2a6f318c356e834eef1b3cb83bb",
"0xd54005db97678ec1d1048c5d10a9a1bce032473295983e56878e501ec68e25c958c3e3d2a09729fe0179f9dac9edcb0",
"0x1778e7166fcc6db74e0609d307e55412d7f5e4656a8dbf25f1b33289f1b330835336e25ce3107193c5b388641d9b6861",
"0xe99726a3199f4436642b4b3e4118e5499db995a1257fb3f086eeb65982fac18985a286f301e77c451154ce9ac8895d9",
"0x1630c3250d7313ff01d1201bf7a74ab5db3cb17dd952799b9ed3ab9097e68f90a0870d2dcae73d19cd13c1c66f652983",
"0xd6ed6553fe44d296a3726c38ae652bfb11586264f0f8ce19008e218f9c86b2a8da25128c1052ecaddd7f225a139ed84",
"0x17b81e7701abdbe2e8743884d1117e53356de5ab275b4db1a682c62ef0f2753339b7c8f8c8f475af9ccb5618e3f0c88e",
"0x80d3cf1f9a78fc47b90b33563be990dc43b756ce79f5574a2c596c928c5d1de4fa295f296b74e956d71986a8497e317",
"0x169b1f8e1bcfa7c42e0c37515d138f22dd2ecb803a0c5c99676314baf4bb1b7fa3190b2edc0327797f241067be390c9e",
"0x10321da079ce07e272d8ec09d2565b0dfa7dccdde6787f96d50af36003b14866f69b771f8c285decca67df3f1605fb7b",
"0x6e08c248e260e70bd1e962381edee3d31d79d7e22c837bc23c0bf1bc24c6b68c24b1b80b64d391fa9c8ba2e8ba2d229"
],
// xDen
[
"0x8ca8d548cff19ae18b2e62f4bd3fa6f01d5ef4ba35b48ba9c9588617fc8ac62b558d681be343df8993cf9fa40d21b1c",
"0x12561a5deb559c4348b4711298e536367041e8ca0cf0800c0126c2588c48bf5713daa8846cb026e9e5c8276ec82b3bff",
"0xb2962fe57a3225e8137e629bff2991f6f89416f5a718cd1fca64e00b11aceacd6a3d0967c94fedcfcc239ba5cb83e19",
"0x3425581a58ae2fec83aafef7c40eb545b08243f16b1655154cca8abc28d6fd04976d5243eecf5c4130de8938dc62cd8",
"0x13a8e162022914a80a6f1d5f43e7a07dffdfc759a12062bb8d6b44e833b306da9bd29ba81f35781d539d395b3532a21e",
"0xe7355f8e4e667b955390f7f0506c6e9395735e9ce9cad4d0a43bcef24b8982f7400d24bc4228f11c02df9a29f6304a5",
"0x772caacf16936190f3e0c63e0596721570f5799af53a1894e2e073062aede9cea73b3538f0de06cec2574496ee84a3a",
"0x14a7ac2a9d64a8b230b3f5b074cf01996e7f63c21bca68a81996e1cdf9822c580fa5b9489d11e2d311f7d99bbdcc5a5e",
"0xa10ecf6ada54f825e920b3dafc7a3cce07f8d1d7161366b74100da67f39883503826692abba43704776ec3a79a1d641",
"0x95fc13ab9e92ad4476d6e3eb3a56680f682b4ee96f7d03776df533978f31c1593174e4b4b7865002d6384d168ecdd0a",
"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"
// LAST 1
],
// yNum
[
"0x90d97c81ba24ee0259d1f094980dcfa11ad138e48a869522b52af6c956543d3cd0c7aee9b3ba3c2be9845719707bb33",
"0x134996a104ee5811d51036d776fb46831223e96c254f383d0f906343eb67ad34d6c56711962fa8bfe097e75a2e41c696",
"0xcc786baa966e66f4a384c86a3b49942552e2d658a31ce2c344be4b91400da7d26d521628b00523b8dfe240c72de1f6",
"0x1f86376e8981c217898751ad8746757d42aa7b90eeb791c09e4a3ec03251cf9de405aba9ec61deca6355c77b0e5f4cb",
"0x8cc03fdefe0ff135caf4fe2a21529c4195536fbe3ce50b879833fd221351adc2ee7f8dc099040a841b6daecf2e8fedb",
"0x16603fca40634b6a2211e11db8f0a6a074a7d0d4afadb7bd76505c3d3ad5544e203f6326c95a807299b23ab13633a5f0",
"0x4ab0b9bcfac1bbcb2c977d027796b3ce75bb8ca2be184cb5231413c4d634f3747a87ac2460f415ec961f8855fe9d6f2",
"0x987c8d5333ab86fde9926bd2ca6c674170a05bfe3bdd81ffd038da6c26c842642f64550fedfe935a15e4ca31870fb29",
"0x9fc4018bd96684be88c9e221e4da1bb8f3abd16679dc26c1e8b6e6a1f20cabe69d65201c78607a360370e577bdba587",
"0xe1bba7a1186bdb5223abde7ada14a23c42a0ca7915af6fe06985e7ed1e4d43b9b3f7055dd4eba6f2bafaaebca731c30",
"0x19713e47937cd1be0dfd0b8f1d43fb93cd2fcbcb6caf493fd1183e416389e61031bf3a5cce3fbafce813711ad011c132",
"0x18b46a908f36f6deb918c143fed2edcc523559b8aaf0c2462e6bfe7f911f643249d9cdf41b44d606ce07c8a4d0074d8e",
"0xb182cac101b9399d155096004f53f447aa7b12a3426b08ec02710e807b4633f06c851c1919211f20d4c04f00b971ef8",
"0x245a394ad1eca9b72fc00ae7be315dc757b3b080d4c158013e6632d3c40659cc6cf90ad1c232a6442d9d3f5db980133",
"0x5c129645e44cf1102a159f748c4a3fc5e673d81d7e86568d9ab0f5d396a7ce46ba1049b6579afb7866b1e715475224b",
"0x15e6be4e990f03ce4ea50b3b42df2eb5cb181d8f84965a3957add4fa95af01b2b665027efec01c7704b456be69c8b604"
],
// yDen
[
"0x16112c4c3a9c98b252181140fad0eae9601a6de578980be6eec3232b5be72e7a07f3688ef60c206d01479253b03663c1",
"0x1962d75c2381201e1a0cbd6c43c348b885c84ff731c4d59ca4a10356f453e01f78a4260763529e3532f6102c2e49a03d",
"0x58df3306640da276faaae7d6e8eb15778c4855551ae7f310c35a5dd279cd2eca6757cd636f96f891e2538b53dbf67f2",
"0x16b7d288798e5395f20d23bf89edb4d1d115c5dbddbcd30e123da489e726af41727364f2c28297ada8d26d98445f5416",
"0xbe0e079545f43e4b00cc912f8228ddcc6d19c9f0f69bbb0542eda0fc9dec916a20b15dc0fd2ededda39142311a5001d",
"0x8d9e5297186db2d9fb266eaac783182b70152c65550d881c5ecd87b6f0f5a6449f38db9dfa9cce202c6477faaf9b7ac",
"0x166007c08a99db2fc3ba8734ace9824b5eecfdfa8d0cf8ef5dd365bc400a0051d5fa9c01a58b1fb93d1a1399126a775c",
"0x16a3ef08be3ea7ea03bcddfabba6ff6ee5a4375efa1f4fd7feb34fd206357132b920f5b00801dee460ee415a15812ed9",
"0x1866c8ed336c61231a1be54fd1d74cc4f9fb0ce4c6af5920abc5750c4bf39b4852cfe2f7bb9248836b233d9d55535d4a",
"0x167a55cda70a6e1cea820597d94a84903216f763e13d87bb5308592e7ea7d4fbc7385ea3d529b35e346ef48bb8913f55",
"0x4d2f259eea405bd48f010a01ad2911d9c6dd039bb61a6290e591b36e636a5c871a5c29f4f83060400f8b49cba8f6aa8",
"0xaccbb67481d033ff5852c1e48c50c477f94ff8aefce42d28c0f9a88cea7913516f968986f7ebbea9684b529e2561092",
"0xad6b9514c767fe3c3613144b45f1496543346d98adf02267d5ceef9a00d9b8693000763e3b90ac11e99b138573345cc",
"0x2660400eb2e4f3b628bdd0d53cd76f2bf565b94e72927c1cb748df27942480e420517bd8714cc80d1fadc1326ed06f7",
"0xe0fa1d816ddc03e6b24255e0d7819c171c40f65e273b853324efcd6356caa205ca2f570f13497804415473a1d634b8f",
"0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"
// LAST 1
]
].map((i) => i.map((j) => BigInt(j))));
var G1_SWU;
var G2_SWU;
var getG1_SWU = () => G1_SWU || (G1_SWU = mapToCurveSimpleSWU(Fp, {
A: Fp.create(BigInt("0x144698a3b8e9433d693a02c96d4982b0ea985383ee66a8d8e8981aefd881ac98936f8da0e0f97f5cf428082d584c1d")),
B: Fp.create(BigInt("0x12e2908d11688030018b12e8753eee3b2016c1f0f24f4070a0b9c14fcef35ef55a23215a316ceaa5d1cc48e98e172be0")),
Z: Fp.create(BigInt(11))
}));
var getG2_SWU = () => G2_SWU || (G2_SWU = mapToCurveSimpleSWU(Fp2, {
// SWU map for the RFC 9380 §8.8.2 pre-isogeny G2 curve E':
// y² = x³ + 240i * x + 1012 + 1012i
A: Fp2.create({ c0: Fp.create(_0n9), c1: Fp.create(BigInt(240)) }),
// A' = 240 * I
B: Fp2.create({ c0: Fp.create(BigInt(1012)), c1: Fp.create(BigInt(1012)) }),
// B' = 1012 * (1 + I)
Z: Fp2.create({ c0: Fp.create(BigInt(-2)), c1: Fp.create(BigInt(-1)) })
// Z: -(2 + I)
}));
function mapToG1(scalars) {
const { x, y } = getG1_SWU()(Fp.create(scalars[0]));
return isogenyMapG1(x, y);
}
function mapToG2(scalars) {
const { x, y } = getG2_SWU()(Fp2.fromBigTuple(scalars));
return isogenyMapG2(x, y);
}
// site/verify/core.js
var DST_VOTE = "IGNEUM_VOTE_V1_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_";
var KEY_HASH_DOMAIN = "IgneumVoteKeyHash";
var BLOCK_HASH_DOMAIN = "BlockHash";
var te = new TextEncoder();
function hexToBytes3(h) {
if (typeof h !== "string" || h.length % 2 || /[^0-9a-f]/i.test(h)) throw new Error("bad hex");
const out = new Uint8Array(h.length / 2);
for (let i = 0; i < out.length; i++) out[i] = parseInt(h.slice(2 * i, 2 * i + 2), 16);
return out;
}
function bytesToHex3(b) {
let s = "";
for (const x of b) s += x.toString(16).padStart(2, "0");
return s;
}
var u16 = (v) => {
const b = new Uint8Array(2);
new DataView(b.buffer).setUint16(0, Number(v), true);
return b;
};
var u322 = (v) => {
const b = new Uint8Array(4);
new DataView(b.buffer).setUint32(0, Number(v), true);
return b;
};
var u64 = (v) => {
const b = new Uint8Array(8);
new DataView(b.buffer).setBigUint64(0, BigInt(v), true);
return b;
};
function concat(parts) {
const n = parts.reduce((a, p) => a + p.length, 0);
const m = new Uint8Array(n);
let o = 0;
for (const p of parts) {
m.set(p, o);
o += p.length;
}
return m;
}
function headerHash(h, blake2b2) {
const levels = h.parents_by_level || [];
const parts = [u16(h.version), u64(levels.length)];
for (const level of levels) {
parts.push(u64(level.length));
for (const p of level) parts.push(hexToBytes3(p));
}
parts.push(
hexToBytes3(h.hash_merkle_root),
hexToBytes3(h.accepted_id_merkle_root),
hexToBytes3(h.utxo_commitment),
u64(h.timestamp),
u322(h.bits),
u64(h.nonce),
u64(h.daa_score),
u64(h.blue_score)
);
const bw = String(h.blue_work).replace(/^0+/, "");
const bwBytes = bw.length ? hexToBytes3(bw.length % 2 ? "0" + bw : bw) : new Uint8Array(0);
parts.push(u64(bwBytes.length), bwBytes, hexToBytes3(h.pruning_point), hexToBytes3(h.vote_key_hash));
return bytesToHex3(blake2b2(concat(parts), { dkLen: 32, key: te.encode(BLOCK_HASH_DOMAIN) }));
}
function voteKeyHash(pubkey, blake2b2) {
return bytesToHex3(blake2b2(pubkey, { dkLen: 32, key: te.encode(KEY_HASH_DOMAIN) }));
}
function voteMessage(chainId, index, checkpointHex) {
const head = te.encode("igneum-vote-v1/" + chainId);
return concat([head, new Uint8Array([0]), u64(index), hexToBytes3(checkpointHex)]);
}
function signerPositions(bitmapHex, voterCount) {
const bm = hexToBytes3(bitmapHex);
const out = [];
for (let p = 0; p < voterCount; p++) if (bm[p >> 3] & 1 << (p & 7)) out.push(p);
return out;
}
var fail = (reason, extra = {}) => ({ verified: false, reason, ...extra });
function verifyCheckpoint(data, deps2) {
const t0 = (typeof performance !== "undefined" ? performance : Date).now();
const done = (r2) => ({ ...r2, ms: Math.round(((typeof performance !== "undefined" ? performance : Date).now() - t0) * 10) / 10 });
const { blake2b: blake2b2, bls: bls2 } = deps2;
try {
if (!data || !data.ok) return done(fail(data && data.error ? data.error : "no checkpoint data"));
const cert = data.certificate || {};
const index = Number(data.index);
const voters = data.voters || [];
const headers = data.headers || [];
if (!headers.length) return done(fail("no headers"));
let checked = 0;
for (let i = 0; i < headers.length; i++) {
const h = headers[i];
const got = headerHash(h, blake2b2);
if (got !== h.hash) return done(fail(`header ${i} hash does not recompute (${got.slice(0, 12)} vs ${String(h.hash).slice(0, 12)})`, { headers_checked: checked }));
if (i > 0) {
const direct = h.parents_by_level && h.parents_by_level[0] || [];
if (!direct.includes(headers[i - 1].hash)) return done(fail(`header ${i} does not name header ${i - 1} as a parent`, { headers_checked: checked }));
}
checked++;
}
const top = headers[headers.length - 1];
if (top.hash !== data.hash) return done(fail("the last header is not the certified checkpoint block", { headers_checked: checked }));
if (data.previous && headers[0].hash !== data.previous.hash) return done(fail("the first header is not the previous locked checkpoint", { headers_checked: checked }));
if (BigInt(top.blue_score) < 30n * BigInt(index)) return done(fail(`checkpoint ${index} needs blue score at least ${30 * index}, header has ${top.blue_score}`, { headers_checked: checked }));
if (voters.length !== Number(cert.voter_count)) return done(fail(`certificate names ${cert.voter_count} voters, ${voters.length} given`, { headers_checked: checked }));
for (let i = 0; i < voters.length; i++) {
const v = voters[i];
const pk = hexToBytes3(v.pubkey_hex);
if (pk.length !== 48) return done(fail(`voter ${i} key is not 48 bytes`, { headers_checked: checked }));
const derived = voteKeyHash(pk, blake2b2);
if (v.vote_key_hash && derived !== v.vote_key_hash) return done(fail(`voter ${i} key does not hash to its vote_key_hash`, { headers_checked: checked }));
v.vote_key_hash = derived;
if (i > 0 && !(voters[i - 1].vote_key_hash < v.vote_key_hash)) return done(fail("voter list is not in canonical order", { headers_checked: checked }));
if (!(Number(v.weight) >= 0) || !(Number(v.participation) >= 0 && Number(v.participation) <= 1)) return done(fail(`voter ${i} has a bad weight or participation`, { headers_checked: checked }));
}
const positions = signerPositions(cert.bitmap_hex, voters.length);
if (!positions.length) return done(fail("certificate has no signers", { headers_checked: checked }));
const L = bls2.longSignatures;
let aggPk, hm, sigOk;
try {
aggPk = L.aggregatePublicKeys(positions.map((p) => hexToBytes3(voters[p].pubkey_hex)));
hm = L.hash(voteMessage(data.chain_id, index, data.hash), DST_VOTE);
sigOk = L.verify(hexToBytes3(cert.aggregate_signature_hex), hm, aggPk);
} catch (e) {
return done(fail(`signature check failed: ${String(e.message || e).slice(0, 80)}`, { headers_checked: checked, signers: positions.length }));
}
if (!sigOk) return done(fail("aggregate signature does not verify", { headers_checked: checked, signers: positions.length }));
let signed = 0n, total = 0n, active = 0;
for (let i = 0; i < voters.length; i++) {
const w = BigInt(Math.round(Number(voters[i].weight)));
total += w;
active += Number(w) * Number(voters[i].participation);
}
for (const p of positions) signed += BigInt(Math.round(Number(voters[p].weight)));
if (total === 0n) return done(fail("total weight is zero", { headers_checked: checked, signers: positions.length }));
const fracActive = active > 0 ? Number(signed) / active : 0;
const fracTotal = Number(signed) / Number(total);
const quorum = 3 * Number(signed) >= 2 * active;
const floor = 30n * signed >= 17n * total;
const result = {
index,
hash: data.hash,
source: data.source,
network: data.chain_id,
signers: positions.length,
voters: voters.length,
signed_weight: Number(signed),
active_weight: active,
total_weight: Number(total),
weight_fraction_active: Math.round(fracActive * 1e4) / 1e4,
weight_fraction_total: Math.round(fracTotal * 1e4) / 1e4,
headers_checked: checked,
weights_at_index: data.voters_at_index,
weights_exact: Number(data.voters_at_index) === index
};
if (!quorum) return done({ ...fail(`signed weight is ${(fracActive * 100).toFixed(1)}% of active, below 2/3`), ...result });
if (!floor) return done({ ...fail(`signed weight is ${(fracTotal * 100).toFixed(1)}% of total, below 56.7%`), ...result });
return done({ verified: true, ...result });
} catch (e) {
return done(fail(`error: ${String(e.message || e).slice(0, 100)}`));
}
}
// site/lc/core.js
var SEGMENT_RECORD_LEN = 2 + 8 + 8 + 32 + 48 + 20 + 340 + 32 + 96;
var ZERO32 = new Uint8Array(32);
var te2 = new TextEncoder();
var strip = (s) => String(s).replace(/^0x/i, "");
function concat2(parts) {
const n = parts.reduce((a, p) => a + p.length, 0);
const m = new Uint8Array(n);
let o = 0;
for (const p of parts) {
m.set(p, o);
o += p.length;
}
return m;
}
var bigOf = (b) => {
let v = 0n;
for (const x of b) v = v << 8n | BigInt(x);
return v;
};
var keyed = (blake2b2, key) => (data) => blake2b2(data, { dkLen: 32, key: te2.encode(key) });
function merkleRootFromPath(leaf, index, siblings, blake2b2) {
const H = keyed(blake2b2, "MerkleBranchHash");
let h = leaf, i = index;
for (const s of siblings) {
h = i % 2 === 0 ? H(concat2([h, s])) : H(concat2([s, h]));
i = i >> 1;
}
return h;
}
function rlpDecode(b) {
const [item, rest] = rlpItem(b, 0);
if (rest !== b.length) throw new Error("rlp: trailing bytes");
return item;
}
function rlpItem(b, o) {
if (o >= b.length) throw new Error("rlp: short");
const x = b[o];
if (x < 128) return [b.subarray(o, o + 1), o + 1];
if (x < 184) {
const n2 = x - 128;
return [b.subarray(o + 1, o + 1 + n2), o + 1 + n2];
}
if (x < 192) {
const ll = x - 183;
const n2 = Number(bigOf(b.subarray(o + 1, o + 1 + ll)));
return [b.subarray(o + 1 + ll, o + 1 + ll + n2), o + 1 + ll + n2];
}
let n, start;
if (x < 248) {
n = x - 192;
start = o + 1;
} else {
const ll = x - 247;
n = Number(bigOf(b.subarray(o + 1, o + 1 + ll)));
start = o + 1 + ll;
}
const end = start + n;
if (end > b.length) throw new Error("rlp: list overruns");
const items = [];
let p = start;
while (p < end) {
const [it, q] = rlpItem(b, p);
items.push(it);
p = q;
}
return [items, end];
}
function verifyHeaderPath(headers, blake2b2, fromHash, toHash) {
if (!headers.length) throw new Error("no headers");
for (let i = 0; i < headers.length; i++) {
const h = headers[i];
const got = headerHash(h, blake2b2);
if (got !== strip(h.hash)) throw new Error(`header ${i} (${strip(h.hash).slice(0, 12)}) does not recompute: ${got.slice(0, 12)}`);
if (i > 0) {
const direct = h.parents_by_level && h.parents_by_level[0] || [];
if (!direct.includes(strip(headers[i - 1].hash))) throw new Error(`header ${i} does not name header ${i - 1} as a direct parent`);
}
}
if (fromHash && strip(headers[0].hash) !== strip(fromHash)) throw new Error("the first header is not the block the proof starts from");
if (toHash && strip(headers[headers.length - 1].hash) !== strip(toHash)) throw new Error("the last header is not the certified checkpoint");
return headers.length;
}
function verifyReceipt(receipt2, deps2) {
const { blake2b: blake2b2, bls: bls2, keccak } = deps2;
const steps = [];
const t0 = now();
const step = (name, fn) => {
try {
const d = fn();
steps.push({ name, ok: true, detail: d });
return d;
} catch (e) {
steps.push({ name, ok: false, detail: String(e.message || e) });
throw e;
}
};
const done = (extra) => ({ ...extra, steps, ms: Math.round((now() - t0) * 10) / 10 });
try {
const cp = receipt2.checkpoint.certificate;
const cert = step("certificate: BLS aggregate over the checkpoint, 2/3 of active and 17/30 of total weight", () => {
const r2 = verifyCheckpoint(cp, { blake2b: blake2b2, bls: bls2 });
if (!r2.verified) throw new Error(r2.reason);
if (strip(cp.hash) !== strip(receipt2.checkpoint.hash) || receipt2.chain_id !== cp.chain_id) throw new Error("the receipt names another checkpoint or chain than its certificate");
return `checkpoint ${r2.index} on ${cp.chain_id}, ${r2.signers} of ${r2.voters} voters, ${(r2.weight_fraction_total * 100).toFixed(1)}% of total weight`;
});
const tx = step("the transaction hash is keccak256 of the raw signed transaction", () => {
const raw = hexToBytes3(strip(receipt2.raw_tx_hex));
const h = bytesToHex3(keccak(raw));
if (h !== strip(receipt2.tx_hash)) throw new Error(`the raw bytes hash to ${h.slice(0, 12)}, not ${strip(receipt2.tx_hash).slice(0, 12)}`);
return parseTx(raw);
});
const n = step("header chain from the including block up to the checkpoint (every hash recomputed, every parent link checked)", () => verifyHeaderPath(receipt2.headers, blake2b2, receipt2.including_block.header.hash, cp.hash));
step("the transaction is a leaf of the including block's hash_merkle_root", () => {
const ib = receipt2.including_block;
const sibs = ib.merkle_siblings.map((s) => hexToBytes3(strip(s)));
const root = merkleRootFromPath(hexToBytes3(strip(receipt2.tx_hash)), Number(ib.leaf_index), sibs, blake2b2);
if (bytesToHex3(root) !== strip(receipt2.headers[0].hash_merkle_root)) throw new Error("the merkle path does not reach the including block's hash_merkle_root");
return `leaf ${ib.leaf_index} of ${ib.leaf_count}`;
});
return done({ verified: true, tx, headers: n, checkpoint: Number(cp.index), certificate: cert, block: strip(receipt2.headers[0].hash), block_daa: receipt2.headers[0].daa_score, block_time: receipt2.headers[0].timestamp });
} catch (e) {
return done({ verified: false, reason: String(e.message || e) });
}
}
function parseTx(raw) {
const type = raw[0] <= 127 ? raw[0] : 0;
const body = rlpDecode(type ? raw.subarray(1) : raw);
const hex = (b) => "0x" + bytesToHex3(b);
if (type === 2) return { type, chain_id: bigOf(body[0]).toString(), nonce: bigOf(body[1]).toString(), to: body[5].length ? hex(body[5]) : null, value: bigOf(body[6]).toString(), data: hex(body[7]), gas: bigOf(body[4]).toString() };
if (type === 1) return { type, chain_id: bigOf(body[0]).toString(), nonce: bigOf(body[1]).toString(), to: body[4].length ? hex(body[4]) : null, value: bigOf(body[5]).toString(), data: hex(body[6]), gas: bigOf(body[3]).toString() };
return { type: 0, nonce: bigOf(body[0]).toString(), to: body[3].length ? hex(body[3]) : null, value: bigOf(body[4]).toString(), data: hex(body[5]), gas: bigOf(body[2]).toString() };
}
function formatIgn(wei, decimals = 18) {
const v = BigInt(wei);
const base = 10n ** BigInt(decimals);
const whole = v / base;
let frac = (v % base).toString().padStart(decimals, "0").replace(/0+$/, "");
if (frac.length > 6) frac = frac.slice(0, 6);
return whole.toString() + (frac ? "." + frac : "");
}
var now = () => (typeof performance !== "undefined" ? performance : Date).now();
// tools/reference-apps/receipt/verify-receipt.src.mjs
var args = process.argv.slice(2);
var file = args.find((a) => !a.startsWith("--"));
if (!file) {
console.error("usage: node verify-receipt.js receipt.json [--tamper] (Igneum receipt, format igneum-receipt-v1; verifies offline)");
process.exit(2);
}
var receipt = JSON.parse((0, import_node_fs.readFileSync)(file, "utf8"));
if (receipt.format !== "igneum-receipt-v1") {
console.error(`REFUSED: not an igneum-receipt-v1 file (format ${receipt.format})`);
process.exit(1);
}
var deps = { blake2b, bls: bls12_381, keccak: keccak_256 };
var print = (r2) => {
for (const s of r2.steps) console.log(` ${s.ok ? "ok " : "REFUSED"} ${s.name}
${s.detail}`);
};
if (args.includes("--tamper")) {
const bad = JSON.parse(JSON.stringify(receipt));
const h = bad.raw_tx_hex;
const i = 40;
bad.raw_tx_hex = h.slice(0, i) + (parseInt(h[i], 16) ^ 1).toString(16) + h.slice(i + 1);
const t2 = verifyReceipt(bad, deps);
console.log(`tampered copy (one nibble of the raw transaction): ${t2.verified ? "NOT REFUSED, this verifier is broken" : "REFUSED"}${t2.reason ? " :: " + t2.reason : ""}`);
if (t2.verified) process.exit(1);
}
var r = verifyReceipt(receipt, deps);
console.log(`receipt 0x${receipt.tx_hash} on ${receipt.chain_id} (Devnet 3, no value)`);
print(r);
if (!r.verified) {
console.log(`REFUSED: ${r.reason}`);
process.exit(1);
}
var t = r.tx;
console.log(`VERIFIED in ${r.ms} ms: ${formatIgn(t.value)} IGN to ${t.to || "contract creation"} (${t.value} wei), in block ${r.block.slice(0, 16)} at DAA ${r.block_daa} (${new Date(Number(r.block_time)).toISOString()}), final under checkpoint ${r.checkpoint}; ${r.headers} headers checked; ${r.certificate}.`);
console.log("As reported by the node, not proven by this file: from " + (receipt.tx_as_reported && receipt.tx_as_reported.from) + (receipt.execution ? `, execution status ${receipt.execution.status === "0x1" ? "success" : "failed"}` : "") + ". The voter table with weights came from the node (spec 10.1).");