'use strict'; var threads = require('worker_threads'); var crypto = require('crypto'); var os = require('os'); var URL = require('url'); var VM = require('vm'); var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; function getDefaultExportFromCjs (x) { return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } var lib = {}; var FixedMerkleTree = {}; var simpleHash$1 = {}; Object.defineProperty(simpleHash$1, "__esModule", { value: true }); simpleHash$1.simpleHash = void 0; /*** * This is insecure hash function, just for example only * @param data * @param seed * @param hashLength */ function simpleHash(data, seed, hashLength = 40) { const str = data.join(''); let i, l, hval = seed !== null && seed !== void 0 ? seed : 0x811c9dcc5; for (i = 0, l = str.length; i < l; i++) { hval ^= str.charCodeAt(i); hval += (hval << 1) + (hval << 4) + (hval << 6) + (hval << 8) + (hval << 24); } const hash = (hval >>> 0).toString(16); return BigInt('0x' + hash.padEnd(hashLength - (hash.length - 1), '0')).toString(10); } simpleHash$1.simpleHash = simpleHash; simpleHash$1.default = (left, right) => simpleHash([left, right]); var BaseTree$1 = {}; Object.defineProperty(BaseTree$1, "__esModule", { value: true }); BaseTree$1.BaseTree = void 0; class BaseTree { get capacity() { return 2 ** this.levels; } get layers() { return this._layers.slice(); } get zeros() { return this._zeros.slice(); } get elements() { return this._layers[0].slice(); } get root() { var _a; return (_a = this._layers[this.levels][0]) !== null && _a !== void 0 ? _a : this._zeros[this.levels]; } /** * Find an element in the tree * @param elements elements of tree * @param element An element to find * @param comparator A function that checks leaf value equality * @param fromIndex The index to start the search at. If the index is greater than or equal to the array's length, -1 is returned * @returns {number} Index if element is found, otherwise -1 */ static indexOf(elements, element, fromIndex, comparator) { if (comparator) { return elements.findIndex((el) => comparator(element, el)); } else { return elements.indexOf(element, fromIndex); } } /** * Insert new element into the tree * @param element Element to insert */ insert(element) { if (this._layers[0].length >= this.capacity) { throw new Error('Tree is full'); } this.update(this._layers[0].length, element); } /* * Insert multiple elements into the tree. * @param {Array} elements Elements to insert */ bulkInsert(elements) { if (!elements.length) { return; } if (this._layers[0].length + elements.length > this.capacity) { throw new Error('Tree is full'); } // First we insert all elements except the last one // updating only full subtree hashes (all layers where inserted element has odd index) // the last element will update the full path to the root making the tree consistent again for (let i = 0; i < elements.length - 1; i++) { this._layers[0].push(elements[i]); let level = 0; let index = this._layers[0].length - 1; while (index % 2 === 1) { level++; index >>= 1; const left = this._layers[level - 1][index * 2]; const right = this._layers[level - 1][index * 2 + 1]; this._layers[level][index] = this._hashFn(left, right); } } this.insert(elements[elements.length - 1]); } /** * Change an element in the tree * @param {number} index Index of element to change * @param element Updated element value */ update(index, element) { if (isNaN(Number(index)) || index < 0 || index > this._layers[0].length || index >= this.capacity) { throw new Error('Insert index out of bounds: ' + index); } this._layers[0][index] = element; this._processUpdate(index); } /** * Get merkle path to a leaf * @param {number} index Leaf index to generate path for * @returns {{pathElements: Object[], pathIndex: number[]}} An object containing adjacent elements and left-right index */ path(index) { if (isNaN(Number(index)) || index < 0 || index >= this._layers[0].length) { throw new Error('Index out of bounds: ' + index); } let elIndex = +index; const pathElements = []; const pathIndices = []; const pathPositions = []; for (let level = 0; level < this.levels; level++) { pathIndices[level] = elIndex % 2; const leafIndex = elIndex ^ 1; if (leafIndex < this._layers[level].length) { pathElements[level] = this._layers[level][leafIndex]; pathPositions[level] = leafIndex; } else { pathElements[level] = this._zeros[level]; pathPositions[level] = 0; } elIndex >>= 1; } return { pathElements, pathIndices, pathPositions, pathRoot: this.root, }; } _buildZeros() { this._zeros = [this.zeroElement]; for (let i = 1; i <= this.levels; i++) { this._zeros[i] = this._hashFn(this._zeros[i - 1], this._zeros[i - 1]); } } _processNodes(nodes, layerIndex) { const length = nodes.length; let currentLength = Math.ceil(length / 2); const currentLayer = new Array(currentLength); currentLength--; const starFrom = length - ((length % 2) ^ 1); let j = 0; for (let i = starFrom; i >= 0; i -= 2) { if (nodes[i - 1] === undefined) break; const left = nodes[i - 1]; const right = (i === starFrom && length % 2 === 1) ? this._zeros[layerIndex - 1] : nodes[i]; currentLayer[currentLength - j] = this._hashFn(left, right); j++; } return currentLayer; } _processUpdate(index) { for (let level = 1; level <= this.levels; level++) { index >>= 1; const left = this._layers[level - 1][index * 2]; const right = index * 2 + 1 < this._layers[level - 1].length ? this._layers[level - 1][index * 2 + 1] : this._zeros[level - 1]; this._layers[level][index] = this._hashFn(left, right); } } } BaseTree$1.BaseTree = BaseTree; var __importDefault$1 = (commonjsGlobal && commonjsGlobal.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(FixedMerkleTree, "__esModule", { value: true }); const simpleHash_1$1 = __importDefault$1(simpleHash$1); const BaseTree_1$1 = BaseTree$1; class MerkleTree extends BaseTree_1$1.BaseTree { constructor(levels, elements = [], { hashFunction = simpleHash_1$1.default, zeroElement = 0, } = {}) { super(); this.levels = levels; if (elements.length > this.capacity) { throw new Error('Tree is full'); } this._hashFn = hashFunction; this.zeroElement = zeroElement; this._layers = []; const leaves = elements.slice(); this._layers = [leaves]; this._buildZeros(); this._buildHashes(); } _buildHashes() { for (let layerIndex = 1; layerIndex <= this.levels; layerIndex++) { const nodes = this._layers[layerIndex - 1]; this._layers[layerIndex] = this._processNodes(nodes, layerIndex); } } /** * Insert multiple elements into the tree. * @param {Array} elements Elements to insert */ bulkInsert(elements) { if (!elements.length) { return; } if (this._layers[0].length + elements.length > this.capacity) { throw new Error('Tree is full'); } // First we insert all elements except the last one // updating only full subtree hashes (all layers where inserted element has odd index) // the last element will update the full path to the root making the tree consistent again for (let i = 0; i < elements.length - 1; i++) { this._layers[0].push(elements[i]); let level = 0; let index = this._layers[0].length - 1; while (index % 2 === 1) { level++; index >>= 1; this._layers[level][index] = this._hashFn(this._layers[level - 1][index * 2], this._layers[level - 1][index * 2 + 1]); } } this.insert(elements[elements.length - 1]); } indexOf(element, comparator) { return BaseTree_1$1.BaseTree.indexOf(this._layers[0], element, 0, comparator); } proof(element) { const index = this.indexOf(element); return this.path(index); } getTreeEdge(edgeIndex) { const edgeElement = this._layers[0][edgeIndex]; if (edgeElement === undefined) { throw new Error('Element not found'); } const edgePath = this.path(edgeIndex); return { edgePath, edgeElement, edgeIndex, edgeElementsCount: this._layers[0].length }; } /** * 🪓 * @param count */ getTreeSlices(count = 4) { const length = this._layers[0].length; let size = Math.ceil(length / count); if (size % 2) size++; const slices = []; for (let i = 0; i < length; i += size) { const edgeLeft = i; const edgeRight = i + size; slices.push({ edge: this.getTreeEdge(edgeLeft), elements: this.elements.slice(edgeLeft, edgeRight) }); } return slices; } /** * Serialize entire tree state including intermediate layers into a plain object * Deserializing it back will not require to recompute any hashes * Elements are not converted to a plain type, this is responsibility of the caller */ serialize() { return { levels: this.levels, _zeros: this._zeros, _layers: this._layers, }; } /** * Deserialize data into a MerkleTree instance * Make sure to provide the same hashFunction as was used in the source tree, * otherwise the tree state will be invalid */ static deserialize(data, hashFunction) { const instance = Object.assign(Object.create(this.prototype), data); instance._hashFn = hashFunction || simpleHash_1$1.default; instance.zeroElement = instance._zeros[0]; return instance; } toString() { return JSON.stringify(this.serialize()); } } FixedMerkleTree.default = MerkleTree; var PartialMerkleTree$1 = {}; var __importDefault = (commonjsGlobal && commonjsGlobal.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(PartialMerkleTree$1, "__esModule", { value: true }); PartialMerkleTree$1.PartialMerkleTree = void 0; const simpleHash_1 = __importDefault(simpleHash$1); const BaseTree_1 = BaseTree$1; class PartialMerkleTree extends BaseTree_1.BaseTree { constructor(levels, { edgePath, edgeElement, edgeIndex, edgeElementsCount, }, leaves, { hashFunction, zeroElement } = {}) { super(); if (edgeIndex + leaves.length !== edgeElementsCount) throw new Error('Invalid number of elements'); this._edgeLeafProof = edgePath; this._initialRoot = edgePath.pathRoot; this.zeroElement = zeroElement !== null && zeroElement !== void 0 ? zeroElement : 0; this._edgeLeaf = { data: edgeElement, index: edgeIndex }; this._leavesAfterEdge = leaves; this.levels = levels; this._hashFn = hashFunction || simpleHash_1.default; this._createProofMap(); this._buildTree(); } get edgeIndex() { return this._edgeLeaf.index; } get edgeElement() { return this._edgeLeaf.data; } get edgeLeafProof() { return this._edgeLeafProof; } _createProofMap() { this._proofMap = this.edgeLeafProof.pathPositions.reduce((p, c, i) => { p.set(i, [c, this.edgeLeafProof.pathElements[i]]); return p; }, new Map()); this._proofMap.set(this.levels, [0, this.edgeLeafProof.pathRoot]); } _buildTree() { const edgeLeafIndex = this._edgeLeaf.index; this._leaves = Array(edgeLeafIndex).concat(this._leavesAfterEdge); if (this._proofMap.has(0)) { const [proofPos, proofEl] = this._proofMap.get(0); this._leaves[proofPos] = proofEl; } this._layers = [this._leaves]; this._buildZeros(); this._buildHashes(); } _buildHashes() { for (let layerIndex = 1; layerIndex <= this.levels; layerIndex++) { const nodes = this._layers[layerIndex - 1]; const currentLayer = this._processNodes(nodes, layerIndex); if (this._proofMap.has(layerIndex)) { const [proofPos, proofEl] = this._proofMap.get(layerIndex); if (!currentLayer[proofPos]) currentLayer[proofPos] = proofEl; } this._layers[layerIndex] = currentLayer; } } /** * Change an element in the tree * @param {number} index Index of element to change * @param element Updated element value */ update(index, element) { if (isNaN(Number(index)) || index < 0 || index > this._layers[0].length || index >= this.capacity) { throw new Error('Insert index out of bounds: ' + index); } if (index < this._edgeLeaf.index) { throw new Error(`Index ${index} is below the edge: ${this._edgeLeaf.index}`); } this._layers[0][index] = element; this._processUpdate(index); } path(index) { var _a; if (isNaN(Number(index)) || index < 0 || index >= this._layers[0].length) { throw new Error('Index out of bounds: ' + index); } if (index < this._edgeLeaf.index) { throw new Error(`Index ${index} is below the edge: ${this._edgeLeaf.index}`); } let elIndex = Number(index); const pathElements = []; const pathIndices = []; const pathPositions = []; for (let level = 0; level < this.levels; level++) { pathIndices[level] = elIndex % 2; const leafIndex = elIndex ^ 1; if (leafIndex < this._layers[level].length) { pathElements[level] = this._layers[level][leafIndex]; pathPositions[level] = leafIndex; } else { pathElements[level] = this._zeros[level]; pathPositions[level] = 0; } const [proofPos, proofEl] = this._proofMap.get(level); pathElements[level] = (_a = pathElements[level]) !== null && _a !== void 0 ? _a : (proofPos === leafIndex ? proofEl : this._zeros[level]); elIndex >>= 1; } return { pathElements, pathIndices, pathPositions, pathRoot: this.root, }; } indexOf(element, comparator) { return BaseTree_1.BaseTree.indexOf(this._layers[0], element, this.edgeIndex, comparator); } proof(element) { const index = this.indexOf(element); return this.path(index); } /** * Shifts edge of tree to left * @param edge new TreeEdge below current edge * @param elements leaves between old and new edge */ shiftEdge(edge, elements) { if (this._edgeLeaf.index <= edge.edgeIndex) { throw new Error(`New edgeIndex should be smaller then ${this._edgeLeaf.index}`); } if (elements.length !== (this._edgeLeaf.index - edge.edgeIndex)) { throw new Error(`Elements length should be ${this._edgeLeaf.index - edge.edgeIndex}`); } this._edgeLeafProof = edge.edgePath; this._edgeLeaf = { index: edge.edgeIndex, data: edge.edgeElement }; this._leavesAfterEdge = [...elements, ...this._leavesAfterEdge]; this._createProofMap(); this._buildTree(); } serialize() { return { _edgeLeafProof: this._edgeLeafProof, _edgeLeaf: this._edgeLeaf, _layers: this._layers, _zeros: this._zeros, levels: this.levels, }; } static deserialize(data, hashFunction) { const instance = Object.assign(Object.create(this.prototype), data); instance._hashFn = hashFunction || simpleHash_1.default; instance._initialRoot = data._edgeLeafProof.pathRoot; instance.zeroElement = instance._zeros[0]; instance._leavesAfterEdge = instance._layers[0].slice(data._edgeLeaf.index); instance._createProofMap(); return instance; } toString() { return JSON.stringify(this.serialize()); } } PartialMerkleTree$1.PartialMerkleTree = PartialMerkleTree; (function (exports) { var __importDefault = (commonjsGlobal && commonjsGlobal.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.MerkleTree = exports.simpleHash = exports.PartialMerkleTree = void 0; const FixedMerkleTree_1 = __importDefault(FixedMerkleTree); Object.defineProperty(exports, "MerkleTree", { enumerable: true, get: function () { return FixedMerkleTree_1.default; } }); var PartialMerkleTree_1 = PartialMerkleTree$1; Object.defineProperty(exports, "PartialMerkleTree", { enumerable: true, get: function () { return PartialMerkleTree_1.PartialMerkleTree; } }); var simpleHash_1 = simpleHash$1; Object.defineProperty(exports, "simpleHash", { enumerable: true, get: function () { return simpleHash_1.simpleHash; } }); exports.default = FixedMerkleTree_1.default; } (lib)); /* global BigInt */ const hexLen = [ 0, 1, 2, 2, 3, 3, 3, 3, 4 ,4 ,4 ,4 ,4 ,4 ,4 ,4]; function fromString$2(s, radix) { if ((!radix)||(radix==10)) { return BigInt(s); } else if (radix==16) { if (s.slice(0,2) == "0x") { return BigInt(s); } else { return BigInt("0x"+s); } } } const e$2 = fromString$2; function fromArray$2(a, radix) { let acc =BigInt(0); radix = BigInt(radix); for (let i=0; i> BigInt(n); } const shl$2 = shiftLeft$2; const shr$2 = shiftRight$2; function isOdd$2(a) { return (BigInt(a) & BigInt(1)) == BigInt(1); } function naf$2(n) { let E = BigInt(n); const res = []; while (E) { if (E & BigInt(1)) { const z = 2 - Number(E % BigInt(4)); res.push( z ); E = E - BigInt(z); } else { res.push( 0 ); } E = E >> BigInt(1); } return res; } function bits$2(n) { let E = BigInt(n); const res = []; while (E) { if (E & BigInt(1)) { res.push(1); } else { res.push( 0 ); } E = E >> BigInt(1); } return res; } function toNumber$3(s) { if (s>BigInt(Number.MAX_SAFE_INTEGER )) { throw new Error("Number too big"); } return Number(s); } function toArray$2(s, radix) { const res = []; let rem = BigInt(s); radix = BigInt(radix); while (rem) { res.unshift( Number(rem % radix)); rem = rem / radix; } return res; } function add$2(a, b) { return BigInt(a) + BigInt(b); } function sub$2(a, b) { return BigInt(a) - BigInt(b); } function neg$2(a) { return -BigInt(a); } function mul$2(a, b) { return BigInt(a) * BigInt(b); } function square$2(a) { return BigInt(a) * BigInt(a); } function pow$2(a, b) { return BigInt(a) ** BigInt(b); } function exp$2(a, b) { return BigInt(a) ** BigInt(b); } function abs$2(a) { return BigInt(a) >= 0 ? BigInt(a) : -BigInt(a); } function div$2(a, b) { return BigInt(a) / BigInt(b); } function mod$2(a, b) { return BigInt(a) % BigInt(b); } function eq$2(a, b) { return BigInt(a) == BigInt(b); } function neq$2(a, b) { return BigInt(a) != BigInt(b); } function lt$2(a, b) { return BigInt(a) < BigInt(b); } function gt$2(a, b) { return BigInt(a) > BigInt(b); } function leq$2(a, b) { return BigInt(a) <= BigInt(b); } function geq$2(a, b) { return BigInt(a) >= BigInt(b); } function band$2(a, b) { return BigInt(a) & BigInt(b); } function bor$2(a, b) { return BigInt(a) | BigInt(b); } function bxor$2(a, b) { return BigInt(a) ^ BigInt(b); } function land$2(a, b) { return BigInt(a) && BigInt(b); } function lor$2(a, b) { return BigInt(a) || BigInt(b); } function lnot$2(a) { return !BigInt(a); } var Scalar_native = /*#__PURE__*/Object.freeze({ __proto__: null, abs: abs$2, add: add$2, band: band$2, bitLength: bitLength$2, bits: bits$2, bor: bor$2, bxor: bxor$2, div: div$2, e: e$2, eq: eq$2, exp: exp$2, fromArray: fromArray$2, fromString: fromString$2, geq: geq$2, gt: gt$2, isNegative: isNegative$2, isOdd: isOdd$2, isZero: isZero$2, land: land$2, leq: leq$2, lnot: lnot$2, lor: lor$2, lt: lt$2, mod: mod$2, mul: mul$2, naf: naf$2, neg: neg$2, neq: neq$2, pow: pow$2, shiftLeft: shiftLeft$2, shiftRight: shiftRight$2, shl: shl$2, shr: shr$2, square: square$2, sub: sub$2, toArray: toArray$2, toNumber: toNumber$3 }); var BigInteger = {exports: {}}; (function (module) { var bigInt = (function (undefined$1) { var BASE = 1e7, LOG_BASE = 7, MAX_INT = 9007199254740992, MAX_INT_ARR = smallToArray(MAX_INT), DEFAULT_ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyz"; var supportsNativeBigInt = typeof BigInt === "function"; function Integer(v, radix, alphabet, caseSensitive) { if (typeof v === "undefined") return Integer[0]; if (typeof radix !== "undefined") return +radix === 10 && !alphabet ? parseValue(v) : parseBase(v, radix, alphabet, caseSensitive); return parseValue(v); } function BigInteger(value, sign) { this.value = value; this.sign = sign; this.isSmall = false; } BigInteger.prototype = Object.create(Integer.prototype); function SmallInteger(value) { this.value = value; this.sign = value < 0; this.isSmall = true; } SmallInteger.prototype = Object.create(Integer.prototype); function NativeBigInt(value) { this.value = value; } NativeBigInt.prototype = Object.create(Integer.prototype); function isPrecise(n) { return -MAX_INT < n && n < MAX_INT; } function smallToArray(n) { // For performance reasons doesn't reference BASE, need to change this function if BASE changes if (n < 1e7) return [n]; if (n < 1e14) return [n % 1e7, Math.floor(n / 1e7)]; return [n % 1e7, Math.floor(n / 1e7) % 1e7, Math.floor(n / 1e14)]; } function arrayToSmall(arr) { // If BASE changes this function may need to change trim(arr); var length = arr.length; if (length < 4 && compareAbs(arr, MAX_INT_ARR) < 0) { switch (length) { case 0: return 0; case 1: return arr[0]; case 2: return arr[0] + arr[1] * BASE; default: return arr[0] + (arr[1] + arr[2] * BASE) * BASE; } } return arr; } function trim(v) { var i = v.length; while (v[--i] === 0); v.length = i + 1; } function createArray(length) { // function shamelessly stolen from Yaffle's library https://github.com/Yaffle/BigInteger var x = new Array(length); var i = -1; while (++i < length) { x[i] = 0; } return x; } function truncate(n) { if (n > 0) return Math.floor(n); return Math.ceil(n); } function add(a, b) { // assumes a and b are arrays with a.length >= b.length var l_a = a.length, l_b = b.length, r = new Array(l_a), carry = 0, base = BASE, sum, i; for (i = 0; i < l_b; i++) { sum = a[i] + b[i] + carry; carry = sum >= base ? 1 : 0; r[i] = sum - carry * base; } while (i < l_a) { sum = a[i] + carry; carry = sum === base ? 1 : 0; r[i++] = sum - carry * base; } if (carry > 0) r.push(carry); return r; } function addAny(a, b) { if (a.length >= b.length) return add(a, b); return add(b, a); } function addSmall(a, carry) { // assumes a is array, carry is number with 0 <= carry < MAX_INT var l = a.length, r = new Array(l), base = BASE, sum, i; for (i = 0; i < l; i++) { sum = a[i] - base + carry; carry = Math.floor(sum / base); r[i] = sum - carry * base; carry += 1; } while (carry > 0) { r[i++] = carry % base; carry = Math.floor(carry / base); } return r; } BigInteger.prototype.add = function (v) { var n = parseValue(v); if (this.sign !== n.sign) { return this.subtract(n.negate()); } var a = this.value, b = n.value; if (n.isSmall) { return new BigInteger(addSmall(a, Math.abs(b)), this.sign); } return new BigInteger(addAny(a, b), this.sign); }; BigInteger.prototype.plus = BigInteger.prototype.add; SmallInteger.prototype.add = function (v) { var n = parseValue(v); var a = this.value; if (a < 0 !== n.sign) { return this.subtract(n.negate()); } var b = n.value; if (n.isSmall) { if (isPrecise(a + b)) return new SmallInteger(a + b); b = smallToArray(Math.abs(b)); } return new BigInteger(addSmall(b, Math.abs(a)), a < 0); }; SmallInteger.prototype.plus = SmallInteger.prototype.add; NativeBigInt.prototype.add = function (v) { return new NativeBigInt(this.value + parseValue(v).value); }; NativeBigInt.prototype.plus = NativeBigInt.prototype.add; function subtract(a, b) { // assumes a and b are arrays with a >= b var a_l = a.length, b_l = b.length, r = new Array(a_l), borrow = 0, base = BASE, i, difference; for (i = 0; i < b_l; i++) { difference = a[i] - borrow - b[i]; if (difference < 0) { difference += base; borrow = 1; } else borrow = 0; r[i] = difference; } for (i = b_l; i < a_l; i++) { difference = a[i] - borrow; if (difference < 0) difference += base; else { r[i++] = difference; break; } r[i] = difference; } for (; i < a_l; i++) { r[i] = a[i]; } trim(r); return r; } function subtractAny(a, b, sign) { var value; if (compareAbs(a, b) >= 0) { value = subtract(a, b); } else { value = subtract(b, a); sign = !sign; } value = arrayToSmall(value); if (typeof value === "number") { if (sign) value = -value; return new SmallInteger(value); } return new BigInteger(value, sign); } function subtractSmall(a, b, sign) { // assumes a is array, b is number with 0 <= b < MAX_INT var l = a.length, r = new Array(l), carry = -b, base = BASE, i, difference; for (i = 0; i < l; i++) { difference = a[i] + carry; carry = Math.floor(difference / base); difference %= base; r[i] = difference < 0 ? difference + base : difference; } r = arrayToSmall(r); if (typeof r === "number") { if (sign) r = -r; return new SmallInteger(r); } return new BigInteger(r, sign); } BigInteger.prototype.subtract = function (v) { var n = parseValue(v); if (this.sign !== n.sign) { return this.add(n.negate()); } var a = this.value, b = n.value; if (n.isSmall) return subtractSmall(a, Math.abs(b), this.sign); return subtractAny(a, b, this.sign); }; BigInteger.prototype.minus = BigInteger.prototype.subtract; SmallInteger.prototype.subtract = function (v) { var n = parseValue(v); var a = this.value; if (a < 0 !== n.sign) { return this.add(n.negate()); } var b = n.value; if (n.isSmall) { return new SmallInteger(a - b); } return subtractSmall(b, Math.abs(a), a >= 0); }; SmallInteger.prototype.minus = SmallInteger.prototype.subtract; NativeBigInt.prototype.subtract = function (v) { return new NativeBigInt(this.value - parseValue(v).value); }; NativeBigInt.prototype.minus = NativeBigInt.prototype.subtract; BigInteger.prototype.negate = function () { return new BigInteger(this.value, !this.sign); }; SmallInteger.prototype.negate = function () { var sign = this.sign; var small = new SmallInteger(-this.value); small.sign = !sign; return small; }; NativeBigInt.prototype.negate = function () { return new NativeBigInt(-this.value); }; BigInteger.prototype.abs = function () { return new BigInteger(this.value, false); }; SmallInteger.prototype.abs = function () { return new SmallInteger(Math.abs(this.value)); }; NativeBigInt.prototype.abs = function () { return new NativeBigInt(this.value >= 0 ? this.value : -this.value); }; function multiplyLong(a, b) { var a_l = a.length, b_l = b.length, l = a_l + b_l, r = createArray(l), base = BASE, product, carry, i, a_i, b_j; for (i = 0; i < a_l; ++i) { a_i = a[i]; for (var j = 0; j < b_l; ++j) { b_j = b[j]; product = a_i * b_j + r[i + j]; carry = Math.floor(product / base); r[i + j] = product - carry * base; r[i + j + 1] += carry; } } trim(r); return r; } function multiplySmall(a, b) { // assumes a is array, b is number with |b| < BASE var l = a.length, r = new Array(l), base = BASE, carry = 0, product, i; for (i = 0; i < l; i++) { product = a[i] * b + carry; carry = Math.floor(product / base); r[i] = product - carry * base; } while (carry > 0) { r[i++] = carry % base; carry = Math.floor(carry / base); } return r; } function shiftLeft(x, n) { var r = []; while (n-- > 0) r.push(0); return r.concat(x); } function multiplyKaratsuba(x, y) { var n = Math.max(x.length, y.length); if (n <= 30) return multiplyLong(x, y); n = Math.ceil(n / 2); var b = x.slice(n), a = x.slice(0, n), d = y.slice(n), c = y.slice(0, n); var ac = multiplyKaratsuba(a, c), bd = multiplyKaratsuba(b, d), abcd = multiplyKaratsuba(addAny(a, b), addAny(c, d)); var product = addAny(addAny(ac, shiftLeft(subtract(subtract(abcd, ac), bd), n)), shiftLeft(bd, 2 * n)); trim(product); return product; } // The following function is derived from a surface fit of a graph plotting the performance difference // between long multiplication and karatsuba multiplication versus the lengths of the two arrays. function useKaratsuba(l1, l2) { return -0.012 * l1 - 0.012 * l2 + 0.000015 * l1 * l2 > 0; } BigInteger.prototype.multiply = function (v) { var n = parseValue(v), a = this.value, b = n.value, sign = this.sign !== n.sign, abs; if (n.isSmall) { if (b === 0) return Integer[0]; if (b === 1) return this; if (b === -1) return this.negate(); abs = Math.abs(b); if (abs < BASE) { return new BigInteger(multiplySmall(a, abs), sign); } b = smallToArray(abs); } if (useKaratsuba(a.length, b.length)) // Karatsuba is only faster for certain array sizes return new BigInteger(multiplyKaratsuba(a, b), sign); return new BigInteger(multiplyLong(a, b), sign); }; BigInteger.prototype.times = BigInteger.prototype.multiply; function multiplySmallAndArray(a, b, sign) { // a >= 0 if (a < BASE) { return new BigInteger(multiplySmall(b, a), sign); } return new BigInteger(multiplyLong(b, smallToArray(a)), sign); } SmallInteger.prototype._multiplyBySmall = function (a) { if (isPrecise(a.value * this.value)) { return new SmallInteger(a.value * this.value); } return multiplySmallAndArray(Math.abs(a.value), smallToArray(Math.abs(this.value)), this.sign !== a.sign); }; BigInteger.prototype._multiplyBySmall = function (a) { if (a.value === 0) return Integer[0]; if (a.value === 1) return this; if (a.value === -1) return this.negate(); return multiplySmallAndArray(Math.abs(a.value), this.value, this.sign !== a.sign); }; SmallInteger.prototype.multiply = function (v) { return parseValue(v)._multiplyBySmall(this); }; SmallInteger.prototype.times = SmallInteger.prototype.multiply; NativeBigInt.prototype.multiply = function (v) { return new NativeBigInt(this.value * parseValue(v).value); }; NativeBigInt.prototype.times = NativeBigInt.prototype.multiply; function square(a) { //console.assert(2 * BASE * BASE < MAX_INT); var l = a.length, r = createArray(l + l), base = BASE, product, carry, i, a_i, a_j; for (i = 0; i < l; i++) { a_i = a[i]; carry = 0 - a_i * a_i; for (var j = i; j < l; j++) { a_j = a[j]; product = 2 * (a_i * a_j) + r[i + j] + carry; carry = Math.floor(product / base); r[i + j] = product - carry * base; } r[i + l] = carry; } trim(r); return r; } BigInteger.prototype.square = function () { return new BigInteger(square(this.value), false); }; SmallInteger.prototype.square = function () { var value = this.value * this.value; if (isPrecise(value)) return new SmallInteger(value); return new BigInteger(square(smallToArray(Math.abs(this.value))), false); }; NativeBigInt.prototype.square = function (v) { return new NativeBigInt(this.value * this.value); }; function divMod1(a, b) { // Left over from previous version. Performs faster than divMod2 on smaller input sizes. var a_l = a.length, b_l = b.length, base = BASE, result = createArray(b.length), divisorMostSignificantDigit = b[b_l - 1], // normalization lambda = Math.ceil(base / (2 * divisorMostSignificantDigit)), remainder = multiplySmall(a, lambda), divisor = multiplySmall(b, lambda), quotientDigit, shift, carry, borrow, i, l, q; if (remainder.length <= a_l) remainder.push(0); divisor.push(0); divisorMostSignificantDigit = divisor[b_l - 1]; for (shift = a_l - b_l; shift >= 0; shift--) { quotientDigit = base - 1; if (remainder[shift + b_l] !== divisorMostSignificantDigit) { quotientDigit = Math.floor((remainder[shift + b_l] * base + remainder[shift + b_l - 1]) / divisorMostSignificantDigit); } // quotientDigit <= base - 1 carry = 0; borrow = 0; l = divisor.length; for (i = 0; i < l; i++) { carry += quotientDigit * divisor[i]; q = Math.floor(carry / base); borrow += remainder[shift + i] - (carry - q * base); carry = q; if (borrow < 0) { remainder[shift + i] = borrow + base; borrow = -1; } else { remainder[shift + i] = borrow; borrow = 0; } } while (borrow !== 0) { quotientDigit -= 1; carry = 0; for (i = 0; i < l; i++) { carry += remainder[shift + i] - base + divisor[i]; if (carry < 0) { remainder[shift + i] = carry + base; carry = 0; } else { remainder[shift + i] = carry; carry = 1; } } borrow += carry; } result[shift] = quotientDigit; } // denormalization remainder = divModSmall(remainder, lambda)[0]; return [arrayToSmall(result), arrayToSmall(remainder)]; } function divMod2(a, b) { // Implementation idea shamelessly stolen from Silent Matt's library http://silentmatt.com/biginteger/ // Performs faster than divMod1 on larger input sizes. var a_l = a.length, b_l = b.length, result = [], part = [], base = BASE, guess, xlen, highx, highy, check; while (a_l) { part.unshift(a[--a_l]); trim(part); if (compareAbs(part, b) < 0) { result.push(0); continue; } xlen = part.length; highx = part[xlen - 1] * base + part[xlen - 2]; highy = b[b_l - 1] * base + b[b_l - 2]; if (xlen > b_l) { highx = (highx + 1) * base; } guess = Math.ceil(highx / highy); do { check = multiplySmall(b, guess); if (compareAbs(check, part) <= 0) break; guess--; } while (guess); result.push(guess); part = subtract(part, check); } result.reverse(); return [arrayToSmall(result), arrayToSmall(part)]; } function divModSmall(value, lambda) { var length = value.length, quotient = createArray(length), base = BASE, i, q, remainder, divisor; remainder = 0; for (i = length - 1; i >= 0; --i) { divisor = remainder * base + value[i]; q = truncate(divisor / lambda); remainder = divisor - q * lambda; quotient[i] = q | 0; } return [quotient, remainder | 0]; } function divModAny(self, v) { var value, n = parseValue(v); if (supportsNativeBigInt) { return [new NativeBigInt(self.value / n.value), new NativeBigInt(self.value % n.value)]; } var a = self.value, b = n.value; var quotient; if (b === 0) throw new Error("Cannot divide by zero"); if (self.isSmall) { if (n.isSmall) { return [new SmallInteger(truncate(a / b)), new SmallInteger(a % b)]; } return [Integer[0], self]; } if (n.isSmall) { if (b === 1) return [self, Integer[0]]; if (b == -1) return [self.negate(), Integer[0]]; var abs = Math.abs(b); if (abs < BASE) { value = divModSmall(a, abs); quotient = arrayToSmall(value[0]); var remainder = value[1]; if (self.sign) remainder = -remainder; if (typeof quotient === "number") { if (self.sign !== n.sign) quotient = -quotient; return [new SmallInteger(quotient), new SmallInteger(remainder)]; } return [new BigInteger(quotient, self.sign !== n.sign), new SmallInteger(remainder)]; } b = smallToArray(abs); } var comparison = compareAbs(a, b); if (comparison === -1) return [Integer[0], self]; if (comparison === 0) return [Integer[self.sign === n.sign ? 1 : -1], Integer[0]]; // divMod1 is faster on smaller input sizes if (a.length + b.length <= 200) value = divMod1(a, b); else value = divMod2(a, b); quotient = value[0]; var qSign = self.sign !== n.sign, mod = value[1], mSign = self.sign; if (typeof quotient === "number") { if (qSign) quotient = -quotient; quotient = new SmallInteger(quotient); } else quotient = new BigInteger(quotient, qSign); if (typeof mod === "number") { if (mSign) mod = -mod; mod = new SmallInteger(mod); } else mod = new BigInteger(mod, mSign); return [quotient, mod]; } BigInteger.prototype.divmod = function (v) { var result = divModAny(this, v); return { quotient: result[0], remainder: result[1] }; }; NativeBigInt.prototype.divmod = SmallInteger.prototype.divmod = BigInteger.prototype.divmod; BigInteger.prototype.divide = function (v) { return divModAny(this, v)[0]; }; NativeBigInt.prototype.over = NativeBigInt.prototype.divide = function (v) { return new NativeBigInt(this.value / parseValue(v).value); }; SmallInteger.prototype.over = SmallInteger.prototype.divide = BigInteger.prototype.over = BigInteger.prototype.divide; BigInteger.prototype.mod = function (v) { return divModAny(this, v)[1]; }; NativeBigInt.prototype.mod = NativeBigInt.prototype.remainder = function (v) { return new NativeBigInt(this.value % parseValue(v).value); }; SmallInteger.prototype.remainder = SmallInteger.prototype.mod = BigInteger.prototype.remainder = BigInteger.prototype.mod; BigInteger.prototype.pow = function (v) { var n = parseValue(v), a = this.value, b = n.value, value, x, y; if (b === 0) return Integer[1]; if (a === 0) return Integer[0]; if (a === 1) return Integer[1]; if (a === -1) return n.isEven() ? Integer[1] : Integer[-1]; if (n.sign) { return Integer[0]; } if (!n.isSmall) throw new Error("The exponent " + n.toString() + " is too large."); if (this.isSmall) { if (isPrecise(value = Math.pow(a, b))) return new SmallInteger(truncate(value)); } x = this; y = Integer[1]; while (true) { if (b & 1 === 1) { y = y.times(x); --b; } if (b === 0) break; b /= 2; x = x.square(); } return y; }; SmallInteger.prototype.pow = BigInteger.prototype.pow; NativeBigInt.prototype.pow = function (v) { var n = parseValue(v); var a = this.value, b = n.value; var _0 = BigInt(0), _1 = BigInt(1), _2 = BigInt(2); if (b === _0) return Integer[1]; if (a === _0) return Integer[0]; if (a === _1) return Integer[1]; if (a === BigInt(-1)) return n.isEven() ? Integer[1] : Integer[-1]; if (n.isNegative()) return new NativeBigInt(_0); var x = this; var y = Integer[1]; while (true) { if ((b & _1) === _1) { y = y.times(x); --b; } if (b === _0) break; b /= _2; x = x.square(); } return y; }; BigInteger.prototype.modPow = function (exp, mod) { exp = parseValue(exp); mod = parseValue(mod); if (mod.isZero()) throw new Error("Cannot take modPow with modulus 0"); var r = Integer[1], base = this.mod(mod); if (exp.isNegative()) { exp = exp.multiply(Integer[-1]); base = base.modInv(mod); } while (exp.isPositive()) { if (base.isZero()) return Integer[0]; if (exp.isOdd()) r = r.multiply(base).mod(mod); exp = exp.divide(2); base = base.square().mod(mod); } return r; }; NativeBigInt.prototype.modPow = SmallInteger.prototype.modPow = BigInteger.prototype.modPow; function compareAbs(a, b) { if (a.length !== b.length) { return a.length > b.length ? 1 : -1; } for (var i = a.length - 1; i >= 0; i--) { if (a[i] !== b[i]) return a[i] > b[i] ? 1 : -1; } return 0; } BigInteger.prototype.compareAbs = function (v) { var n = parseValue(v), a = this.value, b = n.value; if (n.isSmall) return 1; return compareAbs(a, b); }; SmallInteger.prototype.compareAbs = function (v) { var n = parseValue(v), a = Math.abs(this.value), b = n.value; if (n.isSmall) { b = Math.abs(b); return a === b ? 0 : a > b ? 1 : -1; } return -1; }; NativeBigInt.prototype.compareAbs = function (v) { var a = this.value; var b = parseValue(v).value; a = a >= 0 ? a : -a; b = b >= 0 ? b : -b; return a === b ? 0 : a > b ? 1 : -1; }; BigInteger.prototype.compare = function (v) { // See discussion about comparison with Infinity: // https://github.com/peterolson/BigInteger.js/issues/61 if (v === Infinity) { return -1; } if (v === -Infinity) { return 1; } var n = parseValue(v), a = this.value, b = n.value; if (this.sign !== n.sign) { return n.sign ? 1 : -1; } if (n.isSmall) { return this.sign ? -1 : 1; } return compareAbs(a, b) * (this.sign ? -1 : 1); }; BigInteger.prototype.compareTo = BigInteger.prototype.compare; SmallInteger.prototype.compare = function (v) { if (v === Infinity) { return -1; } if (v === -Infinity) { return 1; } var n = parseValue(v), a = this.value, b = n.value; if (n.isSmall) { return a == b ? 0 : a > b ? 1 : -1; } if (a < 0 !== n.sign) { return a < 0 ? -1 : 1; } return a < 0 ? 1 : -1; }; SmallInteger.prototype.compareTo = SmallInteger.prototype.compare; NativeBigInt.prototype.compare = function (v) { if (v === Infinity) { return -1; } if (v === -Infinity) { return 1; } var a = this.value; var b = parseValue(v).value; return a === b ? 0 : a > b ? 1 : -1; }; NativeBigInt.prototype.compareTo = NativeBigInt.prototype.compare; BigInteger.prototype.equals = function (v) { return this.compare(v) === 0; }; NativeBigInt.prototype.eq = NativeBigInt.prototype.equals = SmallInteger.prototype.eq = SmallInteger.prototype.equals = BigInteger.prototype.eq = BigInteger.prototype.equals; BigInteger.prototype.notEquals = function (v) { return this.compare(v) !== 0; }; NativeBigInt.prototype.neq = NativeBigInt.prototype.notEquals = SmallInteger.prototype.neq = SmallInteger.prototype.notEquals = BigInteger.prototype.neq = BigInteger.prototype.notEquals; BigInteger.prototype.greater = function (v) { return this.compare(v) > 0; }; NativeBigInt.prototype.gt = NativeBigInt.prototype.greater = SmallInteger.prototype.gt = SmallInteger.prototype.greater = BigInteger.prototype.gt = BigInteger.prototype.greater; BigInteger.prototype.lesser = function (v) { return this.compare(v) < 0; }; NativeBigInt.prototype.lt = NativeBigInt.prototype.lesser = SmallInteger.prototype.lt = SmallInteger.prototype.lesser = BigInteger.prototype.lt = BigInteger.prototype.lesser; BigInteger.prototype.greaterOrEquals = function (v) { return this.compare(v) >= 0; }; NativeBigInt.prototype.geq = NativeBigInt.prototype.greaterOrEquals = SmallInteger.prototype.geq = SmallInteger.prototype.greaterOrEquals = BigInteger.prototype.geq = BigInteger.prototype.greaterOrEquals; BigInteger.prototype.lesserOrEquals = function (v) { return this.compare(v) <= 0; }; NativeBigInt.prototype.leq = NativeBigInt.prototype.lesserOrEquals = SmallInteger.prototype.leq = SmallInteger.prototype.lesserOrEquals = BigInteger.prototype.leq = BigInteger.prototype.lesserOrEquals; BigInteger.prototype.isEven = function () { return (this.value[0] & 1) === 0; }; SmallInteger.prototype.isEven = function () { return (this.value & 1) === 0; }; NativeBigInt.prototype.isEven = function () { return (this.value & BigInt(1)) === BigInt(0); }; BigInteger.prototype.isOdd = function () { return (this.value[0] & 1) === 1; }; SmallInteger.prototype.isOdd = function () { return (this.value & 1) === 1; }; NativeBigInt.prototype.isOdd = function () { return (this.value & BigInt(1)) === BigInt(1); }; BigInteger.prototype.isPositive = function () { return !this.sign; }; SmallInteger.prototype.isPositive = function () { return this.value > 0; }; NativeBigInt.prototype.isPositive = SmallInteger.prototype.isPositive; BigInteger.prototype.isNegative = function () { return this.sign; }; SmallInteger.prototype.isNegative = function () { return this.value < 0; }; NativeBigInt.prototype.isNegative = SmallInteger.prototype.isNegative; BigInteger.prototype.isUnit = function () { return false; }; SmallInteger.prototype.isUnit = function () { return Math.abs(this.value) === 1; }; NativeBigInt.prototype.isUnit = function () { return this.abs().value === BigInt(1); }; BigInteger.prototype.isZero = function () { return false; }; SmallInteger.prototype.isZero = function () { return this.value === 0; }; NativeBigInt.prototype.isZero = function () { return this.value === BigInt(0); }; BigInteger.prototype.isDivisibleBy = function (v) { var n = parseValue(v); if (n.isZero()) return false; if (n.isUnit()) return true; if (n.compareAbs(2) === 0) return this.isEven(); return this.mod(n).isZero(); }; NativeBigInt.prototype.isDivisibleBy = SmallInteger.prototype.isDivisibleBy = BigInteger.prototype.isDivisibleBy; function isBasicPrime(v) { var n = v.abs(); if (n.isUnit()) return false; if (n.equals(2) || n.equals(3) || n.equals(5)) return true; if (n.isEven() || n.isDivisibleBy(3) || n.isDivisibleBy(5)) return false; if (n.lesser(49)) return true; // we don't know if it's prime: let the other functions figure it out } function millerRabinTest(n, a) { var nPrev = n.prev(), b = nPrev, r = 0, d, i, x; while (b.isEven()) b = b.divide(2), r++; next: for (i = 0; i < a.length; i++) { if (n.lesser(a[i])) continue; x = bigInt(a[i]).modPow(b, n); if (x.isUnit() || x.equals(nPrev)) continue; for (d = r - 1; d != 0; d--) { x = x.square().mod(n); if (x.isUnit()) return false; if (x.equals(nPrev)) continue next; } return false; } return true; } // Set "strict" to true to force GRH-supported lower bound of 2*log(N)^2 BigInteger.prototype.isPrime = function (strict) { var isPrime = isBasicPrime(this); if (isPrime !== undefined$1) return isPrime; var n = this.abs(); var bits = n.bitLength(); if (bits <= 64) return millerRabinTest(n, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]); var logN = Math.log(2) * bits.toJSNumber(); var t = Math.ceil((strict === true) ? (2 * Math.pow(logN, 2)) : logN); for (var a = [], i = 0; i < t; i++) { a.push(bigInt(i + 2)); } return millerRabinTest(n, a); }; NativeBigInt.prototype.isPrime = SmallInteger.prototype.isPrime = BigInteger.prototype.isPrime; BigInteger.prototype.isProbablePrime = function (iterations, rng) { var isPrime = isBasicPrime(this); if (isPrime !== undefined$1) return isPrime; var n = this.abs(); var t = iterations === undefined$1 ? 5 : iterations; for (var a = [], i = 0; i < t; i++) { a.push(bigInt.randBetween(2, n.minus(2), rng)); } return millerRabinTest(n, a); }; NativeBigInt.prototype.isProbablePrime = SmallInteger.prototype.isProbablePrime = BigInteger.prototype.isProbablePrime; BigInteger.prototype.modInv = function (n) { var t = bigInt.zero, newT = bigInt.one, r = parseValue(n), newR = this.abs(), q, lastT, lastR; while (!newR.isZero()) { q = r.divide(newR); lastT = t; lastR = r; t = newT; r = newR; newT = lastT.subtract(q.multiply(newT)); newR = lastR.subtract(q.multiply(newR)); } if (!r.isUnit()) throw new Error(this.toString() + " and " + n.toString() + " are not co-prime"); if (t.compare(0) === -1) { t = t.add(n); } if (this.isNegative()) { return t.negate(); } return t; }; NativeBigInt.prototype.modInv = SmallInteger.prototype.modInv = BigInteger.prototype.modInv; BigInteger.prototype.next = function () { var value = this.value; if (this.sign) { return subtractSmall(value, 1, this.sign); } return new BigInteger(addSmall(value, 1), this.sign); }; SmallInteger.prototype.next = function () { var value = this.value; if (value + 1 < MAX_INT) return new SmallInteger(value + 1); return new BigInteger(MAX_INT_ARR, false); }; NativeBigInt.prototype.next = function () { return new NativeBigInt(this.value + BigInt(1)); }; BigInteger.prototype.prev = function () { var value = this.value; if (this.sign) { return new BigInteger(addSmall(value, 1), true); } return subtractSmall(value, 1, this.sign); }; SmallInteger.prototype.prev = function () { var value = this.value; if (value - 1 > -MAX_INT) return new SmallInteger(value - 1); return new BigInteger(MAX_INT_ARR, true); }; NativeBigInt.prototype.prev = function () { return new NativeBigInt(this.value - BigInt(1)); }; var powersOfTwo = [1]; while (2 * powersOfTwo[powersOfTwo.length - 1] <= BASE) powersOfTwo.push(2 * powersOfTwo[powersOfTwo.length - 1]); var powers2Length = powersOfTwo.length, highestPower2 = powersOfTwo[powers2Length - 1]; function shift_isSmall(n) { return Math.abs(n) <= BASE; } BigInteger.prototype.shiftLeft = function (v) { var n = parseValue(v).toJSNumber(); if (!shift_isSmall(n)) { throw new Error(String(n) + " is too large for shifting."); } if (n < 0) return this.shiftRight(-n); var result = this; if (result.isZero()) return result; while (n >= powers2Length) { result = result.multiply(highestPower2); n -= powers2Length - 1; } return result.multiply(powersOfTwo[n]); }; NativeBigInt.prototype.shiftLeft = SmallInteger.prototype.shiftLeft = BigInteger.prototype.shiftLeft; BigInteger.prototype.shiftRight = function (v) { var remQuo; var n = parseValue(v).toJSNumber(); if (!shift_isSmall(n)) { throw new Error(String(n) + " is too large for shifting."); } if (n < 0) return this.shiftLeft(-n); var result = this; while (n >= powers2Length) { if (result.isZero() || (result.isNegative() && result.isUnit())) return result; remQuo = divModAny(result, highestPower2); result = remQuo[1].isNegative() ? remQuo[0].prev() : remQuo[0]; n -= powers2Length - 1; } remQuo = divModAny(result, powersOfTwo[n]); return remQuo[1].isNegative() ? remQuo[0].prev() : remQuo[0]; }; NativeBigInt.prototype.shiftRight = SmallInteger.prototype.shiftRight = BigInteger.prototype.shiftRight; function bitwise(x, y, fn) { y = parseValue(y); var xSign = x.isNegative(), ySign = y.isNegative(); var xRem = xSign ? x.not() : x, yRem = ySign ? y.not() : y; var xDigit = 0, yDigit = 0; var xDivMod = null, yDivMod = null; var result = []; while (!xRem.isZero() || !yRem.isZero()) { xDivMod = divModAny(xRem, highestPower2); xDigit = xDivMod[1].toJSNumber(); if (xSign) { xDigit = highestPower2 - 1 - xDigit; // two's complement for negative numbers } yDivMod = divModAny(yRem, highestPower2); yDigit = yDivMod[1].toJSNumber(); if (ySign) { yDigit = highestPower2 - 1 - yDigit; // two's complement for negative numbers } xRem = xDivMod[0]; yRem = yDivMod[0]; result.push(fn(xDigit, yDigit)); } var sum = fn(xSign ? 1 : 0, ySign ? 1 : 0) !== 0 ? bigInt(-1) : bigInt(0); for (var i = result.length - 1; i >= 0; i -= 1) { sum = sum.multiply(highestPower2).add(bigInt(result[i])); } return sum; } BigInteger.prototype.not = function () { return this.negate().prev(); }; NativeBigInt.prototype.not = SmallInteger.prototype.not = BigInteger.prototype.not; BigInteger.prototype.and = function (n) { return bitwise(this, n, function (a, b) { return a & b; }); }; NativeBigInt.prototype.and = SmallInteger.prototype.and = BigInteger.prototype.and; BigInteger.prototype.or = function (n) { return bitwise(this, n, function (a, b) { return a | b; }); }; NativeBigInt.prototype.or = SmallInteger.prototype.or = BigInteger.prototype.or; BigInteger.prototype.xor = function (n) { return bitwise(this, n, function (a, b) { return a ^ b; }); }; NativeBigInt.prototype.xor = SmallInteger.prototype.xor = BigInteger.prototype.xor; var LOBMASK_I = 1 << 30, LOBMASK_BI = (BASE & -BASE) * (BASE & -BASE) | LOBMASK_I; function roughLOB(n) { // get lowestOneBit (rough) // SmallInteger: return Min(lowestOneBit(n), 1 << 30) // BigInteger: return Min(lowestOneBit(n), 1 << 14) [BASE=1e7] var v = n.value, x = typeof v === "number" ? v | LOBMASK_I : typeof v === "bigint" ? v | BigInt(LOBMASK_I) : v[0] + v[1] * BASE | LOBMASK_BI; return x & -x; } function integerLogarithm(value, base) { if (base.compareTo(value) <= 0) { var tmp = integerLogarithm(value, base.square(base)); var p = tmp.p; var e = tmp.e; var t = p.multiply(base); return t.compareTo(value) <= 0 ? { p: t, e: e * 2 + 1 } : { p: p, e: e * 2 }; } return { p: bigInt(1), e: 0 }; } BigInteger.prototype.bitLength = function () { var n = this; if (n.compareTo(bigInt(0)) < 0) { n = n.negate().subtract(bigInt(1)); } if (n.compareTo(bigInt(0)) === 0) { return bigInt(0); } return bigInt(integerLogarithm(n, bigInt(2)).e).add(bigInt(1)); }; NativeBigInt.prototype.bitLength = SmallInteger.prototype.bitLength = BigInteger.prototype.bitLength; function max(a, b) { a = parseValue(a); b = parseValue(b); return a.greater(b) ? a : b; } function min(a, b) { a = parseValue(a); b = parseValue(b); return a.lesser(b) ? a : b; } function gcd(a, b) { a = parseValue(a).abs(); b = parseValue(b).abs(); if (a.equals(b)) return a; if (a.isZero()) return b; if (b.isZero()) return a; var c = Integer[1], d, t; while (a.isEven() && b.isEven()) { d = min(roughLOB(a), roughLOB(b)); a = a.divide(d); b = b.divide(d); c = c.multiply(d); } while (a.isEven()) { a = a.divide(roughLOB(a)); } do { while (b.isEven()) { b = b.divide(roughLOB(b)); } if (a.greater(b)) { t = b; b = a; a = t; } b = b.subtract(a); } while (!b.isZero()); return c.isUnit() ? a : a.multiply(c); } function lcm(a, b) { a = parseValue(a).abs(); b = parseValue(b).abs(); return a.divide(gcd(a, b)).multiply(b); } function randBetween(a, b, rng) { a = parseValue(a); b = parseValue(b); var usedRNG = rng || Math.random; var low = min(a, b), high = max(a, b); var range = high.subtract(low).add(1); if (range.isSmall) return low.add(Math.floor(usedRNG() * range)); var digits = toBase(range, BASE).value; var result = [], restricted = true; for (var i = 0; i < digits.length; i++) { var top = restricted ? digits[i] + (i + 1 < digits.length ? digits[i + 1] / BASE : 0) : BASE; var digit = truncate(usedRNG() * top); result.push(digit); if (digit < digits[i]) restricted = false; } return low.add(Integer.fromArray(result, BASE, false)); } var parseBase = function (text, base, alphabet, caseSensitive) { alphabet = alphabet || DEFAULT_ALPHABET; text = String(text); if (!caseSensitive) { text = text.toLowerCase(); alphabet = alphabet.toLowerCase(); } var length = text.length; var i; var absBase = Math.abs(base); var alphabetValues = {}; for (i = 0; i < alphabet.length; i++) { alphabetValues[alphabet[i]] = i; } for (i = 0; i < length; i++) { var c = text[i]; if (c === "-") continue; if (c in alphabetValues) { if (alphabetValues[c] >= absBase) { if (c === "1" && absBase === 1) continue; throw new Error(c + " is not a valid digit in base " + base + "."); } } } base = parseValue(base); var digits = []; var isNegative = text[0] === "-"; for (i = isNegative ? 1 : 0; i < text.length; i++) { var c = text[i]; if (c in alphabetValues) digits.push(parseValue(alphabetValues[c])); else if (c === "<") { var start = i; do { i++; } while (text[i] !== ">" && i < text.length); digits.push(parseValue(text.slice(start + 1, i))); } else throw new Error(c + " is not a valid character"); } return parseBaseFromArray(digits, base, isNegative); }; function parseBaseFromArray(digits, base, isNegative) { var val = Integer[0], pow = Integer[1], i; for (i = digits.length - 1; i >= 0; i--) { val = val.add(digits[i].times(pow)); pow = pow.times(base); } return isNegative ? val.negate() : val; } function stringify(digit, alphabet) { alphabet = alphabet || DEFAULT_ALPHABET; if (digit < alphabet.length) { return alphabet[digit]; } return "<" + digit + ">"; } function toBase(n, base) { base = bigInt(base); if (base.isZero()) { if (n.isZero()) return { value: [0], isNegative: false }; throw new Error("Cannot convert nonzero numbers to base 0."); } if (base.equals(-1)) { if (n.isZero()) return { value: [0], isNegative: false }; if (n.isNegative()) return { value: [].concat.apply([], Array.apply(null, Array(-n.toJSNumber())) .map(Array.prototype.valueOf, [1, 0]) ), isNegative: false }; var arr = Array.apply(null, Array(n.toJSNumber() - 1)) .map(Array.prototype.valueOf, [0, 1]); arr.unshift([1]); return { value: [].concat.apply([], arr), isNegative: false }; } var neg = false; if (n.isNegative() && base.isPositive()) { neg = true; n = n.abs(); } if (base.isUnit()) { if (n.isZero()) return { value: [0], isNegative: false }; return { value: Array.apply(null, Array(n.toJSNumber())) .map(Number.prototype.valueOf, 1), isNegative: neg }; } var out = []; var left = n, divmod; while (left.isNegative() || left.compareAbs(base) >= 0) { divmod = left.divmod(base); left = divmod.quotient; var digit = divmod.remainder; if (digit.isNegative()) { digit = base.minus(digit).abs(); left = left.next(); } out.push(digit.toJSNumber()); } out.push(left.toJSNumber()); return { value: out.reverse(), isNegative: neg }; } function toBaseString(n, base, alphabet) { var arr = toBase(n, base); return (arr.isNegative ? "-" : "") + arr.value.map(function (x) { return stringify(x, alphabet); }).join(''); } BigInteger.prototype.toArray = function (radix) { return toBase(this, radix); }; SmallInteger.prototype.toArray = function (radix) { return toBase(this, radix); }; NativeBigInt.prototype.toArray = function (radix) { return toBase(this, radix); }; BigInteger.prototype.toString = function (radix, alphabet) { if (radix === undefined$1) radix = 10; if (radix !== 10 || alphabet) return toBaseString(this, radix, alphabet); var v = this.value, l = v.length, str = String(v[--l]), zeros = "0000000", digit; while (--l >= 0) { digit = String(v[l]); str += zeros.slice(digit.length) + digit; } var sign = this.sign ? "-" : ""; return sign + str; }; SmallInteger.prototype.toString = function (radix, alphabet) { if (radix === undefined$1) radix = 10; if (radix != 10 || alphabet) return toBaseString(this, radix, alphabet); return String(this.value); }; NativeBigInt.prototype.toString = SmallInteger.prototype.toString; NativeBigInt.prototype.toJSON = BigInteger.prototype.toJSON = SmallInteger.prototype.toJSON = function () { return this.toString(); }; BigInteger.prototype.valueOf = function () { return parseInt(this.toString(), 10); }; BigInteger.prototype.toJSNumber = BigInteger.prototype.valueOf; SmallInteger.prototype.valueOf = function () { return this.value; }; SmallInteger.prototype.toJSNumber = SmallInteger.prototype.valueOf; NativeBigInt.prototype.valueOf = NativeBigInt.prototype.toJSNumber = function () { return parseInt(this.toString(), 10); }; function parseStringValue(v) { if (isPrecise(+v)) { var x = +v; if (x === truncate(x)) return supportsNativeBigInt ? new NativeBigInt(BigInt(x)) : new SmallInteger(x); throw new Error("Invalid integer: " + v); } var sign = v[0] === "-"; if (sign) v = v.slice(1); var split = v.split(/e/i); if (split.length > 2) throw new Error("Invalid integer: " + split.join("e")); if (split.length === 2) { var exp = split[1]; if (exp[0] === "+") exp = exp.slice(1); exp = +exp; if (exp !== truncate(exp) || !isPrecise(exp)) throw new Error("Invalid integer: " + exp + " is not a valid exponent."); var text = split[0]; var decimalPlace = text.indexOf("."); if (decimalPlace >= 0) { exp -= text.length - decimalPlace - 1; text = text.slice(0, decimalPlace) + text.slice(decimalPlace + 1); } if (exp < 0) throw new Error("Cannot include negative exponent part for integers"); text += (new Array(exp + 1)).join("0"); v = text; } var isValid = /^([0-9][0-9]*)$/.test(v); if (!isValid) throw new Error("Invalid integer: " + v); if (supportsNativeBigInt) { return new NativeBigInt(BigInt(sign ? "-" + v : v)); } var r = [], max = v.length, l = LOG_BASE, min = max - l; while (max > 0) { r.push(+v.slice(min, max)); min -= l; if (min < 0) min = 0; max -= l; } trim(r); return new BigInteger(r, sign); } function parseNumberValue(v) { if (supportsNativeBigInt) { return new NativeBigInt(BigInt(v)); } if (isPrecise(v)) { if (v !== truncate(v)) throw new Error(v + " is not an integer."); return new SmallInteger(v); } return parseStringValue(v.toString()); } function parseValue(v) { if (typeof v === "number") { return parseNumberValue(v); } if (typeof v === "string") { return parseStringValue(v); } if (typeof v === "bigint") { return new NativeBigInt(v); } return v; } // Pre-define numbers in range [-999,999] for (var i = 0; i < 1000; i++) { Integer[i] = parseValue(i); if (i > 0) Integer[-i] = parseValue(-i); } // Backwards compatibility Integer.one = Integer[1]; Integer.zero = Integer[0]; Integer.minusOne = Integer[-1]; Integer.max = max; Integer.min = min; Integer.gcd = gcd; Integer.lcm = lcm; Integer.isInstance = function (x) { return x instanceof BigInteger || x instanceof SmallInteger || x instanceof NativeBigInt; }; Integer.randBetween = randBetween; Integer.fromArray = function (digits, base, isNegative) { return parseBaseFromArray(digits.map(parseValue), parseValue(base || 10), isNegative); }; return Integer; })(); // Node.js check if (module.hasOwnProperty("exports")) { module.exports = bigInt; } } (BigInteger)); var BigIntegerExports = BigInteger.exports; var bigInt$8 = /*@__PURE__*/getDefaultExportFromCjs(BigIntegerExports); function fromString$1(s, radix) { if (typeof s == "string") { if (s.slice(0,2) == "0x") { return bigInt$8(s.slice(2), 16); } else { return bigInt$8(s,radix); } } else { return bigInt$8(s, radix); } } const e$1 = fromString$1; function fromArray$1(a, radix) { return bigInt$8.fromArray(a, radix); } function bitLength$1(a) { return bigInt$8(a).bitLength(); } function isNegative$1(a) { return bigInt$8(a).isNegative(); } function isZero$1(a) { return bigInt$8(a).isZero(); } function shiftLeft$1(a, n) { return bigInt$8(a).shiftLeft(n); } function shiftRight$1(a, n) { return bigInt$8(a).shiftRight(n); } const shl$1 = shiftLeft$1; const shr$1 = shiftRight$1; function isOdd$1(a) { return bigInt$8(a).isOdd(); } function naf$1(n) { let E = bigInt$8(n); const res = []; while (E.gt(bigInt$8.zero)) { if (E.isOdd()) { const z = 2 - E.mod(4).toJSNumber(); res.push( z ); E = E.minus(z); } else { res.push( 0 ); } E = E.shiftRight(1); } return res; } function bits$1(n) { let E = bigInt$8(n); const res = []; while (E.gt(bigInt$8.zero)) { if (E.isOdd()) { res.push(1); } else { res.push( 0 ); } E = E.shiftRight(1); } return res; } function toNumber$2(s) { if (!s.lt(bigInt$8("9007199254740992", 10))) { throw new Error("Number too big"); } return s.toJSNumber(); } function toArray$1(s, radix) { return bigInt$8(s).toArray(radix); } function add$1(a, b) { return bigInt$8(a).add(bigInt$8(b)); } function sub$1(a, b) { return bigInt$8(a).minus(bigInt$8(b)); } function neg$1(a) { return bigInt$8.zero.minus(bigInt$8(a)); } function mul$1(a, b) { return bigInt$8(a).times(bigInt$8(b)); } function square$1(a) { return bigInt$8(a).square(); } function pow$1(a, b) { return bigInt$8(a).pow(bigInt$8(b)); } function exp$1(a, b) { return bigInt$8(a).pow(bigInt$8(b)); } function abs$1(a) { return bigInt$8(a).abs(); } function div$1(a, b) { return bigInt$8(a).divide(bigInt$8(b)); } function mod$1(a, b) { return bigInt$8(a).mod(bigInt$8(b)); } function eq$1(a, b) { return bigInt$8(a).eq(bigInt$8(b)); } function neq$1(a, b) { return bigInt$8(a).neq(bigInt$8(b)); } function lt$1(a, b) { return bigInt$8(a).lt(bigInt$8(b)); } function gt$1(a, b) { return bigInt$8(a).gt(bigInt$8(b)); } function leq$1(a, b) { return bigInt$8(a).leq(bigInt$8(b)); } function geq$1(a, b) { return bigInt$8(a).geq(bigInt$8(b)); } function band$1(a, b) { return bigInt$8(a).and(bigInt$8(b)); } function bor$1(a, b) { return bigInt$8(a).or(bigInt$8(b)); } function bxor$1(a, b) { return bigInt$8(a).xor(bigInt$8(b)); } function land$1(a, b) { return (!bigInt$8(a).isZero()) && (!bigInt$8(b).isZero()); } function lor$1(a, b) { return (!bigInt$8(a).isZero()) || (!bigInt$8(b).isZero()); } function lnot$1(a) { return bigInt$8(a).isZero(); } var Scalar_bigint = /*#__PURE__*/Object.freeze({ __proto__: null, abs: abs$1, add: add$1, band: band$1, bitLength: bitLength$1, bits: bits$1, bor: bor$1, bxor: bxor$1, div: div$1, e: e$1, eq: eq$1, exp: exp$1, fromArray: fromArray$1, fromString: fromString$1, geq: geq$1, gt: gt$1, isNegative: isNegative$1, isOdd: isOdd$1, isZero: isZero$1, land: land$1, leq: leq$1, lnot: lnot$1, lor: lor$1, lt: lt$1, mod: mod$1, mul: mul$1, naf: naf$1, neg: neg$1, neq: neq$1, pow: pow$1, shiftLeft: shiftLeft$1, shiftRight: shiftRight$1, shl: shl$1, shr: shr$1, square: square$1, sub: sub$1, toArray: toArray$1, toNumber: toNumber$2 }); const supportsNativeBigInt$1 = typeof BigInt === "function"; let Scalar$1 = {}; if (supportsNativeBigInt$1) { Object.assign(Scalar$1, Scalar_native); } else { Object.assign(Scalar$1, Scalar_bigint); } // Returns a buffer with Little Endian Representation Scalar$1.toRprLE = function rprBE(buff, o, e, n8) { const s = "0000000" + e.toString(16); const v = new Uint32Array(buff.buffer, o, n8/4); const l = (((s.length-7)*4 - 1) >> 5)+1; // Number of 32bit words; for (let i=0; i> 5)+1; // Number of 32bit words; for (let i=0; i a[a.length-i-1] = ch.toString(16).padStart(8,"0") ); return Scalar$1.fromString(a.join(""), 16); }; // Pases a buffer with Big Endian Representation Scalar$1.fromRprBE = function rprLEM(buff, o, n8) { n8 = n8 || buff.byteLength; o = o || 0; const v = new DataView(buff.buffer, buff.byteOffset + o, n8); const a = new Array(n8/4); for (let i=0; i>> 0; st[d] = (st[d] ^ st[a]) >>> 0; st[d] = ((st[d] << 16) | ((st[d]>>>16) & 0xFFFF)) >>> 0; st[c] = (st[c] + st[d]) >>> 0; st[b] = (st[b] ^ st[c]) >>> 0; st[b] = ((st[b] << 12) | ((st[b]>>>20) & 0xFFF)) >>> 0; st[a] = (st[a] + st[b]) >>> 0; st[d] = (st[d] ^ st[a]) >>> 0; st[d] = ((st[d] << 8) | ((st[d]>>>24) & 0xFF)) >>> 0; st[c] = (st[c] + st[d]) >>> 0; st[b] = (st[b] ^ st[c]) >>> 0; st[b] = ((st[b] << 7) | ((st[b]>>>25) & 0x7F)) >>> 0; } function doubleRound(st) { quarterRound(st, 0, 4, 8,12); quarterRound(st, 1, 5, 9,13); quarterRound(st, 2, 6,10,14); quarterRound(st, 3, 7,11,15); quarterRound(st, 0, 5,10,15); quarterRound(st, 1, 6,11,12); quarterRound(st, 2, 7, 8,13); quarterRound(st, 3, 4, 9,14); } class ChaCha { constructor(seed) { seed = seed || [0,0,0,0,0,0,0,0]; this.state = [ 0x61707865, 0x3320646E, 0x79622D32, 0x6B206574, seed[0], seed[1], seed[2], seed[3], seed[4], seed[5], seed[6], seed[7], 0, 0, 0, 0 ]; this.idx = 16; this.buff = new Array(16); } nextU32() { if (this.idx == 16) this.update(); return this.buff[this.idx++]; } nextU64() { return add(mul(this.nextU32(), 0x100000000), this.nextU32()); } nextBool() { return (this.nextU32() & 1) == 1; } update() { // Copy the state for (let i=0; i<16; i++) this.buff[i] = this.state[i]; // Apply the rounds for (let i=0; i<10; i++) doubleRound(this.buff); // Add to the initial for (let i=0; i<16; i++) this.buff[i] = (this.buff[i] + this.state[i]) >>> 0; this.idx = 0; this.state[12] = (this.state[12] + 1) >>> 0; if (this.state[12] != 0) return; this.state[13] = (this.state[13] + 1) >>> 0; if (this.state[13] != 0) return; this.state[14] = (this.state[14] + 1) >>> 0; if (this.state[14] != 0) return; this.state[15] = (this.state[15] + 1) >>> 0; } } function getRandomBytes(n) { let array = new Uint8Array(n); if (process.browser) { // Browser if (typeof globalThis.crypto !== "undefined") { // Supported globalThis.crypto.getRandomValues(array); } else { // fallback for (let i=0; i>>0; } } } else { // NodeJS crypto.randomFillSync(array); } return array; } function getRandomSeed() { const arr = getRandomBytes(32); const arrV = new Uint32Array(arr.buffer); const seed = []; for (let i=0; i<8; i++) { seed.push(arrV[i]); } return seed; } let threadRng = null; function getThreadRng() { if (threadRng) return threadRng; threadRng = new ChaCha(getRandomSeed()); return threadRng; } var utils$b = {}; /* Copyright 2019 0KIMS association. This file is part of wasmsnark (Web Assembly zkSnark Prover). wasmsnark is a free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. wasmsnark is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with wasmsnark. If not, see . */ const bigInt$7 = BigIntegerExports; utils$b.bigInt2BytesLE = function bigInt2BytesLE(_a, len) { const b = Array(len); let v = bigInt$7(_a); for (let i=0; i. */ const utils$a = utils$b; var build_int = function buildInt(module, n64, _prefix) { const prefix = _prefix || "int"; if (module.modules[prefix]) return prefix; // already builded module.modules[prefix] = {}; const n32 = n64*2; const n8 = n64*8; module.alloc(n8, utils$a.bigInt2BytesLE(1, n8)); function buildCopy() { const f = module.addFunction(prefix+"_copy"); f.addParam("px", "i32"); f.addParam("pr", "i32"); const c = f.getCodeBuilder(); for (let i=0; i>1) )&&(i>1, k>>1) ) ) ); f.addCode( c.setLocal(c1, c.i64_add( c.getLocal(c1), c.i64_shr_u( c.getLocal(c0), c.i64_const(32) ) ) ) ); } // Add the old carry if (k>0) { f.addCode( c.setLocal(c0, c.i64_add( c.i64_and( c.getLocal(c0), c.i64_const(0xFFFFFFFF) ), c.i64_and( c.getLocal(c0_old), c.i64_const(0xFFFFFFFF) ), ) ) ); f.addCode( c.setLocal(c1, c.i64_add( c.i64_add( c.getLocal(c1), c.i64_shr_u( c.getLocal(c0), c.i64_const(32) ) ), c.getLocal(c1_old) ) ) ); } f.addCode( c.i64_store32( c.getLocal("r"), k*4, c.getLocal(c0) ) ); f.addCode( c.setLocal( c0_old, c.getLocal(c1) ), c.setLocal( c1_old, c.i64_shr_u( c.getLocal(c0_old), c.i64_const(32) ) ) ); } f.addCode( c.i64_store32( c.getLocal("r"), n32*4*2-4, c.getLocal(c0_old) ) ); } function buildSquareOld() { const f = module.addFunction(prefix+"_squareOld"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); f.addCode(c.call(prefix + "_mul", c.getLocal("x"), c.getLocal("x"), c.getLocal("r"))); } function _buildMul1() { const f = module.addFunction(prefix+"__mul1"); f.addParam("px", "i32"); f.addParam("y", "i64"); f.addParam("pr", "i32"); f.addLocal("c", "i64"); const c = f.getCodeBuilder(); f.addCode(c.setLocal( "c", c.i64_mul( c.i64_load32_u(c.getLocal("px"), 0, 0), c.getLocal("y") ) )); f.addCode(c.i64_store32( c.getLocal("pr"), 0, 0, c.getLocal("c"), )); for (let i=1; i3)&&(Y[eY]==0) ey--; f.addCode(c.block(c.loop( c.br_if( 1, c.i32_or( c.i32_load8_u( c.i32_add(Y , c.getLocal("eY")), 0, 0 ), c.i32_eq( c.getLocal("eY"), c.i32_const(3) ) ) ), c.setLocal("eY", c.i32_sub(c.getLocal("eY"), c.i32_const(1))), c.br(0) ))); f.addCode( c.setLocal( "sy", c.i64_add( c.i64_load32_u( c.i32_sub( c.i32_add( Y, c.getLocal("eY")), c.i32_const(3) ), 0, 0 ), c.i64_const(1) ) ) ); // Force a divide by 0 if quotien is 0 f.addCode( c.if( c.i64_eq( c.getLocal("sy"), c.i64_const(1) ), c.drop(c.i64_div_u(c.i64_const(0), c.i64_const(0))) ) ); f.addCode(c.block(c.loop( // while (eX>7)&&(Y[eX]==0) ex--; c.block(c.loop( c.br_if( 1, c.i32_or( c.i32_load8_u( c.i32_add(R , c.getLocal("eX")), 0, 0 ), c.i32_eq( c.getLocal("eX"), c.i32_const(7) ) ) ), c.setLocal("eX", c.i32_sub(c.getLocal("eX"), c.i32_const(1))), c.br(0) )), c.setLocal( "sx", c.i64_load( c.i32_sub( c.i32_add( R, c.getLocal("eX")), c.i32_const(7) ), 0, 0 ) ), c.setLocal( "sx", c.i64_div_u( c.getLocal("sx"), c.getLocal("sy") ) ), c.setLocal( "ec", c.i32_sub( c.i32_sub( c.getLocal("eX"), c.getLocal("eY") ), c.i32_const(4) ) ), // While greater than 32 bits or ec is neg, shr and inc exp c.block(c.loop( c.br_if( 1, c.i32_and( c.i64_eqz( c.i64_and( c.getLocal("sx"), c.i64_const("0xFFFFFFFF00000000") ) ), c.i32_ge_s( c.getLocal("ec"), c.i32_const(0) ) ) ), c.setLocal( "sx", c.i64_shr_u( c.getLocal("sx"), c.i64_const(8) ) ), c.setLocal( "ec", c.i32_add( c.getLocal("ec"), c.i32_const(1) ) ), c.br(0) )), c.if( c.i64_eqz(c.getLocal("sx")), [ ...c.br_if( 2, c.i32_eqz(c.call(prefix + "_gte", R, Y)) ), ...c.setLocal("sx", c.i64_const(1)), ...c.setLocal("ec", c.i32_const(0)) ] ), c.call(prefix + "__mul1", Y, c.getLocal("sx"), R2), c.drop(c.call( prefix + "_sub", R, c.i32_sub(R2, c.getLocal("ec")), R )), c.call( prefix + "__add1", c.i32_add(C, c.getLocal("ec")), c.getLocal("sx") ), c.br(0) ))); } function buildInverseMod() { const f = module.addFunction(prefix+"_inverseMod"); f.addParam("px", "i32"); f.addParam("pm", "i32"); f.addParam("pr", "i32"); f.addLocal("t", "i32"); f.addLocal("newt", "i32"); f.addLocal("r", "i32"); f.addLocal("qq", "i32"); f.addLocal("qr", "i32"); f.addLocal("newr", "i32"); f.addLocal("swp", "i32"); f.addLocal("x", "i32"); f.addLocal("signt", "i32"); f.addLocal("signnewt", "i32"); f.addLocal("signx", "i32"); const c = f.getCodeBuilder(); const aux1 = c.i32_const(module.alloc(n8)); const aux2 = c.i32_const(module.alloc(n8)); const aux3 = c.i32_const(module.alloc(n8)); const aux4 = c.i32_const(module.alloc(n8)); const aux5 = c.i32_const(module.alloc(n8)); const aux6 = c.i32_const(module.alloc(n8)); const mulBuff = c.i32_const(module.alloc(n8*2)); const aux7 = c.i32_const(module.alloc(n8)); f.addCode( c.setLocal("t", aux1), c.call(prefix + "_zero", aux1), c.setLocal("signt", c.i32_const(0)), ); f.addCode( c.setLocal("r", aux2), c.call(prefix + "_copy", c.getLocal("pm"), aux2) ); f.addCode( c.setLocal("newt", aux3), c.call(prefix + "_one", aux3), c.setLocal("signnewt", c.i32_const(0)), ); f.addCode( c.setLocal("newr", aux4), c.call(prefix + "_copy", c.getLocal("px"), aux4) ); f.addCode(c.setLocal("qq", aux5)); f.addCode(c.setLocal("qr", aux6)); f.addCode(c.setLocal("x", aux7)); f.addCode(c.block(c.loop( c.br_if( 1, c.call(prefix + "_isZero", c.getLocal("newr") ) ), c.call(prefix + "_div", c.getLocal("r"), c.getLocal("newr"), c.getLocal("qq"), c.getLocal("qr")), c.call(prefix + "_mul", c.getLocal("qq"), c.getLocal("newt"), mulBuff), c.if( c.getLocal("signt"), c.if( c.getLocal("signnewt"), c.if ( c.call(prefix + "_gte", mulBuff, c.getLocal("t")), [ ...c.drop(c.call(prefix + "_sub", mulBuff, c.getLocal("t"), c.getLocal("x"))), ...c.setLocal("signx", c.i32_const(0)) ], [ ...c.drop(c.call(prefix + "_sub", c.getLocal("t"), mulBuff, c.getLocal("x"))), ...c.setLocal("signx", c.i32_const(1)) ], ), [ ...c.drop(c.call(prefix + "_add", mulBuff, c.getLocal("t"), c.getLocal("x"))), ...c.setLocal("signx", c.i32_const(1)) ] ), c.if( c.getLocal("signnewt"), [ ...c.drop(c.call(prefix + "_add", mulBuff, c.getLocal("t"), c.getLocal("x"))), ...c.setLocal("signx", c.i32_const(0)) ], c.if ( c.call(prefix + "_gte", c.getLocal("t"), mulBuff), [ ...c.drop(c.call(prefix + "_sub", c.getLocal("t"), mulBuff, c.getLocal("x"))), ...c.setLocal("signx", c.i32_const(0)) ], [ ...c.drop(c.call(prefix + "_sub", mulBuff, c.getLocal("t"), c.getLocal("x"))), ...c.setLocal("signx", c.i32_const(1)) ] ) ) ), c.setLocal("swp", c.getLocal("t")), c.setLocal("t", c.getLocal("newt")), c.setLocal("newt", c.getLocal("x")), c.setLocal("x", c.getLocal("swp")), c.setLocal("signt", c.getLocal("signnewt")), c.setLocal("signnewt", c.getLocal("signx")), c.setLocal("swp", c.getLocal("r")), c.setLocal("r", c.getLocal("newr")), c.setLocal("newr", c.getLocal("qr")), c.setLocal("qr", c.getLocal("swp")), c.br(0) ))); f.addCode(c.if( c.getLocal("signt"), c.drop(c.call(prefix + "_sub", c.getLocal("pm"), c.getLocal("t"), c.getLocal("pr"))), c.call(prefix + "_copy", c.getLocal("t"), c.getLocal("pr")) )); } buildCopy(); buildZero(); buildIsZero(); buildOne(); buildEq(); buildGte(); buildAdd(); buildSub(); buildMul(); buildSquare(); buildSquareOld(); buildDiv(); buildInverseMod(); module.exportFunction(prefix+"_copy"); module.exportFunction(prefix+"_zero"); module.exportFunction(prefix+"_one"); module.exportFunction(prefix+"_isZero"); module.exportFunction(prefix+"_eq"); module.exportFunction(prefix+"_gte"); module.exportFunction(prefix+"_add"); module.exportFunction(prefix+"_sub"); module.exportFunction(prefix+"_mul"); module.exportFunction(prefix+"_square"); module.exportFunction(prefix+"_squareOld"); module.exportFunction(prefix+"_div"); module.exportFunction(prefix+"_inverseMod"); return prefix; }; /* Copyright 2019 0KIMS association. This file is part of wasmsnark (Web Assembly zkSnark Prover). wasmsnark is a free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. wasmsnark is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with wasmsnark. If not, see . */ var build_timesscalar = function buildTimesScalar(module, fnName, elementLen, opAB, opAA, opCopy, opInit) { const f = module.addFunction(fnName); f.addParam("base", "i32"); f.addParam("scalar", "i32"); f.addParam("scalarLength", "i32"); f.addParam("r", "i32"); f.addLocal("i", "i32"); f.addLocal("b", "i32"); const c = f.getCodeBuilder(); const aux = c.i32_const(module.alloc(elementLen)); f.addCode( c.if( c.i32_eqz(c.getLocal("scalarLength")), [ ...c.call(opInit, c.getLocal("r")), ...c.ret([]) ] ) ); f.addCode(c.call(opCopy, c.getLocal("base"), aux)); f.addCode(c.call(opInit, c.getLocal("r"))); f.addCode(c.setLocal("i", c.getLocal("scalarLength"))); f.addCode(c.block(c.loop( c.setLocal("i", c.i32_sub(c.getLocal("i"), c.i32_const(1))), c.setLocal( "b", c.i32_load8_u( c.i32_add( c.getLocal("scalar"), c.getLocal("i") ) ) ), ...innerLoop(), c.br_if(1, c.i32_eqz ( c.getLocal("i") )), c.br(0) ))); function innerLoop() { const code = []; for (let i=0; i<8; i++) { code.push( ...c.call(opAA, c.getLocal("r"), c.getLocal("r")), ...c.if( c.i32_ge_u( c.getLocal("b"), c.i32_const(0x80 >> i)), [ ...c.setLocal( "b", c.i32_sub( c.getLocal("b"), c.i32_const(0x80 >> i) ) ), ...c.call(opAB, c.getLocal("r"),aux, c.getLocal("r")) ] ) ); } return code; } }; var build_batchinverse = buildBatchInverse$3; function buildBatchInverse$3(module, prefix) { const n8 = module.modules[prefix].n64*8; const f = module.addFunction(prefix+"_batchInverse"); f.addParam("pIn", "i32"); f.addParam("inStep", "i32"); f.addParam("n", "i32"); f.addParam("pOut", "i32"); f.addParam("outStep", "i32"); f.addLocal("itAux", "i32"); f.addLocal("itIn", "i32"); f.addLocal("itOut","i32"); f.addLocal("i","i32"); const c = f.getCodeBuilder(); const AUX = c.i32_const(module.alloc(n8)); // Alloc Working space for accumulated umltiplications f.addCode( c.setLocal("itAux", c.i32_load( c.i32_const(0) )), c.i32_store( c.i32_const(0), c.i32_add( c.getLocal("itAux"), c.i32_mul( c.i32_add( c.getLocal("n"), c.i32_const(1) ), c.i32_const(n8) ) ) ) ); f.addCode( // aux[0] = a; c.call(prefix+"_one", c.getLocal("itAux")), // for (i=0;i. */ const bigInt$6 = BigIntegerExports; const buildInt = build_int; const utils$9 = utils$b; const buildExp$2 = build_timesscalar; const buildBatchInverse$2 = build_batchinverse; const buildBatchConvertion$1 = build_batchconvertion; const buildBatchOp = build_batchop; var build_f1m = function buildF1m(module, _q, _prefix, _intPrefix) { const q = bigInt$6(_q); const n64 = Math.floor((q.minus(1).bitLength() - 1)/64) +1; const n32 = n64*2; const n8 = n64*8; const prefix = _prefix || "f1m"; if (module.modules[prefix]) return prefix; // already builded const intPrefix = buildInt(module, n64, _intPrefix); const pq = module.alloc(n8, utils$9.bigInt2BytesLE(q, n8)); module.alloc(utils$9.bigInt2BytesLE(bigInt$6.one.shiftLeft(n64*64).mod(q), n8)); const pR2 = module.alloc(utils$9.bigInt2BytesLE(bigInt$6.one.shiftLeft(n64*64).square().mod(q), n8)); const pOne = module.alloc(utils$9.bigInt2BytesLE(bigInt$6.one.shiftLeft(n64*64).mod(q), n8)); const pZero = module.alloc(utils$9.bigInt2BytesLE(bigInt$6.zero, n8)); const _minusOne = q.minus(bigInt$6.one); const _e = _minusOne.shiftRight(1); // e = (p-1)/2 const pe = module.alloc(n8, utils$9.bigInt2BytesLE(_e, n8)); const _ePlusOne = _e.add(bigInt$6.one); // e = (p-1)/2 const pePlusOne = module.alloc(n8, utils$9.bigInt2BytesLE(_ePlusOne, n8)); module.modules[prefix] = { pq: pq, pR2: pR2, n64: n64, q: q, pOne: pOne, pZero: pZero, pePlusOne: pePlusOne }; function buildOne() { const f = module.addFunction(prefix+"_one"); f.addParam("pr", "i32"); const c = f.getCodeBuilder(); f.addCode(c.call(intPrefix + "_copy", c.i32_const(pOne), c.getLocal("pr"))); } function buildAdd() { const f = module.addFunction(prefix+"_add"); f.addParam("x", "i32"); f.addParam("y", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); f.addCode( c.if( c.call(intPrefix+"_add", c.getLocal("x"), c.getLocal("y"), c.getLocal("r")), c.drop(c.call(intPrefix+"_sub", c.getLocal("r"), c.i32_const(pq), c.getLocal("r"))), c.if( c.call(intPrefix+"_gte", c.getLocal("r"), c.i32_const(pq) ), c.drop(c.call(intPrefix+"_sub", c.getLocal("r"), c.i32_const(pq), c.getLocal("r"))), ) ) ); } function buildSub() { const f = module.addFunction(prefix+"_sub"); f.addParam("x", "i32"); f.addParam("y", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); f.addCode( c.if( c.call(intPrefix+"_sub", c.getLocal("x"), c.getLocal("y"), c.getLocal("r")), c.drop(c.call(intPrefix+"_add", c.getLocal("r"), c.i32_const(pq), c.getLocal("r"))) ) ); } function buildNeg() { const f = module.addFunction(prefix+"_neg"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); f.addCode( c.call(prefix + "_sub", c.i32_const(pZero), c.getLocal("x"), c.getLocal("r")) ); } function buildIsNegative() { const f = module.addFunction(prefix+"_isNegative"); f.addParam("x", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); const AUX = c.i32_const(module.alloc(n8)); f.addCode( c.call(prefix + "_fromMontgomery", c.getLocal("x"), AUX), c.call(intPrefix + "_gte", AUX, c.i32_const(pePlusOne) ) ); } /* function buildIsNegative() { const f = module.addFunction(prefix+"_isNegative"); f.addParam("x", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); const AUX = c.i32_const(module.alloc(n8)); f.addCode( c.call(prefix + "_fromMontgomery", c.getLocal("x"), AUX), c.i32_and( c.i32_load(AUX), c.i32_const(1) ) ); } */ function buildSign() { const f = module.addFunction(prefix+"_sign"); f.addParam("x", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); const AUX = c.i32_const(module.alloc(n8)); f.addCode( c.if ( c.call(intPrefix + "_isZero", c.getLocal("x")), c.ret(c.i32_const(0)) ), c.call(prefix + "_fromMontgomery", c.getLocal("x"), AUX), c.if( c.call(intPrefix + "_gte", AUX, c.i32_const(pePlusOne)), c.ret(c.i32_const(-1)) ), c.ret(c.i32_const(1)) ); } function buildMReduct() { const carries = module.alloc(n32*n32*8); const f = module.addFunction(prefix+"_mReduct"); f.addParam("t", "i32"); f.addParam("r", "i32"); f.addLocal("np32", "i64"); f.addLocal("c", "i64"); f.addLocal("m", "i64"); const c = f.getCodeBuilder(); const np32 = bigInt$6("100000000",16).minus( q.modInv(bigInt$6("100000000",16))).toJSNumber(); f.addCode(c.setLocal("np32", c.i64_const(np32))); for (let i=0; i=n32) { f.addCode( c.i64_store32( c.getLocal("r"), (k-n32)*4, c.getLocal(c0) ) ); } [c0, c1] = [c1, c0]; f.addCode( c.setLocal(c1, c.i64_shr_u( c.getLocal(c0), c.i64_const(32) ) ) ); } f.addCode( c.i64_store32( c.getLocal("r"), n32*4-4, c.getLocal(c0) ) ); f.addCode( c.if( c.i32_wrap_i64(c.getLocal(c1)), c.drop(c.call(intPrefix+"_sub", c.getLocal("r"), c.i32_const(pq), c.getLocal("r"))), c.if( c.call(intPrefix+"_gte", c.getLocal("r"), c.i32_const(pq) ), c.drop(c.call(intPrefix+"_sub", c.getLocal("r"), c.i32_const(pq), c.getLocal("r"))), ) ) ); } function buildSquare() { const f = module.addFunction(prefix+"_square"); f.addParam("x", "i32"); f.addParam("r", "i32"); f.addLocal("c0", "i64"); f.addLocal("c1", "i64"); f.addLocal("c0_old", "i64"); f.addLocal("c1_old", "i64"); f.addLocal("np32", "i64"); for (let i=0;i>1) )&&(i>1, k>>1) ) ) ); f.addCode( c.setLocal(c1, c.i64_add( c.getLocal(c1), c.i64_shr_u( c.getLocal(c0), c.i64_const(32) ) ) ) ); } // Add the old carry if (k>0) { f.addCode( c.setLocal(c0, c.i64_add( c.i64_and( c.getLocal(c0), c.i64_const(0xFFFFFFFF) ), c.i64_and( c.getLocal(c0_old), c.i64_const(0xFFFFFFFF) ), ) ) ); f.addCode( c.setLocal(c1, c.i64_add( c.i64_add( c.getLocal(c1), c.i64_shr_u( c.getLocal(c0), c.i64_const(32) ) ), c.getLocal(c1_old) ) ) ); } for (let i=Math.max(1, k-n32+1); (i<=k)&&(i=n32) { f.addCode( c.i64_store32( c.getLocal("r"), (k-n32)*4, c.getLocal(c0) ) ); } f.addCode( c.setLocal( c0_old, c.getLocal(c1) ), c.setLocal( c1_old, c.i64_shr_u( c.getLocal(c0_old), c.i64_const(32) ) ) ); } f.addCode( c.i64_store32( c.getLocal("r"), n32*4-4, c.getLocal(c0_old) ) ); f.addCode( c.if( c.i32_wrap_i64(c.getLocal(c1_old)), c.drop(c.call(intPrefix+"_sub", c.getLocal("r"), c.i32_const(pq), c.getLocal("r"))), c.if( c.call(intPrefix+"_gte", c.getLocal("r"), c.i32_const(pq) ), c.drop(c.call(intPrefix+"_sub", c.getLocal("r"), c.i32_const(pq), c.getLocal("r"))), ) ) ); } function buildSquareOld() { const f = module.addFunction(prefix+"_squareOld"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); f.addCode(c.call(prefix + "_mul", c.getLocal("x"), c.getLocal("x"), c.getLocal("r"))); } function buildToMontgomery() { const f = module.addFunction(prefix+"_toMontgomery"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); f.addCode(c.call(prefix+"_mul", c.getLocal("x"), c.i32_const(pR2), c.getLocal("r"))); } function buildFromMontgomery() { const pAux2 = module.alloc(n8*2); const f = module.addFunction(prefix+"_fromMontgomery"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); f.addCode(c.call(intPrefix + "_copy", c.getLocal("x"), c.i32_const(pAux2) )); f.addCode(c.call(intPrefix + "_zero", c.i32_const(pAux2 + n8) )); f.addCode(c.call(prefix+"_mReduct", c.i32_const(pAux2), c.getLocal("r"))); } function buildInverse() { const f = module.addFunction(prefix+ "_inverse"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); f.addCode(c.call(prefix + "_fromMontgomery", c.getLocal("x"), c.getLocal("r"))); f.addCode(c.call(intPrefix + "_inverseMod", c.getLocal("r"), c.i32_const(pq), c.getLocal("r"))); f.addCode(c.call(prefix + "_toMontgomery", c.getLocal("r"), c.getLocal("r"))); } // Calculate various valuse needed for sqrt let _nqr = bigInt$6(2); if (q.isPrime()) { while (!_nqr.modPow(_e, q).equals(_minusOne)) _nqr = _nqr.add(bigInt$6.one); } module.alloc(utils$9.bigInt2BytesLE(_nqr.shiftLeft(n64*64).mod(q), n8)); let s2 = 0; let _t = _minusOne; while ((!_t.isOdd())&&(!_t.isZero())) { s2++; _t = _t.shiftRight(1); } const pt = module.alloc(n8, utils$9.bigInt2BytesLE(_t, n8)); const _nqrToT = _nqr.modPow(_t, q); const pNqrToT = module.alloc(utils$9.bigInt2BytesLE(_nqrToT.shiftLeft(n64*64).mod(q), n8)); const _tPlusOneOver2 = _t.add(1).shiftRight(1); const ptPlusOneOver2 = module.alloc(n8, utils$9.bigInt2BytesLE(_tPlusOneOver2, n8)); function buildSqrt() { const f = module.addFunction(prefix+ "_sqrt"); f.addParam("n", "i32"); f.addParam("r", "i32"); f.addLocal("m", "i32"); f.addLocal("i", "i32"); f.addLocal("j", "i32"); const c = f.getCodeBuilder(); const ONE = c.i32_const(pOne); const C = c.i32_const(module.alloc(n8)); const T = c.i32_const(module.alloc(n8)); const R = c.i32_const(module.alloc(n8)); const SQ = c.i32_const(module.alloc(n8)); const B = c.i32_const(module.alloc(n8)); f.addCode( // If (n==0) return 0 c.if( c.call(prefix + "_isZero", c.getLocal("n")), c.ret( c.call(prefix + "_zero", c.getLocal("r")) ) ), c.setLocal("m", c.i32_const(s2)), c.call(prefix + "_copy", c.i32_const(pNqrToT), C), c.call(prefix + "_exp", c.getLocal("n"), c.i32_const(pt), c.i32_const(n8), T), c.call(prefix + "_exp", c.getLocal("n"), c.i32_const(ptPlusOneOver2), c.i32_const(n8), R), c.block(c.loop( c.br_if(1, c.call(prefix + "_eq", T, ONE)), c.call(prefix + "_square", T, SQ), c.setLocal("i", c.i32_const(1)), c.block(c.loop( c.br_if(1, c.call(prefix + "_eq", SQ, ONE)), c.call(prefix + "_square", SQ, SQ), c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))), c.br(0) )), c.call(prefix + "_copy", C, B), c.setLocal("j", c.i32_sub(c.i32_sub( c.getLocal("m"), c.getLocal("i")), c.i32_const(1)) ), c.block(c.loop( c.br_if(1, c.i32_eqz(c.getLocal("j"))), c.call(prefix + "_square", B, B), c.setLocal("j", c.i32_sub(c.getLocal("j"), c.i32_const(1))), c.br(0) )), c.setLocal("m", c.getLocal("i")), c.call(prefix + "_square", B, C), c.call(prefix + "_mul", T, C, T), c.call(prefix + "_mul", R, B, R), c.br(0) )), c.if( c.call(prefix + "_isNegative", R), c.call(prefix + "_neg", R, c.getLocal("r")), c.call(prefix + "_copy", R, c.getLocal("r")), ) ); } function buildIsSquare() { const f = module.addFunction(prefix+"_isSquare"); f.addParam("n", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); const ONE = c.i32_const(pOne); const AUX = c.i32_const(module.alloc(n8)); f.addCode( c.if( c.call(prefix + "_isZero", c.getLocal("n")), c.ret(c.i32_const(1)) ), c.call(prefix + "_exp", c.getLocal("n"), c.i32_const(pe), c.i32_const(n8), AUX), c.call(prefix + "_eq", AUX, ONE) ); } function buildLoad() { const f = module.addFunction(prefix+"_load"); f.addParam("scalar", "i32"); f.addParam("scalarLen", "i32"); f.addParam("r", "i32"); f.addLocal("p", "i32"); f.addLocal("l", "i32"); f.addLocal("i", "i32"); f.addLocal("j", "i32"); const c = f.getCodeBuilder(); const R = c.i32_const(module.alloc(n8)); const pAux = module.alloc(n8); const AUX = c.i32_const(pAux); f.addCode( c.call(intPrefix + "_zero", c.getLocal("r")), c.setLocal("i", c.i32_const(n8)), c.setLocal("p", c.getLocal("scalar")), c.block(c.loop( c.br_if(1, c.i32_gt_u(c.getLocal("i"), c.getLocal("scalarLen"))), c.if( c.i32_eq(c.getLocal("i"), c.i32_const(n8)), c.call(prefix + "_one", R), c.call(prefix + "_mul", R, c.i32_const(pR2), R) ), c.call(prefix + "_mul", c.getLocal("p"), R, AUX), c.call(prefix + "_add", c.getLocal("r"), AUX, c.getLocal("r")), c.setLocal("p", c.i32_add(c.getLocal("p"), c.i32_const(n8))), c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(n8))), c.br(0) )), c.setLocal("l", c.i32_rem_u( c.getLocal("scalarLen"), c.i32_const(n8))), c.if(c.i32_eqz(c.getLocal("l")), c.ret([])), c.call(intPrefix + "_zero", AUX), c.setLocal("j", c.i32_const(0)), c.block(c.loop( c.br_if(1, c.i32_eq(c.getLocal("j"), c.getLocal("l"))), c.i32_store8( c.getLocal("j"), pAux, c.i32_load8_u(c.getLocal("p")), ), c.setLocal("p", c.i32_add(c.getLocal("p"), c.i32_const(1))), c.setLocal("j", c.i32_add(c.getLocal("j"), c.i32_const(1))), c.br(0) )), c.if( c.i32_eq(c.getLocal("i"), c.i32_const(n8)), c.call(prefix + "_one", R), c.call(prefix + "_mul", R, c.i32_const(pR2), R) ), c.call(prefix + "_mul", AUX, R, AUX), c.call(prefix + "_add", c.getLocal("r"), AUX, c.getLocal("r")), ); } function buildTimesScalar() { const f = module.addFunction(prefix+"_timesScalar"); f.addParam("x", "i32"); f.addParam("scalar", "i32"); f.addParam("scalarLen", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const AUX = c.i32_const(module.alloc(n8)); f.addCode( c.call(prefix + "_load", c.getLocal("scalar"), c.getLocal("scalarLen"), AUX), c.call(prefix + "_toMontgomery", AUX, AUX), c.call(prefix + "_mul", c.getLocal("x"), AUX, c.getLocal("r")), ); } function buildIsOne() { const f = module.addFunction(prefix+"_isOne"); f.addParam("x", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); f.addCode( c.ret(c.call(intPrefix + "_eq", c.getLocal("x"), c.i32_const(pOne))) ); } module.exportFunction(intPrefix + "_copy", prefix+"_copy"); module.exportFunction(intPrefix + "_zero", prefix+"_zero"); module.exportFunction(intPrefix + "_isZero", prefix+"_isZero"); module.exportFunction(intPrefix + "_eq", prefix+"_eq"); buildIsOne(); buildAdd(); buildSub(); buildNeg(); buildMReduct(); buildMul(); buildSquare(); buildSquareOld(); buildToMontgomery(); buildFromMontgomery(); buildIsNegative(); buildSign(); buildInverse(); buildOne(); buildLoad(); buildTimesScalar(); buildBatchInverse$2(module, prefix); buildBatchConvertion$1(module, prefix + "_batchToMontgomery", prefix + "_toMontgomery", n8, n8); buildBatchConvertion$1(module, prefix + "_batchFromMontgomery", prefix + "_fromMontgomery", n8, n8); buildBatchConvertion$1(module, prefix + "_batchNeg", prefix + "_neg", n8, n8); buildBatchOp(module, prefix + "_batchAdd", prefix + "_add", n8, n8); buildBatchOp(module, prefix + "_batchSub", prefix + "_sub", n8, n8); buildBatchOp(module, prefix + "_batchMul", prefix + "_mul", n8, n8); module.exportFunction(prefix + "_add"); module.exportFunction(prefix + "_sub"); module.exportFunction(prefix + "_neg"); module.exportFunction(prefix + "_isNegative"); module.exportFunction(prefix + "_isOne"); module.exportFunction(prefix + "_sign"); module.exportFunction(prefix + "_mReduct"); module.exportFunction(prefix + "_mul"); module.exportFunction(prefix + "_square"); module.exportFunction(prefix + "_squareOld"); module.exportFunction(prefix + "_fromMontgomery"); module.exportFunction(prefix + "_toMontgomery"); module.exportFunction(prefix + "_inverse"); module.exportFunction(prefix + "_one"); module.exportFunction(prefix + "_load"); module.exportFunction(prefix + "_timesScalar"); buildExp$2( module, prefix + "_exp", n8, prefix + "_mul", prefix + "_square", intPrefix + "_copy", prefix + "_one", ); module.exportFunction(prefix + "_exp"); module.exportFunction(prefix + "_batchInverse"); if (q.isPrime()) { buildSqrt(); buildIsSquare(); module.exportFunction(prefix + "_sqrt"); module.exportFunction(prefix + "_isSquare"); } module.exportFunction(prefix + "_batchToMontgomery"); module.exportFunction(prefix + "_batchFromMontgomery"); // console.log(module.functionIdxByName); return prefix; }; /* Copyright 2019 0KIMS association. This file is part of wasmsnark (Web Assembly zkSnark Prover). wasmsnark is a free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. wasmsnark is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with wasmsnark. If not, see . */ const bigInt$5 = BigIntegerExports; const buildF1m$2 =build_f1m; var build_f1 = function buildF1(module, _q, _prefix, _f1mPrefix, _intPrefix) { const q = bigInt$5(_q); const n64 = Math.floor((q.minus(1).bitLength() - 1)/64) +1; const n8 = n64*8; const prefix = _prefix || "f1"; if (module.modules[prefix]) return prefix; // already builded module.modules[prefix] = { n64: n64 }; const intPrefix = _intPrefix || "int"; const f1mPrefix = buildF1m$2(module, q, _f1mPrefix, intPrefix); const pR2 = module.modules[f1mPrefix].pR2; const pq = module.modules[f1mPrefix].pq; const pePlusOne = module.modules[f1mPrefix].pePlusOne; function buildMul() { const pAux1 = module.alloc(n8); const f = module.addFunction(prefix+ "_mul"); f.addParam("x", "i32"); f.addParam("y", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); f.addCode(c.call(f1mPrefix + "_mul", c.getLocal("x"), c.getLocal("y"), c.i32_const(pAux1))); f.addCode(c.call(f1mPrefix + "_mul", c.i32_const(pAux1), c.i32_const(pR2), c.getLocal("r"))); } function buildSquare() { const f = module.addFunction(prefix+"_square"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); f.addCode(c.call(prefix + "_mul", c.getLocal("x"), c.getLocal("x"), c.getLocal("r"))); } function buildInverse() { const f = module.addFunction(prefix+ "_inverse"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); f.addCode(c.call(intPrefix + "_inverseMod", c.getLocal("x"), c.i32_const(pq), c.getLocal("r"))); } function buildIsNegative() { const f = module.addFunction(prefix+"_isNegative"); f.addParam("x", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); f.addCode( c.call(intPrefix + "_gte", c.getLocal("x"), c.i32_const(pePlusOne) ) ); } buildMul(); buildSquare(); buildInverse(); buildIsNegative(); module.exportFunction(f1mPrefix + "_add", prefix + "_add"); module.exportFunction(f1mPrefix + "_sub", prefix + "_sub"); module.exportFunction(f1mPrefix + "_neg", prefix + "_neg"); module.exportFunction(prefix + "_mul"); module.exportFunction(prefix + "_square"); module.exportFunction(prefix + "_inverse"); module.exportFunction(prefix + "_isNegative"); module.exportFunction(f1mPrefix + "_copy", prefix+"_copy"); module.exportFunction(f1mPrefix + "_zero", prefix+"_zero"); module.exportFunction(f1mPrefix + "_one", prefix+"_one"); module.exportFunction(f1mPrefix + "_isZero", prefix+"_isZero"); module.exportFunction(f1mPrefix + "_eq", prefix+"_eq"); return prefix; }; /* Copyright 2019 0KIMS association. This file is part of wasmsnark (Web Assembly zkSnark Prover). wasmsnark is a free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. wasmsnark is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with wasmsnark. If not, see . */ const buildExp$1 = build_timesscalar; const buildBatchInverse$1 = build_batchinverse; const bigInt$4 = BigIntegerExports; const utils$8 = utils$b; var build_f2m = function buildF2m(module, mulNonResidueFn, prefix, f1mPrefix) { if (module.modules[prefix]) return prefix; // already builded const f1n8 = module.modules[f1mPrefix].n64*8; const q = module.modules[f1mPrefix].q; module.modules[prefix] = { n64: module.modules[f1mPrefix].n64*2 }; function buildAdd() { const f = module.addFunction(prefix+"_add"); f.addParam("x", "i32"); f.addParam("y", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const y0 = c.getLocal("y"); const y1 = c.i32_add(c.getLocal("y"), c.i32_const(f1n8)); const r0 = c.getLocal("r"); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8)); f.addCode( c.call(f1mPrefix+"_add", x0, y0, r0), c.call(f1mPrefix+"_add", x1, y1, r1), ); } function buildTimesScalar() { const f = module.addFunction(prefix+"_timesScalar"); f.addParam("x", "i32"); f.addParam("scalar", "i32"); f.addParam("scalarLen", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const r0 = c.getLocal("r"); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8)); f.addCode( c.call(f1mPrefix+"_timesScalar", x0, c.getLocal("scalar"), c.getLocal("scalarLen"), r0), c.call(f1mPrefix+"_timesScalar", x1, c.getLocal("scalar"), c.getLocal("scalarLen"), r1), ); } function buildSub() { const f = module.addFunction(prefix+"_sub"); f.addParam("x", "i32"); f.addParam("y", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const y0 = c.getLocal("y"); const y1 = c.i32_add(c.getLocal("y"), c.i32_const(f1n8)); const r0 = c.getLocal("r"); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8)); f.addCode( c.call(f1mPrefix+"_sub", x0, y0, r0), c.call(f1mPrefix+"_sub", x1, y1, r1), ); } function buildNeg() { const f = module.addFunction(prefix+"_neg"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const r0 = c.getLocal("r"); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8)); f.addCode( c.call(f1mPrefix+"_neg", x0, r0), c.call(f1mPrefix+"_neg", x1, r1), ); } function buildConjugate() { const f = module.addFunction(prefix+"_conjugate"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const r0 = c.getLocal("r"); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8)); f.addCode( c.call(f1mPrefix+"_copy", x0, r0), c.call(f1mPrefix+"_neg", x1, r1), ); } function buildIsNegative() { const f = module.addFunction(prefix+"_isNegative"); f.addParam("x", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); f.addCode( c.if( c.call(f1mPrefix+"_isZero", x1), c.ret(c.call(f1mPrefix+"_isNegative", x0)) ), c.ret(c.call(f1mPrefix+"_isNegative", x1)) ); } function buildMul() { const f = module.addFunction(prefix+"_mul"); f.addParam("x", "i32"); f.addParam("y", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const y0 = c.getLocal("y"); const y1 = c.i32_add(c.getLocal("y"), c.i32_const(f1n8)); const r0 = c.getLocal("r"); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8)); const A = c.i32_const(module.alloc(f1n8)); const B = c.i32_const(module.alloc(f1n8)); const C = c.i32_const(module.alloc(f1n8)); const D = c.i32_const(module.alloc(f1n8)); f.addCode( c.call(f1mPrefix + "_mul", x0, y0, A), // A = x0*y0 c.call(f1mPrefix + "_mul", x1, y1, B), // B = x1*y1 c.call(f1mPrefix + "_add", x0, x1, C), // C = x0 + x1 c.call(f1mPrefix + "_add", y0, y1, D), // D = y0 + y1 c.call(f1mPrefix + "_mul", C, D, C), // C = (x0 + x1)*(y0 + y1) = x0*y0+x0*y1+x1*y0+x1*y1 // c.call(f1mPrefix + "_mul", B, c.i32_const(pNonResidue), r0), // r0 = nr*(x1*y1) c.call(mulNonResidueFn, B, r0), // r0 = nr*(x1*y1) c.call(f1mPrefix + "_add", A, r0, r0), // r0 = x0*y0 + nr*(x1*y1) c.call(f1mPrefix + "_add", A, B, r1), // r1 = x0*y0+x1*y1 c.call(f1mPrefix + "_sub", C, r1, r1) // r1 = x0*y0+x0*y1+x1*y0+x1*y1 - x0*y0+x1*y1 = x0*y1+x1*y0 ); } function buildMul1() { const f = module.addFunction(prefix+"_mul1"); f.addParam("x", "i32"); f.addParam("y", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const y = c.getLocal("y"); const r0 = c.getLocal("r"); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8)); f.addCode( c.call(f1mPrefix + "_mul", x0, y, r0), // A = x0*y c.call(f1mPrefix + "_mul", x1, y, r1), // B = x1*y ); } function buildSquare() { const f = module.addFunction(prefix+"_square"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const r0 = c.getLocal("r"); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8)); const AB = c.i32_const(module.alloc(f1n8)); const APB = c.i32_const(module.alloc(f1n8)); const APNB = c.i32_const(module.alloc(f1n8)); const ABPNAB = c.i32_const(module.alloc(f1n8)); f.addCode( // AB = x0*y1 c.call(f1mPrefix + "_mul", x0, x1, AB), // APB = x0+y1 c.call(f1mPrefix + "_add", x0, x1, APB), // APBN0 = x0 + nr*x1 c.call(mulNonResidueFn, x1, APNB), c.call(f1mPrefix + "_add", x0, APNB, APNB), // ABPNAB = ab + nr*ab c.call(mulNonResidueFn, AB, ABPNAB), c.call(f1mPrefix + "_add", ABPNAB, AB, ABPNAB), // r0 = APB * APNB - ABPNAB c.call(f1mPrefix + "_mul", APB, APNB, r0), c.call(f1mPrefix + "_sub", r0, ABPNAB, r0), // r1 = AB + AB c.call(f1mPrefix + "_add", AB, AB, r1), ); } function buildToMontgomery() { const f = module.addFunction(prefix+"_toMontgomery"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const r0 = c.getLocal("r"); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8)); f.addCode( c.call(f1mPrefix+"_toMontgomery", x0, r0), c.call(f1mPrefix+"_toMontgomery", x1, r1) ); } function buildFromMontgomery() { const f = module.addFunction(prefix+"_fromMontgomery"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const r0 = c.getLocal("r"); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8)); f.addCode( c.call(f1mPrefix+"_fromMontgomery", x0, r0), c.call(f1mPrefix+"_fromMontgomery", x1, r1) ); } function buildCopy() { const f = module.addFunction(prefix+"_copy"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const r0 = c.getLocal("r"); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8)); f.addCode( c.call(f1mPrefix+"_copy", x0, r0), c.call(f1mPrefix+"_copy", x1, r1) ); } function buildZero() { const f = module.addFunction(prefix+"_zero"); f.addParam("x", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); f.addCode( c.call(f1mPrefix+"_zero", x0), c.call(f1mPrefix+"_zero", x1) ); } function buildOne() { const f = module.addFunction(prefix+"_one"); f.addParam("x", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); f.addCode( c.call(f1mPrefix+"_one", x0), c.call(f1mPrefix+"_zero", x1) ); } function buildEq() { const f = module.addFunction(prefix+"_eq"); f.addParam("x", "i32"); f.addParam("y", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const y0 = c.getLocal("y"); const y1 = c.i32_add(c.getLocal("y"), c.i32_const(f1n8)); f.addCode( c.i32_and( c.call(f1mPrefix+"_eq", x0, y0), c.call(f1mPrefix+"_eq", x1, y1) ) ); } function buildIsZero() { const f = module.addFunction(prefix+"_isZero"); f.addParam("x", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); f.addCode( c.i32_and( c.call(f1mPrefix+"_isZero", x0), c.call(f1mPrefix+"_isZero", x1) ) ); } function buildInverse() { const f = module.addFunction(prefix+"_inverse"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const r0 = c.getLocal("r"); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8)); const t0 = c.i32_const(module.alloc(f1n8)); const t1 = c.i32_const(module.alloc(f1n8)); const t2 = c.i32_const(module.alloc(f1n8)); const t3 = c.i32_const(module.alloc(f1n8)); f.addCode( c.call(f1mPrefix+"_square", x0, t0), c.call(f1mPrefix+"_square", x1, t1), // c.call(f1mPrefix+"_mul", t1, c.i32_const(pNonResidue), t2), c.call(mulNonResidueFn, t1, t2), c.call(f1mPrefix+"_sub", t0, t2, t2), c.call(f1mPrefix+"_inverse", t2, t3), c.call(f1mPrefix+"_mul", x0, t3, r0), c.call(f1mPrefix+"_mul", x1, t3, r1), c.call(f1mPrefix+"_neg", r1, r1), ); } function buildSign() { const f = module.addFunction(prefix+"_sign"); f.addParam("x", "i32"); f.addLocal("s", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); f.addCode( c.setLocal("s" , c.call( f1mPrefix + "_sign", x1)), c.if( c.getLocal("s"), c.ret(c.getLocal("s")) ), c.ret(c.call( f1mPrefix + "_sign", x0)) ); } function buildIsOne() { const f = module.addFunction(prefix+"_isOne"); f.addParam("x", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); f.addCode( c.ret(c.i32_and( c.call(f1mPrefix + "_isOne", x0), c.call(f1mPrefix + "_isZero", x1), )) ); } // Check here: https://eprint.iacr.org/2012/685.pdf // Alg 9adj function buildSqrt() { const f = module.addFunction(prefix+"_sqrt"); f.addParam("a", "i32"); f.addParam("pr", "i32"); const c = f.getCodeBuilder(); const e34 = c.i32_const(module.alloc(utils$8.bigInt2BytesLE(bigInt$4(q).minus(bigInt$4(3)).divide(4), f1n8 ))); const e12 = c.i32_const(module.alloc(utils$8.bigInt2BytesLE(bigInt$4(q).minus(bigInt$4(1)).divide(2), f1n8 ))); const a = c.getLocal("a"); const a1 = c.i32_const(module.alloc(f1n8*2)); const alpha = c.i32_const(module.alloc(f1n8*2)); const a0 = c.i32_const(module.alloc(f1n8*2)); const pn1 = module.alloc(f1n8*2); const n1 = c.i32_const(pn1); const n1a = c.i32_const(pn1); const n1b = c.i32_const(pn1+f1n8); const x0 = c.i32_const(module.alloc(f1n8*2)); const b = c.i32_const(module.alloc(f1n8*2)); f.addCode( c.call(prefix + "_one", n1), c.call(prefix + "_neg", n1, n1), // const a1 = F.pow(a, F.sqrt_e34); c.call(prefix + "_exp", a, e34, c.i32_const(f1n8), a1), // const a1 = F.pow(a, F.sqrt_e34); c.call(prefix + "_square", a1, alpha), c.call(prefix + "_mul", a, alpha, alpha), // const a0 = F.mul(F.frobenius(1, alfa), alfa); c.call(prefix + "_conjugate", alpha, a0), c.call(prefix + "_mul", a0, alpha, a0), // if (F.eq(a0, F.negone)) return null; c.if(c.call(prefix + "_eq",a0,n1), c.unreachable() ), // const x0 = F.mul(a1, a); c.call(prefix + "_mul", a1, a, x0), // if (F.eq(alfa, F.negone)) { c.if( c.call(prefix + "_eq", alpha, n1), [ // x = F.mul(x0, [F.F.zero, F.F.one]); ...c.call(f1mPrefix + "_zero", n1a), ...c.call(f1mPrefix + "_one", n1b), ...c.call(prefix + "_mul", n1, x0, c.getLocal("pr")), ], [ // const b = F.pow(F.add(F.one, alfa), F.sqrt_e12); ...c.call(prefix + "_one", b), ...c.call(prefix + "_add", b, alpha, b), ...c.call(prefix + "_exp", b, e12, c.i32_const(f1n8), b), // x = F.mul(b, x0); ...c.call(prefix + "_mul", b, x0, c.getLocal("pr")), ] ) ); } function buildIsSquare() { const f = module.addFunction(prefix+"_isSquare"); f.addParam("a", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); const e34 = c.i32_const(module.alloc(utils$8.bigInt2BytesLE(bigInt$4(q).minus(bigInt$4(3)).divide(4), f1n8 ))); const a = c.getLocal("a"); const a1 = c.i32_const(module.alloc(f1n8*2)); const alpha = c.i32_const(module.alloc(f1n8*2)); const a0 = c.i32_const(module.alloc(f1n8*2)); const pn1 = module.alloc(f1n8*2); const n1 = c.i32_const(pn1); f.addCode( c.call(prefix + "_one", n1), c.call(prefix + "_neg", n1, n1), // const a1 = F.pow(a, F.sqrt_e34); c.call(prefix + "_exp", a, e34, c.i32_const(f1n8), a1), // const a1 = F.pow(a, F.sqrt_e34); c.call(prefix + "_square", a1, alpha), c.call(prefix + "_mul", a, alpha, alpha), // const a0 = F.mul(F.frobenius(1, alfa), alfa); c.call(prefix + "_conjugate", alpha, a0), c.call(prefix + "_mul", a0, alpha, a0), // if (F.eq(a0, F.negone)) return null; c.if( c.call( prefix + "_eq", a0, n1 ), c.ret(c.i32_const(0)) ), c.ret(c.i32_const(1)) ); } buildIsZero(); buildIsOne(); buildZero(); buildOne(); buildCopy(); buildMul(); buildMul1(); buildSquare(); buildAdd(); buildSub(); buildNeg(); buildConjugate(); buildToMontgomery(); buildFromMontgomery(); buildEq(); buildInverse(); buildTimesScalar(); buildSign(); buildIsNegative(); module.exportFunction(prefix + "_isZero"); module.exportFunction(prefix + "_isOne"); module.exportFunction(prefix + "_zero"); module.exportFunction(prefix + "_one"); module.exportFunction(prefix + "_copy"); module.exportFunction(prefix + "_mul"); module.exportFunction(prefix + "_mul1"); module.exportFunction(prefix + "_square"); module.exportFunction(prefix + "_add"); module.exportFunction(prefix + "_sub"); module.exportFunction(prefix + "_neg"); module.exportFunction(prefix + "_sign"); module.exportFunction(prefix + "_conjugate"); module.exportFunction(prefix + "_fromMontgomery"); module.exportFunction(prefix + "_toMontgomery"); module.exportFunction(prefix + "_eq"); module.exportFunction(prefix + "_inverse"); buildBatchInverse$1(module, prefix); buildExp$1( module, prefix + "_exp", f1n8*2, prefix + "_mul", prefix + "_square", prefix + "_copy", prefix + "_one", ); buildSqrt(); buildIsSquare(); module.exportFunction(prefix + "_exp"); module.exportFunction(prefix + "_timesScalar"); module.exportFunction(prefix + "_batchInverse"); module.exportFunction(prefix + "_sqrt"); module.exportFunction(prefix + "_isSquare"); module.exportFunction(prefix + "_isNegative"); return prefix; }; /* Copyright 2019 0KIMS association. This file is part of wasmsnark (Web Assembly zkSnark Prover). wasmsnark is a free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. wasmsnark is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with wasmsnark. If not, see . */ const buildExp = build_timesscalar; const buildBatchInverse = build_batchinverse; var build_f3m = function buildF3m(module, mulNonResidueFn, prefix, f1mPrefix) { if (module.modules[prefix]) return prefix; // already builded const f1n8 = module.modules[f1mPrefix].n64*8; module.modules[prefix] = { n64: module.modules[f1mPrefix].n64*3 }; function buildAdd() { const f = module.addFunction(prefix+"_add"); f.addParam("x", "i32"); f.addParam("y", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8)); const y0 = c.getLocal("y"); const y1 = c.i32_add(c.getLocal("y"), c.i32_const(f1n8)); const y2 = c.i32_add(c.getLocal("y"), c.i32_const(2*f1n8)); const r0 = c.getLocal("r"); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8)); const r2 = c.i32_add(c.getLocal("r"), c.i32_const(2*f1n8)); f.addCode( c.call(f1mPrefix+"_add", x0, y0, r0), c.call(f1mPrefix+"_add", x1, y1, r1), c.call(f1mPrefix+"_add", x2, y2, r2), ); } function buildTimesScalar() { const f = module.addFunction(prefix+"_timesScalar"); f.addParam("x", "i32"); f.addParam("scalar", "i32"); f.addParam("scalarLen", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8)); const r0 = c.getLocal("r"); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8)); const r2 = c.i32_add(c.getLocal("r"), c.i32_const(2*f1n8)); f.addCode( c.call(f1mPrefix+"_timesScalar", x0, c.getLocal("scalar"), c.getLocal("scalarLen"), r0), c.call(f1mPrefix+"_timesScalar", x1, c.getLocal("scalar"), c.getLocal("scalarLen"), r1), c.call(f1mPrefix+"_timesScalar", x2, c.getLocal("scalar"), c.getLocal("scalarLen"), r2), ); } function buildSub() { const f = module.addFunction(prefix+"_sub"); f.addParam("x", "i32"); f.addParam("y", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8)); const y0 = c.getLocal("y"); const y1 = c.i32_add(c.getLocal("y"), c.i32_const(f1n8)); const y2 = c.i32_add(c.getLocal("y"), c.i32_const(2*f1n8)); const r0 = c.getLocal("r"); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8)); const r2 = c.i32_add(c.getLocal("r"), c.i32_const(2*f1n8)); f.addCode( c.call(f1mPrefix+"_sub", x0, y0, r0), c.call(f1mPrefix+"_sub", x1, y1, r1), c.call(f1mPrefix+"_sub", x2, y2, r2), ); } function buildNeg() { const f = module.addFunction(prefix+"_neg"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8)); const r0 = c.getLocal("r"); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8)); const r2 = c.i32_add(c.getLocal("r"), c.i32_const(2*f1n8)); f.addCode( c.call(f1mPrefix+"_neg", x0, r0), c.call(f1mPrefix+"_neg", x1, r1), c.call(f1mPrefix+"_neg", x2, r2), ); } function buildIsNegative() { const f = module.addFunction(prefix+"_isNegative"); f.addParam("x", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8)); f.addCode( c.if( c.call(f1mPrefix+"_isZero", x2), c.if( c.call(f1mPrefix+"_isZero", x1), c.ret(c.call(f1mPrefix+"_isNegative", x0)), c.ret(c.call(f1mPrefix+"_isNegative", x1)) ) ), c.ret(c.call(f1mPrefix+"_isNegative", x2)) ); } function buildMul() { const f = module.addFunction(prefix+"_mul"); f.addParam("x", "i32"); f.addParam("y", "i32"); f.addParam("r", "i32"); const cd = f.getCodeBuilder(); const a = cd.getLocal("x"); const b = cd.i32_add(cd.getLocal("x"), cd.i32_const(f1n8)); const c = cd.i32_add(cd.getLocal("x"), cd.i32_const(2*f1n8)); const A = cd.getLocal("y"); const B = cd.i32_add(cd.getLocal("y"), cd.i32_const(f1n8)); const C = cd.i32_add(cd.getLocal("y"), cd.i32_const(2*f1n8)); const r0 = cd.getLocal("r"); const r1 = cd.i32_add(cd.getLocal("r"), cd.i32_const(f1n8)); const r2 = cd.i32_add(cd.getLocal("r"), cd.i32_const(2*f1n8)); const aA = cd.i32_const(module.alloc(f1n8)); const bB = cd.i32_const(module.alloc(f1n8)); const cC = cd.i32_const(module.alloc(f1n8)); const a_b = cd.i32_const(module.alloc(f1n8)); const A_B = cd.i32_const(module.alloc(f1n8)); const a_c = cd.i32_const(module.alloc(f1n8)); const A_C = cd.i32_const(module.alloc(f1n8)); const b_c = cd.i32_const(module.alloc(f1n8)); const B_C = cd.i32_const(module.alloc(f1n8)); const aA_bB = cd.i32_const(module.alloc(f1n8)); const aA_cC = cd.i32_const(module.alloc(f1n8)); const bB_cC = cd.i32_const(module.alloc(f1n8)); const AUX = cd.i32_const(module.alloc(f1n8)); f.addCode( cd.call(f1mPrefix + "_mul", a, A, aA), cd.call(f1mPrefix + "_mul", b, B, bB), cd.call(f1mPrefix + "_mul", c, C, cC), cd.call(f1mPrefix + "_add", a, b, a_b), cd.call(f1mPrefix + "_add", A, B, A_B), cd.call(f1mPrefix + "_add", a, c, a_c), cd.call(f1mPrefix + "_add", A, C, A_C), cd.call(f1mPrefix + "_add", b, c, b_c), cd.call(f1mPrefix + "_add", B, C, B_C), cd.call(f1mPrefix + "_add", aA, bB, aA_bB), cd.call(f1mPrefix + "_add", aA, cC, aA_cC), cd.call(f1mPrefix + "_add", bB, cC, bB_cC), cd.call(f1mPrefix + "_mul", b_c, B_C, r0), cd.call(f1mPrefix + "_sub", r0, bB_cC, r0), cd.call(mulNonResidueFn, r0, r0), cd.call(f1mPrefix + "_add", aA, r0, r0), cd.call(f1mPrefix + "_mul", a_b, A_B, r1), cd.call(f1mPrefix + "_sub", r1, aA_bB, r1), cd.call(mulNonResidueFn, cC, AUX), cd.call(f1mPrefix + "_add", r1, AUX, r1), cd.call(f1mPrefix + "_mul", a_c, A_C, r2), cd.call(f1mPrefix + "_sub", r2, aA_cC, r2), cd.call(f1mPrefix + "_add", r2, bB, r2), ); } function buildSquare() { const f = module.addFunction(prefix+"_square"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const A = c.getLocal("x"); const B = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const C = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8)); const r0 = c.getLocal("r"); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8)); const r2 = c.i32_add(c.getLocal("r"), c.i32_const(2*f1n8)); const s0 = c.i32_const(module.alloc(f1n8)); const ab = c.i32_const(module.alloc(f1n8)); const s1 = c.i32_const(module.alloc(f1n8)); const s2 = c.i32_const(module.alloc(f1n8)); const bc = c.i32_const(module.alloc(f1n8)); const s3 = c.i32_const(module.alloc(f1n8)); const s4 = c.i32_const(module.alloc(f1n8)); f.addCode( c.call(f1mPrefix + "_square", A, s0), c.call(f1mPrefix + "_mul", A, B, ab), c.call(f1mPrefix + "_add", ab, ab, s1), c.call(f1mPrefix + "_sub", A, B, s2), c.call(f1mPrefix + "_add", s2, C, s2), c.call(f1mPrefix + "_square", s2, s2), c.call(f1mPrefix + "_mul", B, C, bc), c.call(f1mPrefix + "_add", bc, bc, s3), c.call(f1mPrefix + "_square", C, s4), c.call(mulNonResidueFn, s3, r0), c.call(f1mPrefix + "_add", s0, r0, r0), c.call(mulNonResidueFn, s4, r1), c.call(f1mPrefix + "_add", s1, r1, r1), c.call(f1mPrefix + "_add", s0, s4, r2), c.call(f1mPrefix + "_sub", s3, r2, r2), c.call(f1mPrefix + "_add", s2, r2, r2), c.call(f1mPrefix + "_add", s1, r2, r2), ); } function buildToMontgomery() { const f = module.addFunction(prefix+"_toMontgomery"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8)); const r0 = c.getLocal("r"); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8)); const r2 = c.i32_add(c.getLocal("r"), c.i32_const(2*f1n8)); f.addCode( c.call(f1mPrefix+"_toMontgomery", x0, r0), c.call(f1mPrefix+"_toMontgomery", x1, r1), c.call(f1mPrefix+"_toMontgomery", x2, r2) ); } function buildFromMontgomery() { const f = module.addFunction(prefix+"_fromMontgomery"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8)); const r0 = c.getLocal("r"); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8)); const r2 = c.i32_add(c.getLocal("r"), c.i32_const(2*f1n8)); f.addCode( c.call(f1mPrefix+"_fromMontgomery", x0, r0), c.call(f1mPrefix+"_fromMontgomery", x1, r1), c.call(f1mPrefix+"_fromMontgomery", x2, r2) ); } function buildCopy() { const f = module.addFunction(prefix+"_copy"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8)); const r0 = c.getLocal("r"); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8)); const r2 = c.i32_add(c.getLocal("r"), c.i32_const(2*f1n8)); f.addCode( c.call(f1mPrefix+"_copy", x0, r0), c.call(f1mPrefix+"_copy", x1, r1), c.call(f1mPrefix+"_copy", x2, r2), ); } function buildZero() { const f = module.addFunction(prefix+"_zero"); f.addParam("x", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8)); f.addCode( c.call(f1mPrefix+"_zero", x0), c.call(f1mPrefix+"_zero", x1), c.call(f1mPrefix+"_zero", x2), ); } function buildOne() { const f = module.addFunction(prefix+"_one"); f.addParam("x", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8)); f.addCode( c.call(f1mPrefix+"_one", x0), c.call(f1mPrefix+"_zero", x1), c.call(f1mPrefix+"_zero", x2), ); } function buildEq() { const f = module.addFunction(prefix+"_eq"); f.addParam("x", "i32"); f.addParam("y", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8)); const y0 = c.getLocal("y"); const y1 = c.i32_add(c.getLocal("y"), c.i32_const(f1n8)); const y2 = c.i32_add(c.getLocal("y"), c.i32_const(2*f1n8)); f.addCode( c.i32_and( c.i32_and( c.call(f1mPrefix+"_eq", x0, y0), c.call(f1mPrefix+"_eq", x1, y1), ), c.call(f1mPrefix+"_eq", x2, y2) ) ); } function buildIsZero() { const f = module.addFunction(prefix+"_isZero"); f.addParam("x", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8)); f.addCode( c.i32_and( c.i32_and( c.call(f1mPrefix+"_isZero", x0), c.call(f1mPrefix+"_isZero", x1) ), c.call(f1mPrefix+"_isZero", x2) ) ); } function buildInverse() { const f = module.addFunction(prefix+"_inverse"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8)); const r0 = c.getLocal("r"); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8)); const r2 = c.i32_add(c.getLocal("r"), c.i32_const(2*f1n8)); const t0 = c.i32_const(module.alloc(f1n8)); const t1 = c.i32_const(module.alloc(f1n8)); const t2 = c.i32_const(module.alloc(f1n8)); const t3 = c.i32_const(module.alloc(f1n8)); const t4 = c.i32_const(module.alloc(f1n8)); const t5 = c.i32_const(module.alloc(f1n8)); const c0 = c.i32_const(module.alloc(f1n8)); const c1 = c.i32_const(module.alloc(f1n8)); const c2 = c.i32_const(module.alloc(f1n8)); const t6 = c.i32_const(module.alloc(f1n8)); const AUX = c.i32_const(module.alloc(f1n8)); f.addCode( c.call(f1mPrefix+"_square", x0, t0), c.call(f1mPrefix+"_square", x1, t1), c.call(f1mPrefix+"_square", x2, t2), c.call(f1mPrefix+"_mul", x0, x1, t3), c.call(f1mPrefix+"_mul", x0, x2, t4), c.call(f1mPrefix+"_mul", x1, x2, t5), c.call(mulNonResidueFn, t5, c0), c.call(f1mPrefix+"_sub", t0, c0, c0), c.call(mulNonResidueFn, t2, c1), c.call(f1mPrefix+"_sub", c1, t3, c1), c.call(f1mPrefix+"_sub", t1, t4, c2), c.call(f1mPrefix+"_mul", x2, c1, t6), c.call(f1mPrefix+"_mul", x1, c2, AUX), c.call(f1mPrefix+"_add", t6, AUX, t6), c.call(mulNonResidueFn, t6, t6), c.call(f1mPrefix+"_mul", x0, c0, AUX), c.call(f1mPrefix+"_add", AUX, t6, t6), c.call(f1mPrefix+"_inverse", t6, t6), c.call(f1mPrefix+"_mul", t6, c0, r0), c.call(f1mPrefix+"_mul", t6, c1, r1), c.call(f1mPrefix+"_mul", t6, c2, r2) ); } function buildSign() { const f = module.addFunction(prefix+"_sign"); f.addParam("x", "i32"); f.addLocal("s", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8)); f.addCode( c.setLocal("s" , c.call( f1mPrefix + "_sign", x2)), c.if( c.getLocal("s"), c.ret(c.getLocal("s")) ), c.setLocal("s" , c.call( f1mPrefix + "_sign", x1)), c.if( c.getLocal("s"), c.ret(c.getLocal("s")) ), c.ret(c.call( f1mPrefix + "_sign", x0)) ); } function buildIsOne() { const f = module.addFunction(prefix+"_isOne"); f.addParam("x", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8*2)); f.addCode( c.ret( c.i32_and( c.i32_and( c.call(f1mPrefix + "_isOne", x0), c.call(f1mPrefix + "_isZero", x1) ), c.call(f1mPrefix + "_isZero", x2) ) ) ); } buildIsZero(); buildIsOne(); buildZero(); buildOne(); buildCopy(); buildMul(); buildSquare(); buildAdd(); buildSub(); buildNeg(); buildSign(); buildToMontgomery(); buildFromMontgomery(); buildEq(); buildInverse(); buildTimesScalar(); buildIsNegative(); module.exportFunction(prefix + "_isZero"); module.exportFunction(prefix + "_isOne"); module.exportFunction(prefix + "_zero"); module.exportFunction(prefix + "_one"); module.exportFunction(prefix + "_copy"); module.exportFunction(prefix + "_mul"); module.exportFunction(prefix + "_square"); module.exportFunction(prefix + "_add"); module.exportFunction(prefix + "_sub"); module.exportFunction(prefix + "_neg"); module.exportFunction(prefix + "_sign"); module.exportFunction(prefix + "_fromMontgomery"); module.exportFunction(prefix + "_toMontgomery"); module.exportFunction(prefix + "_eq"); module.exportFunction(prefix + "_inverse"); buildBatchInverse(module, prefix); buildExp( module, prefix + "_exp", f1n8*3, prefix + "_mul", prefix + "_square", prefix + "_copy", prefix + "_one" ); module.exportFunction(prefix + "_exp"); module.exportFunction(prefix + "_timesScalar"); module.exportFunction(prefix + "_batchInverse"); module.exportFunction(prefix + "_isNegative"); return prefix; }; /* Copyright 2019 0KIMS association. This file is part of wasmsnark (Web Assembly zkSnark Prover). wasmsnark is a free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. wasmsnark is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with wasmsnark. If not, see . */ var build_timesscalarnaf = function buildTimesScalarNAF(module, fnName, elementLen, opAB, opAA, opAmB, opCopy, opInit) { const f = module.addFunction(fnName); f.addParam("base", "i32"); f.addParam("scalar", "i32"); f.addParam("scalarLength", "i32"); f.addParam("r", "i32"); f.addLocal("old0", "i32"); f.addLocal("nbits", "i32"); f.addLocal("i", "i32"); f.addLocal("last", "i32"); f.addLocal("cur", "i32"); f.addLocal("carry", "i32"); f.addLocal("p", "i32"); const c = f.getCodeBuilder(); const aux = c.i32_const(module.alloc(elementLen)); function getBit(IDX) { return c.i32_and( c.i32_shr_u( c.i32_load( c.i32_add( c.getLocal("scalar"), c.i32_and( c.i32_shr_u( IDX, c.i32_const(3) ), c.i32_const(0xFFFFFFFC) ) ) ), c.i32_and( IDX, c.i32_const(0x1F) ) ), c.i32_const(1) ); } function pushBit(b) { return [ ...c.i32_store8( c.getLocal("p"), c.i32_const(b) ), ...c.setLocal( "p", c.i32_add( c.getLocal("p"), c.i32_const(1) ) ) ]; } f.addCode( c.if( c.i32_eqz(c.getLocal("scalarLength")), [ ...c.call(opInit, c.getLocal("r")), ...c.ret([]) ] ), c.setLocal("nbits", c.i32_shl(c.getLocal("scalarLength"), c.i32_const(3))), c.setLocal("old0", c.i32_load(c.i32_const(0))), c.setLocal("p", c.getLocal("old0")), c.i32_store( c.i32_const(0), c.i32_and( c.i32_add( c.i32_add( c.getLocal("old0"), c.i32_const(32) ), c.getLocal("nbits") ), c.i32_const(0xFFFFFFF8) ) ), c.setLocal("i", c.i32_const(1)), c.setLocal("last",getBit(c.i32_const(0))), c.setLocal("carry",c.i32_const(0)), c.block(c.loop( c.br_if(1, c.i32_eq( c.getLocal("i"), c.getLocal("nbits"))), c.setLocal("cur", getBit(c.getLocal("i"))), c.if( c.getLocal("last"), c.if( c.getLocal("cur"), c.if(c.getLocal("carry"), [ ...c.setLocal("last", c.i32_const(0)), ...c.setLocal("carry", c.i32_const(1)), ...pushBit(1) ] , [ ...c.setLocal("last", c.i32_const(0)), ...c.setLocal("carry", c.i32_const(1)), ...pushBit(255) ], ), c.if(c.getLocal("carry"), [ ...c.setLocal("last", c.i32_const(0)), ...c.setLocal("carry", c.i32_const(1)), ...pushBit(255) ] , [ ...c.setLocal("last", c.i32_const(0)), ...c.setLocal("carry", c.i32_const(0)), ...pushBit(1) ], ), ), c.if( c.getLocal("cur"), c.if(c.getLocal("carry"), [ ...c.setLocal("last", c.i32_const(0)), ...c.setLocal("carry", c.i32_const(1)), ...pushBit(0) ] , [ ...c.setLocal("last", c.i32_const(1)), ...c.setLocal("carry", c.i32_const(0)), ...pushBit(0) ], ), c.if(c.getLocal("carry"), [ ...c.setLocal("last", c.i32_const(1)), ...c.setLocal("carry", c.i32_const(0)), ...pushBit(0) ] , [ ...c.setLocal("last", c.i32_const(0)), ...c.setLocal("carry", c.i32_const(0)), ...pushBit(0) ], ), ) ), c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))), c.br(0) )), c.if( c.getLocal("last"), c.if(c.getLocal("carry"), [ ...pushBit(255), ...pushBit(0), ...pushBit(1) ] , [ ...pushBit(1) ], ), c.if(c.getLocal("carry"), [ ...pushBit(0), ...pushBit(1) ] ), ), c.setLocal("p", c.i32_sub(c.getLocal("p"), c.i32_const(1))), // p already points to the last bit c.call(opCopy, c.getLocal("base"), aux), c.call(opInit, c.getLocal("r")), c.block(c.loop( c.call(opAA, c.getLocal("r"), c.getLocal("r")), c.setLocal("cur", c.i32_load8_u( c.getLocal("p") ) ), c.if( c.getLocal("cur"), c.if( c.i32_eq(c.getLocal("cur"), c.i32_const(1)), c.call(opAB, c.getLocal("r"), aux, c.getLocal("r")), c.call(opAmB, c.getLocal("r"), aux, c.getLocal("r")), ) ), c.br_if(1, c.i32_eq( c.getLocal("old0"), c.getLocal("p"))), c.setLocal("p", c.i32_sub(c.getLocal("p"), c.i32_const(1))), c.br(0) )), c.i32_store( c.i32_const(0), c.getLocal("old0")) ); }; /* Copyright 2019 0KIMS association. This file is part of wasmsnark (Web Assembly zkSnark Prover). wasmsnark is a free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. wasmsnark is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with wasmsnark. If not, see . */ var build_multiexp = function buildMultiexp(module, prefix, fnName, opAdd, n8b) { const n64g = module.modules[prefix].n64; const n8g = n64g*8; function buildGetChunk() { const f = module.addFunction(fnName + "_getChunk"); f.addParam("pScalar", "i32"); f.addParam("scalarSize", "i32"); // Number of bytes of the scalar f.addParam("startBit", "i32"); // Bit to start extract f.addParam("chunkSize", "i32"); // Chunk size in bits f.addLocal("bitsToEnd", "i32"); f.addLocal("mask", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); f.addCode( c.setLocal("bitsToEnd", c.i32_sub( c.i32_mul( c.getLocal("scalarSize"), c.i32_const(8) ), c.getLocal("startBit") ) ), c.if( c.i32_gt_s( c.getLocal("chunkSize"), c.getLocal("bitsToEnd") ), c.setLocal( "mask", c.i32_sub( c.i32_shl( c.i32_const(1), c.getLocal("bitsToEnd") ), c.i32_const(1) ) ), c.setLocal( "mask", c.i32_sub( c.i32_shl( c.i32_const(1), c.getLocal("chunkSize") ), c.i32_const(1) ) ) ), c.i32_and( c.i32_shr_u( c.i32_load( c.i32_add( c.getLocal("pScalar"), c.i32_shr_u( c.getLocal("startBit"), c.i32_const(3) ) ), 0, // offset 0 // align to byte. ), c.i32_and( c.getLocal("startBit"), c.i32_const(0x7) ) ), c.getLocal("mask") ) ); } function buildMutiexpChunk() { const f = module.addFunction(fnName + "_chunk"); f.addParam("pBases", "i32"); f.addParam("pScalars", "i32"); f.addParam("scalarSize", "i32"); // Number of points f.addParam("n", "i32"); // Number of points f.addParam("startBit", "i32"); // bit where it starts the chunk f.addParam("chunkSize", "i32"); // bit where it starts the chunk f.addParam("pr", "i32"); f.addLocal("nChunks", "i32"); f.addLocal("itScalar", "i32"); f.addLocal("endScalar", "i32"); f.addLocal("itBase", "i32"); f.addLocal("i", "i32"); f.addLocal("j", "i32"); f.addLocal("nTable", "i32"); f.addLocal("pTable", "i32"); f.addLocal("idx", "i32"); f.addLocal("pIdxTable", "i32"); const c = f.getCodeBuilder(); f.addCode( c.if( c.i32_eqz(c.getLocal("n")), [ ...c.call(prefix + "_zero", c.getLocal("pr")), ...c.ret([]) ] ), // Allocate memory c.setLocal( "nTable", c.i32_shl( c.i32_const(1), c.getLocal("chunkSize") ) ), c.setLocal("pTable", c.i32_load( c.i32_const(0) )), c.i32_store( c.i32_const(0), c.i32_add( c.getLocal("pTable"), c.i32_mul( c.getLocal("nTable"), c.i32_const(n8g) ) ) ), // Reset Table c.setLocal("j", c.i32_const(0)), c.block(c.loop( c.br_if( 1, c.i32_eq( c.getLocal("j"), c.getLocal("nTable") ) ), c.call( prefix + "_zero", c.i32_add( c.getLocal("pTable"), c.i32_mul( c.getLocal("j"), c.i32_const(n8g) ) ) ), c.setLocal("j", c.i32_add(c.getLocal("j"), c.i32_const(1))), c.br(0) )), // Distribute elements c.setLocal("itBase", c.getLocal("pBases")), c.setLocal("itScalar", c.getLocal("pScalars")), c.setLocal("endScalar", c.i32_add( c.getLocal("pScalars"), c.i32_mul( c.getLocal("n"), c.getLocal("scalarSize") ) ) ), c.block(c.loop( c.br_if( 1, c.i32_eq( c.getLocal("itScalar"), c.getLocal("endScalar") ) ), c.setLocal( "idx", c.call(fnName + "_getChunk", c.getLocal("itScalar"), c.getLocal("scalarSize"), c.getLocal("startBit"), c.getLocal("chunkSize") ) ), c.if( c.getLocal("idx"), [ ...c.setLocal( "pIdxTable", c.i32_add( c.getLocal("pTable"), c.i32_mul( c.i32_sub( c.getLocal("idx"), c.i32_const(1) ), c.i32_const(n8g) ) ) ), ...c.call( opAdd, c.getLocal("pIdxTable"), c.getLocal("itBase"), c.getLocal("pIdxTable"), ) ] ), c.setLocal("itScalar", c.i32_add(c.getLocal("itScalar"), c.getLocal("scalarSize"))), c.setLocal("itBase", c.i32_add(c.getLocal("itBase"), c.i32_const(n8b))), c.br(0) )), c.call(fnName + "_reduceTable", c.getLocal("pTable"), c.getLocal("chunkSize")), c.call( prefix + "_copy", c.getLocal("pTable"), c.getLocal("pr") ), c.i32_store( c.i32_const(0), c.getLocal("pTable") ) ); } function buildMultiexp() { const f = module.addFunction(fnName); f.addParam("pBases", "i32"); f.addParam("pScalars", "i32"); f.addParam("scalarSize", "i32"); // Number of points f.addParam("n", "i32"); // Number of points f.addParam("pr", "i32"); f.addLocal("chunkSize", "i32"); f.addLocal("nChunks", "i32"); f.addLocal("itScalar", "i32"); f.addLocal("endScalar", "i32"); f.addLocal("itBase", "i32"); f.addLocal("itBit", "i32"); f.addLocal("i", "i32"); f.addLocal("j", "i32"); f.addLocal("nTable", "i32"); f.addLocal("pTable", "i32"); f.addLocal("idx", "i32"); f.addLocal("pIdxTable", "i32"); const c = f.getCodeBuilder(); const aux = c.i32_const(module.alloc(n8g)); const pTSizes = module.alloc([ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 16, 16, 15, 14, 13, 13, 12, 11, 10, 9, 8, 7, 7, 6, 5 , 4, 3, 2, 1, 1, 1, 1 ]); f.addCode( c.call(prefix + "_zero", c.getLocal("pr")), c.if( c.i32_eqz(c.getLocal("n")), c.ret([]) ), c.setLocal("chunkSize", c.i32_load8_u( c.i32_clz(c.getLocal("n")), pTSizes )), c.setLocal( "nChunks", c.i32_add( c.i32_div_u( c.i32_sub( c.i32_shl( c.getLocal("scalarSize"), c.i32_const(3) ), c.i32_const(1) ), c.getLocal("chunkSize") ), c.i32_const(1) ) ), // Allocate memory c.setLocal( "itBit", c.i32_mul( c.i32_sub( c.getLocal("nChunks"), c.i32_const(1) ), c.getLocal("chunkSize") ) ), c.block(c.loop( c.br_if( 1, c.i32_lt_s( c.getLocal("itBit"), c.i32_const(0) ) ), // Double nChunk times c.if( c.i32_eqz(c.call(prefix + "_isZero", c.getLocal("pr"))), [ ...c.setLocal("j", c.i32_const(0)), ...c.block(c.loop( c.br_if( 1, c.i32_eq( c.getLocal("j"), c.getLocal("chunkSize") ) ), c.call(prefix + "_double", c.getLocal("pr"), c.getLocal("pr")), c.setLocal("j", c.i32_add(c.getLocal("j"), c.i32_const(1))), c.br(0) )) ] ), c.call( fnName + "_chunk", c.getLocal("pBases"), c.getLocal("pScalars"), c.getLocal("scalarSize"), c.getLocal("n"), c.getLocal("itBit"), c.getLocal("chunkSize"), aux ), c.call( prefix + "_add", c.getLocal("pr"), aux, c.getLocal("pr") ), c.setLocal("itBit", c.i32_sub(c.getLocal("itBit"), c.getLocal("chunkSize"))), c.br(0) )) ); } function buildReduceTable() { const f = module.addFunction(fnName + "_reduceTable"); f.addParam("pTable", "i32"); f.addParam("p", "i32"); // Number of bits of the table f.addLocal("half", "i32"); f.addLocal("it1", "i32"); f.addLocal("it2", "i32"); f.addLocal("pAcc", "i32"); const c = f.getCodeBuilder(); f.addCode( c.if( c.i32_eq(c.getLocal("p"), c.i32_const(1)), c.ret([]) ), c.setLocal( "half", c.i32_shl( c.i32_const(1), c.i32_sub( c.getLocal("p"), c.i32_const(1) ) ) ), c.setLocal("it1", c.getLocal("pTable")), c.setLocal( "it2", c.i32_add( c.getLocal("pTable"), c.i32_mul( c.getLocal("half"), c.i32_const(n8g) ) ) ), c.setLocal("pAcc", c.i32_sub( c.getLocal("it2"), c.i32_const(n8g) ) ), c.block(c.loop( c.br_if( 1, c.i32_eq( c.getLocal("it1"), c.getLocal("pAcc") ) ), c.call( prefix + "_add", c.getLocal("it1"), c.getLocal("it2"), c.getLocal("it1") ), c.call( prefix + "_add", c.getLocal("pAcc"), c.getLocal("it2"), c.getLocal("pAcc") ), c.setLocal("it1", c.i32_add(c.getLocal("it1"), c.i32_const(n8g))), c.setLocal("it2", c.i32_add(c.getLocal("it2"), c.i32_const(n8g))), c.br(0) )), c.call( fnName + "_reduceTable", c.getLocal("pTable"), c.i32_sub( c.getLocal("p"), c.i32_const(1) ) ), c.setLocal("p", c.i32_sub(c.getLocal("p"), c.i32_const(1))), c.block(c.loop( c.br_if(1, c.i32_eqz(c.getLocal("p"))), c.call(prefix + "_double", c.getLocal("pAcc"), c.getLocal("pAcc")), c.setLocal("p", c.i32_sub(c.getLocal("p"), c.i32_const(1))), c.br(0) )), c.call(prefix + "_add", c.getLocal("pTable"), c.getLocal("pAcc"), c.getLocal("pTable")) ); } buildGetChunk(); buildReduceTable(); buildMutiexpChunk(); buildMultiexp(); module.exportFunction(fnName); module.exportFunction(fnName +"_chunk"); }; /* Copyright 2019 0KIMS association. This file is part of wasmsnark (Web Assembly zkSnark Prover). wasmsnark is a free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. wasmsnark is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with wasmsnark. If not, see . */ const buildTimesScalarNAF = build_timesscalarnaf; //const buildTimesScalar = require("./build_timesscalar"); const buildBatchConvertion = build_batchconvertion; const buildMultiexp$1 = build_multiexp; var build_curve_jacobian_a0 = function buildCurve(module, prefix, prefixField, pB) { const n64 = module.modules[prefixField].n64; const n8 = n64*8; if (module.modules[prefix]) return prefix; // already builded module.modules[prefix] = { n64: n64*3 }; function buildIsZero() { const f = module.addFunction(prefix + "_isZero"); f.addParam("p1", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); f.addCode(c.call( prefixField + "_isZero", c.i32_add( c.getLocal("p1"), c.i32_const(n8*2) ) )); } function buildIsZeroAffine() { const f = module.addFunction(prefix + "_isZeroAffine"); f.addParam("p1", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); f.addCode( c.i32_and( c.call( prefixField + "_isZero", c.getLocal("p1") ), c.call( prefixField + "_isZero", c.i32_add( c.getLocal("p1"), c.i32_const(n8) ) ) ) ); } function buildCopy() { const f = module.addFunction(prefix + "_copy"); f.addParam("ps", "i32"); f.addParam("pd", "i32"); const c = f.getCodeBuilder(); for (let i=0; i. */ const bigInt$3 = BigIntegerExports; const utils$7 = utils$b; var build_fft = function buildFFT(module, prefix, gPrefix, fPrefix, opGtimesF) { const n64f = module.modules[fPrefix].n64; const n8f = n64f*8; const n64g = module.modules[gPrefix].n64; const n8g = n64g*8; const q = module.modules[fPrefix].q; let rem = q.minus(bigInt$3(1)); let maxBits = 0; while (!rem.isOdd()) { maxBits ++; rem = rem.shiftRight(1); } let nr = bigInt$3(2); while ( nr.modPow(q.shiftRight(1), q).equals(1) ) nr = nr.add(1); // console.log(nr); const w = new Array(maxBits+1); w[maxBits] = nr.modPow(rem, q); let n=maxBits-1; while (n>=0) { w[n] = w[n+1].modPow(2, q); n--; } const bytes = []; const R = bigInt$3(1).shiftLeft(n8f*8).mod(q); for (let i=0; i> i); } } return r; } const rtable = Array(256); for (let i=0; i<256; i++) { rtable[i] = rev(i); } const REVTABLE = module.alloc(rtable); function buildLog2() { const f = module.addFunction(prefix+"__log2"); f.addParam("n", "i32"); f.setReturnType("i32"); f.addLocal("bits", "i32"); f.addLocal("aux", "i32"); const c = f.getCodeBuilder(); f.addCode( c.setLocal( "aux", c.i32_shr_u( c.getLocal("n"), c.i32_const(1) ) ) ); f.addCode(c.setLocal("bits", c.i32_const(0))); f.addCode(c.block(c.loop( c.br_if( 1, c.i32_eqz(c.getLocal("aux")) ), c.setLocal( "aux", c.i32_shr_u( c.getLocal("aux"), c.i32_const(1) ) ), c.setLocal( "bits", c.i32_add( c.getLocal("bits"), c.i32_const(1) ) ), c.br(0) ))); f.addCode(c.if( c.i32_ne( c.getLocal("n"), c.i32_shl( c.i32_const(1), c.getLocal("bits") ) ), c.unreachable() )); f.addCode(c.if( c.i32_gt_u( c.getLocal("bits"), c.i32_const(maxBits) ), c.unreachable() )); f.addCode(c.getLocal("bits")); } function buildFFT() { const f = module.addFunction(prefix+"_fft"); f.addParam("px", "i32"); f.addParam("n", "i32"); f.addLocal("bits", "i32"); const c = f.getCodeBuilder(); const One = c.i32_const(module.alloc(n8f)); f.addCode( c.setLocal( "bits", c.call( prefix + "__log2", c.getLocal("n") ) ), c.call(fPrefix + "_one", One), c.call( prefix+"_rawfft", c.getLocal("px"), c.getLocal("bits"), c.i32_const(0), One ) ); } function buildIFFT() { const f = module.addFunction(prefix+"_ifft"); f.addParam("px", "i32"); f.addParam("n", "i32"); f.addLocal("bits", "i32"); f.addLocal("pInv2", "i32"); const c = f.getCodeBuilder(); f.addCode( c.setLocal( "bits", c.call( prefix + "__log2", c.getLocal("n") ) ), c.setLocal( "pInv2", c.i32_add( c.i32_const(INV2), c.i32_mul( c.getLocal("bits"), c.i32_const(n8f) ) ) ), c.call( prefix+"_rawfft", c.getLocal("px"), c.getLocal("bits"), c.i32_const(1), c.getLocal("pInv2") ), ); } function buildRawFFT() { const f = module.addFunction(prefix+"_rawfft"); f.addParam("px", "i32"); f.addParam("bits", "i32"); // 2 power f.addParam("reverse", "i32"); f.addParam("mulFactor", "i32"); f.addLocal("s", "i32"); f.addLocal("k", "i32"); f.addLocal("j", "i32"); f.addLocal("m", "i32"); f.addLocal("mdiv2", "i32"); f.addLocal("n", "i32"); f.addLocal("pwm", "i32"); f.addLocal("idx1", "i32"); f.addLocal("idx2", "i32"); const c = f.getCodeBuilder(); const W = c.i32_const(module.alloc(n8f)); const T = c.i32_const(module.alloc(n8g)); const U = c.i32_const(module.alloc(n8g)); f.addCode( c.call(prefix + "__reversePermutation", c.getLocal("px"), c.getLocal("bits")), c.setLocal("n", c.i32_shl(c.i32_const(1), c.getLocal("bits"))), c.setLocal("s", c.i32_const(1)), c.block(c.loop( c.br_if( 1, c.i32_gt_u( c.getLocal("s"), c.getLocal("bits") ) ), c.setLocal("m", c.i32_shl(c.i32_const(1), c.getLocal("s"))), c.setLocal("pwm", c.i32_add( c.i32_const(ROOTs), c.i32_mul( c.getLocal("s"), c.i32_const(n8f) ) ) ), c.setLocal("k", c.i32_const(0)), c.block(c.loop( c.br_if( 1, c.i32_ge_u( c.getLocal("k"), c.getLocal("n") ) ), c.call(fPrefix + "_one", W), c.setLocal("mdiv2", c.i32_shr_u(c.getLocal("m"), c.i32_const(1)) ), c.setLocal("j", c.i32_const(0)), c.block(c.loop( c.br_if( 1, c.i32_ge_u( c.getLocal("j"), c.getLocal("mdiv2") ) ), c.setLocal( "idx1", c.i32_add( c.getLocal("px"), c.i32_mul( c.i32_add( c.getLocal("k"), c.getLocal("j") ), c.i32_const(n8g) ) ) ), c.setLocal( "idx2", c.i32_add( c.getLocal("idx1"), c.i32_mul( c.getLocal("mdiv2"), c.i32_const(n8g) ) ) ), c.call( opGtimesF, c.getLocal("idx2"), W, T ), c.call( gPrefix + "_copy", c.getLocal("idx1"), U ), c.call( gPrefix + "_add", U, T, c.getLocal("idx1"), ), c.call( gPrefix + "_sub", U, T, c.getLocal("idx2"), ), c.call( fPrefix + "_mul", W, c.getLocal("pwm"), W, ), c.setLocal("j", c.i32_add(c.getLocal("j"), c.i32_const(1))), c.br(0) )), c.setLocal("k", c.i32_add(c.getLocal("k"), c.getLocal("m"))), c.br(0) )), c.setLocal("s", c.i32_add(c.getLocal("s"), c.i32_const(1))), c.br(0) )), c.call( prefix + "__fftFinal", c.getLocal("px"), c.getLocal("bits"), c.getLocal("reverse"), c.getLocal("mulFactor") ) ); } function buildFinalInverse() { const f = module.addFunction(prefix+"__fftFinal"); f.addParam("px", "i32"); f.addParam("bits", "i32"); f.addParam("reverse", "i32"); f.addParam("mulFactor", "i32"); f.addLocal("n", "i32"); f.addLocal("ndiv2", "i32"); f.addLocal("pInv2", "i32"); f.addLocal("i", "i32"); f.addLocal("mask", "i32"); f.addLocal("idx1", "i32"); f.addLocal("idx2", "i32"); const c = f.getCodeBuilder(); const T = c.i32_const(module.alloc(n8g)); f.addCode( c.if( c.i32_and( c.i32_eqz(c.getLocal("reverse")), c.call(fPrefix + "_isOne", c.getLocal("mulFactor")) ), c.ret([]) ), c.setLocal("n", c.i32_shl( c.i32_const(1), c.getLocal("bits"))), c.setLocal("mask", c.i32_sub( c.getLocal("n") , c.i32_const(1))), c.setLocal("i", c.i32_const(1)), c.setLocal( "ndiv2", c.i32_shr_u( c.getLocal("n"), c.i32_const(1) ) ), c.block(c.loop( c.br_if( 1, c.i32_ge_u( c.getLocal("i"), c.getLocal("ndiv2") ) ), c.setLocal("idx1", c.i32_add( c.getLocal("px"), c.i32_mul( c.getLocal("i"), c.i32_const(n8g) ) ) ), c.setLocal("idx2", c.i32_add( c.getLocal("px"), c.i32_mul( c.i32_sub( c.getLocal("n"), c.getLocal("i") ), c.i32_const(n8g) ) ) ), c.if( c.getLocal("reverse"), c.if( c.call(fPrefix + "_isOne", c.getLocal("mulFactor")), [ ...c.call(gPrefix + "_copy", c.getLocal("idx1"), T), ...c.call(gPrefix + "_copy", c.getLocal("idx2") , c.getLocal("idx1") ), ...c.call(gPrefix + "_copy", T , c.getLocal("idx2")), ], [ ...c.call(gPrefix + "_copy", c.getLocal("idx1"), T), ...c.call(opGtimesF , c.getLocal("idx2") , c.getLocal("mulFactor"), c.getLocal("idx1") ), ...c.call(opGtimesF , T , c.getLocal("mulFactor"), c.getLocal("idx2")), ] ), c.if( c.call(fPrefix + "_isOne", c.getLocal("mulFactor")), [ // Do nothing (It should not be here) ], [ ...c.call(opGtimesF , c.getLocal("idx1") , c.getLocal("mulFactor"), c.getLocal("idx1") ), ...c.call(opGtimesF , c.getLocal("idx2") , c.getLocal("mulFactor"), c.getLocal("idx2")), ] ) ), c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))), c.br(0) )), c.if( c.call(fPrefix + "_isOne", c.getLocal("mulFactor")), [ // Do nothing (It should not be here) ], [ ...c.call(opGtimesF, c.getLocal("px") , c.getLocal("mulFactor"), c.getLocal("px")), ...c.setLocal("idx2", c.i32_add( c.getLocal("px"), c.i32_mul( c.getLocal("ndiv2"), c.i32_const(n8g) ) ) ), ...c.call(opGtimesF, c.getLocal("idx2"),c.getLocal("mulFactor"), c.getLocal("idx2")) ] ) ); } function buildReversePermutation() { const f = module.addFunction(prefix+"__reversePermutation"); f.addParam("px", "i32"); f.addParam("bits", "i32"); f.addLocal("n", "i32"); f.addLocal("i", "i32"); f.addLocal("ri", "i32"); f.addLocal("idx1", "i32"); f.addLocal("idx2", "i32"); const c = f.getCodeBuilder(); const T = c.i32_const(module.alloc(n8g)); f.addCode( c.setLocal("n", c.i32_shl( c.i32_const(1), c.getLocal("bits"))), c.setLocal("i", c.i32_const(0)), c.block(c.loop( c.br_if( 1, c.i32_eq( c.getLocal("i"), c.getLocal("n") ) ), c.setLocal("idx1", c.i32_add( c.getLocal("px"), c.i32_mul( c.getLocal("i"), c.i32_const(n8g) ) ) ), c.setLocal("ri", c.call(prefix + "__rev", c.getLocal("i"), c.getLocal("bits"))), c.setLocal("idx2", c.i32_add( c.getLocal("px"), c.i32_mul( c.getLocal("ri"), c.i32_const(n8g) ) ) ), c.if( c.i32_lt_u( c.getLocal("i"), c.getLocal("ri") ), [ ...c.call(gPrefix + "_copy", c.getLocal("idx1"), T), ...c.call(gPrefix + "_copy", c.getLocal("idx2") , c.getLocal("idx1")), ...c.call(gPrefix + "_copy", T , c.getLocal("idx2")) ] ), c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))), c.br(0) )) ); } function buildRev() { const f = module.addFunction(prefix+"__rev"); f.addParam("x", "i32"); f.addParam("bits", "i32"); f.setReturnType("i32"); const c = f.getCodeBuilder(); f.addCode( c.i32_rotl( c.i32_add( c.i32_add( c.i32_shl( c.i32_load8_u( c.i32_and( c.getLocal("x"), c.i32_const(0xFF) ), REVTABLE, 0 ), c.i32_const(24) ), c.i32_shl( c.i32_load8_u( c.i32_and( c.i32_shr_u( c.getLocal("x"), c.i32_const(8) ), c.i32_const(0xFF) ), REVTABLE, 0 ), c.i32_const(16) ), ), c.i32_add( c.i32_shl( c.i32_load8_u( c.i32_and( c.i32_shr_u( c.getLocal("x"), c.i32_const(16) ), c.i32_const(0xFF) ), REVTABLE, 0 ), c.i32_const(8) ), c.i32_load8_u( c.i32_and( c.i32_shr_u( c.getLocal("x"), c.i32_const(24) ), c.i32_const(0xFF) ), REVTABLE, 0 ), ) ), c.getLocal("bits") ) ); } function buildFFTJoin() { const f = module.addFunction(prefix+"_fftJoin"); f.addParam("pBuff1", "i32"); f.addParam("pBuff2", "i32"); f.addParam("n", "i32"); f.addParam("first", "i32"); f.addParam("inc", "i32"); f.addLocal("idx1", "i32"); f.addLocal("idx2", "i32"); f.addLocal("i", "i32"); const c = f.getCodeBuilder(); const W = c.i32_const(module.alloc(n8f)); const T = c.i32_const(module.alloc(n8g)); const U = c.i32_const(module.alloc(n8g)); f.addCode( c.call( fPrefix + "_copy", c.getLocal("first"), W), c.setLocal("i", c.i32_const(0)), c.block(c.loop( c.br_if( 1, c.i32_eq( c.getLocal("i"), c.getLocal("n") ) ), c.setLocal( "idx1", c.i32_add( c.getLocal("pBuff1"), c.i32_mul( c.getLocal("i"), c.i32_const(n8g) ) ) ), c.setLocal( "idx2", c.i32_add( c.getLocal("pBuff2"), c.i32_mul( c.getLocal("i"), c.i32_const(n8g) ) ) ), c.call( opGtimesF, c.getLocal("idx2"), W, T ), c.call( gPrefix + "_copy", c.getLocal("idx1"), U ), c.call( gPrefix + "_add", U, T, c.getLocal("idx1"), ), c.call( gPrefix + "_sub", U, T, c.getLocal("idx2"), ), c.call( fPrefix + "_mul", W, c.getLocal("inc"), W, ), c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))), c.br(0) )) ); } function buildFFTJoinExt() { const f = module.addFunction(prefix+"_fftJoinExt"); f.addParam("pBuff1", "i32"); f.addParam("pBuff2", "i32"); f.addParam("n", "i32"); f.addParam("first", "i32"); f.addParam("inc", "i32"); f.addParam("totalBits", "i32"); f.addLocal("idx1", "i32"); f.addLocal("idx2", "i32"); f.addLocal("i", "i32"); f.addLocal("pShiftToM", "i32"); const c = f.getCodeBuilder(); const W = c.i32_const(module.alloc(n8f)); const U = c.i32_const(module.alloc(n8g)); f.addCode( c.setLocal("pShiftToM", c.i32_add( c.i32_const(SHIFT_TO_M), c.i32_mul( c.getLocal("totalBits"), c.i32_const(n8f) ) ) ), c.call( fPrefix + "_copy", c.getLocal("first"), W), c.setLocal("i", c.i32_const(0)), c.block(c.loop( c.br_if( 1, c.i32_eq( c.getLocal("i"), c.getLocal("n") ) ), c.setLocal( "idx1", c.i32_add( c.getLocal("pBuff1"), c.i32_mul( c.getLocal("i"), c.i32_const(n8g) ) ) ), c.setLocal( "idx2", c.i32_add( c.getLocal("pBuff2"), c.i32_mul( c.getLocal("i"), c.i32_const(n8g) ) ) ), c.call( gPrefix + "_add", c.getLocal("idx1"), c.getLocal("idx2"), U ), c.call( opGtimesF, c.getLocal("idx2"), c.getLocal("pShiftToM"), c.getLocal("idx2") ), c.call( gPrefix + "_add", c.getLocal("idx1"), c.getLocal("idx2"), c.getLocal("idx2") ), c.call( opGtimesF, c.getLocal("idx2"), W, c.getLocal("idx2"), ), c.call( gPrefix + "_copy", U, c.getLocal("idx1") ), c.call( fPrefix + "_mul", W, c.getLocal("inc"), W ), c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))), c.br(0) )) ); } function buildFFTJoinExtInv() { const f = module.addFunction(prefix+"_fftJoinExtInv"); f.addParam("pBuff1", "i32"); f.addParam("pBuff2", "i32"); f.addParam("n", "i32"); f.addParam("first", "i32"); f.addParam("inc", "i32"); f.addParam("totalBits", "i32"); f.addLocal("idx1", "i32"); f.addLocal("idx2", "i32"); f.addLocal("i", "i32"); f.addLocal("pShiftToM", "i32"); f.addLocal("pSConst", "i32"); const c = f.getCodeBuilder(); const W = c.i32_const(module.alloc(n8f)); const U = c.i32_const(module.alloc(n8g)); f.addCode( c.setLocal("pShiftToM", c.i32_add( c.i32_const(SHIFT_TO_M), c.i32_mul( c.getLocal("totalBits"), c.i32_const(n8f) ) ) ), c.setLocal("pSConst", c.i32_add( c.i32_const(SCONST), c.i32_mul( c.getLocal("totalBits"), c.i32_const(n8f) ) ) ), c.call( fPrefix + "_copy", c.getLocal("first"), W), c.setLocal("i", c.i32_const(0)), c.block(c.loop( c.br_if( 1, c.i32_eq( c.getLocal("i"), c.getLocal("n") ) ), c.setLocal( "idx1", c.i32_add( c.getLocal("pBuff1"), c.i32_mul( c.getLocal("i"), c.i32_const(n8g) ) ) ), c.setLocal( "idx2", c.i32_add( c.getLocal("pBuff2"), c.i32_mul( c.getLocal("i"), c.i32_const(n8g) ) ) ), c.call( opGtimesF, c.getLocal("idx2"), W, U ), c.call( gPrefix + "_sub", c.getLocal("idx1"), U, c.getLocal("idx2"), ), c.call( opGtimesF, c.getLocal("idx2"), c.getLocal("pSConst"), c.getLocal("idx2") ), c.call( opGtimesF, c.getLocal("idx1"), c.getLocal("pShiftToM"), c.getLocal("idx1") ), c.call( gPrefix + "_sub", U, c.getLocal("idx1"), c.getLocal("idx1") ), c.call( opGtimesF, c.getLocal("idx1"), c.getLocal("pSConst"), c.getLocal("idx1") ), c.call( fPrefix + "_mul", W, c.getLocal("inc"), W ), c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))), c.br(0) )) ); } function buildPrepareLagrangeEvaluation() { const f = module.addFunction(prefix+"_prepareLagrangeEvaluation"); f.addParam("pBuff1", "i32"); f.addParam("pBuff2", "i32"); f.addParam("n", "i32"); f.addParam("first", "i32"); f.addParam("inc", "i32"); f.addParam("totalBits", "i32"); f.addLocal("idx1", "i32"); f.addLocal("idx2", "i32"); f.addLocal("i", "i32"); f.addLocal("pShiftToM", "i32"); f.addLocal("pSConst", "i32"); const c = f.getCodeBuilder(); const W = c.i32_const(module.alloc(n8f)); const U = c.i32_const(module.alloc(n8g)); f.addCode( c.setLocal("pShiftToM", c.i32_add( c.i32_const(SHIFT_TO_M), c.i32_mul( c.getLocal("totalBits"), c.i32_const(n8f) ) ) ), c.setLocal("pSConst", c.i32_add( c.i32_const(SCONST), c.i32_mul( c.getLocal("totalBits"), c.i32_const(n8f) ) ) ), c.call( fPrefix + "_copy", c.getLocal("first"), W), c.setLocal("i", c.i32_const(0)), c.block(c.loop( c.br_if( 1, c.i32_eq( c.getLocal("i"), c.getLocal("n") ) ), c.setLocal( "idx1", c.i32_add( c.getLocal("pBuff1"), c.i32_mul( c.getLocal("i"), c.i32_const(n8g) ) ) ), c.setLocal( "idx2", c.i32_add( c.getLocal("pBuff2"), c.i32_mul( c.getLocal("i"), c.i32_const(n8g) ) ) ), c.call( opGtimesF, c.getLocal("idx1"), c.getLocal("pShiftToM"), U ), c.call( gPrefix + "_sub", c.getLocal("idx2"), U, U ), c.call( gPrefix + "_sub", c.getLocal("idx1"), c.getLocal("idx2"), c.getLocal("idx2"), ), c.call( opGtimesF, U, c.getLocal("pSConst"), c.getLocal("idx1"), ), c.call( opGtimesF, c.getLocal("idx2"), W, c.getLocal("idx2"), ), c.call( fPrefix + "_mul", W, c.getLocal("inc"), W ), c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))), c.br(0) )) ); } function buildFFTMix() { const f = module.addFunction(prefix+"_fftMix"); f.addParam("pBuff", "i32"); f.addParam("n", "i32"); f.addParam("exp", "i32"); f.addLocal("nGroups", "i32"); f.addLocal("nPerGroup", "i32"); f.addLocal("nPerGroupDiv2", "i32"); f.addLocal("pairOffset", "i32"); f.addLocal("idx1", "i32"); f.addLocal("idx2", "i32"); f.addLocal("i", "i32"); f.addLocal("j", "i32"); f.addLocal("pwm", "i32"); const c = f.getCodeBuilder(); const W = c.i32_const(module.alloc(n8f)); const T = c.i32_const(module.alloc(n8g)); const U = c.i32_const(module.alloc(n8g)); f.addCode( c.setLocal("nPerGroup", c.i32_shl(c.i32_const(1), c.getLocal("exp"))), c.setLocal("nPerGroupDiv2", c.i32_shr_u(c.getLocal("nPerGroup"), c.i32_const(1))), c.setLocal("nGroups", c.i32_shr_u(c.getLocal("n"), c.getLocal("exp"))), c.setLocal("pairOffset", c.i32_mul(c.getLocal("nPerGroupDiv2"), c.i32_const(n8g))), c.setLocal("pwm", c.i32_add( c.i32_const(ROOTs), c.i32_mul( c.getLocal("exp"), c.i32_const(n8f) ) ) ), c.setLocal("i", c.i32_const(0)), c.block(c.loop( c.br_if( 1, c.i32_eq( c.getLocal("i"), c.getLocal("nGroups") ) ), c.call( fPrefix + "_one", W), c.setLocal("j", c.i32_const(0)), c.block(c.loop( c.br_if( 1, c.i32_eq( c.getLocal("j"), c.getLocal("nPerGroupDiv2") ) ), c.setLocal( "idx1", c.i32_add( c.getLocal("pBuff"), c.i32_mul( c.i32_add( c.i32_mul( c.getLocal("i"), c.getLocal("nPerGroup") ), c.getLocal("j") ), c.i32_const(n8g) ) ) ), c.setLocal( "idx2", c.i32_add( c.getLocal("idx1"), c.getLocal("pairOffset") ) ), c.call( opGtimesF, c.getLocal("idx2"), W, T ), c.call( gPrefix + "_copy", c.getLocal("idx1"), U ), c.call( gPrefix + "_add", U, T, c.getLocal("idx1"), ), c.call( gPrefix + "_sub", U, T, c.getLocal("idx2"), ), c.call( fPrefix + "_mul", W, c.getLocal("pwm"), W, ), c.setLocal("j", c.i32_add(c.getLocal("j"), c.i32_const(1))), c.br(0) )), c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))), c.br(0) )) ); } // Reverse all and multiply by factor function buildFFTFinal() { const f = module.addFunction(prefix+"_fftFinal"); f.addParam("pBuff", "i32"); f.addParam("n", "i32"); f.addParam("factor", "i32"); f.addLocal("idx1", "i32"); f.addLocal("idx2", "i32"); f.addLocal("i", "i32"); f.addLocal("ndiv2", "i32"); const c = f.getCodeBuilder(); const T = c.i32_const(module.alloc(n8g)); f.addCode( c.setLocal("ndiv2", c.i32_shr_u(c.getLocal("n"), c.i32_const(1))), c.if( c.i32_and( c.getLocal("n"), c.i32_const(1) ), c.call( opGtimesF, c.i32_add( c.getLocal("pBuff"), c.i32_mul( c.getLocal("ndiv2"), c.i32_const(n8g) ) ), c.getLocal("factor"), c.i32_add( c.getLocal("pBuff"), c.i32_mul( c.getLocal("ndiv2"), c.i32_const(n8g) ) ), ), ), c.setLocal("i", c.i32_const(0)), c.block(c.loop( c.br_if( 1, c.i32_ge_u( c.getLocal("i"), c.getLocal("ndiv2") ) ), c.setLocal( "idx1", c.i32_add( c.getLocal("pBuff"), c.i32_mul( c.getLocal("i"), c.i32_const(n8g) ) ) ), c.setLocal( "idx2", c.i32_add( c.getLocal("pBuff"), c.i32_mul( c.i32_sub( c.i32_sub( c.getLocal("n"), c.i32_const(1) ), c.getLocal("i") ), c.i32_const(n8g) ) ) ), c.call( opGtimesF, c.getLocal("idx2"), c.getLocal("factor"), T ), c.call( opGtimesF, c.getLocal("idx1"), c.getLocal("factor"), c.getLocal("idx2"), ), c.call( gPrefix + "_copy", T, c.getLocal("idx1"), ), c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))), c.br(0) )) ); } buildRev(); buildReversePermutation(); buildFinalInverse(); buildRawFFT(); buildLog2(); buildFFT(); buildIFFT(); buildFFTJoin(); buildFFTJoinExt(); buildFFTJoinExtInv(); buildFFTMix(); buildFFTFinal(); buildPrepareLagrangeEvaluation(); module.exportFunction(prefix+"_fft"); module.exportFunction(prefix+"_ifft"); module.exportFunction(prefix+"_rawfft"); module.exportFunction(prefix+"_fftJoin"); module.exportFunction(prefix+"_fftJoinExt"); module.exportFunction(prefix+"_fftJoinExtInv"); module.exportFunction(prefix+"_fftMix"); module.exportFunction(prefix+"_fftFinal"); module.exportFunction(prefix+"_prepareLagrangeEvaluation"); }; /* Copyright 2019 0KIMS association. This file is part of wasmsnark (Web Assembly zkSnark Prover). wasmsnark is a free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. wasmsnark is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with wasmsnark. If not, see . */ var build_pol = function buildPol(module, prefix, prefixField) { const n64 = module.modules[prefixField].n64; const n8 = n64*8; function buildZero() { const f = module.addFunction(prefix+"_zero"); f.addParam("px", "i32"); f.addParam("n", "i32"); f.addLocal("lastp", "i32"); f.addLocal("p", "i32"); const c = f.getCodeBuilder(); f.addCode( c.setLocal("p", c.getLocal("px")), c.setLocal( "lastp", c.i32_add( c.getLocal("px"), c.i32_mul( c.getLocal("n"), c.i32_const(n8) ) ) ), c.block(c.loop( c.br_if( 1, c.i32_eq( c.getLocal("p"), c.getLocal("lastp") ) ), c.call(prefixField + "_zero", c.getLocal("p")), c.setLocal("p", c.i32_add(c.getLocal("p"), c.i32_const(n8))), c.br(0) )) ); } function buildConstructLC() { const f = module.addFunction(prefix+"_constructLC"); f.addParam("ppolynomials", "i32"); f.addParam("psignals", "i32"); f.addParam("nSignals", "i32"); f.addParam("pres", "i32"); f.addLocal("i", "i32"); f.addLocal("j", "i32"); f.addLocal("pp", "i32"); f.addLocal("ps", "i32"); f.addLocal("pd", "i32"); f.addLocal("ncoefs", "i32"); const c = f.getCodeBuilder(); const aux = c.i32_const(module.alloc(n8)); f.addCode( c.setLocal("i", c.i32_const(0)), c.setLocal("pp", c.getLocal("ppolynomials")), c.setLocal("ps", c.getLocal("psignals")), c.block(c.loop( c.br_if( 1, c.i32_eq( c.getLocal("i"), c.getLocal("nSignals") ) ), c.setLocal("ncoefs", c.i32_load(c.getLocal("pp"))), c.setLocal("pp", c.i32_add(c.getLocal("pp"), c.i32_const(4))), c.setLocal("j", c.i32_const(0)), c.block(c.loop( c.br_if( 1, c.i32_eq( c.getLocal("j"), c.getLocal("ncoefs") ) ), c.setLocal( "pd", c.i32_add( c.getLocal("pres"), c.i32_mul( c.i32_load(c.getLocal("pp")), c.i32_const(n8) ) ) ), c.setLocal("pp", c.i32_add(c.getLocal("pp"), c.i32_const(4))), c.call( prefixField + "_mul", c.getLocal("ps"), c.getLocal("pp"), aux ), c.call( prefixField + "_add", aux, c.getLocal("pd"), c.getLocal("pd") ), c.setLocal("pp", c.i32_add(c.getLocal("pp"), c.i32_const(n8))), c.setLocal("j", c.i32_add(c.getLocal("j"), c.i32_const(1))), c.br(0) )), c.setLocal("ps", c.i32_add(c.getLocal("ps"), c.i32_const(n8))), c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))), c.br(0) )) ); } buildZero(); buildConstructLC(); module.exportFunction(prefix + "_zero"); module.exportFunction(prefix + "_constructLC"); return prefix; }; var build_qap = function buildQAP(module, prefix, prefixField) { const n64 = module.modules[prefixField].n64; const n8 = n64*8; function buildBuildABC() { const f = module.addFunction(prefix+"_buildABC"); f.addParam("pCoefs", "i32"); f.addParam("nCoefs", "i32"); f.addParam("pWitness", "i32"); f.addParam("pA", "i32"); f.addParam("pB", "i32"); f.addParam("pC", "i32"); f.addParam("offsetOut", "i32"); f.addParam("nOut", "i32"); f.addParam("offsetWitness", "i32"); f.addParam("nWitness", "i32"); f.addLocal("it", "i32"); f.addLocal("ita", "i32"); f.addLocal("itb", "i32"); f.addLocal("last", "i32"); f.addLocal("m", "i32"); f.addLocal("c", "i32"); f.addLocal("s", "i32"); f.addLocal("pOut", "i32"); const c = f.getCodeBuilder(); const aux = c.i32_const(module.alloc(n8)); f.addCode( // Set output a and b to 0 c.setLocal("ita", c.getLocal("pA")), c.setLocal("itb", c.getLocal("pB")), c.setLocal( "last", c.i32_add( c.getLocal("pA"), c.i32_mul( c.getLocal("nOut"), c.i32_const(n8) ) ) ), c.block(c.loop( c.br_if( 1, c.i32_eq( c.getLocal("ita"), c.getLocal("last") ) ), c.call(prefixField + "_zero", c.getLocal("ita")), c.call(prefixField + "_zero", c.getLocal("itb")), c.setLocal("ita", c.i32_add(c.getLocal("ita"), c.i32_const(n8))), c.setLocal("itb", c.i32_add(c.getLocal("itb"), c.i32_const(n8))), c.br(0) )), c.setLocal("it", c.getLocal("pCoefs")), c.setLocal( "last", c.i32_add( c.getLocal("pCoefs"), c.i32_mul( c.getLocal("nCoefs"), c.i32_const(n8+12) ) ) ), c.block(c.loop( c.br_if( 1, c.i32_eq( c.getLocal("it"), c.getLocal("last") ) ), c.setLocal( "s", c.i32_load(c.getLocal("it"), 8) ), c.if( c.i32_or( c.i32_lt_u( c.getLocal("s"), c.getLocal("offsetWitness"), ), c.i32_ge_u( c.getLocal("s"), c.i32_add( c.getLocal("offsetWitness"), c.getLocal("nWitness"), ) ) ), [ ...c.setLocal("it", c.i32_add(c.getLocal("it"), c.i32_const(n8+12))), ...c.br(1) ] ), c.setLocal( "m", c.i32_load(c.getLocal("it")) ), c.if( c.i32_eq(c.getLocal("m"), c.i32_const(0)), c.setLocal("pOut", c.getLocal("pA")), c.if( c.i32_eq(c.getLocal("m"), c.i32_const(1)), c.setLocal("pOut", c.getLocal("pB")), [ ...c.setLocal("it", c.i32_add(c.getLocal("it"), c.i32_const(n8+12))), ...c.br(1) ] ) ), c.setLocal( "c", c.i32_load(c.getLocal("it"), 4) ), c.if( c.i32_or( c.i32_lt_u( c.getLocal("c"), c.getLocal("offsetOut"), ), c.i32_ge_u( c.getLocal("c"), c.i32_add( c.getLocal("offsetOut"), c.getLocal("nOut"), ) ) ), [ ...c.setLocal("it", c.i32_add(c.getLocal("it"), c.i32_const(n8+12))), ...c.br(1) ] ), c.setLocal( "pOut", c.i32_add( c.getLocal("pOut"), c.i32_mul( c.i32_sub( c.getLocal("c"), c.getLocal("offsetOut") ), c.i32_const(n8) ) ) ), c.call( prefixField + "_mul", c.i32_add( c.getLocal("pWitness"), c.i32_mul( c.i32_sub(c.getLocal("s"), c.getLocal("offsetWitness")), c.i32_const(n8) ) ), c.i32_add( c.getLocal("it"), c.i32_const(12)), aux ), c.call( prefixField + "_add", c.getLocal("pOut"), aux, c.getLocal("pOut"), ), c.setLocal("it", c.i32_add(c.getLocal("it"), c.i32_const(n8+12))), c.br(0) )), c.setLocal("ita", c.getLocal("pA")), c.setLocal("itb", c.getLocal("pB")), c.setLocal("it", c.getLocal("pC")), c.setLocal( "last", c.i32_add( c.getLocal("pA"), c.i32_mul( c.getLocal("nOut"), c.i32_const(n8) ) ) ), c.block(c.loop( c.br_if( 1, c.i32_eq( c.getLocal("ita"), c.getLocal("last") ) ), c.call( prefixField + "_mul", c.getLocal("ita"), c.getLocal("itb"), c.getLocal("it") ), c.setLocal("ita", c.i32_add(c.getLocal("ita"), c.i32_const(n8))), c.setLocal("itb", c.i32_add(c.getLocal("itb"), c.i32_const(n8))), c.setLocal("it", c.i32_add(c.getLocal("it"), c.i32_const(n8))), c.br(0) )), ); } function buildJoinABC() { const f = module.addFunction(prefix+"_joinABC"); f.addParam("pA", "i32"); f.addParam("pB", "i32"); f.addParam("pC", "i32"); f.addParam("n", "i32"); f.addParam("pP", "i32"); f.addLocal("ita", "i32"); f.addLocal("itb", "i32"); f.addLocal("itc", "i32"); f.addLocal("itp", "i32"); f.addLocal("last", "i32"); const c = f.getCodeBuilder(); const aux = c.i32_const(module.alloc(n8)); f.addCode( c.setLocal("ita", c.getLocal("pA")), c.setLocal("itb", c.getLocal("pB")), c.setLocal("itc", c.getLocal("pC")), c.setLocal("itp", c.getLocal("pP")), c.setLocal( "last", c.i32_add( c.getLocal("pA"), c.i32_mul( c.getLocal("n"), c.i32_const(n8) ) ) ), c.block(c.loop( c.br_if( 1, c.i32_eq( c.getLocal("ita"), c.getLocal("last") ) ), c.call( prefixField + "_mul", c.getLocal("ita"), c.getLocal("itb"), aux ), c.call( prefixField + "_sub", aux, c.getLocal("itc"), c.getLocal("itp"), ), c.setLocal("ita", c.i32_add(c.getLocal("ita"), c.i32_const(n8))), c.setLocal("itb", c.i32_add(c.getLocal("itb"), c.i32_const(n8))), c.setLocal("itc", c.i32_add(c.getLocal("itc"), c.i32_const(n8))), c.setLocal("itp", c.i32_add(c.getLocal("itp"), c.i32_const(n8))), c.br(0) )) ); } function buildBatchAdd() { const f = module.addFunction(prefix+"_batchAdd"); f.addParam("pa", "i32"); f.addParam("pb", "i32"); f.addParam("n", "i32"); f.addParam("pr", "i32"); f.addLocal("ita", "i32"); f.addLocal("itb", "i32"); f.addLocal("itr", "i32"); f.addLocal("last", "i32"); const c = f.getCodeBuilder(); f.addCode( c.setLocal("ita", c.getLocal("pa")), c.setLocal("itb", c.getLocal("pb")), c.setLocal("itr", c.getLocal("pr")), c.setLocal( "last", c.i32_add( c.getLocal("pa"), c.i32_mul( c.getLocal("n"), c.i32_const(n8) ) ) ), c.block(c.loop( c.br_if( 1, c.i32_eq( c.getLocal("ita"), c.getLocal("last") ) ), c.call( prefixField + "_add", c.getLocal("ita"), c.getLocal("itb"), c.getLocal("itr"), ), c.setLocal("ita", c.i32_add(c.getLocal("ita"), c.i32_const(n8))), c.setLocal("itb", c.i32_add(c.getLocal("itb"), c.i32_const(n8))), c.setLocal("itr", c.i32_add(c.getLocal("itr"), c.i32_const(n8))), c.br(0) )) ); } buildBuildABC(); buildJoinABC(); buildBatchAdd(); module.exportFunction(prefix + "_buildABC"); module.exportFunction(prefix + "_joinABC"); module.exportFunction(prefix + "_batchAdd"); return prefix; }; /* Copyright 2019 0KIMS association. This file is part of wasmsnark (Web Assembly zkSnark Prover). wasmsnark is a free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. wasmsnark is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with wasmsnark. If not, see . */ var build_applykey = function buildApplyKey(module, fnName, gPrefix, frPrefix, sizeGIn, sizeGOut, sizeF, opGtimesF) { const f = module.addFunction(fnName); f.addParam("pIn", "i32"); f.addParam("n", "i32"); f.addParam("pFirst", "i32"); f.addParam("pInc", "i32"); f.addParam("pOut", "i32"); f.addLocal("pOldFree", "i32"); f.addLocal("i", "i32"); f.addLocal("pFrom", "i32"); f.addLocal("pTo", "i32"); const c = f.getCodeBuilder(); const t = c.i32_const(module.alloc(sizeF)); f.addCode( c.setLocal("pFrom", c.getLocal("pIn")), c.setLocal("pTo", c.getLocal("pOut")), ); // t = first f.addCode( c.call( frPrefix + "_copy", c.getLocal("pFirst"), t ) ); f.addCode( c.setLocal("i", c.i32_const(0)), c.block(c.loop( c.br_if(1, c.i32_eq ( c.getLocal("i"), c.getLocal("n") )), c.call( opGtimesF, c.getLocal("pFrom"), t, c.getLocal("pTo") ), c.setLocal("pFrom", c.i32_add(c.getLocal("pFrom"), c.i32_const(sizeGIn))), c.setLocal("pTo", c.i32_add(c.getLocal("pTo"), c.i32_const(sizeGOut))), // t = t* inc c.call( frPrefix + "_mul", t, c.getLocal("pInc"), t ), c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))), c.br(0) )) ); module.exportFunction(fnName); }; const bigInt$2 = BigIntegerExports; const utils$6 = utils$b; const buildF1m$1 =build_f1m; const buildF1$1 =build_f1; const buildF2m$1 =build_f2m; const buildF3m$1 =build_f3m; const buildCurve$1 =build_curve_jacobian_a0; const buildFFT$2 = build_fft; const buildPol$1 = build_pol; const buildQAP$1 = build_qap; const buildApplyKey$1 = build_applykey; var build_bn128 = function buildBN128(module, _prefix) { const prefix = _prefix || "bn128"; if (module.modules[prefix]) return prefix; // already builded const q = bigInt$2("21888242871839275222246405745257275088696311157297823662689037894645226208583"); const r = bigInt$2("21888242871839275222246405745257275088548364400416034343698204186575808495617"); const n64 = Math.floor((q.minus(1).bitLength() - 1)/64) +1; const n8 = n64*8; const frsize = n8; const f1size = n8; const f2size = f1size * 2; const ftsize = f1size * 12; const pr = module.alloc(utils$6.bigInt2BytesLE( r, frsize )); const f1mPrefix = buildF1m$1(module, q, "f1m"); buildF1$1(module, r, "fr", "frm"); const pG1b = module.alloc(utils$6.bigInt2BytesLE( toMontgomery(bigInt$2(3)), f1size )); const g1mPrefix = buildCurve$1(module, "g1m", "f1m", pG1b); buildFFT$2(module, "frm", "frm", "frm", "frm_mul"); buildPol$1(module, "pol", "frm"); buildQAP$1(module, "qap", "frm"); const f2mPrefix = buildF2m$1(module, "f1m_neg", "f2m", "f1m"); const pG2b = module.alloc([ ...utils$6.bigInt2BytesLE( toMontgomery(bigInt$2("19485874751759354771024239261021720505790618469301721065564631296452457478373")), f1size ), ...utils$6.bigInt2BytesLE( toMontgomery(bigInt$2("266929791119991161246907387137283842545076965332900288569378510910307636690")), f1size ) ]); const g2mPrefix = buildCurve$1(module, "g2m", "f2m", pG2b); function buildGTimesFr(fnName, opMul) { const f = module.addFunction(fnName); f.addParam("pG", "i32"); f.addParam("pFr", "i32"); f.addParam("pr", "i32"); const c = f.getCodeBuilder(); const AUX = c.i32_const(module.alloc(n8)); f.addCode( c.call("frm_fromMontgomery", c.getLocal("pFr"), AUX), c.call( opMul, c.getLocal("pG"), AUX, c.i32_const(n8), c.getLocal("pr") ) ); module.exportFunction(fnName); } buildGTimesFr("g1m_timesFr", "g1m_timesScalar"); buildFFT$2(module, "g1m", "g1m", "frm", "g1m_timesFr"); buildGTimesFr("g2m_timesFr", "g2m_timesScalar"); buildFFT$2(module, "g2m", "g2m", "frm", "g2m_timesFr"); buildGTimesFr("g1m_timesFrAffine", "g1m_timesScalarAffine"); buildGTimesFr("g2m_timesFrAffine", "g2m_timesScalarAffine"); buildApplyKey$1(module, "frm_batchApplyKey", "fmr", "frm", n8, n8, n8, "frm_mul"); buildApplyKey$1(module, "g1m_batchApplyKey", "g1m", "frm", n8*3, n8*3, n8, "g1m_timesFr"); buildApplyKey$1(module, "g1m_batchApplyKeyMixed", "g1m", "frm", n8*2, n8*3, n8, "g1m_timesFrAffine"); buildApplyKey$1(module, "g2m_batchApplyKey", "g2m", "frm", n8*2*3, n8*3*2, n8, "g2m_timesFr"); buildApplyKey$1(module, "g2m_batchApplyKeyMixed", "g2m", "frm", n8*2*2, n8*3*2, n8, "g2m_timesFrAffine"); function toMontgomery(a) { return bigInt$2(a).times( bigInt$2.one.shiftLeft(f1size*8)).mod(q); } const G1gen = [ bigInt$2("1"), bigInt$2("2"), bigInt$2.one ]; const pG1gen = module.alloc( [ ...utils$6.bigInt2BytesLE( toMontgomery(G1gen[0]), f1size ), ...utils$6.bigInt2BytesLE( toMontgomery(G1gen[1]), f1size ), ...utils$6.bigInt2BytesLE( toMontgomery(G1gen[2]), f1size ), ] ); const G1zero = [ bigInt$2.zero, bigInt$2.one, bigInt$2.zero ]; const pG1zero = module.alloc( [ ...utils$6.bigInt2BytesLE( toMontgomery(G1zero[0]), f1size ), ...utils$6.bigInt2BytesLE( toMontgomery(G1zero[1]), f1size ), ...utils$6.bigInt2BytesLE( toMontgomery(G1zero[2]), f1size ) ] ); const G2gen = [ [ bigInt$2("10857046999023057135944570762232829481370756359578518086990519993285655852781"), bigInt$2("11559732032986387107991004021392285783925812861821192530917403151452391805634"), ],[ bigInt$2("8495653923123431417604973247489272438418190587263600148770280649306958101930"), bigInt$2("4082367875863433681332203403145435568316851327593401208105741076214120093531"), ],[ bigInt$2.one, bigInt$2.zero, ] ]; const pG2gen = module.alloc( [ ...utils$6.bigInt2BytesLE( toMontgomery(G2gen[0][0]), f1size ), ...utils$6.bigInt2BytesLE( toMontgomery(G2gen[0][1]), f1size ), ...utils$6.bigInt2BytesLE( toMontgomery(G2gen[1][0]), f1size ), ...utils$6.bigInt2BytesLE( toMontgomery(G2gen[1][1]), f1size ), ...utils$6.bigInt2BytesLE( toMontgomery(G2gen[2][0]), f1size ), ...utils$6.bigInt2BytesLE( toMontgomery(G2gen[2][1]), f1size ), ] ); const G2zero = [ [ bigInt$2.zero, bigInt$2.zero, ],[ bigInt$2.one, bigInt$2.zero, ],[ bigInt$2.zero, bigInt$2.zero, ] ]; const pG2zero = module.alloc( [ ...utils$6.bigInt2BytesLE( toMontgomery(G2zero[0][0]), f1size ), ...utils$6.bigInt2BytesLE( toMontgomery(G2zero[0][1]), f1size ), ...utils$6.bigInt2BytesLE( toMontgomery(G2zero[1][0]), f1size ), ...utils$6.bigInt2BytesLE( toMontgomery(G2zero[1][1]), f1size ), ...utils$6.bigInt2BytesLE( toMontgomery(G2zero[2][0]), f1size ), ...utils$6.bigInt2BytesLE( toMontgomery(G2zero[2][1]), f1size ), ] ); const pOneT = module.alloc([ ...utils$6.bigInt2BytesLE( toMontgomery(1), f1size ), ...utils$6.bigInt2BytesLE( toMontgomery(0), f1size ), ...utils$6.bigInt2BytesLE( toMontgomery(0), f1size ), ...utils$6.bigInt2BytesLE( toMontgomery(0), f1size ), ...utils$6.bigInt2BytesLE( toMontgomery(0), f1size ), ...utils$6.bigInt2BytesLE( toMontgomery(0), f1size ), ...utils$6.bigInt2BytesLE( toMontgomery(0), f1size ), ...utils$6.bigInt2BytesLE( toMontgomery(0), f1size ), ...utils$6.bigInt2BytesLE( toMontgomery(0), f1size ), ...utils$6.bigInt2BytesLE( toMontgomery(0), f1size ), ...utils$6.bigInt2BytesLE( toMontgomery(0), f1size ), ...utils$6.bigInt2BytesLE( toMontgomery(0), f1size ), ]); const pNonResidueF6 = module.alloc([ ...utils$6.bigInt2BytesLE( toMontgomery(9), f1size ), ...utils$6.bigInt2BytesLE( toMontgomery(1), f1size ), ]); const pTwoInv = module.alloc([ ...utils$6.bigInt2BytesLE( toMontgomery( bigInt$2(2).modInv(q)), f1size ), ...utils$6.bigInt2BytesLE( bigInt$2(0), f1size ) ]); const pAltBn128Twist = pNonResidueF6; const pTwistCoefB = module.alloc([ ...utils$6.bigInt2BytesLE( toMontgomery("19485874751759354771024239261021720505790618469301721065564631296452457478373"), f1size ), ...utils$6.bigInt2BytesLE( toMontgomery("266929791119991161246907387137283842545076965332900288569378510910307636690"), f1size ), ]); function build_mulNR6() { const f = module.addFunction(prefix + "_mulNR6"); f.addParam("x", "i32"); f.addParam("pr", "i32"); const c = f.getCodeBuilder(); f.addCode( c.call( f2mPrefix + "_mul", c.i32_const(pNonResidueF6), c.getLocal("x"), c.getLocal("pr") ) ); } build_mulNR6(); const f6mPrefix = buildF3m$1(module, prefix+"_mulNR6", "f6m", "f2m"); function build_mulNR12() { const f = module.addFunction(prefix + "_mulNR12"); f.addParam("x", "i32"); f.addParam("pr", "i32"); const c = f.getCodeBuilder(); f.addCode( c.call( f2mPrefix + "_mul", c.i32_const(pNonResidueF6), c.i32_add(c.getLocal("x"), c.i32_const(n8*4)), c.getLocal("pr") ), c.call( f2mPrefix + "_copy", c.getLocal("x"), c.i32_add(c.getLocal("pr"), c.i32_const(n8*2)), ), c.call( f2mPrefix + "_copy", c.i32_add(c.getLocal("x"), c.i32_const(n8*2)), c.i32_add(c.getLocal("pr"), c.i32_const(n8*4)), ) ); } build_mulNR12(); const ftmPrefix = buildF2m$1(module, prefix+"_mulNR12", "ftm", f6mPrefix); const ateLoopCount = bigInt$2("29793968203157093288"); const ateLoopBitBytes = bits(ateLoopCount); const pAteLoopBitBytes = module.alloc(ateLoopBitBytes); const ateCoefSize = 3 * f2size; const ateNDblCoefs = ateLoopBitBytes.length-1; const ateNAddCoefs = ateLoopBitBytes.reduce((acc, b) => acc + ( b!=0 ? 1 : 0) ,0); const ateNCoefs = ateNAddCoefs + ateNDblCoefs + 1; const prePSize = 3*2*n8; const preQSize = 3*n8*2 + ateNCoefs*ateCoefSize; module.modules[prefix] = { n64: n64, pG1gen: pG1gen, pG1zero: pG1zero, pG1b: pG1b, pG2gen: pG2gen, pG2zero: pG2zero, pG2b: pG2b, pq: module.modules["f1m"].pq, pr: pr, pOneT: pOneT, prePSize: prePSize, preQSize: preQSize, r: r.toString(), q: q.toString() }; // console.log("PrePSize: " +prePSize); // console.log("PreQSize: " +preQSize); const finalExpZ = bigInt$2("4965661367192848881"); function naf(n) { let E = n; const res = []; while (E.gt(bigInt$2.zero)) { if (E.isOdd()) { const z = 2 - E.mod(4).toJSNumber(); res.push( z ); E = E.minus(z); } else { res.push( 0 ); } E = E.shiftRight(1); } return res; } function bits(n) { let E = n; const res = []; while (E.gt(bigInt$2.zero)) { if (E.isOdd()) { res.push( 1 ); } else { res.push( 0 ); } E = E.shiftRight(1); } return res; } function buildPrepareG1() { const f = module.addFunction(prefix+ "_prepareG1"); f.addParam("pP", "i32"); f.addParam("ppreP", "i32"); const c = f.getCodeBuilder(); f.addCode( c.call(g1mPrefix + "_normalize", c.getLocal("pP"), c.getLocal("ppreP")), // TODO Remove if already in affine ); } function buildPrepAddStep() { const f = module.addFunction(prefix+ "_prepAddStep"); f.addParam("pQ", "i32"); f.addParam("pR", "i32"); f.addParam("pCoef", "i32"); const c = f.getCodeBuilder(); const X2 = c.getLocal("pQ"); const Y2 = c.i32_add(c.getLocal("pQ"), c.i32_const(f2size)); const X1 = c.getLocal("pR"); const Y1 = c.i32_add(c.getLocal("pR"), c.i32_const(f2size)); const Z1 = c.i32_add(c.getLocal("pR"), c.i32_const(2*f2size)); const ELL_0 = c.getLocal("pCoef"); const ELL_VW = c.i32_add(c.getLocal("pCoef"), c.i32_const(f2size)); const ELL_VV = c.i32_add(c.getLocal("pCoef"), c.i32_const(2*f2size)); const D = ELL_VW; const E = c.i32_const(module.alloc(f2size)); const F = c.i32_const(module.alloc(f2size)); const G = c.i32_const(module.alloc(f2size)); const H = c.i32_const(module.alloc(f2size)); const I = c.i32_const(module.alloc(f2size)); const J = c.i32_const(module.alloc(f2size)); const AUX = c.i32_const(module.alloc(f2size)); f.addCode( // D = X1 - X2*Z1 c.call(f2mPrefix + "_mul", X2, Z1, D), c.call(f2mPrefix + "_sub", X1, D, D), // E = Y1 - Y2*Z1 c.call(f2mPrefix + "_mul", Y2, Z1, E), c.call(f2mPrefix + "_sub", Y1, E, E), // F = D^2 c.call(f2mPrefix + "_square", D, F), // G = E^2 c.call(f2mPrefix + "_square", E, G), // H = D*F c.call(f2mPrefix + "_mul", D, F, H), // I = X1 * F c.call(f2mPrefix + "_mul", X1, F, I), // J = H + Z1*G - (I+I) c.call(f2mPrefix + "_add", I, I, AUX), c.call(f2mPrefix + "_mul", Z1, G, J), c.call(f2mPrefix + "_add", H, J, J), c.call(f2mPrefix + "_sub", J, AUX, J), // X3 (X1) = D*J c.call(f2mPrefix + "_mul", D, J, X1), // Y3 (Y1) = E*(I-J)-(H*Y1) c.call(f2mPrefix + "_mul", H, Y1, Y1), c.call(f2mPrefix + "_sub", I, J, AUX), c.call(f2mPrefix + "_mul", E, AUX, AUX), c.call(f2mPrefix + "_sub", AUX, Y1, Y1), // Z3 (Z1) = Z1*H c.call(f2mPrefix + "_mul", Z1, H, Z1), // ell_0 = xi * (E * X2 - D * Y2) c.call(f2mPrefix + "_mul", D, Y2, AUX), c.call(f2mPrefix + "_mul", E, X2, ELL_0), c.call(f2mPrefix + "_sub", ELL_0, AUX, ELL_0), c.call(f2mPrefix + "_mul", ELL_0, c.i32_const(pAltBn128Twist), ELL_0), // ell_VV = - E (later: * xP) c.call(f2mPrefix + "_neg", E, ELL_VV), // ell_VW = D (later: * yP ) // Already assigned ); } function buildPrepDoubleStep() { const f = module.addFunction(prefix+ "_prepDblStep"); f.addParam("pR", "i32"); f.addParam("pCoef", "i32"); const c = f.getCodeBuilder(); const X1 = c.getLocal("pR"); const Y1 = c.i32_add(c.getLocal("pR"), c.i32_const(f2size)); const Z1 = c.i32_add(c.getLocal("pR"), c.i32_const(2*f2size)); const ELL_0 = c.getLocal("pCoef"); const ELL_VW = c.i32_add(c.getLocal("pCoef"), c.i32_const(f2size)); const ELL_VV = c.i32_add(c.getLocal("pCoef"), c.i32_const(2*f2size)); const A = c.i32_const(module.alloc(f2size)); const B = c.i32_const(module.alloc(f2size)); const C = c.i32_const(module.alloc(f2size)); const D = c.i32_const(module.alloc(f2size)); const E = c.i32_const(module.alloc(f2size)); const F = c.i32_const(module.alloc(f2size)); const G = c.i32_const(module.alloc(f2size)); const H = c.i32_const(module.alloc(f2size)); const I = c.i32_const(module.alloc(f2size)); const J = c.i32_const(module.alloc(f2size)); const E2 = c.i32_const(module.alloc(f2size)); const AUX = c.i32_const(module.alloc(f2size)); f.addCode( // A = X1 * Y1 / 2 c.call(f2mPrefix + "_mul", Y1, c.i32_const(pTwoInv), A), c.call(f2mPrefix + "_mul", X1, A, A), // B = Y1^2 c.call(f2mPrefix + "_square", Y1, B), // C = Z1^2 c.call(f2mPrefix + "_square", Z1, C), // D = 3 * C c.call(f2mPrefix + "_add", C, C, D), c.call(f2mPrefix + "_add", D, C, D), // E = twist_b * D c.call(f2mPrefix + "_mul", c.i32_const(pTwistCoefB), D, E), // F = 3 * E c.call(f2mPrefix + "_add", E, E, F), c.call(f2mPrefix + "_add", E, F, F), // G = (B+F)/2 c.call(f2mPrefix + "_add", B, F, G), c.call(f2mPrefix + "_mul", G, c.i32_const(pTwoInv), G), // H = (Y1+Z1)^2-(B+C) c.call(f2mPrefix + "_add", B, C, AUX), c.call(f2mPrefix + "_add", Y1, Z1, H), c.call(f2mPrefix + "_square", H, H), c.call(f2mPrefix + "_sub", H, AUX, H), // I = E-B c.call(f2mPrefix + "_sub", E, B, I), // J = X1^2 c.call(f2mPrefix + "_square", X1, J), // E_squared = E^2 c.call(f2mPrefix + "_square", E, E2), // X3 (X1) = A * (B-F) c.call(f2mPrefix + "_sub", B, F, AUX), c.call(f2mPrefix + "_mul", A, AUX, X1), // Y3 (Y1) = G^2 - 3*E^2 c.call(f2mPrefix + "_add", E2, E2, AUX), c.call(f2mPrefix + "_add", E2, AUX, AUX), c.call(f2mPrefix + "_square", G, Y1), c.call(f2mPrefix + "_sub", Y1, AUX, Y1), // Z3 (Z1) = B * H c.call(f2mPrefix + "_mul", B, H, Z1), // ell_0 = xi * I c.call(f2mPrefix + "_mul", c.i32_const(pAltBn128Twist), I, ELL_0), // ell_VW = - H (later: * yP) c.call(f2mPrefix + "_neg", H, ELL_VW), // ell_VV = 3*J (later: * xP) c.call(f2mPrefix + "_add", J, J, ELL_VV), c.call(f2mPrefix + "_add", J, ELL_VV, ELL_VV), ); } function buildMulByQ() { const f = module.addFunction(prefix + "_mulByQ"); f.addParam("p1", "i32"); f.addParam("pr", "i32"); const c = f.getCodeBuilder(); const x = c.getLocal("p1"); const y = c.i32_add(c.getLocal("p1"), c.i32_const(f2size)); const z = c.i32_add(c.getLocal("p1"), c.i32_const(f2size*2)); const x3 = c.getLocal("pr"); const y3 = c.i32_add(c.getLocal("pr"), c.i32_const(f2size)); const z3 = c.i32_add(c.getLocal("pr"), c.i32_const(f2size*2)); const MulByQX = c.i32_const(module.alloc([ ...utils$6.bigInt2BytesLE( toMontgomery("21575463638280843010398324269430826099269044274347216827212613867836435027261"), f1size ), ...utils$6.bigInt2BytesLE( toMontgomery("10307601595873709700152284273816112264069230130616436755625194854815875713954"), f1size ), ])); const MulByQY = c.i32_const(module.alloc([ ...utils$6.bigInt2BytesLE( toMontgomery("2821565182194536844548159561693502659359617185244120367078079554186484126554"), f1size ), ...utils$6.bigInt2BytesLE( toMontgomery("3505843767911556378687030309984248845540243509899259641013678093033130930403"), f1size ), ])); f.addCode( // The frobeniusMap(1) in this field, is the conjugate c.call(f2mPrefix + "_conjugate", x, x3), c.call(f2mPrefix + "_mul", MulByQX, x3, x3), c.call(f2mPrefix + "_conjugate", y, y3), c.call(f2mPrefix + "_mul", MulByQY, y3, y3), c.call(f2mPrefix + "_conjugate", z, z3), ); } function buildPrepareG2() { buildMulByQ(); const f = module.addFunction(prefix+ "_prepareG2"); f.addParam("pQ", "i32"); f.addParam("ppreQ", "i32"); f.addLocal("pCoef", "i32"); f.addLocal("i", "i32"); const c = f.getCodeBuilder(); const QX = c.getLocal("pQ"); c.i32_add( c.getLocal("pQ"), c.i32_const(f2size)); c.i32_add( c.getLocal("pQ"), c.i32_const(f2size*2)); const pR = module.alloc(f2size*3); const R = c.i32_const(pR); const RX = c.i32_const(pR); const RY = c.i32_const(pR+f2size); const RZ = c.i32_const(pR+2*f2size); const cQX = c.i32_add( c.getLocal("ppreQ"), c.i32_const(0)); const cQY = c.i32_add( c.getLocal("ppreQ"), c.i32_const(f2size)); c.i32_add( c.getLocal("ppreQ"), c.i32_const(f2size*2)); const pQ1 = module.alloc(f2size*3); const Q1 = c.i32_const(pQ1); const pQ2 = module.alloc(f2size*3); const Q2 = c.i32_const(pQ2); c.i32_const(pQ2); const Q2Y = c.i32_const(pQ2 + f2size); c.i32_const(pQ2 + f2size*2); f.addCode( c.call(g2mPrefix + "_normalize", QX, cQX), // TODO Remove if already in affine c.call(f2mPrefix + "_copy", cQX, RX), c.call(f2mPrefix + "_copy", cQY, RY), c.call(f2mPrefix + "_one", RZ), ); f.addCode( c.setLocal("pCoef", c.i32_add( c.getLocal("ppreQ"), c.i32_const(f2size*3))), c.setLocal("i", c.i32_const(ateLoopBitBytes.length-2)), c.block(c.loop( c.call(prefix + "_prepDblStep", R, c.getLocal("pCoef")), c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))), c.if( c.i32_load8_s(c.getLocal("i"), pAteLoopBitBytes), [ ...c.call(prefix + "_prepAddStep", cQX, R, c.getLocal("pCoef")), ...c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))), ] ), c.br_if(1, c.i32_eqz ( c.getLocal("i") )), c.setLocal("i", c.i32_sub(c.getLocal("i"), c.i32_const(1))), c.br(0) )) ); f.addCode( c.call(prefix + "_mulByQ", cQX, Q1), c.call(prefix + "_mulByQ", Q1, Q2) ); f.addCode( c.call(f2mPrefix + "_neg", Q2Y, Q2Y), c.call(prefix + "_prepAddStep", Q1, R, c.getLocal("pCoef")), c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))), c.call(prefix + "_prepAddStep", Q2, R, c.getLocal("pCoef")), c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))), ); } function buildMulBy024Old() { const f = module.addFunction(prefix+ "__mulBy024Old"); f.addParam("pEll0", "i32"); f.addParam("pEllVW", "i32"); f.addParam("pEllVV", "i32"); f.addParam("pR", "i32"); // Result in F12 const c = f.getCodeBuilder(); const x0 = c.getLocal("pEll0"); const x2 = c.getLocal("pEllVV"); const x4 = c.getLocal("pEllVW"); const z0 = c.getLocal("pR"); const pAUX12 = module.alloc(ftsize); const AUX12 = c.i32_const(pAUX12); const AUX12_0 = c.i32_const(pAUX12); const AUX12_2 = c.i32_const(pAUX12+f2size); const AUX12_4 = c.i32_const(pAUX12+f2size*2); const AUX12_6 = c.i32_const(pAUX12+f2size*3); const AUX12_8 = c.i32_const(pAUX12+f2size*4); const AUX12_10 = c.i32_const(pAUX12+f2size*5); f.addCode( c.call(f2mPrefix + "_copy", x0, AUX12_0), c.call(f2mPrefix + "_zero", AUX12_2), c.call(f2mPrefix + "_copy", x2, AUX12_4), c.call(f2mPrefix + "_zero", AUX12_6), c.call(f2mPrefix + "_copy", x4, AUX12_8), c.call(f2mPrefix + "_zero", AUX12_10), c.call(ftmPrefix + "_mul", AUX12, z0, z0), ); } function buildMulBy024() { const f = module.addFunction(prefix+ "__mulBy024"); f.addParam("pEll0", "i32"); f.addParam("pEllVW", "i32"); f.addParam("pEllVV", "i32"); f.addParam("pR", "i32"); // Result in F12 const c = f.getCodeBuilder(); const x0 = c.getLocal("pEll0"); const x2 = c.getLocal("pEllVV"); const x4 = c.getLocal("pEllVW"); const z0 = c.getLocal("pR"); const z1 = c.i32_add(c.getLocal("pR"), c.i32_const(2*n8)); const z2 = c.i32_add(c.getLocal("pR"), c.i32_const(4*n8)); const z3 = c.i32_add(c.getLocal("pR"), c.i32_const(6*n8)); const z4 = c.i32_add(c.getLocal("pR"), c.i32_const(8*n8)); const z5 = c.i32_add(c.getLocal("pR"), c.i32_const(10*n8)); const t0 = c.i32_const(module.alloc(f2size)); const t1 = c.i32_const(module.alloc(f2size)); const t2 = c.i32_const(module.alloc(f2size)); const s0 = c.i32_const(module.alloc(f2size)); const T3 = c.i32_const(module.alloc(f2size)); const T4 = c.i32_const(module.alloc(f2size)); const D0 = c.i32_const(module.alloc(f2size)); const D2 = c.i32_const(module.alloc(f2size)); const D4 = c.i32_const(module.alloc(f2size)); const S1 = c.i32_const(module.alloc(f2size)); const AUX = c.i32_const(module.alloc(f2size)); f.addCode( // D0 = z0 * x0; c.call(f2mPrefix + "_mul", z0, x0, D0), // D2 = z2 * x2; c.call(f2mPrefix + "_mul", z2, x2, D2), // D4 = z4 * x4; c.call(f2mPrefix + "_mul", z4, x4, D4), // t2 = z0 + z4; c.call(f2mPrefix + "_add", z0, z4, t2), // t1 = z0 + z2; c.call(f2mPrefix + "_add", z0, z2, t1), // s0 = z1 + z3 + z5; c.call(f2mPrefix + "_add", z1, z3, s0), c.call(f2mPrefix + "_add", s0, z5, s0), // For z.a_.a_ = z0. // S1 = z1 * x2; c.call(f2mPrefix + "_mul", z1, x2, S1), // T3 = S1 + D4; c.call(f2mPrefix + "_add", S1, D4, T3), // T4 = my_Fp6::non_residue * T3 + D0; c.call(f2mPrefix + "_mul", c.i32_const(pNonResidueF6), T3, T4), c.call(f2mPrefix + "_add", T4, D0, z0), // z0 = T4; // For z.a_.b_ = z1 // T3 = z5 * x4; c.call(f2mPrefix + "_mul", z5, x4, T3), // S1 = S1 + T3; c.call(f2mPrefix + "_add", S1, T3, S1), // T3 = T3 + D2; c.call(f2mPrefix + "_add", T3, D2, T3), // T4 = my_Fp6::non_residue * T3; c.call(f2mPrefix + "_mul", c.i32_const(pNonResidueF6), T3, T4), // T3 = z1 * x0; c.call(f2mPrefix + "_mul", z1, x0, T3), // S1 = S1 + T3; c.call(f2mPrefix + "_add", S1, T3, S1), // T4 = T4 + T3; c.call(f2mPrefix + "_add", T4, T3, z1), // z1 = T4; // For z.a_.c_ = z2 // t0 = x0 + x2; c.call(f2mPrefix + "_add", x0, x2, t0), // T3 = t1 * t0 - D0 - D2; c.call(f2mPrefix + "_mul", t1, t0, T3), c.call(f2mPrefix + "_add", D0, D2, AUX), c.call(f2mPrefix + "_sub", T3, AUX, T3), // T4 = z3 * x4; c.call(f2mPrefix + "_mul", z3, x4, T4), // S1 = S1 + T4; c.call(f2mPrefix + "_add", S1, T4, S1), // For z.b_.a_ = z3 (z3 needs z2) // t0 = z2 + z4; c.call(f2mPrefix + "_add", z2, z4, t0), // T3 = T3 + T4; // z2 = T3; c.call(f2mPrefix + "_add", T3, T4, z2), // t1 = x2 + x4; c.call(f2mPrefix + "_add", x2, x4, t1), // T3 = t0 * t1 - D2 - D4; c.call(f2mPrefix + "_mul", t1, t0, T3), c.call(f2mPrefix + "_add", D2, D4, AUX), c.call(f2mPrefix + "_sub", T3, AUX, T3), // T4 = my_Fp6::non_residue * T3; c.call(f2mPrefix + "_mul", c.i32_const(pNonResidueF6), T3, T4), // T3 = z3 * x0; c.call(f2mPrefix + "_mul", z3, x0, T3), // S1 = S1 + T3; c.call(f2mPrefix + "_add", S1, T3, S1), // T4 = T4 + T3; c.call(f2mPrefix + "_add", T4, T3, z3), // z3 = T4; // For z.b_.b_ = z4 // T3 = z5 * x2; c.call(f2mPrefix + "_mul", z5, x2, T3), // S1 = S1 + T3; c.call(f2mPrefix + "_add", S1, T3, S1), // T4 = my_Fp6::non_residue * T3; c.call(f2mPrefix + "_mul", c.i32_const(pNonResidueF6), T3, T4), // t0 = x0 + x4; c.call(f2mPrefix + "_add", x0, x4, t0), // T3 = t2 * t0 - D0 - D4; c.call(f2mPrefix + "_mul", t2, t0, T3), c.call(f2mPrefix + "_add", D0, D4, AUX), c.call(f2mPrefix + "_sub", T3, AUX, T3), // T4 = T4 + T3; c.call(f2mPrefix + "_add", T4, T3, z4), // z4 = T4; // For z.b_.c_ = z5. // t0 = x0 + x2 + x4; c.call(f2mPrefix + "_add", x0, x2, t0), c.call(f2mPrefix + "_add", t0, x4, t0), // T3 = s0 * t0 - S1; c.call(f2mPrefix + "_mul", s0, t0, T3), c.call(f2mPrefix + "_sub", T3, S1, z5), // z5 = T3; ); } function buildMillerLoop() { const f = module.addFunction(prefix+ "_millerLoop"); f.addParam("ppreP", "i32"); f.addParam("ppreQ", "i32"); f.addParam("r", "i32"); f.addLocal("pCoef", "i32"); f.addLocal("i", "i32"); const c = f.getCodeBuilder(); const preP_PX = c.getLocal("ppreP"); const preP_PY = c.i32_add(c.getLocal("ppreP"), c.i32_const(f1size)); const ELL_0 = c.getLocal("pCoef"); const ELL_VW = c.i32_add(c.getLocal("pCoef"), c.i32_const(f2size)); const ELL_VV = c.i32_add(c.getLocal("pCoef"), c.i32_const(2*f2size)); const pVW = module.alloc(f2size); const VW = c.i32_const(pVW); const pVV = module.alloc(f2size); const VV = c.i32_const(pVV); const F = c.getLocal("r"); f.addCode( c.call(ftmPrefix + "_one", F), c.setLocal("pCoef", c.i32_add( c.getLocal("ppreQ"), c.i32_const(f2size*3))), c.setLocal("i", c.i32_const(ateLoopBitBytes.length-2)), c.block(c.loop( c.call(ftmPrefix + "_square", F, F), c.call(f2mPrefix + "_mul1", ELL_VW,preP_PY, VW), c.call(f2mPrefix + "_mul1", ELL_VV, preP_PX, VV), c.call(prefix + "__mulBy024", ELL_0, VW, VV, F), c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))), c.if( c.i32_load8_s(c.getLocal("i"), pAteLoopBitBytes), [ ...c.call(f2mPrefix + "_mul1", ELL_VW, preP_PY, VW), ...c.call(f2mPrefix + "_mul1", ELL_VV, preP_PX, VV), ...c.call(prefix + "__mulBy024", ELL_0, VW, VV, F), ...c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))), ] ), c.br_if(1, c.i32_eqz ( c.getLocal("i") )), c.setLocal("i", c.i32_sub(c.getLocal("i"), c.i32_const(1))), c.br(0) )) ); f.addCode( c.call(f2mPrefix + "_mul1", ELL_VW, preP_PY, VW), c.call(f2mPrefix + "_mul1", ELL_VV, preP_PX, VV), c.call(prefix + "__mulBy024", ELL_0, VW, VV, F), c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))), c.call(f2mPrefix + "_mul1", ELL_VW, preP_PY, VW), c.call(f2mPrefix + "_mul1", ELL_VV, preP_PX, VV), c.call(prefix + "__mulBy024", ELL_0, VW, VV, F), c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))), ); } function buildFrobeniusMap(n) { const F12 = [ [ [bigInt$2("1"), bigInt$2("0")], [bigInt$2("1"), bigInt$2("0")], [bigInt$2("1"), bigInt$2("0")], [bigInt$2("1"), bigInt$2("0")], [bigInt$2("1"), bigInt$2("0")], [bigInt$2("1"), bigInt$2("0")], [bigInt$2("1"), bigInt$2("0")], [bigInt$2("1"), bigInt$2("0")], [bigInt$2("1"), bigInt$2("0")], [bigInt$2("1"), bigInt$2("0")], [bigInt$2("1"), bigInt$2("0")], [bigInt$2("1"), bigInt$2("0")], ], [ [bigInt$2("1"), bigInt$2("0")], [bigInt$2("8376118865763821496583973867626364092589906065868298776909617916018768340080"), bigInt$2("16469823323077808223889137241176536799009286646108169935659301613961712198316")], [bigInt$2("21888242871839275220042445260109153167277707414472061641714758635765020556617"), bigInt$2("0")], [bigInt$2("11697423496358154304825782922584725312912383441159505038794027105778954184319"), bigInt$2("303847389135065887422783454877609941456349188919719272345083954437860409601")], [bigInt$2("21888242871839275220042445260109153167277707414472061641714758635765020556616"), bigInt$2("0")], [bigInt$2("3321304630594332808241809054958361220322477375291206261884409189760185844239"), bigInt$2("5722266937896532885780051958958348231143373700109372999374820235121374419868")], [bigInt$2("21888242871839275222246405745257275088696311157297823662689037894645226208582"), bigInt$2("0")], [bigInt$2("13512124006075453725662431877630910996106405091429524885779419978626457868503"), bigInt$2("5418419548761466998357268504080738289687024511189653727029736280683514010267")], [bigInt$2("2203960485148121921418603742825762020974279258880205651966"), bigInt$2("0")], [bigInt$2("10190819375481120917420622822672549775783927716138318623895010788866272024264"), bigInt$2("21584395482704209334823622290379665147239961968378104390343953940207365798982")], [bigInt$2("2203960485148121921418603742825762020974279258880205651967"), bigInt$2("0")], [bigInt$2("18566938241244942414004596690298913868373833782006617400804628704885040364344"), bigInt$2("16165975933942742336466353786298926857552937457188450663314217659523851788715")], ] ]; const F6 = [ [ [bigInt$2("1"), bigInt$2("0")], [bigInt$2("1"), bigInt$2("0")], [bigInt$2("1"), bigInt$2("0")], [bigInt$2("1"), bigInt$2("0")], [bigInt$2("1"), bigInt$2("0")], [bigInt$2("1"), bigInt$2("0")], ], [ [bigInt$2("1"), bigInt$2("0")], [bigInt$2("21575463638280843010398324269430826099269044274347216827212613867836435027261"), bigInt$2("10307601595873709700152284273816112264069230130616436755625194854815875713954")], [bigInt$2("21888242871839275220042445260109153167277707414472061641714758635765020556616"), bigInt$2("0")], [bigInt$2("3772000881919853776433695186713858239009073593817195771773381919316419345261"), bigInt$2("2236595495967245188281701248203181795121068902605861227855261137820944008926")], [bigInt$2("2203960485148121921418603742825762020974279258880205651966"), bigInt$2("0")], [bigInt$2("18429021223477853657660792034369865839114504446431234726392080002137598044644"), bigInt$2("9344045779998320333812420223237981029506012124075525679208581902008406485703")], ], [ [bigInt$2("1"), bigInt$2("0")], [bigInt$2("2581911344467009335267311115468803099551665605076196740867805258568234346338"), bigInt$2("19937756971775647987995932169929341994314640652964949448313374472400716661030")], [bigInt$2("2203960485148121921418603742825762020974279258880205651966"), bigInt$2("0")], [bigInt$2("5324479202449903542726783395506214481928257762400643279780343368557297135718"), bigInt$2("16208900380737693084919495127334387981393726419856888799917914180988844123039")], [bigInt$2("21888242871839275220042445260109153167277707414472061641714758635765020556616"), bigInt$2("0")], [bigInt$2("13981852324922362344252311234282257507216387789820983642040889267519694726527"), bigInt$2("7629828391165209371577384193250820201684255241773809077146787135900891633097")], ] ]; const f = module.addFunction(prefix+ "__frobeniusMap"+n); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); for (let i=0; i<6; i++) { const X = (i==0) ? c.getLocal("x") : c.i32_add(c.getLocal("x"), c.i32_const(i*f2size)); const Xc0 = X; const Xc1 = c.i32_add(c.getLocal("x"), c.i32_const(i*f2size + f1size)); const R = (i==0) ? c.getLocal("r") : c.i32_add(c.getLocal("r"), c.i32_const(i*f2size)); const Rc0 = R; const Rc1 = c.i32_add(c.getLocal("r"), c.i32_const(i*f2size + f1size)); const coef = mul2(F12[Math.floor(i/3)][n%12] , F6[i%3][n%6]); const pCoef = module.alloc([ ...utils$6.bigInt2BytesLE(toMontgomery(coef[0]), 32), ...utils$6.bigInt2BytesLE(toMontgomery(coef[1]), 32), ]); if (n%2 == 1) { f.addCode( c.call(f1mPrefix + "_copy", Xc0, Rc0), c.call(f1mPrefix + "_neg", Xc1, Rc1), c.call(f2mPrefix + "_mul", R, c.i32_const(pCoef), R), ); } else { f.addCode(c.call(f2mPrefix + "_mul", X, c.i32_const(pCoef), R)); } } function mul2(a, b) { const ac0 = bigInt$2(a[0]); const ac1 = bigInt$2(a[1]); const bc0 = bigInt$2(b[0]); const bc1 = bigInt$2(b[1]); const res = [ ac0.times(bc0).minus( ac1.times(bc1) ).mod(q), ac0.times(bc1).add( ac1.times(bc0) ).mod(q), ]; if (res[0].isNegative()) res[0] = res[0].add(q); return res; } } function buildFinalExponentiationFirstChunk() { const f = module.addFunction(prefix+ "__finalExponentiationFirstChunk"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const elt = c.getLocal("x"); const eltC0 = elt; const eltC1 = c.i32_add(elt, c.i32_const(n8*6)); const r = c.getLocal("r"); const pA = module.alloc(ftsize); const A = c.i32_const(pA); const Ac0 = A; const Ac1 = c.i32_const(pA + n8*6); const B = c.i32_const(module.alloc(ftsize)); const C = c.i32_const(module.alloc(ftsize)); const D = c.i32_const(module.alloc(ftsize)); f.addCode( // const alt_bn128_Fq12 A = alt_bn128_Fq12(elt.c0,-elt.c1); c.call(f6mPrefix + "_copy", eltC0, Ac0), c.call(f6mPrefix + "_neg", eltC1, Ac1), // const alt_bn128_Fq12 B = elt.inverse(); c.call(ftmPrefix + "_inverse", elt, B), // const alt_bn128_Fq12 C = A * B; c.call(ftmPrefix + "_mul", A, B, C), // const alt_bn128_Fq12 D = C.Frobenius_map(2); c.call(prefix + "__frobeniusMap2", C, D), // const alt_bn128_Fq12 result = D * C; c.call(ftmPrefix + "_mul", C, D, r), ); } function buildCyclotomicSquare() { const f = module.addFunction(prefix+ "__cyclotomicSquare"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x4 = c.i32_add(c.getLocal("x"), c.i32_const(f2size)); const x3 = c.i32_add(c.getLocal("x"), c.i32_const(2*f2size)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(3*f2size)); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(4*f2size)); const x5 = c.i32_add(c.getLocal("x"), c.i32_const(5*f2size)); const r0 = c.getLocal("r"); const r4 = c.i32_add(c.getLocal("r"), c.i32_const(f2size)); const r3 = c.i32_add(c.getLocal("r"), c.i32_const(2*f2size)); const r2 = c.i32_add(c.getLocal("r"), c.i32_const(3*f2size)); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(4*f2size)); const r5 = c.i32_add(c.getLocal("r"), c.i32_const(5*f2size)); const t0 = c.i32_const(module.alloc(f2size)); const t1 = c.i32_const(module.alloc(f2size)); const t2 = c.i32_const(module.alloc(f2size)); const t3 = c.i32_const(module.alloc(f2size)); const t4 = c.i32_const(module.alloc(f2size)); const t5 = c.i32_const(module.alloc(f2size)); const tmp = c.i32_const(module.alloc(f2size)); const AUX = c.i32_const(module.alloc(f2size)); f.addCode( // c.call(ftmPrefix + "_square", x0, r0), // // t0 + t1*y = (z0 + z1*y)^2 = a^2 // tmp = z0 * z1; // t0 = (z0 + z1) * (z0 + my_Fp6::non_residue * z1) - tmp - my_Fp6::non_residue * tmp; // t1 = tmp + tmp; c.call(f2mPrefix + "_mul", x0, x1, tmp), c.call(f2mPrefix + "_mul", x1, c.i32_const(pNonResidueF6), t0), c.call(f2mPrefix + "_add", x0, t0, t0), c.call(f2mPrefix + "_add", x0, x1, AUX), c.call(f2mPrefix + "_mul", AUX, t0, t0), c.call(f2mPrefix + "_mul", c.i32_const(pNonResidueF6), tmp, AUX), c.call(f2mPrefix + "_add", tmp, AUX, AUX), c.call(f2mPrefix + "_sub", t0, AUX, t0), c.call(f2mPrefix + "_add", tmp, tmp, t1), // // t2 + t3*y = (z2 + z3*y)^2 = b^2 // tmp = z2 * z3; // t2 = (z2 + z3) * (z2 + my_Fp6::non_residue * z3) - tmp - my_Fp6::non_residue * tmp; // t3 = tmp + tmp; c.call(f2mPrefix + "_mul", x2, x3, tmp), c.call(f2mPrefix + "_mul", x3, c.i32_const(pNonResidueF6), t2), c.call(f2mPrefix + "_add", x2, t2, t2), c.call(f2mPrefix + "_add", x2, x3, AUX), c.call(f2mPrefix + "_mul", AUX, t2, t2), c.call(f2mPrefix + "_mul", c.i32_const(pNonResidueF6), tmp, AUX), c.call(f2mPrefix + "_add", tmp, AUX, AUX), c.call(f2mPrefix + "_sub", t2, AUX, t2), c.call(f2mPrefix + "_add", tmp, tmp, t3), // // t4 + t5*y = (z4 + z5*y)^2 = c^2 // tmp = z4 * z5; // t4 = (z4 + z5) * (z4 + my_Fp6::non_residue * z5) - tmp - my_Fp6::non_residue * tmp; // t5 = tmp + tmp; c.call(f2mPrefix + "_mul", x4, x5, tmp), c.call(f2mPrefix + "_mul", x5, c.i32_const(pNonResidueF6), t4), c.call(f2mPrefix + "_add", x4, t4, t4), c.call(f2mPrefix + "_add", x4, x5, AUX), c.call(f2mPrefix + "_mul", AUX, t4, t4), c.call(f2mPrefix + "_mul", c.i32_const(pNonResidueF6), tmp, AUX), c.call(f2mPrefix + "_add", tmp, AUX, AUX), c.call(f2mPrefix + "_sub", t4, AUX, t4), c.call(f2mPrefix + "_add", tmp, tmp, t5), // For A // z0 = 3 * t0 - 2 * z0 c.call(f2mPrefix + "_sub", t0, x0, r0), c.call(f2mPrefix + "_add", r0, r0, r0), c.call(f2mPrefix + "_add", t0, r0, r0), // z1 = 3 * t1 + 2 * z1 c.call(f2mPrefix + "_add", t1, x1, r1), c.call(f2mPrefix + "_add", r1, r1, r1), c.call(f2mPrefix + "_add", t1, r1, r1), // For B // z2 = 3 * (xi * t5) + 2 * z2 c.call(f2mPrefix + "_mul", t5, c.i32_const(pAltBn128Twist), AUX), c.call(f2mPrefix + "_add", AUX, x2, r2), c.call(f2mPrefix + "_add", r2, r2, r2), c.call(f2mPrefix + "_add", AUX, r2, r2), // z3 = 3 * t4 - 2 * z3 c.call(f2mPrefix + "_sub", t4, x3, r3), c.call(f2mPrefix + "_add", r3, r3, r3), c.call(f2mPrefix + "_add", t4, r3, r3), // For C // z4 = 3 * t2 - 2 * z4 c.call(f2mPrefix + "_sub", t2, x4, r4), c.call(f2mPrefix + "_add", r4, r4, r4), c.call(f2mPrefix + "_add", t2, r4, r4), // z5 = 3 * t3 + 2 * z5 c.call(f2mPrefix + "_add", t3, x5, r5), c.call(f2mPrefix + "_add", r5, r5, r5), c.call(f2mPrefix + "_add", t3, r5, r5), ); } function buildCyclotomicExp(exponent, fnName) { const exponentNafBytes = naf(exponent).map( (b) => (b==-1 ? 0xFF: b) ); const pExponentNafBytes = module.alloc(exponentNafBytes); module.alloc(utils$6.bigInt2BytesLE(exponent, 32)); const f = module.addFunction(prefix+ "__cyclotomicExp_"+fnName); f.addParam("x", "i32"); f.addParam("r", "i32"); f.addLocal("bit", "i32"); f.addLocal("i", "i32"); const c = f.getCodeBuilder(); const x = c.getLocal("x"); const res = c.getLocal("r"); const inverse = c.i32_const(module.alloc(ftsize)); f.addCode( // c.call(ftmPrefix + "_exp", x, c.i32_const(pExponent), c.i32_const(32), res), c.call(ftmPrefix + "_conjugate", x, inverse), c.call(ftmPrefix + "_one", res), c.if( c.teeLocal("bit", c.i32_load8_s(c.i32_const(exponentNafBytes.length-1), pExponentNafBytes)), c.if( c.i32_eq( c.getLocal("bit"), c.i32_const(1) ), c.call(ftmPrefix + "_mul", res, x, res), c.call(ftmPrefix + "_mul", res, inverse, res), ) ), c.setLocal("i", c.i32_const(exponentNafBytes.length-2)), c.block(c.loop( // c.call(ftmPrefix + "_square", res, res), c.call(prefix + "__cyclotomicSquare", res, res), c.if( c.teeLocal("bit", c.i32_load8_s(c.getLocal("i"), pExponentNafBytes)), c.if( c.i32_eq( c.getLocal("bit"), c.i32_const(1) ), c.call(ftmPrefix + "_mul", res, x, res), c.call(ftmPrefix + "_mul", res, inverse, res), ) ), c.br_if(1, c.i32_eqz ( c.getLocal("i") )), c.setLocal("i", c.i32_sub(c.getLocal("i"), c.i32_const(1))), c.br(0) )) ); } function buildFinalExponentiationLastChunk() { buildCyclotomicSquare(); buildCyclotomicExp(finalExpZ, "w0"); const f = module.addFunction(prefix+ "__finalExponentiationLastChunk"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const elt = c.getLocal("x"); const result = c.getLocal("r"); const A = c.i32_const(module.alloc(ftsize)); const B = c.i32_const(module.alloc(ftsize)); const C = c.i32_const(module.alloc(ftsize)); const D = c.i32_const(module.alloc(ftsize)); const E = c.i32_const(module.alloc(ftsize)); const F = c.i32_const(module.alloc(ftsize)); const G = c.i32_const(module.alloc(ftsize)); const H = c.i32_const(module.alloc(ftsize)); const I = c.i32_const(module.alloc(ftsize)); const J = c.i32_const(module.alloc(ftsize)); const K = c.i32_const(module.alloc(ftsize)); const L = c.i32_const(module.alloc(ftsize)); const M = c.i32_const(module.alloc(ftsize)); const N = c.i32_const(module.alloc(ftsize)); const O = c.i32_const(module.alloc(ftsize)); const P = c.i32_const(module.alloc(ftsize)); const Q = c.i32_const(module.alloc(ftsize)); const R = c.i32_const(module.alloc(ftsize)); const S = c.i32_const(module.alloc(ftsize)); const T = c.i32_const(module.alloc(ftsize)); const U = c.i32_const(module.alloc(ftsize)); f.addCode( // A = exp_by_neg_z(elt) // = elt^(-z) c.call(prefix + "__cyclotomicExp_w0", elt, A), c.call(ftmPrefix + "_conjugate", A, A), // B = A^2 // = elt^(-2*z) c.call(prefix + "__cyclotomicSquare", A, B), // C = B^2 // = elt^(-4*z) c.call(prefix + "__cyclotomicSquare", B, C), // D = C * B // = elt^(-6*z) c.call(ftmPrefix + "_mul", C, B, D), // E = exp_by_neg_z(D) // = elt^(6*z^2) c.call(prefix + "__cyclotomicExp_w0", D, E), c.call(ftmPrefix + "_conjugate", E, E), // F = E^2 // = elt^(12*z^2) c.call(prefix + "__cyclotomicSquare", E, F), // G = epx_by_neg_z(F) // = elt^(-12*z^3) c.call(prefix + "__cyclotomicExp_w0", F, G), c.call(ftmPrefix + "_conjugate", G, G), // H = conj(D) // = elt^(6*z) c.call(ftmPrefix + "_conjugate", D, H), // I = conj(G) // = elt^(12*z^3) c.call(ftmPrefix + "_conjugate", G, I), // J = I * E // = elt^(12*z^3 + 6*z^2) c.call(ftmPrefix + "_mul", I, E, J), // K = J * H // = elt^(12*z^3 + 6*z^2 + 6*z) c.call(ftmPrefix + "_mul", J, H, K), // L = K * B // = elt^(12*z^3 + 6*z^2 + 4*z) c.call(ftmPrefix + "_mul", K, B, L), // M = K * E // = elt^(12*z^3 + 12*z^2 + 6*z) c.call(ftmPrefix + "_mul", K, E, M), // N = M * elt // = elt^(12*z^3 + 12*z^2 + 6*z + 1) c.call(ftmPrefix + "_mul", M, elt, N), // O = L.Frobenius_map(1) // = elt^(q*(12*z^3 + 6*z^2 + 4*z)) c.call(prefix + "__frobeniusMap1", L, O), // P = O * N // = elt^(q*(12*z^3 + 6*z^2 + 4*z) * (12*z^3 + 12*z^2 + 6*z + 1)) c.call(ftmPrefix + "_mul", O, N, P), // Q = K.Frobenius_map(2) // = elt^(q^2 * (12*z^3 + 6*z^2 + 6*z)) c.call(prefix + "__frobeniusMap2", K, Q), // R = Q * P // = elt^(q^2 * (12*z^3 + 6*z^2 + 6*z) + q*(12*z^3 + 6*z^2 + 4*z) * (12*z^3 + 12*z^2 + 6*z + 1)) c.call(ftmPrefix + "_mul", Q, P, R), // S = conj(elt) // = elt^(-1) c.call(ftmPrefix + "_conjugate", elt, S), // T = S * L // = elt^(12*z^3 + 6*z^2 + 4*z - 1) c.call(ftmPrefix + "_mul", S, L, T), // U = T.Frobenius_map(3) // = elt^(q^3(12*z^3 + 6*z^2 + 4*z - 1)) c.call(prefix + "__frobeniusMap3", T, U), // V = U * R // = elt^(q^3(12*z^3 + 6*z^2 + 4*z - 1) + q^2 * (12*z^3 + 6*z^2 + 6*z) + q*(12*z^3 + 6*z^2 + 4*z) * (12*z^3 + 12*z^2 + 6*z + 1)) c.call(ftmPrefix + "_mul", U, R, result), // result = V ); } function buildFinalExponentiation() { buildFinalExponentiationFirstChunk(); buildFinalExponentiationLastChunk(); const f = module.addFunction(prefix+ "_finalExponentiation"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const elt = c.getLocal("x"); const result = c.getLocal("r"); const eltToFirstChunk = c.i32_const(module.alloc(ftsize)); f.addCode( c.call(prefix + "__finalExponentiationFirstChunk", elt, eltToFirstChunk ), c.call(prefix + "__finalExponentiationLastChunk", eltToFirstChunk, result ) ); } function buildFinalExponentiationOld() { const f = module.addFunction(prefix+ "_finalExponentiationOld"); f.addParam("x", "i32"); f.addParam("r", "i32"); const exponent = bigInt$2("552484233613224096312617126783173147097382103762957654188882734314196910839907541213974502761540629817009608548654680343627701153829446747810907373256841551006201639677726139946029199968412598804882391702273019083653272047566316584365559776493027495458238373902875937659943504873220554161550525926302303331747463515644711876653177129578303191095900909191624817826566688241804408081892785725967931714097716709526092261278071952560171111444072049229123565057483750161460024353346284167282452756217662335528813519139808291170539072125381230815729071544861602750936964829313608137325426383735122175229541155376346436093930287402089517426973178917569713384748081827255472576937471496195752727188261435633271238710131736096299798168852925540549342330775279877006784354801422249722573783561685179618816480037695005515426162362431072245638324744480"); const pExponent = module.alloc(utils$6.bigInt2BytesLE( exponent, 352 )); const c = f.getCodeBuilder(); f.addCode( c.call(ftmPrefix + "_exp", c.getLocal("x"), c.i32_const(pExponent), c.i32_const(352), c.getLocal("r")), ); } const pPreP = module.alloc(prePSize); const pPreQ = module.alloc(preQSize); function buildPairingEquation(nPairings) { const f = module.addFunction(prefix+ "_pairingEq"+nPairings); for (let i=0; i acc + ( b!=0 ? 1 : 0) ,0); const ateNCoefs = ateNAddCoefs + ateNDblCoefs + 1; const prePSize = 3*2*n8q; const preQSize = 3*n8q*2 + ateNCoefs*ateCoefSize; const finalExpIsNegative = true; const finalExpZ = bigInt$1("15132376222941642752"); module.modules[prefix] = { n64q: n64q, n64r: n64r, n8q: n8q, n8r: n8r, pG1gen: pG1gen, pG1zero: pG1zero, pG1b: pG1b, pG2gen: pG2gen, pG2zero: pG2zero, pG2b: pG2b, pq: module.modules["f1m"].pq, pr: pr, pOneT: pOneT, r: r, q: q, prePSize: prePSize, preQSize: preQSize }; function naf(n) { let E = n; const res = []; while (E.gt(bigInt$1.zero)) { if (E.isOdd()) { const z = 2 - E.mod(4).toJSNumber(); res.push( z ); E = E.minus(z); } else { res.push( 0 ); } E = E.shiftRight(1); } return res; } function bits(n) { let E = n; const res = []; while (E.gt(bigInt$1.zero)) { if (E.isOdd()) { res.push( 1 ); } else { res.push( 0 ); } E = E.shiftRight(1); } return res; } function buildPrepareG1() { const f = module.addFunction(prefix+ "_prepareG1"); f.addParam("pP", "i32"); f.addParam("ppreP", "i32"); const c = f.getCodeBuilder(); f.addCode( c.call(g1mPrefix + "_normalize", c.getLocal("pP"), c.getLocal("ppreP")), // TODO Remove if already in affine ); } function buildPrepDoubleStep() { const f = module.addFunction(prefix+ "_prepDblStep"); f.addParam("R", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const Rx = c.getLocal("R"); const Ry = c.i32_add(c.getLocal("R"), c.i32_const(2*n8q)); const Rz = c.i32_add(c.getLocal("R"), c.i32_const(4*n8q)); const t0 = c.getLocal("r"); const t3 = c.i32_add(c.getLocal("r"), c.i32_const(2*n8q)); const t6 = c.i32_add(c.getLocal("r"), c.i32_const(4*n8q)); const zsquared = c.i32_const(module.alloc(f2size)); const t1 = c.i32_const(module.alloc(f2size)); const t2 = c.i32_const(module.alloc(f2size)); const t4 = c.i32_const(module.alloc(f2size)); const t5 = c.i32_const(module.alloc(f2size)); f.addCode( // tmp0 = r.x.square(); c.call(f2mPrefix + "_square", Rx, t0), // tmp1 = r.y.square(); c.call(f2mPrefix + "_square", Ry, t1), // tmp2 = tmp1.square(); c.call(f2mPrefix + "_square", t1, t2), // tmp3 = (tmp1 + r.x).square() - tmp0 - tmp2; c.call(f2mPrefix + "_add", t1, Rx, t3), c.call(f2mPrefix + "_square", t3, t3), c.call(f2mPrefix + "_sub", t3, t0, t3), c.call(f2mPrefix + "_sub", t3, t2, t3), // tmp3 = tmp3 + tmp3; c.call(f2mPrefix + "_add", t3, t3, t3), // tmp4 = tmp0 + tmp0 + tmp0; c.call(f2mPrefix + "_add", t0, t0, t4), c.call(f2mPrefix + "_add", t4, t0, t4), // tmp6 = r.x + tmp4; c.call(f2mPrefix + "_add", Rx, t4, t6), // tmp5 = tmp4.square(); c.call(f2mPrefix + "_square", t4, t5), // zsquared = r.z.square(); c.call(f2mPrefix + "_square", Rz, zsquared), // r.x = tmp5 - tmp3 - tmp3; c.call(f2mPrefix + "_sub", t5, t3, Rx), c.call(f2mPrefix + "_sub", Rx, t3, Rx), // r.z = (r.z + r.y).square() - tmp1 - zsquared; c.call(f2mPrefix + "_add", Rz, Ry, Rz), c.call(f2mPrefix + "_square", Rz, Rz), c.call(f2mPrefix + "_sub", Rz, t1, Rz), c.call(f2mPrefix + "_sub", Rz, zsquared, Rz), // r.y = (tmp3 - r.x) * tmp4; c.call(f2mPrefix + "_sub", t3, Rx, Ry), c.call(f2mPrefix + "_mul", Ry, t4, Ry), // tmp2 = tmp2 + tmp2; c.call(f2mPrefix + "_add", t2, t2, t2), // tmp2 = tmp2 + tmp2; c.call(f2mPrefix + "_add", t2, t2, t2), // tmp2 = tmp2 + tmp2; c.call(f2mPrefix + "_add", t2, t2, t2), // r.y -= tmp2; c.call(f2mPrefix + "_sub", Ry, t2, Ry), // tmp3 = tmp4 * zsquared; c.call(f2mPrefix + "_mul", t4, zsquared, t3), // tmp3 = tmp3 + tmp3; c.call(f2mPrefix + "_add", t3, t3, t3), // tmp3 = -tmp3; c.call(f2mPrefix + "_neg", t3, t3), // tmp6 = tmp6.square() - tmp0 - tmp5; c.call(f2mPrefix + "_square", t6, t6), c.call(f2mPrefix + "_sub", t6, t0, t6), c.call(f2mPrefix + "_sub", t6, t5, t6), // tmp1 = tmp1 + tmp1; c.call(f2mPrefix + "_add", t1, t1, t1), // tmp1 = tmp1 + tmp1; c.call(f2mPrefix + "_add", t1, t1, t1), // tmp6 = tmp6 - tmp1; c.call(f2mPrefix + "_sub", t6, t1, t6), // tmp0 = r.z * zsquared; c.call(f2mPrefix + "_mul", Rz, zsquared, t0), // tmp0 = tmp0 + tmp0; c.call(f2mPrefix + "_add", t0, t0, t0), ); } function buildPrepAddStep() { const f = module.addFunction(prefix+ "_prepAddStep"); f.addParam("R", "i32"); f.addParam("Q", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const Rx = c.getLocal("R"); const Ry = c.i32_add(c.getLocal("R"), c.i32_const(2*n8q)); const Rz = c.i32_add(c.getLocal("R"), c.i32_const(4*n8q)); const Qx = c.getLocal("Q"); const Qy = c.i32_add(c.getLocal("Q"), c.i32_const(2*n8q)); const t10 = c.getLocal("r"); const t1 = c.i32_add(c.getLocal("r"), c.i32_const(2*n8q)); const t9 = c.i32_add(c.getLocal("r"), c.i32_const(4*n8q)); const zsquared = c.i32_const(module.alloc(f2size)); const ysquared = c.i32_const(module.alloc(f2size)); const ztsquared = c.i32_const(module.alloc(f2size)); const t0 = c.i32_const(module.alloc(f2size)); const t2 = c.i32_const(module.alloc(f2size)); const t3 = c.i32_const(module.alloc(f2size)); const t4 = c.i32_const(module.alloc(f2size)); const t5 = c.i32_const(module.alloc(f2size)); const t6 = c.i32_const(module.alloc(f2size)); const t7 = c.i32_const(module.alloc(f2size)); const t8 = c.i32_const(module.alloc(f2size)); f.addCode( // zsquared = r.z.square(); c.call(f2mPrefix + "_square", Rz, zsquared), // ysquared = q.y.square(); c.call(f2mPrefix + "_square", Qy, ysquared), // t0 = zsquared * q.x; c.call(f2mPrefix + "_mul", zsquared, Qx, t0), // t1 = ((q.y + r.z).square() - ysquared - zsquared) * zsquared; c.call(f2mPrefix + "_add", Qy, Rz, t1), c.call(f2mPrefix + "_square", t1, t1), c.call(f2mPrefix + "_sub", t1, ysquared, t1), c.call(f2mPrefix + "_sub", t1, zsquared, t1), c.call(f2mPrefix + "_mul", t1, zsquared, t1), // t2 = t0 - r.x; c.call(f2mPrefix + "_sub", t0, Rx, t2), // t3 = t2.square(); c.call(f2mPrefix + "_square", t2, t3), // t4 = t3 + t3; c.call(f2mPrefix + "_add", t3, t3, t4), // t4 = t4 + t4; c.call(f2mPrefix + "_add", t4, t4, t4), // t5 = t4 * t2; c.call(f2mPrefix + "_mul", t4, t2, t5), // t6 = t1 - r.y - r.y; c.call(f2mPrefix + "_sub", t1, Ry, t6), c.call(f2mPrefix + "_sub", t6, Ry, t6), // t9 = t6 * q.x; c.call(f2mPrefix + "_mul", t6, Qx, t9), // t7 = t4 * r.x; c.call(f2mPrefix + "_mul", t4, Rx, t7), // r.x = t6.square() - t5 - t7 - t7; c.call(f2mPrefix + "_square", t6, Rx), c.call(f2mPrefix + "_sub", Rx, t5, Rx), c.call(f2mPrefix + "_sub", Rx, t7, Rx), c.call(f2mPrefix + "_sub", Rx, t7, Rx), // r.z = (r.z + t2).square() - zsquared - t3; c.call(f2mPrefix + "_add", Rz, t2, Rz), c.call(f2mPrefix + "_square", Rz, Rz), c.call(f2mPrefix + "_sub", Rz, zsquared, Rz), c.call(f2mPrefix + "_sub", Rz, t3, Rz), // t10 = q.y + r.z; c.call(f2mPrefix + "_add", Qy, Rz, t10), // t8 = (t7 - r.x) * t6; c.call(f2mPrefix + "_sub", t7, Rx, t8), c.call(f2mPrefix + "_mul", t8, t6, t8), // t0 = r.y * t5; c.call(f2mPrefix + "_mul", Ry, t5, t0), // t0 = t0 + t0; c.call(f2mPrefix + "_add", t0, t0, t0), // r.y = t8 - t0; c.call(f2mPrefix + "_sub", t8, t0, Ry), // t10 = t10.square() - ysquared; c.call(f2mPrefix + "_square", t10, t10), c.call(f2mPrefix + "_sub", t10, ysquared, t10), // ztsquared = r.z.square(); c.call(f2mPrefix + "_square", Rz, ztsquared), // t10 = t10 - ztsquared; c.call(f2mPrefix + "_sub", t10, ztsquared, t10), // t9 = t9 + t9 - t10; c.call(f2mPrefix + "_add", t9, t9, t9), c.call(f2mPrefix + "_sub", t9, t10, t9), // t10 = r.z + r.z; c.call(f2mPrefix + "_add", Rz, Rz, t10), // t6 = -t6; c.call(f2mPrefix + "_neg", t6, t6), // t1 = t6 + t6; c.call(f2mPrefix + "_add", t6, t6, t1), ); } function buildPrepareG2() { const f = module.addFunction(prefix+ "_prepareG2"); f.addParam("pQ", "i32"); f.addParam("ppreQ", "i32"); f.addLocal("pCoef", "i32"); f.addLocal("i", "i32"); const c = f.getCodeBuilder(); const Q = c.getLocal("pQ"); const pR = module.alloc(f2size*3); const R = c.i32_const(pR); const base = c.getLocal("ppreQ"); f.addCode( c.call(g2mPrefix + "_normalize", Q, base), c.if( c.call(g2mPrefix + "_isZero", base), c.ret([]) ), c.call(g2mPrefix + "_copy", base, R), c.setLocal("pCoef", c.i32_add(c.getLocal("ppreQ"), c.i32_const(f2size*3))), ); f.addCode( c.setLocal("i", c.i32_const(ateLoopBitBytes.length-2)), c.block(c.loop( c.call(prefix + "_prepDblStep", R, c.getLocal("pCoef")), c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))), c.if( c.i32_load8_s(c.getLocal("i"), pAteLoopBitBytes), [ ...c.call(prefix + "_prepAddStep", R, base, c.getLocal("pCoef")), ...c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))), ] ), c.br_if(1, c.i32_eqz ( c.getLocal("i") )), c.setLocal("i", c.i32_sub(c.getLocal("i"), c.i32_const(1))), c.br(0) )) ); } function buildF6Mul1() { const f = module.addFunction(f6mPrefix+ "_mul1"); f.addParam("pA", "i32"); // F6 f.addParam("pC1", "i32"); // F2 f.addParam("pR", "i32"); // F6 const c = f.getCodeBuilder(); const A_c0 = c.getLocal("pA"); const A_c1 = c.i32_add(c.getLocal("pA"), c.i32_const(f1size*2)); const A_c2 = c.i32_add(c.getLocal("pA"), c.i32_const(f1size*4)); const c1 = c.getLocal("pC1"); const t1 = c.getLocal("pR"); const t2 = c.i32_add(c.getLocal("pR"), c.i32_const(f1size*2)); const b_b = c.i32_add(c.getLocal("pR"), c.i32_const(f1size*4)); const Ac0_Ac1 = c.i32_const(module.alloc(f1size*2)); const Ac1_Ac2 = c.i32_const(module.alloc(f1size*2)); f.addCode( c.call(f2mPrefix + "_add", A_c0, A_c1, Ac0_Ac1), c.call(f2mPrefix + "_add", A_c1, A_c2, Ac1_Ac2), // let b_b = self.c1 * c1; c.call(f2mPrefix + "_mul", A_c1, c1, b_b), // let t1 = (self.c1 + self.c2) * c1 - b_b; c.call(f2mPrefix + "_mul", Ac1_Ac2, c1, t1), c.call(f2mPrefix + "_sub", t1, b_b, t1), // let t1 = t1.mul_by_nonresidue(); c.call(f2mPrefix + "_mulNR", t1, t1), // let t2 = (self.c0 + self.c1) * c1 - b_b; c.call(f2mPrefix + "_mul", Ac0_Ac1, c1, t2), c.call(f2mPrefix + "_sub", t2, b_b, t2), ); } buildF6Mul1(); function buildF6Mul01() { const f = module.addFunction(f6mPrefix+ "_mul01"); f.addParam("pA", "i32"); // F6 f.addParam("pC0", "i32"); // F2 f.addParam("pC1", "i32"); // F2 f.addParam("pR", "i32"); // F6 const c = f.getCodeBuilder(); const A_c0 = c.getLocal("pA"); const A_c1 = c.i32_add(c.getLocal("pA"), c.i32_const(f1size*2)); const A_c2 = c.i32_add(c.getLocal("pA"), c.i32_const(f1size*4)); const c0 = c.getLocal("pC0"); const c1 = c.getLocal("pC1"); const t1 = c.getLocal("pR"); const t2 = c.i32_add(c.getLocal("pR"), c.i32_const(f1size*2)); const t3 = c.i32_add(c.getLocal("pR"), c.i32_const(f1size*4)); const a_a = c.i32_const(module.alloc(f1size*2)); const b_b = c.i32_const(module.alloc(f1size*2)); const Ac0_Ac1 = c.i32_const(module.alloc(f1size*2)); const Ac0_Ac2 = c.i32_const(module.alloc(f1size*2)); f.addCode( // let a_a = self.c0 * c0; c.call(f2mPrefix + "_mul", A_c0, c0, a_a), // let b_b = self.c1 * c1; c.call(f2mPrefix + "_mul", A_c1, c1, b_b), c.call(f2mPrefix + "_add", A_c0, A_c1, Ac0_Ac1), c.call(f2mPrefix + "_add", A_c0, A_c2, Ac0_Ac2), // let t1 = (self.c1 + self.c2) * c1 - b_b; c.call(f2mPrefix + "_add", A_c1, A_c2, t1), c.call(f2mPrefix + "_mul", t1, c1, t1), c.call(f2mPrefix + "_sub", t1, b_b, t1), // let t1 = t1.mul_by_nonresidue() + a_a; c.call(f2mPrefix + "_mulNR", t1, t1), c.call(f2mPrefix + "_add", t1, a_a, t1), // let t2 = (c0 + c1) * (self.c0 + self.c1) - a_a - b_b; c.call(f2mPrefix + "_add", c0, c1, t2), c.call(f2mPrefix + "_mul", t2, Ac0_Ac1, t2), c.call(f2mPrefix + "_sub", t2, a_a, t2), c.call(f2mPrefix + "_sub", t2, b_b, t2), // let t3 = (self.c0 + self.c2) * c0 - a_a + b_b; c.call(f2mPrefix + "_mul", Ac0_Ac2, c0, t3), c.call(f2mPrefix + "_sub", t3, a_a, t3), c.call(f2mPrefix + "_add", t3, b_b, t3), ); } buildF6Mul01(); function buildF12Mul014() { const f = module.addFunction(ftmPrefix+ "_mul014"); f.addParam("pA", "i32"); // F12 f.addParam("pC0", "i32"); // F2 f.addParam("pC1", "i32"); // F2 f.addParam("pC4", "i32"); // F2 f.addParam("pR", "i32"); // F12 const c = f.getCodeBuilder(); const A_c0 = c.getLocal("pA"); const A_c1 = c.i32_add(c.getLocal("pA"), c.i32_const(f1size*6)); const c0 = c.getLocal("pC0"); const c1 = c.getLocal("pC1"); const c4 = c.getLocal("pC4"); const aa = c.i32_const(module.alloc(f1size*6)); const bb = c.i32_const(module.alloc(f1size*6)); const o = c.i32_const(module.alloc(f1size*2)); const R_c0 = c.getLocal("pR"); const R_c1 = c.i32_add(c.getLocal("pR"), c.i32_const(f1size*6)); f.addCode( // let aa = self.c0.mul_by_01(c0, c1); c.call(f6mPrefix + "_mul01", A_c0, c0, c1, aa), // let bb = self.c1.mul_by_1(c4); c.call(f6mPrefix + "_mul1", A_c1, c4, bb), // let o = c1 + c4; c.call(f2mPrefix + "_add", c1, c4, o), // let c1 = self.c1 + self.c0; c.call(f6mPrefix + "_add", A_c1, A_c0, R_c1), // let c1 = c1.mul_by_01(c0, &o); c.call(f6mPrefix + "_mul01", R_c1, c0, o, R_c1), // let c1 = c1 - aa - bb; c.call(f6mPrefix + "_sub", R_c1, aa, R_c1), c.call(f6mPrefix + "_sub", R_c1, bb, R_c1), // let c0 = bb; c.call(f6mPrefix + "_copy", bb, R_c0), // let c0 = c0.mul_by_nonresidue(); c.call(f6mPrefix + "_mulNR", R_c0, R_c0), // let c0 = c0 + aa; c.call(f6mPrefix + "_add", R_c0, aa, R_c0), ); } buildF12Mul014(); function buildELL() { const f = module.addFunction(prefix+ "_ell"); f.addParam("pP", "i32"); f.addParam("pCoefs", "i32"); f.addParam("pF", "i32"); const c = f.getCodeBuilder(); const Px = c.getLocal("pP"); const Py = c.i32_add(c.getLocal("pP"), c.i32_const(n8q)); const F = c.getLocal("pF"); const coef0_0 = c.getLocal("pCoefs"); const coef0_1 = c.i32_add(c.getLocal("pCoefs"), c.i32_const(f1size)); const coef1_0 = c.i32_add(c.getLocal("pCoefs"), c.i32_const(f1size*2)); const coef1_1 = c.i32_add(c.getLocal("pCoefs"), c.i32_const(f1size*3)); const coef2 = c.i32_add(c.getLocal("pCoefs"), c.i32_const(f1size*4)); const pc0 = module.alloc(f1size*2); const c0 = c.i32_const(pc0); const c0_c0 = c.i32_const(pc0); const c0_c1 = c.i32_const(pc0+f1size); const pc1 = module.alloc(f1size*2); const c1 = c.i32_const(pc1); const c1_c0 = c.i32_const(pc1); const c1_c1 = c.i32_const(pc1+f1size); f.addCode( // let mut c0 = coeffs.0; // let mut c1 = coeffs.1; // // c0.c0 *= p.y; // c0.c1 *= p.y; // // c1.c0 *= p.x; // c1.c1 *= p.x; // // f.mul_by_014(&coeffs.2, &c1, &c0) c.call(f1mPrefix + "_mul", coef0_0, Py, c0_c0), c.call(f1mPrefix + "_mul", coef0_1, Py, c0_c1), c.call(f1mPrefix + "_mul", coef1_0, Px, c1_c0), c.call(f1mPrefix + "_mul", coef1_1, Px, c1_c1), c.call(ftmPrefix + "_mul014", F, coef2, c1, c0, F), ); } buildELL(); function buildMillerLoop() { const f = module.addFunction(prefix+ "_millerLoop"); f.addParam("ppreP", "i32"); f.addParam("ppreQ", "i32"); f.addParam("r", "i32"); f.addLocal("pCoef", "i32"); f.addLocal("i", "i32"); const c = f.getCodeBuilder(); const preP = c.getLocal("ppreP"); c.getLocal("ppreQ"); const coefs = c.getLocal("pCoef"); const F = c.getLocal("r"); f.addCode( c.call(ftmPrefix + "_one", F), c.if( c.call(g1mPrefix + "_isZero", preP), c.ret([]) ), c.if( c.call(g1mPrefix + "_isZero", c.getLocal("ppreQ")), c.ret([]) ), c.setLocal("pCoef", c.i32_add( c.getLocal("ppreQ"), c.i32_const(f2size*3))), c.setLocal("i", c.i32_const(ateLoopBitBytes.length-2)), c.block(c.loop( c.call(prefix + "_ell", preP, coefs, F), c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))), c.if( c.i32_load8_s(c.getLocal("i"), pAteLoopBitBytes), [ ...c.call(prefix + "_ell", preP, coefs, F), ...c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))), ] ), c.call(ftmPrefix + "_square", F, F), c.br_if(1, c.i32_eq ( c.getLocal("i"), c.i32_const(1) )), c.setLocal("i", c.i32_sub(c.getLocal("i"), c.i32_const(1))), c.br(0) )), c.call(prefix + "_ell", preP, coefs, F), ); { f.addCode( c.call(ftmPrefix + "_conjugate", F, F), ); } } function buildFrobeniusMap(n) { const F12 = [ [ [bigInt$1("1"), bigInt$1("0")], [bigInt$1("1"), bigInt$1("0")], [bigInt$1("1"), bigInt$1("0")], [bigInt$1("1"), bigInt$1("0")], [bigInt$1("1"), bigInt$1("0")], [bigInt$1("1"), bigInt$1("0")], [bigInt$1("1"), bigInt$1("0")], [bigInt$1("1"), bigInt$1("0")], [bigInt$1("1"), bigInt$1("0")], [bigInt$1("1"), bigInt$1("0")], [bigInt$1("1"), bigInt$1("0")], [bigInt$1("1"), bigInt$1("0")], ], [ [bigInt$1("1"), bigInt$1("0")], [bigInt$1("3850754370037169011952147076051364057158807420970682438676050522613628423219637725072182697113062777891589506424760"), bigInt$1("151655185184498381465642749684540099398075398968325446656007613510403227271200139370504932015952886146304766135027")], [bigInt$1("793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620351"), bigInt$1("0")], [bigInt$1("2973677408986561043442465346520108879172042883009249989176415018091420807192182638567116318576472649347015917690530"), bigInt$1("1028732146235106349975324479215795277384839936929757896155643118032610843298655225875571310552543014690878354869257")], [bigInt$1("793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350"), bigInt$1("0")], [bigInt$1("3125332594171059424908108096204648978570118281977575435832422631601824034463382777937621250592425535493320683825557"), bigInt$1("877076961050607968509681729531255177986764537961432449499635504522207616027455086505066378536590128544573588734230")], [bigInt$1("4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559786"), bigInt$1("0")], [bigInt$1("151655185184498381465642749684540099398075398968325446656007613510403227271200139370504932015952886146304766135027"), bigInt$1("3850754370037169011952147076051364057158807420970682438676050522613628423219637725072182697113062777891589506424760")], [bigInt$1("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436"), bigInt$1("0")], [bigInt$1("1028732146235106349975324479215795277384839936929757896155643118032610843298655225875571310552543014690878354869257"), bigInt$1("2973677408986561043442465346520108879172042883009249989176415018091420807192182638567116318576472649347015917690530")], [bigInt$1("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437"), bigInt$1("0")], [bigInt$1("877076961050607968509681729531255177986764537961432449499635504522207616027455086505066378536590128544573588734230"), bigInt$1("3125332594171059424908108096204648978570118281977575435832422631601824034463382777937621250592425535493320683825557")], ] ]; const F6 = [ [ [bigInt$1("1"), bigInt$1("0")], [bigInt$1("1"), bigInt$1("0")], [bigInt$1("1"), bigInt$1("0")], [bigInt$1("1"), bigInt$1("0")], [bigInt$1("1"), bigInt$1("0")], [bigInt$1("1"), bigInt$1("0")], ], [ [bigInt$1("1"), bigInt$1("0")], [bigInt$1("0"), bigInt$1("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436")], [bigInt$1("793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350"), bigInt$1("0")], [bigInt$1("0"), bigInt$1("1")], [bigInt$1("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436"), bigInt$1("0")], [bigInt$1("0"), bigInt$1("793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350")], ], [ [bigInt$1("1"), bigInt$1("0")], [bigInt$1("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437"), bigInt$1("0")], [bigInt$1("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436"), bigInt$1("0")], [bigInt$1("4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559786"), bigInt$1("0")], [bigInt$1("793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350"), bigInt$1("0")], [bigInt$1("793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620351"), bigInt$1("0")], ] ]; const f = module.addFunction(ftmPrefix + "_frobeniusMap"+n); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); for (let i=0; i<6; i++) { const X = (i==0) ? c.getLocal("x") : c.i32_add(c.getLocal("x"), c.i32_const(i*f2size)); const Xc0 = X; const Xc1 = c.i32_add(c.getLocal("x"), c.i32_const(i*f2size + f1size)); const R = (i==0) ? c.getLocal("r") : c.i32_add(c.getLocal("r"), c.i32_const(i*f2size)); const Rc0 = R; const Rc1 = c.i32_add(c.getLocal("r"), c.i32_const(i*f2size + f1size)); const coef = mul2(F12[Math.floor(i/3)][n%12] , F6[i%3][n%6]); const pCoef = module.alloc([ ...utils$5.bigInt2BytesLE(toMontgomery(coef[0]), n8q), ...utils$5.bigInt2BytesLE(toMontgomery(coef[1]), n8q), ]); if (n%2 == 1) { f.addCode( c.call(f1mPrefix + "_copy", Xc0, Rc0), c.call(f1mPrefix + "_neg", Xc1, Rc1), c.call(f2mPrefix + "_mul", R, c.i32_const(pCoef), R), ); } else { f.addCode(c.call(f2mPrefix + "_mul", X, c.i32_const(pCoef), R)); } } function mul2(a, b) { const ac0 = bigInt$1(a[0]); const ac1 = bigInt$1(a[1]); const bc0 = bigInt$1(b[0]); const bc1 = bigInt$1(b[1]); const res = [ ac0.times(bc0).minus( ac1.times(bc1) ).mod(q), ac0.times(bc1).add( ac1.times(bc0) ).mod(q), ]; if (res[0].isNegative()) res[0] = res[0].add(q); return res; } } function buildCyclotomicSquare() { const f = module.addFunction(prefix+ "__cyclotomicSquare"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const x0 = c.getLocal("x"); const x4 = c.i32_add(c.getLocal("x"), c.i32_const(f2size)); const x3 = c.i32_add(c.getLocal("x"), c.i32_const(2*f2size)); const x2 = c.i32_add(c.getLocal("x"), c.i32_const(3*f2size)); const x1 = c.i32_add(c.getLocal("x"), c.i32_const(4*f2size)); const x5 = c.i32_add(c.getLocal("x"), c.i32_const(5*f2size)); const r0 = c.getLocal("r"); const r4 = c.i32_add(c.getLocal("r"), c.i32_const(f2size)); const r3 = c.i32_add(c.getLocal("r"), c.i32_const(2*f2size)); const r2 = c.i32_add(c.getLocal("r"), c.i32_const(3*f2size)); const r1 = c.i32_add(c.getLocal("r"), c.i32_const(4*f2size)); const r5 = c.i32_add(c.getLocal("r"), c.i32_const(5*f2size)); const t0 = c.i32_const(module.alloc(f2size)); const t1 = c.i32_const(module.alloc(f2size)); const t2 = c.i32_const(module.alloc(f2size)); const t3 = c.i32_const(module.alloc(f2size)); const t4 = c.i32_const(module.alloc(f2size)); const t5 = c.i32_const(module.alloc(f2size)); const tmp = c.i32_const(module.alloc(f2size)); const AUX = c.i32_const(module.alloc(f2size)); f.addCode( // c.call(ftmPrefix + "_square", x0, r0), // // t0 + t1*y = (z0 + z1*y)^2 = a^2 // tmp = z0 * z1; // t0 = (z0 + z1) * (z0 + my_Fp6::non_residue * z1) - tmp - my_Fp6::non_residue * tmp; // t1 = tmp + tmp; c.call(f2mPrefix + "_mul", x0, x1, tmp), c.call(f2mPrefix + "_mulNR", x1, t0), c.call(f2mPrefix + "_add", x0, t0, t0), c.call(f2mPrefix + "_add", x0, x1, AUX), c.call(f2mPrefix + "_mul", AUX, t0, t0), c.call(f2mPrefix + "_mulNR", tmp, AUX), c.call(f2mPrefix + "_add", tmp, AUX, AUX), c.call(f2mPrefix + "_sub", t0, AUX, t0), c.call(f2mPrefix + "_add", tmp, tmp, t1), // // t2 + t3*y = (z2 + z3*y)^2 = b^2 // tmp = z2 * z3; // t2 = (z2 + z3) * (z2 + my_Fp6::non_residue * z3) - tmp - my_Fp6::non_residue * tmp; // t3 = tmp + tmp; c.call(f2mPrefix + "_mul", x2, x3, tmp), c.call(f2mPrefix + "_mulNR", x3, t2), c.call(f2mPrefix + "_add", x2, t2, t2), c.call(f2mPrefix + "_add", x2, x3, AUX), c.call(f2mPrefix + "_mul", AUX, t2, t2), c.call(f2mPrefix + "_mulNR", tmp, AUX), c.call(f2mPrefix + "_add", tmp, AUX, AUX), c.call(f2mPrefix + "_sub", t2, AUX, t2), c.call(f2mPrefix + "_add", tmp, tmp, t3), // // t4 + t5*y = (z4 + z5*y)^2 = c^2 // tmp = z4 * z5; // t4 = (z4 + z5) * (z4 + my_Fp6::non_residue * z5) - tmp - my_Fp6::non_residue * tmp; // t5 = tmp + tmp; c.call(f2mPrefix + "_mul", x4, x5, tmp), c.call(f2mPrefix + "_mulNR", x5, t4), c.call(f2mPrefix + "_add", x4, t4, t4), c.call(f2mPrefix + "_add", x4, x5, AUX), c.call(f2mPrefix + "_mul", AUX, t4, t4), c.call(f2mPrefix + "_mulNR", tmp, AUX), c.call(f2mPrefix + "_add", tmp, AUX, AUX), c.call(f2mPrefix + "_sub", t4, AUX, t4), c.call(f2mPrefix + "_add", tmp, tmp, t5), // For A // z0 = 3 * t0 - 2 * z0 c.call(f2mPrefix + "_sub", t0, x0, r0), c.call(f2mPrefix + "_add", r0, r0, r0), c.call(f2mPrefix + "_add", t0, r0, r0), // z1 = 3 * t1 + 2 * z1 c.call(f2mPrefix + "_add", t1, x1, r1), c.call(f2mPrefix + "_add", r1, r1, r1), c.call(f2mPrefix + "_add", t1, r1, r1), // For B // z2 = 3 * (xi * t5) + 2 * z2 c.call(f2mPrefix + "_mul", t5, c.i32_const(pBls12381Twist), AUX), c.call(f2mPrefix + "_add", AUX, x2, r2), c.call(f2mPrefix + "_add", r2, r2, r2), c.call(f2mPrefix + "_add", AUX, r2, r2), // z3 = 3 * t4 - 2 * z3 c.call(f2mPrefix + "_sub", t4, x3, r3), c.call(f2mPrefix + "_add", r3, r3, r3), c.call(f2mPrefix + "_add", t4, r3, r3), // For C // z4 = 3 * t2 - 2 * z4 c.call(f2mPrefix + "_sub", t2, x4, r4), c.call(f2mPrefix + "_add", r4, r4, r4), c.call(f2mPrefix + "_add", t2, r4, r4), // z5 = 3 * t3 + 2 * z5 c.call(f2mPrefix + "_add", t3, x5, r5), c.call(f2mPrefix + "_add", r5, r5, r5), c.call(f2mPrefix + "_add", t3, r5, r5), ); } function buildCyclotomicExp(exponent, isExpNegative, fnName) { const exponentNafBytes = naf(exponent).map( (b) => (b==-1 ? 0xFF: b) ); const pExponentNafBytes = module.alloc(exponentNafBytes); // const pExponent = module.alloc(utils.bigInt2BytesLE(exponent, n8)); const f = module.addFunction(prefix+ "__cyclotomicExp_"+fnName); f.addParam("x", "i32"); f.addParam("r", "i32"); f.addLocal("bit", "i32"); f.addLocal("i", "i32"); const c = f.getCodeBuilder(); const x = c.getLocal("x"); const res = c.getLocal("r"); const inverse = c.i32_const(module.alloc(ftsize)); f.addCode( // c.call(ftmPrefix + "_exp", x, c.i32_const(pExponent), c.i32_const(32), res), c.call(ftmPrefix + "_conjugate", x, inverse), c.call(ftmPrefix + "_one", res), c.if( c.teeLocal("bit", c.i32_load8_s(c.i32_const(exponentNafBytes.length-1), pExponentNafBytes)), c.if( c.i32_eq( c.getLocal("bit"), c.i32_const(1) ), c.call(ftmPrefix + "_mul", res, x, res), c.call(ftmPrefix + "_mul", res, inverse, res), ) ), c.setLocal("i", c.i32_const(exponentNafBytes.length-2)), c.block(c.loop( // c.call(ftmPrefix + "_square", res, res), c.call(prefix + "__cyclotomicSquare", res, res), c.if( c.teeLocal("bit", c.i32_load8_s(c.getLocal("i"), pExponentNafBytes)), c.if( c.i32_eq( c.getLocal("bit"), c.i32_const(1) ), c.call(ftmPrefix + "_mul", res, x, res), c.call(ftmPrefix + "_mul", res, inverse, res), ) ), c.br_if(1, c.i32_eqz ( c.getLocal("i") )), c.setLocal("i", c.i32_sub(c.getLocal("i"), c.i32_const(1))), c.br(0) )) ); if (isExpNegative) { f.addCode( c.call(ftmPrefix + "_conjugate", res, res), ); } } function buildFinalExponentiation() { buildCyclotomicSquare(); buildCyclotomicExp(finalExpZ, finalExpIsNegative, "w0"); const f = module.addFunction(prefix+ "_finalExponentiation"); f.addParam("x", "i32"); f.addParam("r", "i32"); const c = f.getCodeBuilder(); const elt = c.getLocal("x"); const res = c.getLocal("r"); const t0 = c.i32_const(module.alloc(ftsize)); const t1 = c.i32_const(module.alloc(ftsize)); const t2 = c.i32_const(module.alloc(ftsize)); const t3 = c.i32_const(module.alloc(ftsize)); const t4 = c.i32_const(module.alloc(ftsize)); const t5 = c.i32_const(module.alloc(ftsize)); const t6 = c.i32_const(module.alloc(ftsize)); f.addCode( // let mut t0 = f.frobenius_map(6) c.call(ftmPrefix + "_frobeniusMap6", elt, t0), // let t1 = f.invert() c.call(ftmPrefix + "_inverse", elt, t1), // let mut t2 = t0 * t1; c.call(ftmPrefix + "_mul", t0, t1, t2), // t1 = t2.clone(); c.call(ftmPrefix + "_copy", t2, t1), // t2 = t2.frobenius_map().frobenius_map(); c.call(ftmPrefix + "_frobeniusMap2", t2, t2), // t2 *= t1; c.call(ftmPrefix + "_mul", t2, t1, t2), // t1 = cyclotomic_square(t2).conjugate(); c.call(prefix + "__cyclotomicSquare", t2, t1), c.call(ftmPrefix + "_conjugate", t1, t1), // let mut t3 = cycolotomic_exp(t2); c.call(prefix + "__cyclotomicExp_w0", t2, t3), // let mut t4 = cyclotomic_square(t3); c.call(prefix + "__cyclotomicSquare", t3, t4), // let mut t5 = t1 * t3; c.call(ftmPrefix + "_mul", t1, t3, t5), // t1 = cycolotomic_exp(t5); c.call(prefix + "__cyclotomicExp_w0", t5, t1), // t0 = cycolotomic_exp(t1); c.call(prefix + "__cyclotomicExp_w0", t1, t0), // let mut t6 = cycolotomic_exp(t0); c.call(prefix + "__cyclotomicExp_w0", t0, t6), // t6 *= t4; c.call(ftmPrefix + "_mul", t6, t4, t6), // t4 = cycolotomic_exp(t6); c.call(prefix + "__cyclotomicExp_w0", t6, t4), // t5 = t5.conjugate(); c.call(ftmPrefix + "_conjugate", t5, t5), // t4 *= t5 * t2; c.call(ftmPrefix + "_mul", t4, t5, t4), c.call(ftmPrefix + "_mul", t4, t2, t4), // t5 = t2.conjugate(); c.call(ftmPrefix + "_conjugate", t2, t5), // t1 *= t2; c.call(ftmPrefix + "_mul", t1, t2, t1), // t1 = t1.frobenius_map().frobenius_map().frobenius_map(); c.call(ftmPrefix + "_frobeniusMap3", t1, t1), // t6 *= t5; c.call(ftmPrefix + "_mul", t6, t5, t6), // t6 = t6.frobenius_map(); c.call(ftmPrefix + "_frobeniusMap1", t6, t6), // t3 *= t0; c.call(ftmPrefix + "_mul", t3, t0, t3), // t3 = t3.frobenius_map().frobenius_map(); c.call(ftmPrefix + "_frobeniusMap2", t3, t3), // t3 *= t1; c.call(ftmPrefix + "_mul", t3, t1, t3), // t3 *= t6; c.call(ftmPrefix + "_mul", t3, t6, t3), // f = t3 * t4; c.call(ftmPrefix + "_mul", t3, t4, res), ); } function buildFinalExponentiationOld() { const f = module.addFunction(prefix+ "_finalExponentiationOld"); f.addParam("x", "i32"); f.addParam("r", "i32"); const exponent = bigInt$1("322277361516934140462891564586510139908379969514828494218366688025288661041104682794998680497580008899973249814104447692778988208376779573819485263026159588510513834876303014016798809919343532899164848730280942609956670917565618115867287399623286813270357901731510188149934363360381614501334086825442271920079363289954510565375378443704372994881406797882676971082200626541916413184642520269678897559532260949334760604962086348898118982248842634379637598665468817769075878555493752214492790122785850202957575200176084204422751485957336465472324810982833638490904279282696134323072515220044451592646885410572234451732790590013479358343841220074174848221722017083597872017638514103174122784843925578370430843522959600095676285723737049438346544753168912974976791528535276317256904336520179281145394686565050419250614107803233314658825463117900250701199181529205942363159325765991819433914303908860460720581408201373164047773794825411011922305820065611121544561808414055302212057471395719432072209245600258134364584636810093520285711072578721435517884103526483832733289802426157301542744476740008494780363354305116978805620671467071400711358839553375340724899735460480144599782014906586543813292157922220645089192130209334926661588737007768565838519456601560804957985667880395221049249803753582637708560"); const pExponent = module.alloc(utils$5.bigInt2BytesLE( exponent, 544 )); const c = f.getCodeBuilder(); f.addCode( c.call(ftmPrefix + "_exp", c.getLocal("x"), c.i32_const(pExponent), c.i32_const(544), c.getLocal("r")), ); } const pPreP = module.alloc(prePSize); const pPreQ = module.alloc(preQSize); function buildPairingEquation(nPairings) { const f = module.addFunction(prefix+ "_pairingEq"+nPairings); for (let i=0; i. */ // module.exports.bn128_wasm = require("./build/bn128_wasm.js"); // module.exports.bls12381_wasm = require("./build/bls12381_wasm.js"); // module.exports.mnt6753_wasm = require("./build/mnt6753_wasm.js"); var buildBn128$1 = build_bn128; var buildBls12381$1 = build_bls12381; /* global BigInt */ function stringifyBigInts$2(o) { if ((typeof(o) == "bigint") || o.eq !== undefined) { return o.toString(10); } else if (o instanceof Uint8Array) { return fromRprLE(o, 0); } else if (Array.isArray(o)) { return o.map(stringifyBigInts$2); } else if (typeof o == "object") { const res = {}; const keys = Object.keys(o); keys.forEach( (k) => { res[k] = stringifyBigInts$2(o[k]); }); return res; } else { return o; } } function unstringifyBigInts$2(o) { if ((typeof(o) == "string") && (/^[0-9]+$/.test(o) )) { return BigInt(o); } else if ((typeof(o) == "string") && (/^0x[0-9a-fA-F]+$/.test(o) )) { return BigInt(o); } else if (Array.isArray(o)) { return o.map(unstringifyBigInts$2); } else if (typeof o == "object") { if (o===null) return null; const res = {}; const keys = Object.keys(o); keys.forEach( (k) => { res[k] = unstringifyBigInts$2(o[k]); }); return res; } else { return o; } } function beBuff2int$2(buff) { let res = BigInt(0); let i = buff.length; let offset = 0; const buffV = new DataView(buff.buffer, buff.byteOffset, buff.byteLength); while (i>0) { if (i >= 4) { i -= 4; res += BigInt(buffV.getUint32(i)) << BigInt(offset*8); offset += 4; } else if (i >= 2) { i -= 2; res += BigInt(buffV.getUint16(i)) << BigInt(offset*8); offset += 2; } else { i -= 1; res += BigInt(buffV.getUint8(i)) << BigInt(offset*8); offset += 1; } } return res; } function beInt2Buff$2(n, len) { let r = n; const buff = new Uint8Array(len); const buffV = new DataView(buff.buffer); let o = len; while (o > 0) { if (o-4 >= 0) { o -= 4; buffV.setUint32(o, Number(r & BigInt(0xFFFFFFFF))); r = r >> BigInt(32); } else if (o-2 >= 0) { o -= 2; buffV.setUint16(o, Number(r & BigInt(0xFFFF))); r = r >> BigInt(16); } else { o -= 1; buffV.setUint8(o, Number(r & BigInt(0xFF))); r = r >> BigInt(8); } } if (r) { throw new Error("Number does not fit in this length"); } return buff; } function leBuff2int$2(buff) { let res = BigInt(0); let i = 0; const buffV = new DataView(buff.buffer, buff.byteOffset, buff.byteLength); while (i> BigInt(32); } else if (o+2 <= len) { buffV.setUint16(Number(o, r & BigInt(0xFFFF)), true ); o += 2; r = r >> BigInt(16); } else { buffV.setUint8(Number(o, r & BigInt(0xFF)), true ); o += 1; r = r >> BigInt(8); } } if (r) { throw new Error("Number does not fit in this length"); } return buff; } function stringifyFElements$1(F, o) { if ((typeof(o) == "bigint") || o.eq !== undefined) { return o.toString(10); } else if (o instanceof Uint8Array) { return F.toString(F.e(o)); } else if (Array.isArray(o)) { return o.map(stringifyFElements$1.bind(this,F)); } else if (typeof o == "object") { const res = {}; const keys = Object.keys(o); keys.forEach( (k) => { res[k] = stringifyFElements$1(F, o[k]); }); return res; } else { return o; } } function unstringifyFElements$1(F, o) { if ((typeof(o) == "string") && (/^[0-9]+$/.test(o) )) { return F.e(o); } else if ((typeof(o) == "string") && (/^0x[0-9a-fA-F]+$/.test(o) )) { return F.e(o); } else if (Array.isArray(o)) { return o.map(unstringifyFElements$1.bind(this,F)); } else if (typeof o == "object") { if (o===null) return null; const res = {}; const keys = Object.keys(o); keys.forEach( (k) => { res[k] = unstringifyFElements$1(F, o[k]); }); return res; } else { return o; } } var utils_native = /*#__PURE__*/Object.freeze({ __proto__: null, beBuff2int: beBuff2int$2, beInt2Buff: beInt2Buff$2, leBuff2int: leBuff2int$2, leInt2Buff: leInt2Buff$2, stringifyBigInts: stringifyBigInts$2, stringifyFElements: stringifyFElements$1, unstringifyBigInts: unstringifyBigInts$2, unstringifyFElements: unstringifyFElements$1 }); function stringifyBigInts$1(o) { if ((typeof(o) == "bigint") || o.eq !== undefined) { return o.toString(10); } else if (Array.isArray(o)) { return o.map(stringifyBigInts$1); } else if (typeof o == "object") { const res = {}; const keys = Object.keys(o); keys.forEach( (k) => { res[k] = stringifyBigInts$1(o[k]); }); return res; } else { return o; } } function unstringifyBigInts$1(o) { if ((typeof(o) == "string") && (/^[0-9]+$/.test(o) )) { return bigInt$8(o); } else if ((typeof(o) == "string") && (/^0x[0-9a-fA-F]+$/.test(o) )) { return bigInt$8(o); } else if (Array.isArray(o)) { return o.map(unstringifyBigInts$1); } else if (typeof o == "object") { const res = {}; const keys = Object.keys(o); keys.forEach( (k) => { res[k] = unstringifyBigInts$1(o[k]); }); return res; } else { return o; } } function beBuff2int$1(buff) { let res = bigInt$8.zero; for (let i=0; i=0)) { let c = Number(r.and(bigInt$8("255"))); buff[o] = c; o--; r = r.shiftRight(8); } if (!r.eq(bigInt$8.zero)) { throw new Error("Number does not fit in this length"); } return buff; } function leBuff2int$1 (buff) { let res = bigInt$8.zero; for (let i=0; i>=1; } return res; } utils$4.bitReverse = function bitReverse(idx, bits) { return ( _revTable[idx >>> 24] | (_revTable[(idx >>> 16) & 0xFF] << 8) | (_revTable[(idx >>> 8) & 0xFF] << 16) | (_revTable[idx & 0xFF] << 24) ) >>> (32-bits); }; utils$4.log2 = function log2( V ) { return( ( ( V & 0xFFFF0000 ) !== 0 ? ( V &= 0xFFFF0000, 16 ) : 0 ) | ( ( V & 0xFF00FF00 ) !== 0 ? ( V &= 0xFF00FF00, 8 ) : 0 ) | ( ( V & 0xF0F0F0F0 ) !== 0 ? ( V &= 0xF0F0F0F0, 4 ) : 0 ) | ( ( V & 0xCCCCCCCC ) !== 0 ? ( V &= 0xCCCCCCCC, 2 ) : 0 ) | ( ( V & 0xAAAAAAAA ) !== 0 ) ); }; utils$4.buffReverseBits = function buffReverseBits(buff, eSize) { const n = buff.byteLength /eSize; const bits = utils$4.log2(n); if (n != (1 << bits)) { throw new Error("Invalid number of pointers"); } for (let i=0; ir) { const tmp = buff.slice(i*eSize, (i+1)*eSize); buff.set( buff.slice(r*eSize, (r+1)*eSize), i*eSize); buff.set(tmp, r*eSize); } } }; utils$4.array2buffer = function(arr, sG) { const buff = new Uint8Array(sG*arr.length); for (let i=0; i0) { // bytes to copy from this page const l = (o+r > PAGE_SIZE) ? (PAGE_SIZE -o) : r; const srcView = new Uint8Array(this.buffers[p].buffer, this.buffers[p].byteOffset+o, l); if (l == len) return srcView.slice(); if (!buff) { if (len <= PAGE_SIZE) { buff = new Uint8Array(len); } else { buff = new BigBuffer(len); } } buff.set(srcView, len-r); r = r-l; p ++; o = 0; } return buff; } set(buff, offset) { if (offset === undefined) offset = 0; const len = buff.byteLength; if (len==0) return; const firstPage = Math.floor(offset / PAGE_SIZE); const lastPage = Math.floor((offset+len-1) / PAGE_SIZE); if (firstPage == lastPage) { if ((buff instanceof BigBuffer)&&(buff.buffers.length==1)) { return this.buffers[firstPage].set(buff.buffers[0], offset % PAGE_SIZE); } else { return this.buffers[firstPage].set(buff, offset % PAGE_SIZE); } } let p = firstPage; let o = offset % PAGE_SIZE; let r = len; while (r>0) { const l = (o+r > PAGE_SIZE) ? (PAGE_SIZE -o) : r; const srcView = buff.slice( len -r, len -r+l); const dstView = new Uint8Array(this.buffers[p].buffer, this.buffers[p].byteOffset + o, l); dstView.set(srcView); r = r-l; p ++; o = 0; } } } function buildBatchConvert(tm, fnName, sIn, sOut) { return async function batchConvert(buffIn) { const nPoints = Math.floor(buffIn.byteLength / sIn); if ( nPoints * sIn !== buffIn.byteLength) { throw new Error("Invalid buffer size"); } const pointsPerChunk = Math.floor(nPoints/tm.concurrency); const opPromises = []; for (let i=0; i=0; i--) { this.w[i] = this.square(this.w[i+1]); } if (!this.eq(this.w[0], this.one)) { throw new Error("Error calculating roots of unity"); } this.batchToMontgomery = buildBatchConvert(tm, prefix + "_batchToMontgomery", this.n8, this.n8); this.batchFromMontgomery = buildBatchConvert(tm, prefix + "_batchFromMontgomery", this.n8, this.n8); } op2(opName, a, b) { this.tm.setBuff(this.pOp1, a); this.tm.setBuff(this.pOp2, b); this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp2, this.pOp3); return this.tm.getBuff(this.pOp3, this.n8); } op2Bool(opName, a, b) { this.tm.setBuff(this.pOp1, a); this.tm.setBuff(this.pOp2, b); return !!this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp2); } op1(opName, a) { this.tm.setBuff(this.pOp1, a); this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp3); return this.tm.getBuff(this.pOp3, this.n8); } op1Bool(opName, a) { this.tm.setBuff(this.pOp1, a); return !!this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp3); } add(a,b) { return this.op2("_add", a, b); } eq(a,b) { return this.op2Bool("_eq", a, b); } isZero(a) { return this.op1Bool("_isZero", a); } sub(a,b) { return this.op2("_sub", a, b); } neg(a) { return this.op1("_neg", a); } inv(a) { return this.op1("_inverse", a); } toMontgomery(a) { return this.op1("_toMontgomery", a); } fromMontgomery(a) { return this.op1("_fromMontgomery", a); } mul(a,b) { return this.op2("_mul", a, b); } div(a, b) { this.tm.setBuff(this.pOp1, a); this.tm.setBuff(this.pOp2, b); this.tm.instance.exports[this.prefix + "_inverse"](this.pOp2, this.pOp2); this.tm.instance.exports[this.prefix + "_mul"](this.pOp1, this.pOp2, this.pOp3); return this.tm.getBuff(this.pOp3, this.n8); } square(a) { return this.op1("_square", a); } isSquare(a) { return this.op1Bool("_isSquare", a); } sqrt(a) { return this.op1("_sqrt", a); } exp(a, b) { if (!(b instanceof Uint8Array)) { b = toLEBuff(e(b)); } this.tm.setBuff(this.pOp1, a); this.tm.setBuff(this.pOp2, b); this.tm.instance.exports[this.prefix + "_exp"](this.pOp1, this.pOp2, b.byteLength, this.pOp3); return this.tm.getBuff(this.pOp3, this.n8); } isNegative(a) { return this.op1Bool("_isNegative", a); } e(a, b) { if (a instanceof Uint8Array) return a; let ra = e(a, b); if (isNegative(ra)) { ra = neg(ra); if (gt(ra, this.p)) { ra = mod(ra, this.p); } ra = sub(this.p, ra); } else { if (gt(ra, this.p)) { ra = mod(ra, this.p); } } const buff = leInt2Buff(ra, this.n8); return this.toMontgomery(buff); } toString(a, radix) { const an = this.fromMontgomery(a); const s = fromRprLE(an, 0); return toString(s, radix); } fromRng(rng) { let v; const buff = new Uint8Array(this.n8); do { v = zero; for (let i=0; i memory.buffer.byteLength) { const currentPages = memory.buffer.byteLength / 0x10000; let requiredPages = Math.floor((u32[0] + length) / 0x10000)+1; if (requiredPages>MAXMEM) requiredPages=MAXMEM; memory.grow(requiredPages-currentPages); } return res; } function allocBuffer(buffer) { const p = alloc(buffer.byteLength); setBuffer(p, buffer); return p; } function getBuffer(pointer, length) { const u8 = new Uint8Array(memory.buffer); return new Uint8Array(u8.buffer, u8.byteOffset + pointer, length); } function setBuffer(pointer, buffer) { const u8 = new Uint8Array(memory.buffer); u8.set(new Uint8Array(buffer), pointer); } function runTask(task) { if (task[0].cmd == "INIT") { return init(task[0]); } const ctx = { vars: [], out: [] }; const u32a = new Uint32Array(memory.buffer, 0, 1); const oldAlloc = u32a[0]; for (let i=0; i { try { handler.call(this, event); } catch (err) { console.error(err); } }); } addEventListener(type, fn) { let events = this[EVENTS].get(type); if (!events) this[EVENTS].set(type, events = []); events.push(fn); } removeEventListener(type, fn) { let events = this[EVENTS].get(type); if (events) { const index = events.indexOf(fn); if (index !== -1) events.splice(index, 1); } } } function Event(type, target) { this.type = type; this.timeStamp = Date.now(); this.target = this.currentTarget = this.data = null; } // this module is used self-referentially on both sides of the // thread boundary, but behaves differently in each context. var Worker = threads.isMainThread ? mainThread() : workerThread(); const baseUrl = URL.pathToFileURL(process.cwd() + '/'); function mainThread() { /** * A web-compatible Worker implementation atop Node's worker_threads. * - uses DOM-style events (Event.data, Event.type, etc) * - supports event handler properties (worker.onmessage) * - Worker() constructor accepts a module URL * - accepts the {type:'module'} option * - emulates WorkerGlobalScope within the worker * @param {string} url The URL or module specifier to load * @param {object} [options] Worker construction options * @param {string} [options.name] Available as `self.name` within the Worker * @param {string} [options.type="classic"] Pass "module" to create a Module Worker. */ class Worker extends EventTarget { constructor(url, options) { super(); const { name, type } = options || {}; url += ''; let mod; if (/^data:/.test(url)) { mod = url; } else { mod = URL.fileURLToPath(new URL.URL(url, baseUrl)); } const worker = new threads.Worker( __filename, { workerData: { mod, name, type } } ); Object.defineProperty(this, WORKER, { value: worker }); worker.on('message', data => { const event = new Event('message'); event.data = data; this.dispatchEvent(event); }); worker.on('error', error => { error.type = 'error'; this.dispatchEvent(error); }); worker.on('exit', () => { this.dispatchEvent(new Event('close')); }); } postMessage(data, transferList) { this[WORKER].postMessage(data, transferList); } terminate() { this[WORKER].terminate(); } } Worker.prototype.onmessage = Worker.prototype.onerror = Worker.prototype.onclose = null; return Worker; } function workerThread() { let { mod, name, type } = threads.workerData; if (!mod) return mainThread(); // turn global into a mock WorkerGlobalScope const self = global.self = global; // enqueue messages to dispatch after modules are loaded let q = []; function flush() { const buffered = q; q = null; buffered.forEach(event => { self.dispatchEvent(event); }); } threads.parentPort.on('message', data => { const event = new Event('message'); event.data = data; if (q == null) self.dispatchEvent(event); else q.push(event); }); threads.parentPort.on('error', err => { err.type = 'Error'; self.dispatchEvent(err); }); class WorkerGlobalScope extends EventTarget { postMessage(data, transferList) { threads.parentPort.postMessage(data, transferList); } // Emulates https://developer.mozilla.org/en-US/docs/Web/API/DedicatedWorkerGlobalScope/close close() { process.exit(); } } let proto = Object.getPrototypeOf(global); delete proto.constructor; Object.defineProperties(WorkerGlobalScope.prototype, proto); proto = Object.setPrototypeOf(global, new WorkerGlobalScope()); ['postMessage', 'addEventListener', 'removeEventListener', 'dispatchEvent'].forEach(fn => { proto[fn] = proto[fn].bind(global); }); global.name = name; const isDataUrl = /^data:/.test(mod); if (type === 'module') { import(mod) .catch(err => { if (isDataUrl && err.message === 'Not supported') { console.warn('Worker(): Importing data: URLs requires Node 12.10+. Falling back to classic worker.'); return evaluateDataUrl(mod, name); } console.error(err); }) .then(flush); } else { try { if (/^data:/.test(mod)) { evaluateDataUrl(mod, name); } else { require(mod); } } catch (err) { console.error(err); } Promise.resolve().then(flush); } } function evaluateDataUrl(url, name) { const { data } = parseDataUrl(url); return VM.runInThisContext(data, { filename: 'worker.<'+(name || 'data:')+'>' }); } function parseDataUrl(url) { let [m, type, encoding, data] = url.match(/^data: *([^;,]*)(?: *; *([^,]*))? *,(.*)$/) || []; if (!m) throw Error('Invalid Data URL.'); if (encoding) switch (encoding.toLowerCase()) { case 'base64': data = Buffer.from(data, 'base64').toString(); break; default: throw Error('Unknown Data URL encoding "' + encoding + '"'); } return { type, data }; } /* global navigator, WebAssembly */ /* Copyright 2019 0KIMS association. This file is part of wasmsnark (Web Assembly zkSnark Prover). wasmsnark is a free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. wasmsnark is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with wasmsnark. If not, see . */ // const MEM_SIZE = 1000; // Memory size in 64K Pakes (512Mb) const MEM_SIZE = 25; // Memory size in 64K Pakes (1600Kb) class Deferred { constructor() { this.promise = new Promise((resolve, reject)=> { this.reject = reject; this.resolve = resolve; }); } } function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } function stringToBase64(str) { if (process.browser) { return globalThis.btoa(str); } else { return Buffer.from(str).toString("base64"); } } const threadSource = stringToBase64("(" + thread.toString() + ")(self)"); const workerSource = "data:application/javascript;base64," + threadSource; async function buildThreadManager(wasm, singleThread) { const tm = new ThreadManager(); tm.memory = new WebAssembly.Memory({initial:MEM_SIZE}); tm.u8 = new Uint8Array(tm.memory.buffer); tm.u32 = new Uint32Array(tm.memory.buffer); const wasmModule = await WebAssembly.compile(wasm.code); tm.instance = await WebAssembly.instantiate(wasmModule, { env: { "memory": tm.memory } }); tm.singleThread = singleThread; tm.initalPFree = tm.u32[0]; // Save the Pointer to free space. tm.pq = wasm.pq; tm.pr = wasm.pr; tm.pG1gen = wasm.pG1gen; tm.pG1zero = wasm.pG1zero; tm.pG2gen = wasm.pG2gen; tm.pG2zero = wasm.pG2zero; tm.pOneT = wasm.pOneT; // tm.pTmp0 = tm.alloc(curve.G2.F.n8*3); // tm.pTmp1 = tm.alloc(curve.G2.F.n8*3); if (singleThread) { tm.code = wasm.code; tm.taskManager = thread(); await tm.taskManager([{ cmd: "INIT", init: MEM_SIZE, code: tm.code.slice() }]); tm.concurrency = 1; } else { tm.workers = []; tm.pendingDeferreds = []; tm.working = []; let concurrency; if ((typeof(navigator) === "object") && navigator.hardwareConcurrency) { concurrency = navigator.hardwareConcurrency; } else { concurrency = os.cpus().length; } if(concurrency == 0){ concurrency = 2; } // Limit to 64 threads for memory reasons. if (concurrency>64) concurrency=64; tm.concurrency = concurrency; for (let i = 0; i 0); i++) { if (this.working[i] == false) { const work = this.actionQueue.shift(); this.postAction(i, work.data, work.transfers, work.deferred); } } } queueAction(actionData, transfers) { const d = new Deferred(); if (this.singleThread) { const res = this.taskManager(actionData); d.resolve(res); } else { this.actionQueue.push({ data: actionData, transfers: transfers, deferred: d }); this.processWorks(); } return d.promise; } resetMemory() { this.u32[0] = this.initalPFree; } allocBuff(buff) { const pointer = this.alloc(buff.byteLength); this.setBuff(pointer, buff); return pointer; } getBuff(pointer, length) { return this.u8.slice(pointer, pointer+ length); } setBuff(pointer, buffer) { this.u8.set(new Uint8Array(buffer), pointer); } alloc(length) { while (this.u32[0] & 3) this.u32[0]++; // Return always aligned pointers const res = this.u32[0]; this.u32[0] += length; return res; } async terminate() { for (let i=0; i=0; i--) { if (!G.isZero(res)) { for (let j=0; jMAX_CHUNK_SIZE) chunkSize = MAX_CHUNK_SIZE; if (chunkSize { if (logger) logger.debug(`Multiexp end: ${logText}: ${i}/${nPoints}`); return r; })); } const result = await Promise.all(opPromises); let res = G.zero; for (let i=result.length-1; i>=0; i--) { res = G.add(res, result[i]); } return res; } G.multiExp = async function multiExpAffine(buffBases, buffScalars, logger, logText) { return await _multiExp(buffBases, buffScalars, "jacobian", logger, logText); }; G.multiExpAffine = async function multiExpAffine(buffBases, buffScalars, logger, logText) { return await _multiExp(buffBases, buffScalars, "affine", logger, logText); }; } function buildFFT(curve, groupName) { const G = curve[groupName]; const Fr = curve.Fr; const tm = G.tm; async function _fft(buff, inverse, inType, outType, logger, loggerTxt) { inType = inType || "affine"; outType = outType || "affine"; const MAX_BITS_THREAD = 14; let sIn, sMid, sOut, fnIn2Mid, fnMid2Out, fnFFTMix, fnFFTJoin, fnFFTFinal; if (groupName == "G1") { if (inType == "affine") { sIn = G.F.n8*2; fnIn2Mid = "g1m_batchToJacobian"; } else { sIn = G.F.n8*3; } sMid = G.F.n8*3; if (inverse) { fnFFTFinal = "g1m_fftFinal"; } fnFFTJoin = "g1m_fftJoin"; fnFFTMix = "g1m_fftMix"; if (outType == "affine") { sOut = G.F.n8*2; fnMid2Out = "g1m_batchToAffine"; } else { sOut = G.F.n8*3; } } else if (groupName == "G2") { if (inType == "affine") { sIn = G.F.n8*2; fnIn2Mid = "g2m_batchToJacobian"; } else { sIn = G.F.n8*3; } sMid = G.F.n8*3; if (inverse) { fnFFTFinal = "g2m_fftFinal"; } fnFFTJoin = "g2m_fftJoin"; fnFFTMix = "g2m_fftMix"; if (outType == "affine") { sOut = G.F.n8*2; fnMid2Out = "g2m_batchToAffine"; } else { sOut = G.F.n8*3; } } else if (groupName == "Fr") { sIn = G.n8; sMid = G.n8; sOut = G.n8; if (inverse) { fnFFTFinal = "frm_fftFinal"; } fnFFTMix = "frm_fftMix"; fnFFTJoin = "frm_fftJoin"; } let returnArray = false; if (Array.isArray(buff)) { buff = array2buffer(buff, sIn); returnArray = true; } else { buff = buff.slice(0, buff.byteLength); } const nPoints = buff.byteLength / sIn; const bits = log2(nPoints); if ((1 << bits) != nPoints) { throw new Error("fft must be multiple of 2" ); } if (bits == Fr.s +1) { let buffOut; if (inverse) { buffOut = await _fftExtInv(buff, inType, outType, logger, loggerTxt); } else { buffOut = await _fftExt(buff, inType, outType, logger, loggerTxt); } if (returnArray) { return buffer2array(buffOut, sOut); } else { return buffOut; } } let inv; if (inverse) { inv = Fr.inv(Fr.e(nPoints)); } let buffOut; buffReverseBits(buff, sIn); let chunks; let pointsInChunk = Math.min(1 << MAX_BITS_THREAD, nPoints); let nChunks = nPoints / pointsInChunk; while ((nChunks < tm.concurrency)&&(pointsInChunk>=16)) { nChunks *= 2; pointsInChunk /= 2; } const l2Chunk = log2(pointsInChunk); const promises = []; for (let i = 0; i< nChunks; i++) { if (logger) logger.debug(`${loggerTxt}: fft ${bits} mix start: ${i}/${nChunks}`); const task = []; task.push({cmd: "ALLOC", var: 0, len: sMid*pointsInChunk}); const buffChunk = buff.slice( (pointsInChunk * i)*sIn, (pointsInChunk * (i+1))*sIn); task.push({cmd: "SET", var: 0, buff: buffChunk}); if (fnIn2Mid) { task.push({cmd: "CALL", fnName:fnIn2Mid, params: [{var:0}, {val: pointsInChunk}, {var: 0}]}); } for (let j=1; j<=l2Chunk;j++) { task.push({cmd: "CALL", fnName:fnFFTMix, params: [{var:0}, {val: pointsInChunk}, {val: j}]}); } if (l2Chunk==bits) { if (fnFFTFinal) { task.push({cmd: "ALLOCSET", var: 1, buff: inv}); task.push({cmd: "CALL", fnName: fnFFTFinal, params:[ {var: 0}, {val: pointsInChunk}, {var: 1}, ]}); } if (fnMid2Out) { task.push({cmd: "CALL", fnName:fnMid2Out, params: [{var:0}, {val: pointsInChunk}, {var: 0}]}); } task.push({cmd: "GET", out: 0, var: 0, len: pointsInChunk*sOut}); } else { task.push({cmd: "GET", out:0, var: 0, len: sMid*pointsInChunk}); } promises.push(tm.queueAction(task).then( (r) => { if (logger) logger.debug(`${loggerTxt}: fft ${bits} mix end: ${i}/${nChunks}`); return r; })); } chunks = await Promise.all(promises); for (let i = 0; i< nChunks; i++) chunks[i] = chunks[i][0]; for (let i = l2Chunk+1; i<=bits; i++) { if (logger) logger.debug(`${loggerTxt}: fft ${bits} join: ${i}/${bits}`); const nGroups = 1 << (bits - i); const nChunksPerGroup = nChunks / nGroups; const opPromises = []; for (let j=0; j { if (logger) logger.debug(`${loggerTxt}: fft ${bits} join ${i}/${bits} ${j+1}/${nGroups} ${k}/${nChunksPerGroup/2}`); return r; })); } } const res = await Promise.all(opPromises); for (let j=0; j0; i--) { buffOut.set(chunks[i], p); p += pointsInChunk*sOut; delete chunks[i]; // Liberate mem } buffOut.set(chunks[0].slice(0, (pointsInChunk-1)*sOut), p); delete chunks[0]; } else { for (let i=0; i (1<<28)) { buffOut = new BigBuffer(res1[0].byteLength*2); } else { buffOut = new Uint8Array(res1[0].byteLength*2); } buffOut.set(res1[0]); buffOut.set(res1[1], res1[0].byteLength); return buffOut; } async function _fftExtInv(buff, inType, outType, logger, loggerTxt) { let b1, b2; b1 = buff.slice( 0 , buff.byteLength/2); b2 = buff.slice( buff.byteLength/2, buff.byteLength); const promises = []; promises.push( _fft(b1, true, inType, "jacobian", logger, loggerTxt)); promises.push( _fft(b2, true, inType, "jacobian", logger, loggerTxt)); [b1, b2] = await Promise.all(promises); const res1 = await _fftJoinExt(b1, b2, "fftJoinExtInv", Fr.one, Fr.shiftInv, "jacobian", outType, logger, loggerTxt); let buffOut; if (res1[0].byteLength > (1<<28)) { buffOut = new BigBuffer(res1[0].byteLength*2); } else { buffOut = new Uint8Array(res1[0].byteLength*2); } buffOut.set(res1[0]); buffOut.set(res1[1], res1[0].byteLength); return buffOut; } async function _fftJoinExt(buff1, buff2, fn, first, inc, inType, outType, logger, loggerTxt) { const MAX_CHUNK_SIZE = 1<<16; const MIN_CHUNK_SIZE = 1<<4; let fnName; let fnIn2Mid, fnMid2Out; let sOut, sIn, sMid; if (groupName == "G1") { if (inType == "affine") { sIn = G.F.n8*2; fnIn2Mid = "g1m_batchToJacobian"; } else { sIn = G.F.n8*3; } sMid = G.F.n8*3; fnName = "g1m_"+fn; if (outType == "affine") { fnMid2Out = "g1m_batchToAffine"; sOut = G.F.n8*2; } else { sOut = G.F.n8*3; } } else if (groupName == "G2") { if (inType == "affine") { sIn = G.F.n8*2; fnIn2Mid = "g2m_batchToJacobian"; } else { sIn = G.F.n8*3; } fnName = "g2m_"+fn; sMid = G.F.n8*3; if (outType == "affine") { fnMid2Out = "g2m_batchToAffine"; sOut = G.F.n8*2; } else { sOut = G.F.n8*3; } } else if (groupName == "Fr") { sIn = Fr.n8; sOut = Fr.n8; sMid = Fr.n8; fnName = "frm_" + fn; } else { throw new Error("Invalid group"); } if (buff1.byteLength != buff2.byteLength) { throw new Error("Invalid buffer size"); } const nPoints = Math.floor(buff1.byteLength / sIn); if (nPoints != 1 << log2(nPoints)) { throw new Error("Invalid number of points"); } let chunkSize = Math.floor(nPoints /tm.concurrency); if (chunkSize < MIN_CHUNK_SIZE) chunkSize = MIN_CHUNK_SIZE; if (chunkSize > MAX_CHUNK_SIZE) chunkSize = MAX_CHUNK_SIZE; const opPromises = []; for (let i=0; i { if (logger) logger.debug(`${loggerTxt}: fftJoinExt End: ${i}/${nPoints}`); return r; }) ); } const result = await Promise.all(opPromises); let fullBuffOut1; let fullBuffOut2; if (nPoints * sOut > 1<<28) { fullBuffOut1 = new BigBuffer(nPoints*sOut); fullBuffOut2 = new BigBuffer(nPoints*sOut); } else { fullBuffOut1 = new Uint8Array(nPoints*sOut); fullBuffOut2 = new Uint8Array(nPoints*sOut); } let p =0; for (let i=0; i Fr.s+1) { if (logger) logger.error("lagrangeEvaluations input too big"); throw new Error("lagrangeEvaluations input too big"); } let t0 = buff.slice(0, buff.byteLength/2); let t1 = buff.slice(buff.byteLength/2, buff.byteLength); const shiftToSmallM = Fr.exp(Fr.shift, nPoints/2); const sConst = Fr.inv( Fr.sub(Fr.one, shiftToSmallM)); [t0, t1] = await _fftJoinExt(t0, t1, "prepareLagrangeEvaluation", sConst, Fr.shiftInv, inType, "jacobian", logger, loggerTxt + " prep"); const promises = []; promises.push( _fft(t0, true, "jacobian", outType, logger, loggerTxt + " t0")); promises.push( _fft(t1, true, "jacobian", outType, logger, loggerTxt + " t1")); [t0, t1] = await Promise.all(promises); let buffOut; if (t0.byteLength > (1<<28)) { buffOut = new BigBuffer(t0.byteLength*2); } else { buffOut = new Uint8Array(t0.byteLength*2); } buffOut.set(t0); buffOut.set(t1, t0.byteLength); return buffOut; }; G.fftMix = async function fftMix(buff) { const sG = G.F.n8*3; let fnName, fnFFTJoin; if (groupName == "G1") { fnName = "g1m_fftMix"; fnFFTJoin = "g1m_fftJoin"; } else if (groupName == "G2") { fnName = "g2m_fftMix"; fnFFTJoin = "g2m_fftJoin"; } else if (groupName == "Fr") { fnName = "frm_fftMix"; fnFFTJoin = "frm_fftJoin"; } else { throw new Error("Invalid group"); } const nPoints = Math.floor(buff.byteLength / sG); const power = log2(nPoints); let nChunks = 1 << log2(tm.concurrency); if (nPoints <= nChunks*2) nChunks = 1; const pointsPerChunk = nPoints / nChunks; const powerChunk = log2(pointsPerChunk); const opPromises = []; for (let i=0; i=0; i--) { fullBuffOut.set(result[i][0], p); p+=result[i][0].byteLength; } return fullBuffOut; }; } async function buildEngine(params) { const tm = await buildThreadManager(params.wasm, params.singleThread); const curve = {}; curve.q = e(params.wasm.q); curve.r = e(params.wasm.r); curve.name = params.name; curve.tm = tm; curve.prePSize = params.wasm.prePSize; curve.preQSize = params.wasm.preQSize; curve.Fr = new WasmField1(tm, "frm", params.n8r, params.r); curve.F1 = new WasmField1(tm, "f1m", params.n8q, params.q); curve.F2 = new WasmField2(tm, "f2m", curve.F1); curve.G1 = new WasmCurve(tm, "g1m", curve.F1, params.wasm.pG1gen, params.wasm.pG1b, params.cofactorG1); curve.G2 = new WasmCurve(tm, "g2m", curve.F2, params.wasm.pG2gen, params.wasm.pG2b, params.cofactorG2); curve.F6 = new WasmField3(tm, "f6m", curve.F2); curve.F12 = new WasmField2(tm, "ftm", curve.F6); curve.Gt = curve.F12; buildBatchApplyKey(curve, "G1"); buildBatchApplyKey(curve, "G2"); buildBatchApplyKey(curve, "Fr"); buildMultiexp(curve, "G1"); buildMultiexp(curve, "G2"); buildFFT(curve, "G1"); buildFFT(curve, "G2"); buildFFT(curve, "Fr"); buildPairing(curve); curve.array2buffer = function(arr, sG) { const buff = new Uint8Array(sG*arr.length); for (let i=0; i. */ const bigInt = BigIntegerExports; function toNumber(n) { let v; if (typeof n=="string") { if (n.slice(0,2).toLowerCase() == "0x") { v = bigInt(n.slice(2),16); } else { v = bigInt(n); } } else { v = bigInt(n); } return v; } function u32(n) { const b = []; const v = toNumber(n); b.push(v.and(0xFF).toJSNumber()); b.push(v.shiftRight(8).and(0xFF).toJSNumber()); b.push(v.shiftRight(16).and(0xFF).toJSNumber()); b.push(v.shiftRight(24).and(0xFF).toJSNumber()); return b; } function u64(n) { const b = []; const v = toNumber(n); b.push(v.and(0xFF).toJSNumber()); b.push(v.shiftRight(8).and(0xFF).toJSNumber()); b.push(v.shiftRight(16).and(0xFF).toJSNumber()); b.push(v.shiftRight(24).and(0xFF).toJSNumber()); b.push(v.shiftRight(32).and(0xFF).toJSNumber()); b.push(v.shiftRight(40).and(0xFF).toJSNumber()); b.push(v.shiftRight(48).and(0xFF).toJSNumber()); b.push(v.shiftRight(56).and(0xFF).toJSNumber()); return b; } function toUTF8Array(str) { var utf8 = []; for (var i=0; i < str.length; i++) { var charcode = str.charCodeAt(i); if (charcode < 0x80) utf8.push(charcode); else if (charcode < 0x800) { utf8.push(0xc0 | (charcode >> 6), 0x80 | (charcode & 0x3f)); } else if (charcode < 0xd800 || charcode >= 0xe000) { utf8.push(0xe0 | (charcode >> 12), 0x80 | ((charcode>>6) & 0x3f), 0x80 | (charcode & 0x3f)); } // surrogate pair else { i++; // UTF-16 encodes 0x10000-0x10FFFF by // subtracting 0x10000 and splitting the // 20 bits of 0x0-0xFFFFF into two halves charcode = 0x10000 + (((charcode & 0x3ff)<<10) | (str.charCodeAt(i) & 0x3ff)); utf8.push(0xf0 | (charcode >>18), 0x80 | ((charcode>>12) & 0x3f), 0x80 | ((charcode>>6) & 0x3f), 0x80 | (charcode & 0x3f)); } } return utf8; } function string(str) { const bytes = toUTF8Array(str); return [ ...varuint32(bytes.length), ...bytes ]; } function varuint(n) { const code = []; let v = toNumber(n); if (v.isNegative()) throw new Error("Number cannot be negative"); while (!v.isZero()) { code.push(v.and(0x7F).toJSNumber()); v = v.shiftRight(7); } if (code.length==0) code.push(0); for (let i=0; i. */ const utils$2 = utils$3; let CodeBuilder$1 = class CodeBuilder { constructor(func) { this.func = func; this.functionName = func.functionName; this.module = func.module; } setLocal(localName, valCode) { const idx = this.func.localIdxByName[localName]; if (idx === undefined) throw new Error(`Local Variable not defined: Function: ${this.functionName} local: ${localName} `); return [...valCode, 0x21, ...utils$2.varuint32( idx )]; } teeLocal(localName, valCode) { const idx = this.func.localIdxByName[localName]; if (idx === undefined) throw new Error(`Local Variable not defined: Function: ${this.functionName} local: ${localName} `); return [...valCode, 0x22, ...utils$2.varuint32( idx )]; } getLocal(localName) { const idx = this.func.localIdxByName[localName]; if (idx === undefined) throw new Error(`Local Variable not defined: Function: ${this.functionName} local: ${localName} `); return [0x20, ...utils$2.varuint32( idx )]; } i64_load8_s(idxCode, _offset, _align) { const offset = _offset || 0; const align = (_align === undefined) ? 0 : _align; // 8 bits alignment by default return [...idxCode, 0x30, align, ...utils$2.varuint32(offset)]; } i64_load8_u(idxCode, _offset, _align) { const offset = _offset || 0; const align = (_align === undefined) ? 0 : _align; // 8 bits alignment by default return [...idxCode, 0x31, align, ...utils$2.varuint32(offset)]; } i64_load16_s(idxCode, _offset, _align) { const offset = _offset || 0; const align = (_align === undefined) ? 1 : _align; // 16 bits alignment by default return [...idxCode, 0x32, align, ...utils$2.varuint32(offset)]; } i64_load16_u(idxCode, _offset, _align) { const offset = _offset || 0; const align = (_align === undefined) ? 1 : _align; // 16 bits alignment by default return [...idxCode, 0x33, align, ...utils$2.varuint32(offset)]; } i64_load32_s(idxCode, _offset, _align) { const offset = _offset || 0; const align = (_align === undefined) ? 2 : _align; // 32 bits alignment by default return [...idxCode, 0x34, align, ...utils$2.varuint32(offset)]; } i64_load32_u(idxCode, _offset, _align) { const offset = _offset || 0; const align = (_align === undefined) ? 2 : _align; // 32 bits alignment by default return [...idxCode, 0x35, align, ...utils$2.varuint32(offset)]; } i64_load(idxCode, _offset, _align) { const offset = _offset || 0; const align = (_align === undefined) ? 3 : _align; // 64 bits alignment by default return [...idxCode, 0x29, align, ...utils$2.varuint32(offset)]; } i64_store(idxCode, _offset, _align, _codeVal) { let offset, align, codeVal; if (Array.isArray(_offset)) { offset = 0; align = 3; codeVal = _offset; } else if (Array.isArray(_align)) { offset = _offset; align = 3; codeVal = _align; } else if (Array.isArray(_codeVal)) { offset = _offset; align = _align; codeVal = _codeVal; } return [...idxCode, ...codeVal, 0x37, align, ...utils$2.varuint32(offset)]; } i64_store32(idxCode, _offset, _align, _codeVal) { let offset, align, codeVal; if (Array.isArray(_offset)) { offset = 0; align = 2; codeVal = _offset; } else if (Array.isArray(_align)) { offset = _offset; align = 2; codeVal = _align; } else if (Array.isArray(_codeVal)) { offset = _offset; align = _align; codeVal = _codeVal; } return [...idxCode, ...codeVal, 0x3e, align, ...utils$2.varuint32(offset)]; } i64_store16(idxCode, _offset, _align, _codeVal) { let offset, align, codeVal; if (Array.isArray(_offset)) { offset = 0; align = 1; codeVal = _offset; } else if (Array.isArray(_align)) { offset = _offset; align = 1; codeVal = _align; } else if (Array.isArray(_codeVal)) { offset = _offset; align = _align; codeVal = _codeVal; } return [...idxCode, ...codeVal, 0x3d, align, ...utils$2.varuint32(offset)]; } i64_store8(idxCode, _offset, _align, _codeVal) { let offset, align, codeVal; if (Array.isArray(_offset)) { offset = 0; align = 0; codeVal = _offset; } else if (Array.isArray(_align)) { offset = _offset; align = 0; codeVal = _align; } else if (Array.isArray(_codeVal)) { offset = _offset; align = _align; codeVal = _codeVal; } return [...idxCode, ...codeVal, 0x3c, align, ...utils$2.varuint32(offset)]; } i32_load8_s(idxCode, _offset, _align) { const offset = _offset || 0; const align = (_align === undefined) ? 0 : _align; // 32 bits alignment by default return [...idxCode, 0x2c, align, ...utils$2.varuint32(offset)]; } i32_load8_u(idxCode, _offset, _align) { const offset = _offset || 0; const align = (_align === undefined) ? 0 : _align; // 32 bits alignment by default return [...idxCode, 0x2d, align, ...utils$2.varuint32(offset)]; } i32_load16_s(idxCode, _offset, _align) { const offset = _offset || 0; const align = (_align === undefined) ? 1 : _align; // 32 bits alignment by default return [...idxCode, 0x2e, align, ...utils$2.varuint32(offset)]; } i32_load16_u(idxCode, _offset, _align) { const offset = _offset || 0; const align = (_align === undefined) ? 1 : _align; // 32 bits alignment by default return [...idxCode, 0x2f, align, ...utils$2.varuint32(offset)]; } i32_load(idxCode, _offset, _align) { const offset = _offset || 0; const align = (_align === undefined) ? 2 : _align; // 32 bits alignment by default return [...idxCode, 0x28, align, ...utils$2.varuint32(offset)]; } i32_store(idxCode, _offset, _align, _codeVal) { let offset, align, codeVal; if (Array.isArray(_offset)) { offset = 0; align = 2; codeVal = _offset; } else if (Array.isArray(_align)) { offset = _offset; align = 2; codeVal = _align; } else if (Array.isArray(_codeVal)) { offset = _offset; align = _align; codeVal = _codeVal; } return [...idxCode, ...codeVal, 0x36, align, ...utils$2.varuint32(offset)]; } i32_store16(idxCode, _offset, _align, _codeVal) { let offset, align, codeVal; if (Array.isArray(_offset)) { offset = 0; align = 1; codeVal = _offset; } else if (Array.isArray(_align)) { offset = _offset; align = 1; codeVal = _align; } else if (Array.isArray(_codeVal)) { offset = _offset; align = _align; codeVal = _codeVal; } return [...idxCode, ...codeVal, 0x3b, align, ...utils$2.varuint32(offset)]; } i32_store8(idxCode, _offset, _align, _codeVal) { let offset, align, codeVal; if (Array.isArray(_offset)) { offset = 0; align = 0; codeVal = _offset; } else if (Array.isArray(_align)) { offset = _offset; align = 0; codeVal = _align; } else if (Array.isArray(_codeVal)) { offset = _offset; align = _align; codeVal = _codeVal; } return [...idxCode, ...codeVal, 0x3a, align, ...utils$2.varuint32(offset)]; } call(fnName, ...args) { const idx = this.module.functionIdxByName[fnName]; if (idx === undefined) throw new Error(`Function not defined: Function: ${fnName}`); return [...[].concat(...args), 0x10, ...utils$2.varuint32(idx)]; } call_indirect(fnIdx, ...args) { return [...[].concat(...args), ...fnIdx, 0x11, 0, 0]; } if(condCode, thenCode, elseCode) { if (elseCode) { return [...condCode, 0x04, 0x40, ...thenCode, 0x05, ...elseCode, 0x0b]; } else { return [...condCode, 0x04, 0x40, ...thenCode, 0x0b]; } } block(bCode) { return [0x02, 0x40, ...bCode, 0x0b]; } loop(...args) { return [0x03, 0x40, ...[].concat(...[...args]), 0x0b]; } br_if(relPath, condCode) { return [...condCode, 0x0d, ...utils$2.varuint32(relPath)]; } br(relPath) { return [0x0c, ...utils$2.varuint32(relPath)]; } ret(rCode) { return [...rCode, 0x0f]; } drop(dCode) { return [...dCode, 0x1a]; } i64_const(num) { return [0x42, ...utils$2.varint64(num)]; } i32_const(num) { return [0x41, ...utils$2.varint32(num)]; } i64_eqz(opcode) { return [...opcode, 0x50]; } i64_eq(op1code, op2code) { return [...op1code, ...op2code, 0x51]; } i64_ne(op1code, op2code) { return [...op1code, ...op2code, 0x52]; } i64_lt_s(op1code, op2code) { return [...op1code, ...op2code, 0x53]; } i64_lt_u(op1code, op2code) { return [...op1code, ...op2code, 0x54]; } i64_gt_s(op1code, op2code) { return [...op1code, ...op2code, 0x55]; } i64_gt_u(op1code, op2code) { return [...op1code, ...op2code, 0x56]; } i64_le_s(op1code, op2code) { return [...op1code, ...op2code, 0x57]; } i64_le_u(op1code, op2code) { return [...op1code, ...op2code, 0x58]; } i64_ge_s(op1code, op2code) { return [...op1code, ...op2code, 0x59]; } i64_ge_u(op1code, op2code) { return [...op1code, ...op2code, 0x5a]; } i64_add(op1code, op2code) { return [...op1code, ...op2code, 0x7c]; } i64_sub(op1code, op2code) { return [...op1code, ...op2code, 0x7d]; } i64_mul(op1code, op2code) { return [...op1code, ...op2code, 0x7e]; } i64_div_s(op1code, op2code) { return [...op1code, ...op2code, 0x7f]; } i64_div_u(op1code, op2code) { return [...op1code, ...op2code, 0x80]; } i64_rem_s(op1code, op2code) { return [...op1code, ...op2code, 0x81]; } i64_rem_u(op1code, op2code) { return [...op1code, ...op2code, 0x82]; } i64_and(op1code, op2code) { return [...op1code, ...op2code, 0x83]; } i64_or(op1code, op2code) { return [...op1code, ...op2code, 0x84]; } i64_xor(op1code, op2code) { return [...op1code, ...op2code, 0x85]; } i64_shl(op1code, op2code) { return [...op1code, ...op2code, 0x86]; } i64_shr_s(op1code, op2code) { return [...op1code, ...op2code, 0x87]; } i64_shr_u(op1code, op2code) { return [...op1code, ...op2code, 0x88]; } i64_extend_i32_s(op1code) { return [...op1code, 0xac]; } i64_extend_i32_u(op1code) { return [...op1code, 0xad]; } i64_clz(op1code) { return [...op1code, 0x79]; } i64_ctz(op1code) { return [...op1code, 0x7a]; } i32_eqz(op1code) { return [...op1code, 0x45]; } i32_eq(op1code, op2code) { return [...op1code, ...op2code, 0x46]; } i32_ne(op1code, op2code) { return [...op1code, ...op2code, 0x47]; } i32_lt_s(op1code, op2code) { return [...op1code, ...op2code, 0x48]; } i32_lt_u(op1code, op2code) { return [...op1code, ...op2code, 0x49]; } i32_gt_s(op1code, op2code) { return [...op1code, ...op2code, 0x4a]; } i32_gt_u(op1code, op2code) { return [...op1code, ...op2code, 0x4b]; } i32_le_s(op1code, op2code) { return [...op1code, ...op2code, 0x4c]; } i32_le_u(op1code, op2code) { return [...op1code, ...op2code, 0x4d]; } i32_ge_s(op1code, op2code) { return [...op1code, ...op2code, 0x4e]; } i32_ge_u(op1code, op2code) { return [...op1code, ...op2code, 0x4f]; } i32_add(op1code, op2code) { return [...op1code, ...op2code, 0x6a]; } i32_sub(op1code, op2code) { return [...op1code, ...op2code, 0x6b]; } i32_mul(op1code, op2code) { return [...op1code, ...op2code, 0x6c]; } i32_div_s(op1code, op2code) { return [...op1code, ...op2code, 0x6d]; } i32_div_u(op1code, op2code) { return [...op1code, ...op2code, 0x6e]; } i32_rem_s(op1code, op2code) { return [...op1code, ...op2code, 0x6f]; } i32_rem_u(op1code, op2code) { return [...op1code, ...op2code, 0x70]; } i32_and(op1code, op2code) { return [...op1code, ...op2code, 0x71]; } i32_or(op1code, op2code) { return [...op1code, ...op2code, 0x72]; } i32_xor(op1code, op2code) { return [...op1code, ...op2code, 0x73]; } i32_shl(op1code, op2code) { return [...op1code, ...op2code, 0x74]; } i32_shr_s(op1code, op2code) { return [...op1code, ...op2code, 0x75]; } i32_shr_u(op1code, op2code) { return [...op1code, ...op2code, 0x76]; } i32_rotl(op1code, op2code) { return [...op1code, ...op2code, 0x77]; } i32_rotr(op1code, op2code) { return [...op1code, ...op2code, 0x78]; } i32_wrap_i64(op1code) { return [...op1code, 0xa7]; } i32_clz(op1code) { return [...op1code, 0x67]; } i32_ctz(op1code) { return [...op1code, 0x68]; } unreachable() { return [ 0x0 ]; } current_memory() { return [ 0x3f, 0]; } comment() { return []; } }; var codebuilder = CodeBuilder$1; /* Copyright 2019 0KIMS association. This file is part of wasmbuilder wasmbuilder is a free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. wasmbuilder is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with wasmbuilder. If not, see . */ const CodeBuilder = codebuilder; const utils$1 = utils$3; const typeCodes = { "i32": 0x7f, "i64": 0x7e, "f32": 0x7d, "f64": 0x7c, "anyfunc": 0x70, "func": 0x60, "emptyblock": 0x40 }; let FunctionBuilder$1 = class FunctionBuilder { constructor (module, fnName, fnType, moduleName, fieldName) { if (fnType == "import") { this.fnType = "import"; this.moduleName = moduleName; this.fieldName = fieldName; } else if (fnType == "internal") { this.fnType = "internal"; } else { throw new Error("Invalid function fnType: " + fnType); } this.module = module; this.fnName = fnName; this.params = []; this.locals = []; this.localIdxByName = {}; this.code = []; this.returnType = null; this.nextLocal =0; } addParam(paramName, paramType) { if (this.localIdxByName[paramName]) throw new Error(`param already exists. Function: ${this.fnName}, Param: ${paramName} `); const idx = this.nextLocal++; this.localIdxByName[paramName] = idx; this.params.push({ type: paramType }); } addLocal(localName, localType, _length) { const length = _length || 1; if (this.localIdxByName[localName]) throw new Error(`local already exists. Function: ${this.fnName}, Param: ${localName} `); const idx = this.nextLocal++; this.localIdxByName[localName] = idx; this.locals.push({ type: localType, length: length }); } setReturnType(returnType) { if (this.returnType) throw new Error(`returnType already defined. Function: ${this.fnName}`); this.returnType = returnType; } getSignature() { const params = [...utils$1.varuint32(this.params.length), ...this.params.map((p) => typeCodes[p.type])]; const returns = this.returnType ? [0x01, typeCodes[this.returnType]] : [0]; return [0x60, ...params, ...returns]; } getBody() { const locals = this.locals.map((l) => [ ...utils$1.varuint32(l.length), typeCodes[l.type] ]); const body = [ ...utils$1.varuint32(this.locals.length), ...[].concat(...locals), ...this.code, 0x0b ]; return [ ...utils$1.varuint32(body.length), ...body ]; } addCode(...code) { this.code.push(...[].concat(...[...code])); } getCodeBuilder() { return new CodeBuilder(this); } }; var functionbuilder = FunctionBuilder$1; /* Copyright 2019 0KIMS association. This file is part of wasmbuilder wasmbuilder is a free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. wasmbuilder is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with wasmbuilder. If not, see . */ const FunctionBuilder = functionbuilder; const utils = utils$3; let ModuleBuilder$1 = class ModuleBuilder { constructor() { this.functions = []; this.functionIdxByName = {}; this.nImportFunctions = 0; this.nInternalFunctions =0; this.memory = { pagesSize: 1, moduleName: "env", fieldName: "memory" }; this.free = 8; this.datas = []; this.modules = {}; this.exports = []; this.functionsTable = []; } build() { this._setSignatures(); return new Uint8Array([ ...utils.u32(0x6d736100), ...utils.u32(1), ...this._buildType(), ...this._buildImport(), ...this._buildFunctionDeclarations(), ...this._buildFunctionsTable(), ...this._buildExports(), ...this._buildElements(), ...this._buildCode(), ...this._buildData() ]); } addFunction(fnName) { if (typeof(this.functionIdxByName[fnName]) !== "undefined") throw new Error(`Function already defined: ${fnName}`); const idx = this.functions.length; this.functionIdxByName[fnName] = idx; this.functions.push(new FunctionBuilder(this, fnName, "internal")); this.nInternalFunctions++; return this.functions[idx]; } addIimportFunction(fnName, moduleName, _fieldName) { if (typeof(this.functionIdxByName[fnName]) !== "undefined") throw new Error(`Function already defined: ${fnName}`); if ( (this.functions.length>0) &&(this.functions[this.functions.length-1].type == "internal")) throw new Error(`Import functions must be declared before internal: ${fnName}`); let fieldName = _fieldName || fnName; const idx = this.functions.length; this.functionIdxByName[fnName] = idx; this.functions.push(new FunctionBuilder(this, fnName, "import", moduleName, fieldName)); this.nImportFunctions ++; return this.functions[idx]; } setMemory(pagesSize, moduleName, fieldName) { this.memory = { pagesSize: pagesSize, moduleName: moduleName || "env", fieldName: fieldName || "memory" }; } exportFunction(fnName, _exportName) { const exportName = _exportName || fnName; if (typeof(this.functionIdxByName[fnName]) === "undefined") throw new Error(`Function not defined: ${fnName}`); const idx = this.functionIdxByName[fnName]; if (exportName != fnName) { this.functionIdxByName[exportName] = idx; } this.exports.push({ exportName: exportName, idx: idx }); } addFunctionToTable(fnName) { const idx = this.functionIdxByName[fnName]; this.functionsTable.push(idx); } addData(offset, bytes) { this.datas.push({ offset: offset, bytes: bytes }); } alloc(a, b) { let size; let bytes; if ((Array.isArray(a) || ArrayBuffer.isView(a)) && (typeof(b) === "undefined")) { size = a.length; bytes = a; } else { size = a; bytes = b; } size = (((size-1)>>3) +1)<<3; // Align to 64 bits. const p = this.free; this.free += size; if (bytes) { this.addData(p, bytes); } return p; } allocString(s) { const encoder = new globalThis.TextEncoder(); const uint8array = encoder.encode(s); return this.alloc([...uint8array, 0]); } _setSignatures() { this.signatures = []; const signatureIdxByName = {}; if (this.functionsTable.length>0) { const signature = this.functions[this.functionsTable[0]].getSignature(); const signatureName = "s_"+utils.toHexString(signature); signatureIdxByName[signatureName] = 0; this.signatures.push(signature); } for (let i=0; i. */ var ModuleBuilder = modulebuilder; globalThis.curve_bn128 = null; async function buildBn128(singleThread, plugins) { const moduleBuilder = new ModuleBuilder(); moduleBuilder.setMemory(25); buildBn128$1(moduleBuilder); if (plugins) plugins(moduleBuilder); const bn128wasm = {}; bn128wasm.code = moduleBuilder.build(); bn128wasm.pq = moduleBuilder.modules.f1m.pq; bn128wasm.pr = moduleBuilder.modules.frm.pq; bn128wasm.pG1gen = moduleBuilder.modules.bn128.pG1gen; bn128wasm.pG1zero = moduleBuilder.modules.bn128.pG1zero; bn128wasm.pG1b = moduleBuilder.modules.bn128.pG1b; bn128wasm.pG2gen = moduleBuilder.modules.bn128.pG2gen; bn128wasm.pG2zero = moduleBuilder.modules.bn128.pG2zero; bn128wasm.pG2b = moduleBuilder.modules.bn128.pG2b; bn128wasm.pOneT = moduleBuilder.modules.bn128.pOneT; bn128wasm.prePSize = moduleBuilder.modules.bn128.prePSize; bn128wasm.preQSize = moduleBuilder.modules.bn128.preQSize; bn128wasm.n8q = 32; bn128wasm.n8r = 32; bn128wasm.q = moduleBuilder.modules.bn128.q; bn128wasm.r = moduleBuilder.modules.bn128.r; if ((!singleThread) && (globalThis.curve_bn128)) return globalThis.curve_bn128; const params = { name: "bn128", wasm: bn128wasm, q: e("21888242871839275222246405745257275088696311157297823662689037894645226208583"), r: e("21888242871839275222246405745257275088548364400416034343698204186575808495617"), n8q: 32, n8r: 32, cofactorG2: e("30644e72e131a029b85045b68181585e06ceecda572a2489345f2299c0f9fa8d", 16), singleThread: singleThread ? true : false }; const curve = await buildEngine(params); curve.terminate = async function () { if (!params.singleThread) { globalThis.curve_bn128 = null; await this.tm.terminate(); } }; if (!singleThread) { globalThis.curve_bn128 = curve; } return curve; } globalThis.curve_bls12381 = null; async function buildBls12381(singleThread, plugins) { const moduleBuilder = new ModuleBuilder(); moduleBuilder.setMemory(25); buildBls12381$1(moduleBuilder); if (plugins) plugins(moduleBuilder); const bls12381wasm = {}; bls12381wasm.code = moduleBuilder.build(); bls12381wasm.pq = moduleBuilder.modules.f1m.pq; bls12381wasm.pr = moduleBuilder.modules.frm.pq; bls12381wasm.pG1gen = moduleBuilder.modules.bls12381.pG1gen; bls12381wasm.pG1zero = moduleBuilder.modules.bls12381.pG1zero; bls12381wasm.pG1b = moduleBuilder.modules.bls12381.pG1b; bls12381wasm.pG2gen = moduleBuilder.modules.bls12381.pG2gen; bls12381wasm.pG2zero = moduleBuilder.modules.bls12381.pG2zero; bls12381wasm.pG2b = moduleBuilder.modules.bls12381.pG2b; bls12381wasm.pOneT = moduleBuilder.modules.bls12381.pOneT; bls12381wasm.prePSize = moduleBuilder.modules.bls12381.prePSize; bls12381wasm.preQSize = moduleBuilder.modules.bls12381.preQSize; bls12381wasm.n8q = 48; bls12381wasm.n8r = 32; bls12381wasm.q = moduleBuilder.modules.bn128.q; bls12381wasm.r = moduleBuilder.modules.bn128.r; if ((!singleThread) && (globalThis.curve_bls12381)) return globalThis.curve_bls12381; const params = { name: "bls12381", wasm: bls12381wasm, q: e("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", 16), r: e("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", 16), n8q: 48, n8r: 32, cofactorG1: e("0x396c8c005555e1568c00aaab0000aaab", 16), cofactorG2: e("0x5d543a95414e7f1091d50792876a202cd91de4547085abaa68a205b2e5a7ddfa628f1cb4d9e82ef21537e293a6691ae1616ec6e786f0c70cf1c38e31c7238e5", 16), singleThread: singleThread ? true : false }; const curve = await buildEngine(params); curve.terminate = async function () { if (!params.singleThread) { globalThis.curve_bls12381 = null; await this.tm.terminate(); } }; if (!singleThread) { globalThis.curve_bls12381 = curve; } return curve; } e("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", 16); e("21888242871839275222246405745257275088548364400416034343698204186575808495617"); e("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", 16); e("21888242871839275222246405745257275088696311157297823662689037894645226208583"); async function getCurveFromName(name, singleThread, plugins) { let curve; const normName = normalizeName(name); if (["BN128", "BN254", "ALTBN128"].indexOf(normName) >= 0) { curve = await buildBn128(singleThread, plugins); } else if (["BLS12381"].indexOf(normName) >= 0) { curve = await buildBls12381(singleThread, plugins); } else { throw new Error(`Curve not supported: ${name}`); } return curve; function normalizeName(n) { return n.toUpperCase().match(/[A-Za-z0-9]+/g).join(""); } } const Scalar=_Scalar; const version$2 = "logger/5.7.0"; let _permanentCensorErrors = false; let _censorErrors = false; const LogLevels = { debug: 1, "default": 2, info: 2, warning: 3, error: 4, off: 5 }; let _logLevel = LogLevels["default"]; let _globalLogger = null; function _checkNormalize() { try { const missing = []; // Make sure all forms of normalization are supported ["NFD", "NFC", "NFKD", "NFKC"].forEach((form) => { try { if ("test".normalize(form) !== "test") { throw new Error("bad normalize"); } } catch (error) { missing.push(form); } }); if (missing.length) { throw new Error("missing " + missing.join(", ")); } if (String.fromCharCode(0xe9).normalize("NFD") !== String.fromCharCode(0x65, 0x0301)) { throw new Error("broken implementation"); } } catch (error) { return error.message; } return null; } const _normalizeError = _checkNormalize(); var LogLevel; (function (LogLevel) { LogLevel["DEBUG"] = "DEBUG"; LogLevel["INFO"] = "INFO"; LogLevel["WARNING"] = "WARNING"; LogLevel["ERROR"] = "ERROR"; LogLevel["OFF"] = "OFF"; })(LogLevel || (LogLevel = {})); var ErrorCode; (function (ErrorCode) { /////////////////// // Generic Errors // Unknown Error ErrorCode["UNKNOWN_ERROR"] = "UNKNOWN_ERROR"; // Not Implemented ErrorCode["NOT_IMPLEMENTED"] = "NOT_IMPLEMENTED"; // Unsupported Operation // - operation ErrorCode["UNSUPPORTED_OPERATION"] = "UNSUPPORTED_OPERATION"; // Network Error (i.e. Ethereum Network, such as an invalid chain ID) // - event ("noNetwork" is not re-thrown in provider.ready; otherwise thrown) ErrorCode["NETWORK_ERROR"] = "NETWORK_ERROR"; // Some sort of bad response from the server ErrorCode["SERVER_ERROR"] = "SERVER_ERROR"; // Timeout ErrorCode["TIMEOUT"] = "TIMEOUT"; /////////////////// // Operational Errors // Buffer Overrun ErrorCode["BUFFER_OVERRUN"] = "BUFFER_OVERRUN"; // Numeric Fault // - operation: the operation being executed // - fault: the reason this faulted ErrorCode["NUMERIC_FAULT"] = "NUMERIC_FAULT"; /////////////////// // Argument Errors // Missing new operator to an object // - name: The name of the class ErrorCode["MISSING_NEW"] = "MISSING_NEW"; // Invalid argument (e.g. value is incompatible with type) to a function: // - argument: The argument name that was invalid // - value: The value of the argument ErrorCode["INVALID_ARGUMENT"] = "INVALID_ARGUMENT"; // Missing argument to a function: // - count: The number of arguments received // - expectedCount: The number of arguments expected ErrorCode["MISSING_ARGUMENT"] = "MISSING_ARGUMENT"; // Too many arguments // - count: The number of arguments received // - expectedCount: The number of arguments expected ErrorCode["UNEXPECTED_ARGUMENT"] = "UNEXPECTED_ARGUMENT"; /////////////////// // Blockchain Errors // Call exception // - transaction: the transaction // - address?: the contract address // - args?: The arguments passed into the function // - method?: The Solidity method signature // - errorSignature?: The EIP848 error signature // - errorArgs?: The EIP848 error parameters // - reason: The reason (only for EIP848 "Error(string)") ErrorCode["CALL_EXCEPTION"] = "CALL_EXCEPTION"; // Insufficient funds (< value + gasLimit * gasPrice) // - transaction: the transaction attempted ErrorCode["INSUFFICIENT_FUNDS"] = "INSUFFICIENT_FUNDS"; // Nonce has already been used // - transaction: the transaction attempted ErrorCode["NONCE_EXPIRED"] = "NONCE_EXPIRED"; // The replacement fee for the transaction is too low // - transaction: the transaction attempted ErrorCode["REPLACEMENT_UNDERPRICED"] = "REPLACEMENT_UNDERPRICED"; // The gas limit could not be estimated // - transaction: the transaction passed to estimateGas ErrorCode["UNPREDICTABLE_GAS_LIMIT"] = "UNPREDICTABLE_GAS_LIMIT"; // The transaction was replaced by one with a higher gas price // - reason: "cancelled", "replaced" or "repriced" // - cancelled: true if reason == "cancelled" or reason == "replaced") // - hash: original transaction hash // - replacement: the full TransactionsResponse for the replacement // - receipt: the receipt of the replacement ErrorCode["TRANSACTION_REPLACED"] = "TRANSACTION_REPLACED"; /////////////////// // Interaction Errors // The user rejected the action, such as signing a message or sending // a transaction ErrorCode["ACTION_REJECTED"] = "ACTION_REJECTED"; })(ErrorCode || (ErrorCode = {})); const HEX = "0123456789abcdef"; class Logger { constructor(version) { Object.defineProperty(this, "version", { enumerable: true, value: version, writable: false }); } _log(logLevel, args) { const level = logLevel.toLowerCase(); if (LogLevels[level] == null) { this.throwArgumentError("invalid log level name", "logLevel", logLevel); } if (_logLevel > LogLevels[level]) { return; } console.log.apply(console, args); } debug(...args) { this._log(Logger.levels.DEBUG, args); } info(...args) { this._log(Logger.levels.INFO, args); } warn(...args) { this._log(Logger.levels.WARNING, args); } makeError(message, code, params) { // Errors are being censored if (_censorErrors) { return this.makeError("censored error", code, {}); } if (!code) { code = Logger.errors.UNKNOWN_ERROR; } if (!params) { params = {}; } const messageDetails = []; Object.keys(params).forEach((key) => { const value = params[key]; try { if (value instanceof Uint8Array) { let hex = ""; for (let i = 0; i < value.length; i++) { hex += HEX[value[i] >> 4]; hex += HEX[value[i] & 0x0f]; } messageDetails.push(key + "=Uint8Array(0x" + hex + ")"); } else { messageDetails.push(key + "=" + JSON.stringify(value)); } } catch (error) { messageDetails.push(key + "=" + JSON.stringify(params[key].toString())); } }); messageDetails.push(`code=${code}`); messageDetails.push(`version=${this.version}`); const reason = message; let url = ""; switch (code) { case ErrorCode.NUMERIC_FAULT: { url = "NUMERIC_FAULT"; const fault = message; switch (fault) { case "overflow": case "underflow": case "division-by-zero": url += "-" + fault; break; case "negative-power": case "negative-width": url += "-unsupported"; break; case "unbound-bitwise-result": url += "-unbound-result"; break; } break; } case ErrorCode.CALL_EXCEPTION: case ErrorCode.INSUFFICIENT_FUNDS: case ErrorCode.MISSING_NEW: case ErrorCode.NONCE_EXPIRED: case ErrorCode.REPLACEMENT_UNDERPRICED: case ErrorCode.TRANSACTION_REPLACED: case ErrorCode.UNPREDICTABLE_GAS_LIMIT: url = code; break; } if (url) { message += " [ See: https:/\/links.ethers.org/v5-errors-" + url + " ]"; } if (messageDetails.length) { message += " (" + messageDetails.join(", ") + ")"; } // @TODO: Any?? const error = new Error(message); error.reason = reason; error.code = code; Object.keys(params).forEach(function (key) { error[key] = params[key]; }); return error; } throwError(message, code, params) { throw this.makeError(message, code, params); } throwArgumentError(message, name, value) { return this.throwError(message, Logger.errors.INVALID_ARGUMENT, { argument: name, value: value }); } assert(condition, message, code, params) { if (!!condition) { return; } this.throwError(message, code, params); } assertArgument(condition, message, name, value) { if (!!condition) { return; } this.throwArgumentError(message, name, value); } checkNormalize(message) { if (_normalizeError) { this.throwError("platform missing String.prototype.normalize", Logger.errors.UNSUPPORTED_OPERATION, { operation: "String.prototype.normalize", form: _normalizeError }); } } checkSafeUint53(value, message) { if (typeof (value) !== "number") { return; } if (message == null) { message = "value not safe"; } if (value < 0 || value >= 0x1fffffffffffff) { this.throwError(message, Logger.errors.NUMERIC_FAULT, { operation: "checkSafeInteger", fault: "out-of-safe-range", value: value }); } if (value % 1) { this.throwError(message, Logger.errors.NUMERIC_FAULT, { operation: "checkSafeInteger", fault: "non-integer", value: value }); } } checkArgumentCount(count, expectedCount, message) { if (message) { message = ": " + message; } else { message = ""; } if (count < expectedCount) { this.throwError("missing argument" + message, Logger.errors.MISSING_ARGUMENT, { count: count, expectedCount: expectedCount }); } if (count > expectedCount) { this.throwError("too many arguments" + message, Logger.errors.UNEXPECTED_ARGUMENT, { count: count, expectedCount: expectedCount }); } } checkNew(target, kind) { if (target === Object || target == null) { this.throwError("missing new", Logger.errors.MISSING_NEW, { name: kind.name }); } } checkAbstract(target, kind) { if (target === kind) { this.throwError("cannot instantiate abstract class " + JSON.stringify(kind.name) + " directly; use a sub-class", Logger.errors.UNSUPPORTED_OPERATION, { name: target.name, operation: "new" }); } else if (target === Object || target == null) { this.throwError("missing new", Logger.errors.MISSING_NEW, { name: kind.name }); } } static globalLogger() { if (!_globalLogger) { _globalLogger = new Logger(version$2); } return _globalLogger; } static setCensorship(censorship, permanent) { if (!censorship && permanent) { this.globalLogger().throwError("cannot permanently disable censorship", Logger.errors.UNSUPPORTED_OPERATION, { operation: "setCensorship" }); } if (_permanentCensorErrors) { if (!censorship) { return; } this.globalLogger().throwError("error censorship permanent", Logger.errors.UNSUPPORTED_OPERATION, { operation: "setCensorship" }); } _censorErrors = !!censorship; _permanentCensorErrors = !!permanent; } static setLogLevel(logLevel) { const level = LogLevels[logLevel.toLowerCase()]; if (level == null) { Logger.globalLogger().warn("invalid log level - " + logLevel); return; } _logLevel = level; } static from(version) { return new Logger(version); } } Logger.errors = ErrorCode; Logger.levels = LogLevel; const version$1 = "bytes/5.7.0"; const logger$1 = new Logger(version$1); /////////////////////////////// function isHexable(value) { return !!(value.toHexString); } function addSlice(array) { if (array.slice) { return array; } array.slice = function () { const args = Array.prototype.slice.call(arguments); return addSlice(new Uint8Array(Array.prototype.slice.apply(array, args))); }; return array; } function isInteger(value) { return (typeof (value) === "number" && value == value && (value % 1) === 0); } function isBytes(value) { if (value == null) { return false; } if (value.constructor === Uint8Array) { return true; } if (typeof (value) === "string") { return false; } if (!isInteger(value.length) || value.length < 0) { return false; } for (let i = 0; i < value.length; i++) { const v = value[i]; if (!isInteger(v) || v < 0 || v >= 256) { return false; } } return true; } function arrayify(value, options) { if (!options) { options = {}; } if (typeof (value) === "number") { logger$1.checkSafeUint53(value, "invalid arrayify value"); const result = []; while (value) { result.unshift(value & 0xff); value = parseInt(String(value / 256)); } if (result.length === 0) { result.push(0); } return addSlice(new Uint8Array(result)); } if (options.allowMissingPrefix && typeof (value) === "string" && value.substring(0, 2) !== "0x") { value = "0x" + value; } if (isHexable(value)) { value = value.toHexString(); } if (isHexString(value)) { let hex = value.substring(2); if (hex.length % 2) { if (options.hexPad === "left") { hex = "0" + hex; } else if (options.hexPad === "right") { hex += "0"; } else { logger$1.throwArgumentError("hex data is odd-length", "value", value); } } const result = []; for (let i = 0; i < hex.length; i += 2) { result.push(parseInt(hex.substring(i, i + 2), 16)); } return addSlice(new Uint8Array(result)); } if (isBytes(value)) { return addSlice(new Uint8Array(value)); } return logger$1.throwArgumentError("invalid arrayify value", "value", value); } function isHexString(value, length) { if (typeof (value) !== "string" || !value.match(/^0x[0-9A-Fa-f]*$/)) { return false; } if (length && value.length !== 2 + 2 * length) { return false; } return true; } var sha3$1 = {exports: {}}; /** * [js-sha3]{@link https://github.com/emn178/js-sha3} * * @version 0.8.0 * @author Chen, Yi-Cyuan [emn178@gmail.com] * @copyright Chen, Yi-Cyuan 2015-2018 * @license MIT */ (function (module) { /*jslint bitwise: true */ (function () { var INPUT_ERROR = 'input is invalid type'; var FINALIZE_ERROR = 'finalize already called'; var WINDOW = typeof window === 'object'; var root = WINDOW ? window : {}; if (root.JS_SHA3_NO_WINDOW) { WINDOW = false; } var WEB_WORKER = !WINDOW && typeof self === 'object'; var NODE_JS = !root.JS_SHA3_NO_NODE_JS && typeof process === 'object' && process.versions && process.versions.node; if (NODE_JS) { root = commonjsGlobal; } else if (WEB_WORKER) { root = self; } var COMMON_JS = !root.JS_SHA3_NO_COMMON_JS && 'object' === 'object' && module.exports; var ARRAY_BUFFER = !root.JS_SHA3_NO_ARRAY_BUFFER && typeof ArrayBuffer !== 'undefined'; var HEX_CHARS = '0123456789abcdef'.split(''); var SHAKE_PADDING = [31, 7936, 2031616, 520093696]; var CSHAKE_PADDING = [4, 1024, 262144, 67108864]; var KECCAK_PADDING = [1, 256, 65536, 16777216]; var PADDING = [6, 1536, 393216, 100663296]; var SHIFT = [0, 8, 16, 24]; var RC = [1, 0, 32898, 0, 32906, 2147483648, 2147516416, 2147483648, 32907, 0, 2147483649, 0, 2147516545, 2147483648, 32777, 2147483648, 138, 0, 136, 0, 2147516425, 0, 2147483658, 0, 2147516555, 0, 139, 2147483648, 32905, 2147483648, 32771, 2147483648, 32770, 2147483648, 128, 2147483648, 32778, 0, 2147483658, 2147483648, 2147516545, 2147483648, 32896, 2147483648, 2147483649, 0, 2147516424, 2147483648]; var BITS = [224, 256, 384, 512]; var SHAKE_BITS = [128, 256]; var OUTPUT_TYPES = ['hex', 'buffer', 'arrayBuffer', 'array', 'digest']; var CSHAKE_BYTEPAD = { '128': 168, '256': 136 }; if (root.JS_SHA3_NO_NODE_JS || !Array.isArray) { Array.isArray = function (obj) { return Object.prototype.toString.call(obj) === '[object Array]'; }; } if (ARRAY_BUFFER && (root.JS_SHA3_NO_ARRAY_BUFFER_IS_VIEW || !ArrayBuffer.isView)) { ArrayBuffer.isView = function (obj) { return typeof obj === 'object' && obj.buffer && obj.buffer.constructor === ArrayBuffer; }; } var createOutputMethod = function (bits, padding, outputType) { return function (message) { return new Keccak(bits, padding, bits).update(message)[outputType](); }; }; var createShakeOutputMethod = function (bits, padding, outputType) { return function (message, outputBits) { return new Keccak(bits, padding, outputBits).update(message)[outputType](); }; }; var createCshakeOutputMethod = function (bits, padding, outputType) { return function (message, outputBits, n, s) { return methods['cshake' + bits].update(message, outputBits, n, s)[outputType](); }; }; var createKmacOutputMethod = function (bits, padding, outputType) { return function (key, message, outputBits, s) { return methods['kmac' + bits].update(key, message, outputBits, s)[outputType](); }; }; var createOutputMethods = function (method, createMethod, bits, padding) { for (var i = 0; i < OUTPUT_TYPES.length; ++i) { var type = OUTPUT_TYPES[i]; method[type] = createMethod(bits, padding, type); } return method; }; var createMethod = function (bits, padding) { var method = createOutputMethod(bits, padding, 'hex'); method.create = function () { return new Keccak(bits, padding, bits); }; method.update = function (message) { return method.create().update(message); }; return createOutputMethods(method, createOutputMethod, bits, padding); }; var createShakeMethod = function (bits, padding) { var method = createShakeOutputMethod(bits, padding, 'hex'); method.create = function (outputBits) { return new Keccak(bits, padding, outputBits); }; method.update = function (message, outputBits) { return method.create(outputBits).update(message); }; return createOutputMethods(method, createShakeOutputMethod, bits, padding); }; var createCshakeMethod = function (bits, padding) { var w = CSHAKE_BYTEPAD[bits]; var method = createCshakeOutputMethod(bits, padding, 'hex'); method.create = function (outputBits, n, s) { if (!n && !s) { return methods['shake' + bits].create(outputBits); } else { return new Keccak(bits, padding, outputBits).bytepad([n, s], w); } }; method.update = function (message, outputBits, n, s) { return method.create(outputBits, n, s).update(message); }; return createOutputMethods(method, createCshakeOutputMethod, bits, padding); }; var createKmacMethod = function (bits, padding) { var w = CSHAKE_BYTEPAD[bits]; var method = createKmacOutputMethod(bits, padding, 'hex'); method.create = function (key, outputBits, s) { return new Kmac(bits, padding, outputBits).bytepad(['KMAC', s], w).bytepad([key], w); }; method.update = function (key, message, outputBits, s) { return method.create(key, outputBits, s).update(message); }; return createOutputMethods(method, createKmacOutputMethod, bits, padding); }; var algorithms = [ { name: 'keccak', padding: KECCAK_PADDING, bits: BITS, createMethod: createMethod }, { name: 'sha3', padding: PADDING, bits: BITS, createMethod: createMethod }, { name: 'shake', padding: SHAKE_PADDING, bits: SHAKE_BITS, createMethod: createShakeMethod }, { name: 'cshake', padding: CSHAKE_PADDING, bits: SHAKE_BITS, createMethod: createCshakeMethod }, { name: 'kmac', padding: CSHAKE_PADDING, bits: SHAKE_BITS, createMethod: createKmacMethod } ]; var methods = {}, methodNames = []; for (var i = 0; i < algorithms.length; ++i) { var algorithm = algorithms[i]; var bits = algorithm.bits; for (var j = 0; j < bits.length; ++j) { var methodName = algorithm.name + '_' + bits[j]; methodNames.push(methodName); methods[methodName] = algorithm.createMethod(bits[j], algorithm.padding); if (algorithm.name !== 'sha3') { var newMethodName = algorithm.name + bits[j]; methodNames.push(newMethodName); methods[newMethodName] = methods[methodName]; } } } function Keccak(bits, padding, outputBits) { this.blocks = []; this.s = []; this.padding = padding; this.outputBits = outputBits; this.reset = true; this.finalized = false; this.block = 0; this.start = 0; this.blockCount = (1600 - (bits << 1)) >> 5; this.byteCount = this.blockCount << 2; this.outputBlocks = outputBits >> 5; this.extraBytes = (outputBits & 31) >> 3; for (var i = 0; i < 50; ++i) { this.s[i] = 0; } } Keccak.prototype.update = function (message) { if (this.finalized) { throw new Error(FINALIZE_ERROR); } var notString, type = typeof message; if (type !== 'string') { if (type === 'object') { if (message === null) { throw new Error(INPUT_ERROR); } else if (ARRAY_BUFFER && message.constructor === ArrayBuffer) { message = new Uint8Array(message); } else if (!Array.isArray(message)) { if (!ARRAY_BUFFER || !ArrayBuffer.isView(message)) { throw new Error(INPUT_ERROR); } } } else { throw new Error(INPUT_ERROR); } notString = true; } var blocks = this.blocks, byteCount = this.byteCount, length = message.length, blockCount = this.blockCount, index = 0, s = this.s, i, code; while (index < length) { if (this.reset) { this.reset = false; blocks[0] = this.block; for (i = 1; i < blockCount + 1; ++i) { blocks[i] = 0; } } if (notString) { for (i = this.start; index < length && i < byteCount; ++index) { blocks[i >> 2] |= message[index] << SHIFT[i++ & 3]; } } else { for (i = this.start; index < length && i < byteCount; ++index) { code = message.charCodeAt(index); if (code < 0x80) { blocks[i >> 2] |= code << SHIFT[i++ & 3]; } else if (code < 0x800) { blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3]; blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; } else if (code < 0xd800 || code >= 0xe000) { blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3]; blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3]; blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; } else { code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff)); blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3]; blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3]; blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3]; blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; } } } this.lastByteIndex = i; if (i >= byteCount) { this.start = i - byteCount; this.block = blocks[blockCount]; for (i = 0; i < blockCount; ++i) { s[i] ^= blocks[i]; } f(s); this.reset = true; } else { this.start = i; } } return this; }; Keccak.prototype.encode = function (x, right) { var o = x & 255, n = 1; var bytes = [o]; x = x >> 8; o = x & 255; while (o > 0) { bytes.unshift(o); x = x >> 8; o = x & 255; ++n; } if (right) { bytes.push(n); } else { bytes.unshift(n); } this.update(bytes); return bytes.length; }; Keccak.prototype.encodeString = function (str) { var notString, type = typeof str; if (type !== 'string') { if (type === 'object') { if (str === null) { throw new Error(INPUT_ERROR); } else if (ARRAY_BUFFER && str.constructor === ArrayBuffer) { str = new Uint8Array(str); } else if (!Array.isArray(str)) { if (!ARRAY_BUFFER || !ArrayBuffer.isView(str)) { throw new Error(INPUT_ERROR); } } } else { throw new Error(INPUT_ERROR); } notString = true; } var bytes = 0, length = str.length; if (notString) { bytes = length; } else { for (var i = 0; i < str.length; ++i) { var code = str.charCodeAt(i); if (code < 0x80) { bytes += 1; } else if (code < 0x800) { bytes += 2; } else if (code < 0xd800 || code >= 0xe000) { bytes += 3; } else { code = 0x10000 + (((code & 0x3ff) << 10) | (str.charCodeAt(++i) & 0x3ff)); bytes += 4; } } } bytes += this.encode(bytes * 8); this.update(str); return bytes; }; Keccak.prototype.bytepad = function (strs, w) { var bytes = this.encode(w); for (var i = 0; i < strs.length; ++i) { bytes += this.encodeString(strs[i]); } var paddingBytes = w - bytes % w; var zeros = []; zeros.length = paddingBytes; this.update(zeros); return this; }; Keccak.prototype.finalize = function () { if (this.finalized) { return; } this.finalized = true; var blocks = this.blocks, i = this.lastByteIndex, blockCount = this.blockCount, s = this.s; blocks[i >> 2] |= this.padding[i & 3]; if (this.lastByteIndex === this.byteCount) { blocks[0] = blocks[blockCount]; for (i = 1; i < blockCount + 1; ++i) { blocks[i] = 0; } } blocks[blockCount - 1] |= 0x80000000; for (i = 0; i < blockCount; ++i) { s[i] ^= blocks[i]; } f(s); }; Keccak.prototype.toString = Keccak.prototype.hex = function () { this.finalize(); var blockCount = this.blockCount, s = this.s, outputBlocks = this.outputBlocks, extraBytes = this.extraBytes, i = 0, j = 0; var hex = '', block; while (j < outputBlocks) { for (i = 0; i < blockCount && j < outputBlocks; ++i, ++j) { block = s[i]; hex += HEX_CHARS[(block >> 4) & 0x0F] + HEX_CHARS[block & 0x0F] + HEX_CHARS[(block >> 12) & 0x0F] + HEX_CHARS[(block >> 8) & 0x0F] + HEX_CHARS[(block >> 20) & 0x0F] + HEX_CHARS[(block >> 16) & 0x0F] + HEX_CHARS[(block >> 28) & 0x0F] + HEX_CHARS[(block >> 24) & 0x0F]; } if (j % blockCount === 0) { f(s); i = 0; } } if (extraBytes) { block = s[i]; hex += HEX_CHARS[(block >> 4) & 0x0F] + HEX_CHARS[block & 0x0F]; if (extraBytes > 1) { hex += HEX_CHARS[(block >> 12) & 0x0F] + HEX_CHARS[(block >> 8) & 0x0F]; } if (extraBytes > 2) { hex += HEX_CHARS[(block >> 20) & 0x0F] + HEX_CHARS[(block >> 16) & 0x0F]; } } return hex; }; Keccak.prototype.arrayBuffer = function () { this.finalize(); var blockCount = this.blockCount, s = this.s, outputBlocks = this.outputBlocks, extraBytes = this.extraBytes, i = 0, j = 0; var bytes = this.outputBits >> 3; var buffer; if (extraBytes) { buffer = new ArrayBuffer((outputBlocks + 1) << 2); } else { buffer = new ArrayBuffer(bytes); } var array = new Uint32Array(buffer); while (j < outputBlocks) { for (i = 0; i < blockCount && j < outputBlocks; ++i, ++j) { array[j] = s[i]; } if (j % blockCount === 0) { f(s); } } if (extraBytes) { array[i] = s[i]; buffer = buffer.slice(0, bytes); } return buffer; }; Keccak.prototype.buffer = Keccak.prototype.arrayBuffer; Keccak.prototype.digest = Keccak.prototype.array = function () { this.finalize(); var blockCount = this.blockCount, s = this.s, outputBlocks = this.outputBlocks, extraBytes = this.extraBytes, i = 0, j = 0; var array = [], offset, block; while (j < outputBlocks) { for (i = 0; i < blockCount && j < outputBlocks; ++i, ++j) { offset = j << 2; block = s[i]; array[offset] = block & 0xFF; array[offset + 1] = (block >> 8) & 0xFF; array[offset + 2] = (block >> 16) & 0xFF; array[offset + 3] = (block >> 24) & 0xFF; } if (j % blockCount === 0) { f(s); } } if (extraBytes) { offset = j << 2; block = s[i]; array[offset] = block & 0xFF; if (extraBytes > 1) { array[offset + 1] = (block >> 8) & 0xFF; } if (extraBytes > 2) { array[offset + 2] = (block >> 16) & 0xFF; } } return array; }; function Kmac(bits, padding, outputBits) { Keccak.call(this, bits, padding, outputBits); } Kmac.prototype = new Keccak(); Kmac.prototype.finalize = function () { this.encode(this.outputBits, true); return Keccak.prototype.finalize.call(this); }; var f = function (s) { var h, l, n, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17, b18, b19, b20, b21, b22, b23, b24, b25, b26, b27, b28, b29, b30, b31, b32, b33, b34, b35, b36, b37, b38, b39, b40, b41, b42, b43, b44, b45, b46, b47, b48, b49; for (n = 0; n < 48; n += 2) { c0 = s[0] ^ s[10] ^ s[20] ^ s[30] ^ s[40]; c1 = s[1] ^ s[11] ^ s[21] ^ s[31] ^ s[41]; c2 = s[2] ^ s[12] ^ s[22] ^ s[32] ^ s[42]; c3 = s[3] ^ s[13] ^ s[23] ^ s[33] ^ s[43]; c4 = s[4] ^ s[14] ^ s[24] ^ s[34] ^ s[44]; c5 = s[5] ^ s[15] ^ s[25] ^ s[35] ^ s[45]; c6 = s[6] ^ s[16] ^ s[26] ^ s[36] ^ s[46]; c7 = s[7] ^ s[17] ^ s[27] ^ s[37] ^ s[47]; c8 = s[8] ^ s[18] ^ s[28] ^ s[38] ^ s[48]; c9 = s[9] ^ s[19] ^ s[29] ^ s[39] ^ s[49]; h = c8 ^ ((c2 << 1) | (c3 >>> 31)); l = c9 ^ ((c3 << 1) | (c2 >>> 31)); s[0] ^= h; s[1] ^= l; s[10] ^= h; s[11] ^= l; s[20] ^= h; s[21] ^= l; s[30] ^= h; s[31] ^= l; s[40] ^= h; s[41] ^= l; h = c0 ^ ((c4 << 1) | (c5 >>> 31)); l = c1 ^ ((c5 << 1) | (c4 >>> 31)); s[2] ^= h; s[3] ^= l; s[12] ^= h; s[13] ^= l; s[22] ^= h; s[23] ^= l; s[32] ^= h; s[33] ^= l; s[42] ^= h; s[43] ^= l; h = c2 ^ ((c6 << 1) | (c7 >>> 31)); l = c3 ^ ((c7 << 1) | (c6 >>> 31)); s[4] ^= h; s[5] ^= l; s[14] ^= h; s[15] ^= l; s[24] ^= h; s[25] ^= l; s[34] ^= h; s[35] ^= l; s[44] ^= h; s[45] ^= l; h = c4 ^ ((c8 << 1) | (c9 >>> 31)); l = c5 ^ ((c9 << 1) | (c8 >>> 31)); s[6] ^= h; s[7] ^= l; s[16] ^= h; s[17] ^= l; s[26] ^= h; s[27] ^= l; s[36] ^= h; s[37] ^= l; s[46] ^= h; s[47] ^= l; h = c6 ^ ((c0 << 1) | (c1 >>> 31)); l = c7 ^ ((c1 << 1) | (c0 >>> 31)); s[8] ^= h; s[9] ^= l; s[18] ^= h; s[19] ^= l; s[28] ^= h; s[29] ^= l; s[38] ^= h; s[39] ^= l; s[48] ^= h; s[49] ^= l; b0 = s[0]; b1 = s[1]; b32 = (s[11] << 4) | (s[10] >>> 28); b33 = (s[10] << 4) | (s[11] >>> 28); b14 = (s[20] << 3) | (s[21] >>> 29); b15 = (s[21] << 3) | (s[20] >>> 29); b46 = (s[31] << 9) | (s[30] >>> 23); b47 = (s[30] << 9) | (s[31] >>> 23); b28 = (s[40] << 18) | (s[41] >>> 14); b29 = (s[41] << 18) | (s[40] >>> 14); b20 = (s[2] << 1) | (s[3] >>> 31); b21 = (s[3] << 1) | (s[2] >>> 31); b2 = (s[13] << 12) | (s[12] >>> 20); b3 = (s[12] << 12) | (s[13] >>> 20); b34 = (s[22] << 10) | (s[23] >>> 22); b35 = (s[23] << 10) | (s[22] >>> 22); b16 = (s[33] << 13) | (s[32] >>> 19); b17 = (s[32] << 13) | (s[33] >>> 19); b48 = (s[42] << 2) | (s[43] >>> 30); b49 = (s[43] << 2) | (s[42] >>> 30); b40 = (s[5] << 30) | (s[4] >>> 2); b41 = (s[4] << 30) | (s[5] >>> 2); b22 = (s[14] << 6) | (s[15] >>> 26); b23 = (s[15] << 6) | (s[14] >>> 26); b4 = (s[25] << 11) | (s[24] >>> 21); b5 = (s[24] << 11) | (s[25] >>> 21); b36 = (s[34] << 15) | (s[35] >>> 17); b37 = (s[35] << 15) | (s[34] >>> 17); b18 = (s[45] << 29) | (s[44] >>> 3); b19 = (s[44] << 29) | (s[45] >>> 3); b10 = (s[6] << 28) | (s[7] >>> 4); b11 = (s[7] << 28) | (s[6] >>> 4); b42 = (s[17] << 23) | (s[16] >>> 9); b43 = (s[16] << 23) | (s[17] >>> 9); b24 = (s[26] << 25) | (s[27] >>> 7); b25 = (s[27] << 25) | (s[26] >>> 7); b6 = (s[36] << 21) | (s[37] >>> 11); b7 = (s[37] << 21) | (s[36] >>> 11); b38 = (s[47] << 24) | (s[46] >>> 8); b39 = (s[46] << 24) | (s[47] >>> 8); b30 = (s[8] << 27) | (s[9] >>> 5); b31 = (s[9] << 27) | (s[8] >>> 5); b12 = (s[18] << 20) | (s[19] >>> 12); b13 = (s[19] << 20) | (s[18] >>> 12); b44 = (s[29] << 7) | (s[28] >>> 25); b45 = (s[28] << 7) | (s[29] >>> 25); b26 = (s[38] << 8) | (s[39] >>> 24); b27 = (s[39] << 8) | (s[38] >>> 24); b8 = (s[48] << 14) | (s[49] >>> 18); b9 = (s[49] << 14) | (s[48] >>> 18); s[0] = b0 ^ (~b2 & b4); s[1] = b1 ^ (~b3 & b5); s[10] = b10 ^ (~b12 & b14); s[11] = b11 ^ (~b13 & b15); s[20] = b20 ^ (~b22 & b24); s[21] = b21 ^ (~b23 & b25); s[30] = b30 ^ (~b32 & b34); s[31] = b31 ^ (~b33 & b35); s[40] = b40 ^ (~b42 & b44); s[41] = b41 ^ (~b43 & b45); s[2] = b2 ^ (~b4 & b6); s[3] = b3 ^ (~b5 & b7); s[12] = b12 ^ (~b14 & b16); s[13] = b13 ^ (~b15 & b17); s[22] = b22 ^ (~b24 & b26); s[23] = b23 ^ (~b25 & b27); s[32] = b32 ^ (~b34 & b36); s[33] = b33 ^ (~b35 & b37); s[42] = b42 ^ (~b44 & b46); s[43] = b43 ^ (~b45 & b47); s[4] = b4 ^ (~b6 & b8); s[5] = b5 ^ (~b7 & b9); s[14] = b14 ^ (~b16 & b18); s[15] = b15 ^ (~b17 & b19); s[24] = b24 ^ (~b26 & b28); s[25] = b25 ^ (~b27 & b29); s[34] = b34 ^ (~b36 & b38); s[35] = b35 ^ (~b37 & b39); s[44] = b44 ^ (~b46 & b48); s[45] = b45 ^ (~b47 & b49); s[6] = b6 ^ (~b8 & b0); s[7] = b7 ^ (~b9 & b1); s[16] = b16 ^ (~b18 & b10); s[17] = b17 ^ (~b19 & b11); s[26] = b26 ^ (~b28 & b20); s[27] = b27 ^ (~b29 & b21); s[36] = b36 ^ (~b38 & b30); s[37] = b37 ^ (~b39 & b31); s[46] = b46 ^ (~b48 & b40); s[47] = b47 ^ (~b49 & b41); s[8] = b8 ^ (~b0 & b2); s[9] = b9 ^ (~b1 & b3); s[18] = b18 ^ (~b10 & b12); s[19] = b19 ^ (~b11 & b13); s[28] = b28 ^ (~b20 & b22); s[29] = b29 ^ (~b21 & b23); s[38] = b38 ^ (~b30 & b32); s[39] = b39 ^ (~b31 & b33); s[48] = b48 ^ (~b40 & b42); s[49] = b49 ^ (~b41 & b43); s[0] ^= RC[n]; s[1] ^= RC[n + 1]; } }; if (COMMON_JS) { module.exports = methods; } else { for (i = 0; i < methodNames.length; ++i) { root[methodNames[i]] = methods[methodNames[i]]; } } })(); } (sha3$1)); var sha3Exports = sha3$1.exports; var sha3 = /*@__PURE__*/getDefaultExportFromCjs(sha3Exports); function keccak256(data) { return '0x' + sha3.keccak_256(arrayify(data)); } const version = "strings/5.7.0"; const logger = new Logger(version); /////////////////////////////// var UnicodeNormalizationForm; (function (UnicodeNormalizationForm) { UnicodeNormalizationForm["current"] = ""; UnicodeNormalizationForm["NFC"] = "NFC"; UnicodeNormalizationForm["NFD"] = "NFD"; UnicodeNormalizationForm["NFKC"] = "NFKC"; UnicodeNormalizationForm["NFKD"] = "NFKD"; })(UnicodeNormalizationForm || (UnicodeNormalizationForm = {})); var Utf8ErrorReason; (function (Utf8ErrorReason) { // A continuation byte was present where there was nothing to continue // - offset = the index the codepoint began in Utf8ErrorReason["UNEXPECTED_CONTINUE"] = "unexpected continuation byte"; // An invalid (non-continuation) byte to start a UTF-8 codepoint was found // - offset = the index the codepoint began in Utf8ErrorReason["BAD_PREFIX"] = "bad codepoint prefix"; // The string is too short to process the expected codepoint // - offset = the index the codepoint began in Utf8ErrorReason["OVERRUN"] = "string overrun"; // A missing continuation byte was expected but not found // - offset = the index the continuation byte was expected at Utf8ErrorReason["MISSING_CONTINUE"] = "missing continuation byte"; // The computed code point is outside the range for UTF-8 // - offset = start of this codepoint // - badCodepoint = the computed codepoint; outside the UTF-8 range Utf8ErrorReason["OUT_OF_RANGE"] = "out of UTF-8 range"; // UTF-8 strings may not contain UTF-16 surrogate pairs // - offset = start of this codepoint // - badCodepoint = the computed codepoint; inside the UTF-16 surrogate range Utf8ErrorReason["UTF16_SURROGATE"] = "UTF-16 surrogate"; // The string is an overlong representation // - offset = start of this codepoint // - badCodepoint = the computed codepoint; already bounds checked Utf8ErrorReason["OVERLONG"] = "overlong representation"; })(Utf8ErrorReason || (Utf8ErrorReason = {})); // http://stackoverflow.com/questions/18729405/how-to-convert-utf8-string-to-byte-array function toUtf8Bytes(str, form = UnicodeNormalizationForm.current) { if (form != UnicodeNormalizationForm.current) { logger.checkNormalize(); str = str.normalize(form); } let result = []; for (let i = 0; i < str.length; i++) { const c = str.charCodeAt(i); if (c < 0x80) { result.push(c); } else if (c < 0x800) { result.push((c >> 6) | 0xc0); result.push((c & 0x3f) | 0x80); } else if ((c & 0xfc00) == 0xd800) { i++; const c2 = str.charCodeAt(i); if (i >= str.length || (c2 & 0xfc00) !== 0xdc00) { throw new Error("invalid utf-8 string"); } // Surrogate Pair const pair = 0x10000 + ((c & 0x03ff) << 10) + (c2 & 0x03ff); result.push((pair >> 18) | 0xf0); result.push(((pair >> 12) & 0x3f) | 0x80); result.push(((pair >> 6) & 0x3f) | 0x80); result.push((pair & 0x3f) | 0x80); } else { result.push((c >> 12) | 0xe0); result.push(((c >> 6) & 0x3f) | 0x80); result.push((c & 0x3f) | 0x80); } } return arrayify(result); } const SEED = "mimcsponge"; const NROUNDS = 220; async function buildMimcSponge() { const bn128 = await getCurveFromName("bn128", true); return new MimcSponge(bn128.Fr); } class MimcSponge { constructor (F) { this.F = F; this.cts = this.getConstants(SEED, NROUNDS); } getIV (seed) { const F = this.F; if (typeof seed === "undefined") seed = SEED; const c = keccak256(toUtf8Bytes(seed+"_iv")); const cn = Scalar.e(c); const iv = cn.mod(F.p); return iv; }; getConstants (seed, nRounds) { const F = this.F; if (typeof nRounds === "undefined") nRounds = NROUNDS; const cts = new Array(nRounds); let c = keccak256(toUtf8Bytes(SEED)); for (let i=1; i { return new Promise((resolve, reject) => { var fulfilled = (value) => { try { step(generator.next(value)); } catch (e) { reject(e); } }; var rejected = (value) => { try { step(generator.throw(value)); } catch (e) { reject(e); } }; var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); step((generator = generator.apply(__this, __arguments)).next()); }); }; class Mimc { constructor() { this.mimcPromise = this.initMimc(); } initMimc() { return __async$1(this, null, function* () { this.sponge = yield buildMimcSponge(); this.hash = (left, right) => { var _a, _b; return (_b = this.sponge) == null ? void 0 : _b.F.toString((_a = this.sponge) == null ? void 0 : _a.multiHash([BigInt(left), BigInt(right)])); }; }); } getHash() { return __async$1(this, null, function* () { yield this.mimcPromise; return { sponge: this.sponge, hash: this.hash }; }); } } const mimc = new Mimc(); BigInt.prototype.toJSON = function() { return this.toString(); }; const isNode = !process.browser && typeof globalThis.window === "undefined"; var __async = (__this, __arguments, generator) => { return new Promise((resolve, reject) => { var fulfilled = (value) => { try { step(generator.next(value)); } catch (e) { reject(e); } }; var rejected = (value) => { try { step(generator.throw(value)); } catch (e) { reject(e); } }; var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); step((generator = generator.apply(__this, __arguments)).next()); }); }; function nodePostWork() { return __async(this, null, function* () { const { hash: hashFunction } = yield mimc.getHash(); const { merkleTreeHeight, edge, elements, zeroElement } = threads.workerData; if (edge) { const merkleTree2 = new lib.PartialMerkleTree(merkleTreeHeight, edge, elements, { zeroElement, hashFunction }); threads.parentPort.postMessage(merkleTree2.toString()); return; } const merkleTree = new lib.MerkleTree(merkleTreeHeight, elements, { zeroElement, hashFunction }); threads.parentPort.postMessage(merkleTree.toString()); }); } if (isNode && threads) { nodePostWork(); } else if (!isNode && typeof addEventListener === "function" && typeof postMessage === "function") { addEventListener("message", (e) => __async(undefined, null, function* () { let data; if (e.data) { data = e.data; } else { data = e; } const { hash: hashFunction } = yield mimc.getHash(); const { merkleTreeHeight, edge, elements, zeroElement } = data; if (edge) { const merkleTree2 = new lib.PartialMerkleTree(merkleTreeHeight, edge, elements, { zeroElement, hashFunction }); postMessage(merkleTree2.toString()); return; } const merkleTree = new lib.MerkleTree(merkleTreeHeight, elements, { zeroElement, hashFunction }); postMessage(merkleTree.toString()); })); } else { throw new Error("This browser / environment does not support workers!"); }