5322 lines
174 KiB
JavaScript
5322 lines
174 KiB
JavaScript
#!/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).");
|