From 0bcd74311c48545a73e456a0cae941fdff2220b8 Mon Sep 17 00:00:00 2001 From: Tornado Contrib Date: Wed, 24 Apr 2024 17:26:09 +0000 Subject: [PATCH] Built merkleTreeWorkers --- static/merkleTreeWorker.js | 19828 +++++++++++++++++++++++++++++++ static/merkleTreeWorker.umd.js | 19576 ++++++++++++++++++++++++++++++ 2 files changed, 39404 insertions(+) create mode 100644 static/merkleTreeWorker.js create mode 100644 static/merkleTreeWorker.umd.js diff --git a/static/merkleTreeWorker.js b/static/merkleTreeWorker.js new file mode 100644 index 0000000..c64d6b6 --- /dev/null +++ b/static/merkleTreeWorker.js @@ -0,0 +1,19828 @@ +'use strict'; + +var threads = require('worker_threads'); +var require$$5 = require('crypto'); +var require$$0 = 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)); + +BigInt.prototype.toJSON = function() { + return this.toString(); +}; +const isNode = !process.browser && typeof globalThis.window === "undefined"; + +/* 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 + require$$5.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 = require$$0.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(); + +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 doesn't support workers!"); +} diff --git a/static/merkleTreeWorker.umd.js b/static/merkleTreeWorker.umd.js new file mode 100644 index 0000000..1c73bdc --- /dev/null +++ b/static/merkleTreeWorker.umd.js @@ -0,0 +1,19576 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('os'), require('web-worker')) : + typeof define === 'function' && define.amd ? define(['os', 'web-worker'], factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.require$$0, global.Worker)); +})(this, (function (require$$0, Worker) { 'use strict'; + + 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); + { // Browser + if (typeof globalThis.crypto !== "undefined") { // Supported + globalThis.crypto.getRandomValues(array); + } else { // fallback + for (let i=0; i>>0; + } + } + } + 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. + */ + + // 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) { + { + return globalThis.btoa(str); + } + } + + 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 = require$$0.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(); + + 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()); + }); + }; + if (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 doesn't support workers!"); + } + +}));