diff --git a/build/browser.esm.js b/build/browser.esm.js
index 09713f3..92aa0d0 100644
--- a/build/browser.esm.js
+++ b/build/browser.esm.js
@@ -2757,3501 +2757,3526 @@ class EC {
}
-var utils$6 = {};
-
-/*
- 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 .
-*/
+/* global BigInt */
-utils$6.bigInt2BytesLE = function bigInt2BytesLE(_a, len) {
- const b = Array(len);
- let v = BigInt(_a);
- for (let i=0; i> 8n;
+function stringifyBigInts(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);
+ } else if (typeof o == "object") {
+ const res = {};
+ const keys = Object.keys(o);
+ keys.forEach((k) => {
+ res[k] = stringifyBigInts(o[k]);
+ });
+ return res;
+ } else {
+ return o;
}
- return b;
-};
+}
-utils$6.bigInt2U32LE = function bigInt2BytesLE(_a, len) {
- const b = Array(len);
- let v = BigInt(_a);
- for (let i=0; i> 32n;
+function unstringifyBigInts(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);
+ } else if (typeof o == "object") {
+ if (o === null) return null;
+ const res = {};
+ const keys = Object.keys(o);
+ keys.forEach((k) => {
+ res[k] = unstringifyBigInts(o[k]);
+ });
+ return res;
+ } else {
+ return o;
}
- return b;
-};
-
-utils$6.isOcamNum = function(a) {
- if (!Array.isArray(a)) return false;
- if (a.length != 3) return false;
- if (typeof a[0] !== "number") return false;
- if (typeof a[1] !== "number") return false;
- if (!Array.isArray(a[2])) return false;
- return true;
-};
-
-/*
- 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_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;
-
- 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 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 buildZero() {
- const f = module.addFunction(prefix+"_zero");
- f.addParam("pr", "i32");
-
- const c = f.getCodeBuilder();
-
- for (let i=0; i 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);
}
}
-
- function buildOne() {
- const f = module.addFunction(prefix+"_one");
- f.addParam("pr", "i32");
-
- const c = f.getCodeBuilder();
-
- f.addCode(
- c.i64_store(
- c.getLocal("pr"),
- 0,
- c.i64_const(1)
- )
- );
- for (let i=1; i> BigInt(32);
+ } else if (o + 2 <= len) {
+ buffV.setUint16(o, Number(r & BigInt(0xffff)), true);
+ o += 2;
+ r = r >> BigInt(16);
+ } else {
+ buffV.setUint8(o, Number(r & BigInt(0xff)), true);
+ o += 1;
+ r = r >> BigInt(8);
}
+ }
+ if (r) {
+ throw new Error("Number does not fit in this length");
+ }
+ return buff;
+}
- f.addCode(getCompCode(n64-1));
- f.addCode(c.ret(c.i32_const(0)));
+function stringifyFElements(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.bind(this, F));
+ } else if (typeof o == "object") {
+ const res = {};
+ const keys = Object.keys(o);
+ keys.forEach((k) => {
+ res[k] = stringifyFElements(F, o[k]);
+ });
+ return res;
+ } else {
+ return o;
}
+}
+function unstringifyFElements(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.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(F, o[k]);
+ });
+ return res;
+ } else {
+ return o;
+ }
+}
+const _revTable = [];
+for (let i = 0; i < 256; i++) {
+ _revTable[i] = _revSlow(i, 8);
+}
- function buildGte() {
- const f = module.addFunction(prefix+"_gte");
- f.addParam("px", "i32");
- f.addParam("py", "i32");
- f.setReturnType("i32");
+function _revSlow(idx, bits) {
+ let res = 0;
+ let a = idx;
+ for (let i = 0; i < bits; i++) {
+ res <<= 1;
+ res = res | (a & 1);
+ a >>= 1;
+ }
+ return res;
+}
- const c = f.getCodeBuilder();
+function bitReverse(idx, bits) {
+ return (
+ (_revTable[idx >>> 24] |
+ (_revTable[(idx >>> 16) & 0xff] << 8) |
+ (_revTable[(idx >>> 8) & 0xff] << 16) |
+ (_revTable[idx & 0xff] << 24)) >>>
+ (32 - bits)
+ );
+}
- function getCompCode(n) {
- if (n==0) {
- return c.ret(c.i64_ge_u(
- c.i64_load(c.getLocal("px")),
- c.i64_load(c.getLocal("py"))
- ));
- }
- return c.if(
- c.i64_lt_u(
- c.i64_load(c.getLocal("px"), n*8 ),
- c.i64_load(c.getLocal("py"), n*8 )
- ),
- c.ret(c.i32_const(0)),
- c.if(
- c.i64_gt_u(
- c.i64_load(c.getLocal("px"), n*8 ),
- c.i64_load(c.getLocal("py"), n*8 )
- ),
- c.ret(c.i32_const(1)),
- getCompCode(n-1)
- )
- );
- }
+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)
+ );
+}
- f.addCode(getCompCode(n64-1));
- f.addCode(c.ret(c.i32_const(0)));
+function buffReverseBits(buff, eSize) {
+ const n = buff.byteLength / eSize;
+ const bits = log2(n);
+ if (n != 1 << bits) {
+ throw new Error("Invalid number of pointers");
}
+ for (let i = 0; i < n; i++) {
+ const r = bitReverse(i, bits);
+ if (i > r) {
+ 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);
+ }
+ }
+}
+function array2buffer(arr, sG) {
+ const buff = new Uint8Array(sG * arr.length);
+ for (let i = 0; i < arr.length; i++) {
+ buff.set(arr[i], i * sG);
+ }
- function buildAdd() {
-
- const f = module.addFunction(prefix+"_add");
- f.addParam("x", "i32");
- f.addParam("y", "i32");
- f.addParam("r", "i32");
- f.setReturnType("i32");
- f.addLocal("c", "i64");
+ return buff;
+}
- const c = f.getCodeBuilder();
+function buffer2array(buff, sG) {
+ const n = buff.byteLength / sG;
+ const arr = new Array(n);
+ for (let i = 0; i < n; i++) {
+ arr[i] = buff.slice(i * sG, i * sG + sG);
+ }
+ return arr;
+}
- f.addCode(c.setLocal(
- "c",
- c.i64_add(
- c.i64_load32_u(c.getLocal("x")),
- c.i64_load32_u(c.getLocal("y"))
- )
- ));
+var _utils = /*#__PURE__*/Object.freeze({
+ __proto__: null,
+ array2buffer: array2buffer,
+ beBuff2int: beBuff2int,
+ beInt2Buff: beInt2Buff,
+ bitReverse: bitReverse,
+ buffReverseBits: buffReverseBits,
+ buffer2array: buffer2array,
+ leBuff2int: leBuff2int,
+ leInt2Buff: leInt2Buff,
+ log2: log2,
+ stringifyBigInts: stringifyBigInts,
+ stringifyFElements: stringifyFElements,
+ unstringifyBigInts: unstringifyBigInts,
+ unstringifyFElements: unstringifyFElements
+});
- f.addCode(c.i64_store32(
- c.getLocal("r"),
- c.getLocal("c"),
- ));
+const PAGE_SIZE = ( typeof Buffer !== "undefined" && Buffer.constants && Buffer.constants.MAX_LENGTH ) ? Buffer.constants.MAX_LENGTH : (1 << 30);
- for (let i=1; 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;
}
- f.addCode(c.i32_wrap_i64 ( c.i64_shr_s (c.getLocal("c"), c.i64_const(32))));
+ return buff;
}
+ set(buff, offset) {
+ if (offset === undefined) offset = 0;
- function buildMul() {
+ const len = buff.byteLength;
- const f = module.addFunction(prefix+"_mul");
- f.addParam("x", "i32");
- f.addParam("y", "i32");
- f.addParam("r", "i32");
- f.addLocal("c0", "i64");
- f.addLocal("c1", "i64");
+ 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);
+ }
- for (let i=0;i0) {
+ 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]);
+ }
- for (let i=Math.max(0, k-n32+1); (i<((k+1)>>1) )&&(i>1, k>>1)
- )
- )
- );
+ 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);
+ }
- f.addCode(
- c.setLocal(c1,
- c.i64_add(
- c.getLocal(c1),
- c.i64_shr_u(
- c.getLocal(c0),
- c.i64_const(32)
- )
- )
- )
- );
- }
+ op1Bool(opName, a) {
+ this.tm.setBuff(this.pOp1, a);
+ return !!this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp3);
+ }
- // Add the old carry
+ add(a,b) {
+ return this.op2("_add", a, b);
+ }
- 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)
- )
- )
- );
- }
+ eq(a,b) {
+ return this.op2Bool("_eq", a, b);
+ }
- f.addCode(
- c.i64_store32(
- c.getLocal("r"),
- k*4,
- c.getLocal(c0)
- )
- );
+ isZero(a) {
+ return this.op1Bool("_isZero", a);
+ }
- 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)
- )
- )
- );
+ sub(a,b) {
+ return this.op2("_sub", a, b);
+ }
- }
- f.addCode(
- c.i64_store32(
- c.getLocal("r"),
- n32*4*2-4,
- c.getLocal(c0_old)
- )
- );
+ neg(a) {
+ return this.op1("_neg", a);
+ }
+ inv(a) {
+ return this.op1("_inverse", a);
}
+ toMontgomery(a) {
+ return this.op1("_toMontgomery", a);
+ }
- function buildSquareOld() {
- const f = module.addFunction(prefix+"_squareOld");
- f.addParam("x", "i32");
- f.addParam("r", "i32");
+ fromMontgomery(a) {
+ return this.op1("_fromMontgomery", a);
+ }
- const c = f.getCodeBuilder();
+ mul(a,b) {
+ return this.op2("_mul", a, b);
+ }
- f.addCode(c.call(prefix + "_mul", c.getLocal("x"), c.getLocal("x"), c.getLocal("r")));
+ 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);
}
- function _buildMul1() {
- const f = module.addFunction(prefix+"__mul1");
- f.addParam("px", "i32");
- f.addParam("y", "i64");
- f.addParam("pr", "i32");
- f.addLocal("c", "i64");
+ square(a) {
+ return this.op1("_square", a);
+ }
- const c = f.getCodeBuilder();
+ isSquare(a) {
+ return this.op1Bool("_isSquare", a);
+ }
- f.addCode(c.setLocal(
- "c",
- c.i64_mul(
- c.i64_load32_u(c.getLocal("px"), 0, 0),
- c.getLocal("y")
- )
- ));
+ sqrt(a) {
+ return this.op1("_sqrt", a);
+ }
- f.addCode(c.i64_store32(
- c.getLocal("pr"),
- 0,
- 0,
- c.getLocal("c"),
- ));
+ 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);
+ }
- 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)
- )));
+ this.pOp1 = tm.alloc(F.n8*2);
+ this.pOp2 = tm.alloc(F.n8*2);
+ this.pOp3 = tm.alloc(F.n8*2);
+ this.tm.instance.exports[prefix + "_zero"](this.pOp1);
+ this.zero = tm.getBuff(this.pOp1, this.n8);
+ this.tm.instance.exports[prefix + "_one"](this.pOp1);
+ this.one = tm.getBuff(this.pOp1, this.n8);
- 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)
- )
- )
- );
+ this.negone = this.neg(this.one);
+ this.two = this.add(this.one, this.one);
- // 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(
+ 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);
+ }
- // 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)
- )),
+ 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);
+ }
- c.setLocal(
- "sx",
- c.i64_load(
- c.i32_sub(
- c.i32_add( R, c.getLocal("eX")),
- c.i32_const(7)
- ),
- 0,
- 0
- )
- ),
+ 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);
+ }
- 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)
- )
- ),
+ op1Bool(opName, a) {
+ this.tm.setBuff(this.pOp1, a);
+ return !!this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp3);
+ }
- // 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)
- )
- )
- ),
+ add(a,b) {
+ return this.op2("_add", a, b);
+ }
- c.setLocal(
- "sx",
- c.i64_shr_u(
- c.getLocal("sx"),
- c.i64_const(8)
- )
- ),
+ eq(a,b) {
+ return this.op2Bool("_eq", a, b);
+ }
- c.setLocal(
- "ec",
- c.i32_add(
- c.getLocal("ec"),
- c.i32_const(1)
- )
- ),
- c.br(0)
- )),
+ isZero(a) {
+ return this.op1Bool("_isZero", a);
+ }
- 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))
- ]
- ),
+ sub(a,b) {
+ return this.op2("_sub", a, b);
+ }
- 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)
- )));
+ neg(a) {
+ return this.op1("_neg", a);
}
- function buildInverseMod() {
+ inv(a) {
+ return this.op1("_inverse", a);
+ }
- 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");
+ isNegative(a) {
+ return this.op1Bool("_isNegative", a);
+ }
- const c = f.getCodeBuilder();
+ toMontgomery(a) {
+ return this.op1("_toMontgomery", a);
+ }
- 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));
+ fromMontgomery(a) {
+ return this.op1("_fromMontgomery", a);
+ }
- f.addCode(
- c.setLocal("t", aux1),
- c.call(prefix + "_zero", aux1),
- c.setLocal("signt", c.i32_const(0)),
- );
+ mul(a,b) {
+ return this.op2("_mul", a, b);
+ }
- 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)
- );
+ mul1(a,b) {
+ return this.op2("_mul1", 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);
+ }
- f.addCode(c.setLocal("qq", aux5));
- f.addCode(c.setLocal("qr", aux6));
- f.addCode(c.setLocal("x", aux7));
+ sqrt(a) {
+ return this.op1("_sqrt", a);
+ }
- 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")),
+ 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);
+ }
- c.call(prefix + "_mul", c.getLocal("qq"), c.getLocal("newt"), mulBuff),
+ e(a, b) {
+ if (a instanceof Uint8Array) return a;
+ if ((Array.isArray(a)) && (a.length == 2)) {
+ const c1 = this.F.e(a[0], b);
+ const c2 = this.F.e(a[1], b);
+ const res = new Uint8Array(this.F.n8*2);
+ res.set(c1);
+ res.set(c2, this.F.n8*2);
+ return res;
+ } else {
+ throw new Error("invalid F2");
+ }
+ }
- 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))
- ]
- )
- )
- ),
+ toString(a, radix) {
+ const s1 = this.F.toString(a.slice(0, this.F.n8), radix);
+ const s2 = this.F.toString(a.slice(this.F.n8), radix);
+ return `[${s1}, ${s2}]`;
+ }
- c.setLocal("swp", c.getLocal("t")),
- c.setLocal("t", c.getLocal("newt")),
- c.setLocal("newt", c.getLocal("x")),
- c.setLocal("x", c.getLocal("swp")),
+ fromRng(rng) {
+ const c1 = this.F.fromRng(rng);
+ const c2 = this.F.fromRng(rng);
+ const res = new Uint8Array(this.F.n8*2);
+ res.set(c1);
+ res.set(c2, this.F.n8);
+ return res;
+ }
- c.setLocal("signt", c.getLocal("signnewt")),
- c.setLocal("signnewt", c.getLocal("signx")),
+ random() {
+ return this.fromRng(getThreadRng());
+ }
- c.setLocal("swp", c.getLocal("r")),
- c.setLocal("r", c.getLocal("newr")),
- c.setLocal("newr", c.getLocal("qr")),
- c.setLocal("qr", c.getLocal("swp")),
+ toObject(a) {
+ const c1 = this.F.toObject(a.slice(0, this.F.n8));
+ const c2 = this.F.toObject(a.slice(this.F.n8, this.F.n8*2));
+ return [c1, c2];
+ }
- c.br(0)
- )));
+ fromObject(a) {
+ const buff = new Uint8Array(this.F.n8*2);
+ const b1 = this.F.fromObject(a[0]);
+ const b2 = this.F.fromObject(a[1]);
+ buff.set(b1);
+ buff.set(b2, this.F.n8);
+ return buff;
+ }
- 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"))
- ));
+ c1(a) {
+ return a.slice(0, this.F.n8);
}
+ c2(a) {
+ return a.slice(this.F.n8);
+ }
- 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;
-};
+class WasmField3 {
-/*
- Copyright 2019 0KIMS association.
+ constructor(tm, prefix, F) {
+ this.tm = tm;
+ this.prefix = prefix;
- This file is part of wasmsnark (Web Assembly zkSnark Prover).
+ this.F = F;
+ this.type = "F3";
+ this.m = F.m * 3;
+ this.n8 = this.F.n8*3;
+ this.n32 = this.F.n32*3;
+ this.n64 = this.F.n64*3;
- 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.
+ this.pOp1 = tm.alloc(F.n8*3);
+ this.pOp2 = tm.alloc(F.n8*3);
+ this.pOp3 = tm.alloc(F.n8*3);
+ this.tm.instance.exports[prefix + "_zero"](this.pOp1);
+ this.zero = tm.getBuff(this.pOp1, this.n8);
+ this.tm.instance.exports[prefix + "_one"](this.pOp1);
+ this.one = tm.getBuff(this.pOp1, this.n8);
- 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.
+ this.negone = this.neg(this.one);
+ this.two = this.add(this.one, this.one);
- 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) {
+ 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);
+ }
- 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");
+ 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);
+ }
- const c = f.getCodeBuilder();
+ 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);
+ }
- const aux = c.i32_const(module.alloc(elementLen));
+ op1Bool(opName, a) {
+ this.tm.setBuff(this.pOp1, a);
+ return !!this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp3);
+ }
- 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)
- )));
+ eq(a,b) {
+ return this.op2Bool("_eq", a, b);
+ }
+ isZero(a) {
+ return this.op1Bool("_isZero", a);
+ }
- 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;
+ add(a,b) {
+ return this.op2("_add", a, b);
}
-};
+ sub(a,b) {
+ return this.op2("_sub", a, b);
+ }
-var build_batchinverse = buildBatchInverse$3;
+ neg(a) {
+ return this.op1("_neg", a);
+ }
-function buildBatchInverse$3(module, prefix) {
+ inv(a) {
+ return this.op1("_inverse", a);
+ }
+ isNegative(a) {
+ return this.op1Bool("_isNegative", a);
+ }
- const n8 = module.modules[prefix].n64*8;
+ toMontgomery(a) {
+ return this.op1("_toMontgomery", a);
+ }
- 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");
+ fromMontgomery(a) {
+ return this.op1("_fromMontgomery", a);
+ }
- const c = f.getCodeBuilder();
+ mul(a,b) {
+ return this.op2("_mul", a, b);
+ }
- const AUX = c.i32_const(module.alloc(n8));
+ 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);
+ }
- // 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)
- )
- )
- )
- );
+ isSquare(a) {
+ return this.op1Bool("_isSquare", a);
+ }
- f.addCode(
+ sqrt(a) {
+ return this.op1("_sqrt", a);
+ }
- // aux[0] = a;
- c.call(prefix+"_one", c.getLocal("itAux")),
- // for (i=0;i b ? 1 : -1;
-}
-
-function square$1(n) {
- return n * n;
-}
+ timesFr(a, s) {
+ let fnName;
+ if (a.byteLength == this.F.n8*3) {
+ fnName = this.prefix + "_timesFr";
+ } else if (a.byteLength == this.F.n8*2) {
+ fnName = this.prefix + "_timesFrAffine";
+ } else {
+ throw new Error("invalid point size");
+ }
+ this.tm.setBuff(this.pOp1, a);
+ this.tm.setBuff(this.pOp2, s);
+ this.tm.instance.exports[fnName](this.pOp1, this.pOp2, this.pOp3);
+ return this.tm.getBuff(this.pOp3, this.F.n8*3);
+ }
-function isOdd$4(n) {
- return n % 2n !== 0n;
-}
+ eq(a,b) {
+ if (a.byteLength == this.F.n8*3) {
+ if (b.byteLength == this.F.n8*3) {
+ return this.op2bool("_eq", a, b);
+ } else if (b.byteLength == this.F.n8*2) {
+ return this.op2bool("_eqMixed", a, b);
+ } else {
+ throw new Error("invalid point size");
+ }
+ } else if (a.byteLength == this.F.n8*2) {
+ if (b.byteLength == this.F.n8*3) {
+ return this.op2bool("_eqMixed", b, a);
+ } else if (b.byteLength == this.F.n8*2) {
+ return this.op2bool("_eqAffine", a, b);
+ } else {
+ throw new Error("invalid point size");
+ }
+ } else {
+ throw new Error("invalid point size");
+ }
+ }
-function isEven(n) {
- return n % 2n === 0n;
-}
+ toAffine(a) {
+ if (a.byteLength == this.F.n8*3) {
+ return this.op1Affine("_toAffine", a);
+ } else if (a.byteLength == this.F.n8*2) {
+ return a;
+ } else {
+ throw new Error("invalid point size");
+ }
+ }
-function isNegative$3(n) {
- return n < 0n;
-}
+ toJacobian(a) {
+ if (a.byteLength == this.F.n8*3) {
+ return a;
+ } else if (a.byteLength == this.F.n8*2) {
+ return this.op1("_toJacobian", a);
+ } else {
+ throw new Error("invalid point size");
+ }
+ }
-function isPositive(n) {
- return n > 0n;
-}
+ toRprUncompressed(arr, offset, a) {
+ this.tm.setBuff(this.pOp1, a);
+ if (a.byteLength == this.F.n8*3) {
+ this.tm.instance.exports[this.prefix + "_toAffine"](this.pOp1, this.pOp1);
+ } else if (a.byteLength != this.F.n8*2) {
+ throw new Error("invalid point size");
+ }
+ this.tm.instance.exports[this.prefix + "_LEMtoU"](this.pOp1, this.pOp1);
+ const res = this.tm.getBuff(this.pOp1, this.F.n8*2);
+ arr.set(res, offset);
+ }
-function bitLength$5(n) {
- if (isNegative$3(n)) {
- return n.toString(2).length - 1; // discard the - sign
- } else {
- return n.toString(2).length;
+ fromRprUncompressed(arr, offset) {
+ const buff = arr.slice(offset, offset + this.F.n8*2);
+ this.tm.setBuff(this.pOp1, buff);
+ this.tm.instance.exports[this.prefix + "_UtoLEM"](this.pOp1, this.pOp1);
+ return this.tm.getBuff(this.pOp1, this.F.n8*2);
}
-}
-function abs(n) {
- return n < 0n ? -n : n;
-}
+ toRprCompressed(arr, offset, a) {
+ this.tm.setBuff(this.pOp1, a);
+ if (a.byteLength == this.F.n8*3) {
+ this.tm.instance.exports[this.prefix + "_toAffine"](this.pOp1, this.pOp1);
+ } else if (a.byteLength != this.F.n8*2) {
+ throw new Error("invalid point size");
+ }
+ this.tm.instance.exports[this.prefix + "_LEMtoC"](this.pOp1, this.pOp1);
+ const res = this.tm.getBuff(this.pOp1, this.F.n8);
+ arr.set(res, offset);
+ }
-function isUnit(n) {
- return abs(n) === 1n;
-}
+ fromRprCompressed(arr, offset) {
+ const buff = arr.slice(offset, offset + this.F.n8);
+ this.tm.setBuff(this.pOp1, buff);
+ this.tm.instance.exports[this.prefix + "_CtoLEM"](this.pOp1, this.pOp2);
+ return this.tm.getBuff(this.pOp2, this.F.n8*2);
+ }
-function modInv$3(a, n) {
- var t = 0n, newT = 1n, r = n, newR = abs(a), q, lastT, lastR;
- while (newR !== 0n) {
- q = r / newR;
- lastT = t;
- lastR = r;
- t = newT;
- r = newR;
- newT = lastT - (q * newT);
- newR = lastR - (q * newR);
+ toUncompressed(a) {
+ const buff = new Uint8Array(this.F.n8*2);
+ this.toRprUncompressed(buff, 0, a);
+ return buff;
}
- if (!isUnit(r)) throw new Error(a.toString() + " and " + n.toString() + " are not co-prime");
- if (compare(t, 0n) === -1) {
- t = t + n;
+
+ toRprLEM(arr, offset, a) {
+ if (a.byteLength == this.F.n8*2) {
+ arr.set(a, offset);
+ return;
+ } else if (a.byteLength == this.F.n8*3) {
+ this.tm.setBuff(this.pOp1, a);
+ this.tm.instance.exports[this.prefix + "_toAffine"](this.pOp1, this.pOp1);
+ const res = this.tm.getBuff(this.pOp1, this.F.n8*2);
+ arr.set(res, offset);
+ } else {
+ throw new Error("invalid point size");
+ }
}
- if (isNegative$3(a)) {
- return -t;
+
+ fromRprLEM(arr, offset) {
+ offset = offset || 0;
+ return arr.slice(offset, offset+this.F.n8*2);
}
- return t;
-}
-function modPow$2(n, exp, mod) {
- if (mod === 0n) throw new Error("Cannot take modPow with modulus 0");
- var r = 1n,
- base = n % mod;
- if (isNegative$3(exp)) {
- exp = exp * -1n;
- base = modInv$3(base, mod);
+ toString(a, radix) {
+ if (a.byteLength == this.F.n8*3) {
+ const x = this.F.toString(a.slice(0, this.F.n8), radix);
+ const y = this.F.toString(a.slice(this.F.n8, this.F.n8*2), radix);
+ const z = this.F.toString(a.slice(this.F.n8*2), radix);
+ return `[ ${x}, ${y}, ${z} ]`;
+ } else if (a.byteLength == this.F.n8*2) {
+ const x = this.F.toString(a.slice(0, this.F.n8), radix);
+ const y = this.F.toString(a.slice(this.F.n8), radix);
+ return `[ ${x}, ${y} ]`;
+ } else {
+ throw new Error("invalid point size");
+ }
}
- while (isPositive(exp)) {
- if (base === 0n) return 0n;
- if (isOdd$4(exp)) r = r * base % mod;
- exp = exp / 2n;
- base = square$1(base) % mod;
+
+ isValid(a) {
+ if (this.isZero(a)) return true;
+ const F = this.F;
+ const aa = this.toAffine(a);
+ const x = aa.slice(0, this.F.n8);
+ const y = aa.slice(this.F.n8, this.F.n8*2);
+ const x3b = F.add(F.mul(F.square(x),x), this.b);
+ const y2 = F.square(y);
+ return F.eq(x3b, y2);
}
- return r;
-}
-function compareAbs(a, b) {
- a = a >= 0n ? a : -a;
- b = b >= 0n ? b : -b;
- return a === b ? 0 : a > b ? 1 : -1;
-}
+ fromRng(rng) {
+ const F = this.F;
+ let P = [];
+ let greatest;
+ let x3b;
+ do {
+ P[0] = F.fromRng(rng);
+ greatest = rng.nextBool();
+ x3b = F.add(F.mul(F.square(P[0]), P[0]), this.b);
+ } while (!F.isSquare(x3b));
-function isDivisibleBy(a, n) {
- if (n === 0n) return false;
- if (isUnit(n)) return true;
- if (compareAbs(n, 2n) === 0) return isEven(a);
- return a % n === 0n;
-}
+ P[1] = F.sqrt(x3b);
-function isBasicPrime(v) {
- var n = abs(v);
- if (isUnit(n)) return false;
- if (n === 2n || n === 3n || n === 5n) return true;
- if (isEven(n) || isDivisibleBy(n, 3n) || isDivisibleBy(n, 5n)) return false;
- if (n < 49n) return true;
- // we don't know if it's prime: let the other functions figure it out
-}
+ const s = F.isNegative(P[1]);
+ if (greatest ^ s) P[1] = F.neg(P[1]);
-function prev(n) {
- return n - 1n;
-}
+ let Pbuff = new Uint8Array(this.F.n8*2);
+ Pbuff.set(P[0]);
+ Pbuff.set(P[1], this.F.n8);
-function millerRabinTest(n, a) {
- var nPrev = prev(n),
- b = nPrev,
- r = 0,
- d, i, x;
- while (isEven(b)) b = b / 2n, r++;
- next: for (i = 0; i < a.length; i++) {
- if (n < a[i]) continue;
- x = modPow$2(BigInt(a[i]), b, n);
- if (isUnit(x) || x === nPrev) continue;
- for (d = r - 1; d != 0; d--) {
- x = square$1(x) % n;
- if (isUnit(x)) return false;
- if (x === nPrev) continue next;
+ if (this.cofactor) {
+ Pbuff = this.timesScalar(Pbuff, this.cofactor);
}
- return false;
- }
- return true;
-}
-function isPrime$1(p) {
- var isPrime = isBasicPrime(p);
- if (isPrime !== undefined) return isPrime;
- var n = abs(p);
- var bits = bitLength$5(n);
- if (bits <= 64)
- return millerRabinTest(n, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]);
- var logN = Math.log(2) * Number(bits);
- var t = Math.ceil(logN);
- for (var a = [], i = 0; i < t; i++) {
- a.push(BigInt(i + 2));
+ return Pbuff;
}
- return millerRabinTest(n, a);
-}
-
-bigint.bitLength = bitLength$5;
-bigint.isOdd = isOdd$4;
-bigint.isNegative = isNegative$3;
-bigint.abs = abs;
-bigint.isUnit = isUnit;
-bigint.compare = compare;
-bigint.modInv = modInv$3;
-bigint.modPow = modPow$2;
-bigint.isPrime = isPrime$1;
-bigint.square = square$1;
-/*
- 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.
+ toObject(a) {
+ if (this.isZero(a)) {
+ return [
+ this.F.toObject(this.F.zero),
+ this.F.toObject(this.F.one),
+ this.F.toObject(this.F.zero),
+ ];
+ }
+ const x = this.F.toObject(a.slice(0, this.F.n8));
+ const y = this.F.toObject(a.slice(this.F.n8, this.F.n8*2));
+ let z;
+ if (a.byteLength == this.F.n8*3) {
+ z = this.F.toObject(a.slice(this.F.n8*2, this.F.n8*3));
+ } else {
+ z = this.F.toObject(this.F.one);
+ }
+ return [x, y, z];
+ }
- 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.
+ fromObject(a) {
+ const x = this.F.fromObject(a[0]);
+ const y = this.F.fromObject(a[1]);
+ let z;
+ if (a.length==3) {
+ z = this.F.fromObject(a[2]);
+ } else {
+ z = this.F.one;
+ }
+ if (this.F.isZero(z, this.F.one)) {
+ return this.zeroAffine;
+ } else if (this.F.eq(z, this.F.one)) {
+ const buff = new Uint8Array(this.F.n8*2);
+ buff.set(x);
+ buff.set(y, this.F.n8);
+ return buff;
+ } else {
+ const buff = new Uint8Array(this.F.n8*3);
+ buff.set(x);
+ buff.set(y, this.F.n8);
+ buff.set(z, this.F.n8*2);
+ return buff;
+ }
+ }
- You should have received a copy of the GNU General Public License
- along with wasmsnark. If not, see .
-*/
+ e(a) {
+ if (a instanceof Uint8Array) return a;
+ return this.fromObject(a);
+ }
-const buildInt = build_int;
-const utils$5 = utils$6;
-const buildExp$2 = build_timesscalar;
-const buildBatchInverse$2 = build_batchinverse;
-const buildBatchConvertion$1 = build_batchconvertion;
-const buildBatchOp = build_batchop;
-const { bitLength: bitLength$4, modInv: modInv$2, modPow: modPow$1, isPrime, isOdd: isOdd$3, square } = bigint;
+ x(a) {
+ const tmp = this.toAffine(a);
+ return tmp.slice(0, this.F.n8);
+ }
-var build_f1m = function buildF1m(module, _q, _prefix, _intPrefix) {
- const q = BigInt(_q);
- const n64 = Math.floor((bitLength$4(q - 1n) - 1)/64) +1;
- const n32 = n64*2;
- const n8 = n64*8;
+ y(a) {
+ const tmp = this.toAffine(a);
+ return tmp.slice(this.F.n8);
+ }
- const prefix = _prefix || "f1m";
- if (module.modules[prefix]) return prefix; // already builded
+}
- const intPrefix = buildInt(module, n64, _intPrefix);
- const pq = module.alloc(n8, utils$5.bigInt2BytesLE(q, n8));
+/* global WebAssembly */
- const pR2 = module.alloc(utils$5.bigInt2BytesLE(square(1n << BigInt(n64*64)) % q, n8));
- const pOne = module.alloc(utils$5.bigInt2BytesLE((1n << BigInt(n64*64)) % q, n8));
- const pZero = module.alloc(utils$5.bigInt2BytesLE(0n, n8));
- const _minusOne = q - 1n;
- const _e = _minusOne >> 1n; // e = (p-1)/2
- const pe = module.alloc(n8, utils$5.bigInt2BytesLE(_e, n8));
+function thread(self) {
+ const MAXMEM = 32767;
+ let instance;
+ let memory;
+ let terminationTimeout = 500; // milliseconds
+ let terminationTimer;
- const _ePlusOne = _e + 1n; // e = (p-1)/2
- const pePlusOne = module.alloc(n8, utils$5.bigInt2BytesLE(_ePlusOne, n8));
+ if (self) {
+ self.onmessage = function(e) {
+ let data;
+ if (e.data) {
+ data = e.data;
+ } else {
+ data = e;
+ }
- module.modules[prefix] = {
- pq: pq,
- pR2: pR2,
- n64: n64,
- q: q,
- pOne: pOne,
- pZero: pZero,
- pePlusOne: pePlusOne
- };
+ try {
+ if (data[0].cmd === "INIT") {
+ init(data[0]).then(function() {
+ console.log("INIT DONE");
+ self.postMessage({status: "initialized"});
+ });
+ } else if (data[0].cmd === "TERMINATE") {
+ terminate();
+ } else {
+ if (data[data.length-1].cmd === "TERMINATE") {
+ data.pop();
+ //terminationTimeout = 1;
+ }
+ const res = runTask(data);
+ //self.postMessage(res);
+ let transfers = [];
+ 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);
+ console.log("Growing memory to", memory.buffer.byteLength / 1024 / 1024, "MB");
+ }
+ return res;
}
- 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 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);
+ return new Uint8Array(memory.buffer, pointer, length);
+ }
- function buildIsNegative() {
- const f = module.addFunction(prefix+"_isNegative");
- f.addParam("x", "i32");
- f.setReturnType("i32");
+ function setBuffer(pointer, buffer) {
+ const u8 = new Uint8Array(memory.buffer);
+ u8.set(new Uint8Array(buffer), pointer);
+ }
- const c = f.getCodeBuilder();
+ function runTask(task) {
+ clearTimeout(terminationTimer);
+ 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; i0) {
+ terminationTimer = setTimeout( () => {
+ console.log("Shutting down thread due to inactivity");
+ terminate();
+ }, terminationTimeout);
+ }
}
+ function terminate() {
+ clearTimeout(terminationTimer);
+ instance = null;
+ memory = null;
+ if (self) {
+ console.log("TERMINATE");
+ self.postMessage({status: "terminated"});
+ self.close();
+ }
+ }
- 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();
+ return runTask;
+}
- const np32 = Number(0x100000000n - modInv$2(q, 0x100000000n));
+/*
+ Copyright 2019 0KIMS association.
- f.addCode(c.setLocal("np32", c.i64_const(np32)));
+ This file is part of wasmsnark (Web Assembly zkSnark Prover).
- for (let i=0; i.
+*/
- f.addCode(
- c.setLocal("c",
- c.i64_add(
- c.i64_add(
- c.i64_load32_u(c.getLocal("t"), (i+j)*4),
- c.i64_shr_u(c.getLocal("c"), c.i64_const(32))
- ),
- c.i64_mul(
- c.i64_load32_u(c.i32_const(pq), j*4),
- c.getLocal("m")
- )
- )
- )
- );
+// const MEM_SIZE = 1000; // Memory size in 64K Pakes (512Mb)
+const MEM_SIZE = 25; // Memory size in 64K Pakes (1600Kb)
- f.addCode(
- c.i64_store32(
- c.getLocal("t"),
- (i+j)*4,
- c.getLocal("c")
- )
- );
- }
+class Deferred {
+ constructor() {
+ this.promise = new Promise((resolve, reject)=> {
+ this.reject = reject;
+ this.resolve = resolve;
+ });
+ }
+}
- f.addCode(
- c.i64_store32(
- c.i32_const(carries),
- i*4,
- c.i64_shr_u(c.getLocal("c"), c.i64_const(32))
- )
- );
- }
+let workerSource;
- f.addCode(
- c.call(
- prefix+"_add",
- c.i32_const(carries),
- c.i32_add(
- c.getLocal("t"),
- c.i32_const(n32*4)
- ),
- c.getLocal("r")
- )
- );
+const threadStr = `(${"function thread(self) {\n const MAXMEM = 32767;\n let instance;\n let memory;\n let terminationTimeout = 500; // milliseconds\n let terminationTimer;\n\n if (self) {\n self.onmessage = function(e) {\n let data;\n if (e.data) {\n data = e.data;\n } else {\n data = e;\n }\n\n try {\n if (data[0].cmd === \"INIT\") {\n init(data[0]).then(function() {\n console.log(\"INIT DONE\");\n self.postMessage({status: \"initialized\"});\n });\n } else if (data[0].cmd === \"TERMINATE\") {\n terminate();\n } else {\n let terminateAfterTask = false;\n if (data[data.length-1].cmd === \"TERMINATE\") {\n terminateAfterTask = true;\n data.pop();\n //terminationTimeout = 1;\n }\n const res = runTask(data);\n //self.postMessage(res);\n let transfers = [];\n for (let i=0; i memory.buffer.byteLength) {\n const currentPages = memory.buffer.byteLength / 0x10000;\n let requiredPages = Math.floor((u32[0] + length) / 0x10000)+1;\n if (requiredPages>MAXMEM) requiredPages=MAXMEM;\n memory.grow(requiredPages-currentPages);\n console.log(\"Growing memory to\", memory.buffer.byteLength / 1024 / 1024, \"MB\");\n }\n return res;\n }\n\n function allocBuffer(buffer) {\n const p = alloc(buffer.byteLength);\n setBuffer(p, buffer);\n return p;\n }\n\n function getBuffer(pointer, length) {\n // const u8 = new Uint8Array(memory.buffer);\n // return new Uint8Array(u8.buffer, u8.byteOffset + pointer, length);\n return new Uint8Array(memory.buffer, pointer, length);\n }\n\n function setBuffer(pointer, buffer) {\n const u8 = new Uint8Array(memory.buffer);\n u8.set(new Uint8Array(buffer), pointer);\n }\n\n function runTask(task) {\n clearTimeout(terminationTimer);\n if (task[0].cmd === \"INIT\") {\n return init(task[0]);\n }\n const ctx = {\n vars: [],\n out: []\n };\n const u32a = new Uint32Array(memory.buffer, 0, 1);\n const oldAlloc = u32a[0];\n for (let i=0; i0) {\n terminationTimer = setTimeout( () => {\n console.log(\"Shutting down thread due to inactivity\");\n terminate();\n }, terminationTimeout);\n }\n }\n\n function terminate() {\n clearTimeout(terminationTimer);\n instance = null;\n memory = null;\n if (self) {\n console.log(\"TERMINATE\");\n self.postMessage({status: \"terminated\"});\n self.close();\n }\n }\n\n return runTask;\n}"})(self)`;
+{
+ if(globalThis?.Blob) {
+ const threadBytes= new TextEncoder().encode(threadStr);
+ const workerBlob = new Blob([threadBytes], { type: "application/javascript" }) ;
+ workerSource = URL.createObjectURL(workerBlob);
+ } else {
+ workerSource = "data:application/javascript;base64," + globalThis.btoa(threadStr);
}
+}
- function buildMul() {
+async function buildThreadManager(wasm, singleThread) {
+ const tm = new ThreadManager();
- const f = module.addFunction(prefix+"_mul");
- f.addParam("x", "i32");
- f.addParam("y", "i32");
- f.addParam("r", "i32");
- f.addLocal("c0", "i64");
- f.addLocal("c1", "i64");
- f.addLocal("np32", "i64");
+ 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);
- for (let i=0;i64) concurrency=64;
+ tm.concurrency = concurrency;
- let c0 = "c0";
- let c1 = "c1";
+ // for (let i = 0; i<1; i++) {
+ //
+ // tm.workers[i] = new Worker(workerSource);
+ //
+ // tm.workers[i].addEventListener("message", getOnMsg(i));
+ // //tm.workers[i].addEventListener("error", getOnError(i));
+ //
+ // tm.working[i]=false;
+ // }
+ //
+ // const initPromises = [];
+ // for (let i=0; i=n32) {
- f.addCode(
- c.i64_store32(
- c.getLocal("r"),
- (k-n32)*4,
- c.getLocal(c0)
- )
- );
+ // handle status messages
+ if (data.status) {
+ if (data.status === "initialized") {
+ // Initialization successful message
+ tm.initializing[i]=false;
+ tm.initialized[i]=true;
+ } else if (data.status === "terminated") {
+ // Termination successful message
+ tm.initialized[i]=false;
+ tm.initializing[i]=false;
+ tm.workers[i]=null;
+ }
}
- [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"))),
- )
- )
- );
+ tm.working[i]=false;
+ tm.pendingDeferreds[i].resolve(data);
+ tm.processWorks();
+ };
}
+ getOnError(i) {
+ const tm = this;
+ return function(e) {
+ tm.working[i]=false;
+ tm.pendingDeferreds[i].reject(e.message);
+ throw new Error("Worker error: " + e.message);
+ };
+ }
- function buildSquare() {
+ startWorker(i){
+ this.workers[i] = new Worker(workerSource);
- 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");
+ this.workers[i].addEventListener("message", this.getOnMsg(i));
+ //tm.workers[i].addEventListener("error", this.getOnError(i));
+ //this.working[i]=true;
+ this.initializing[i] = true;
- for (let i=0;i {
+ this.initialized[i] = true;
+ });
+ }
- const np32 = Number(0x100000000n - modInv$2(q, 0x100000000n));
+ startSyncOp() {
+ if (this.oldPFree !== 0) throw new Error("Sync operation in progress");
+ this.oldPFree = this.u32[0];
+ }
- f.addCode(c.setLocal("np32", c.i64_const(np32)));
+ endSyncOp() {
+ if (this.oldPFree === 0) throw new Error("No sync operation in progress");
+ this.u32[0] = this.oldPFree;
+ this.oldPFree = 0;
+ }
+ async postAction(workerId, e, transfers, _deferred) {
+ if (this.working[workerId]) {
+ throw new Error("Posting a job to a working worker");
+ }
+ this.working[workerId] = true;
- const loadX = [];
- const loadQ = [];
- function mulij(i, j) {
- let X,Y;
- if (!loadX[i]) {
- X = c.teeLocal("x"+i, c.i64_load32_u( c.getLocal("x"), i*4));
- loadX[i] = true;
- } else {
- X = c.getLocal("x"+i);
- }
- if (!loadX[j]) {
- Y = c.teeLocal("x"+j, c.i64_load32_u( c.getLocal("x"), j*4));
- loadX[j] = true;
- } else {
- Y = c.getLocal("x"+j);
- }
+ this.pendingDeferreds[workerId] = _deferred ? _deferred : new Deferred();
+ await this.workers[workerId].postMessage(e, transfers);
- return c.i64_mul( X, Y );
- }
+ return this.pendingDeferreds[workerId].promise;
+ }
- function mulqm(i, j) {
- let Q,M;
- if (!loadQ[i]) {
- Q = c.teeLocal("q"+i, c.i64_load32_u(c.i32_const(0), pq+i*4 ));
- loadQ[i] = true;
- } else {
- Q = c.getLocal("q"+i);
+ async processWorks() {
+ for (let i=0; (i 0); i++) {
+ if (this.workers[i] && this.initialized[i] && !this.working[i]) {
+ const work = this.actionQueue.shift();
+ this.postAction(i, work.data, work.transfers, work.deferred);
}
- M = c.getLocal("m"+j);
+ }
- return c.i64_mul( Q, M );
+ // Initialize more workers if needed
+ if (this.actionQueue.length > 0) {
+ // Find a worker that is not initialized yet
+ let initializingCount = 0;
+ for (let i=0; i= this.actionQueue.length) break;
+
+ // Initialize this worker
+ console.log(`Worker ${i} not initialized yet. Initializing...`);
+ initializingCount++;
+ await this.startWorker(i);
+ //this.startWorker(i);
+ }
}
+ }
+ queueAction(actionData, transfers) {
+ const d = new Deferred();
- let c0 = "c0";
- let c1 = "c1";
- let c0_old = "c0_old";
- let c1_old = "c1_old";
+ 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;
+ }
- for (let k=0; k>1) )&&(i>1, k>>1)
- )
- )
- );
+ async terminate() {
+ console.log("terminate!!!");
+ for (let i=0; i0) {
- 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)
- ),
- )
- )
- );
+ const b = buff.slice(i*pointsPerChunk*sGin, i*pointsPerChunk*sGin + n*sGin);
- 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)
- )
- )
- );
+ task.push({
+ cmd: "ALLOCSET",
+ var: 0,
+ buff: b
+ });
+ task.push({cmd: "ALLOCSET", var: 1, buff: t});
+ task.push({cmd: "ALLOCSET", var: 2, buff: inc});
+ task.push({cmd: "ALLOC", var: 3, len: n*Math.max(sGmid, sGout)});
+ task.push({
+ cmd: "CALL",
+ fnName: fnName,
+ params: [
+ {var: 0},
+ {val: n},
+ {var: 1},
+ {var: 2},
+ {var:3}
+ ]
+ });
+ if (fnAffine) {
+ task.push({
+ cmd: "CALL",
+ fnName: fnAffine,
+ params: [
+ {var: 3},
+ {val: n},
+ {var: 3},
+ ]
+ });
}
+ task.push({cmd: "GET", out: 0, var: 3, len: n*sGout});
+ opPromises.push(tm.queueAction(task, [b.buffer]));
+ t = Fr.mul(t, Fr.exp(inc, n));
+ }
- 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)
- )
- );
+ const res = tm.getBuff(pRes, curve.Gt.n8);
- 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"))),
- )
- )
- );
- }
+ tm.endSyncOp();
+ return res;
+ };
+ curve.pairingEq = async function pairingEq() {
+ let buffCt;
+ let nEqs;
+ if ((arguments.length % 2) == 1) {
+ buffCt = arguments[arguments.length-1];
+ nEqs = (arguments.length -1) /2;
+ } else {
+ buffCt = curve.Gt.one;
+ nEqs = arguments.length /2;
+ }
- function buildSquareOld() {
- const f = module.addFunction(prefix+"_squareOld");
- f.addParam("x", "i32");
- f.addParam("r", "i32");
+ const opPromises = [];
+ for (let i=0; i> 1n;
- }
- const pt = module.alloc(n8, utils$5.bigInt2BytesLE(_t, n8));
+ tm.endSyncOp();
- const _nqrToT = modPow$1(_nqr, _t, q);
- const pNqrToT = module.alloc(utils$5.bigInt2BytesLE((_nqrToT << BigInt(n64*64)) % q, n8));
+ return r;
+ };
- const _tPlusOneOver2 = (_t + 1n) >> 1n;
- const ptPlusOneOver2 = module.alloc(n8, utils$5.bigInt2BytesLE(_tPlusOneOver2, n8));
+ curve.prepareG1 = function(p) {
+ this.tm.startSyncOp();
+ const pP = this.tm.allocBuff(p);
+ const pPrepP = this.tm.alloc(this.prePSize);
+ this.tm.instance.exports[this.name + "_prepareG1"](pP, pPrepP);
+ const res = this.tm.getBuff(pPrepP, this.prePSize);
+ this.tm.endSyncOp();
+ return res;
+ };
- function buildSqrt() {
+ curve.prepareG2 = function(q) {
+ this.tm.startSyncOp();
+ const pQ = this.tm.allocBuff(q);
+ const pPrepQ = this.tm.alloc(this.preQSize);
+ this.tm.instance.exports[this.name + "_prepareG2"](pQ, pPrepQ);
+ const res = this.tm.getBuff(pPrepQ, this.preQSize);
+ this.tm.endSyncOp();
+ return res;
+ };
- 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");
+ curve.millerLoop = function(preP, preQ) {
+ this.tm.startSyncOp();
+ const pPreP = this.tm.allocBuff(preP);
+ const pPreQ = this.tm.allocBuff(preQ);
+ const pRes = this.tm.alloc(this.Gt.n8);
+ this.tm.instance.exports[this.name + "_millerLoop"](pPreP, pPreQ, pRes);
+ const res = this.tm.getBuff(pRes, this.Gt.n8);
+ this.tm.endSyncOp();
+ return res;
+ };
- const c = f.getCodeBuilder();
+ curve.finalExponentiation = function(a) {
+ this.tm.startSyncOp();
+ const pA = this.tm.allocBuff(a);
+ const pRes = this.tm.alloc(this.Gt.n8);
+ this.tm.instance.exports[this.name + "_finalExponentiation"](pA, pRes);
+ const res = this.tm.getBuff(pRes, this.Gt.n8);
+ this.tm.endSyncOp();
+ return res;
+ };
- 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(
+/* eslint-disable indent */
- // If (n==0) return 0
- c.if(
- c.call(prefix + "_isZero", c.getLocal("n")),
- c.ret(
- c.call(prefix + "_zero", c.getLocal("r"))
- )
- ),
+const pTSizes = [
+ 1 , 1, 1, 1, 2, 3, 4, 5,
+ 6 , 7, 7, 8, 9, 10, 11, 12,
+ 13, 13, 14, 15, 16, 16, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17
+];
- 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),
+function buildMultiexp$1(curve, groupName) {
+ const G = curve[groupName];
+ const tm = G.tm;
- c.block(c.loop(
- c.br_if(1, c.call(prefix + "_eq", T, ONE)),
+ async function _multiExpChunk(buffBases, buffScalars, inType, logger, logText) {
+ if ( ! (buffBases instanceof Uint8Array) ) {
+ if (logger) logger.error(`${logText} _multiExpChunk buffBases is not Uint8Array`);
+ throw new Error(`${logText} _multiExpChunk buffBases is not Uint8Array`);
+ }
+ if ( ! (buffScalars instanceof Uint8Array) ) {
+ if (logger) logger.error(`${logText} _multiExpChunk buffScalars is not Uint8Array`);
+ throw new Error(`${logText} _multiExpChunk buffScalars is not Uint8Array`);
+ }
+ inType = inType || "affine";
- 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)
- )),
+ let sGIn;
+ let fnName;
+ if (groupName === "G1") {
+ if (inType === "affine") {
+ fnName = "g1m_multiexpAffine";
+ sGIn = G.F.n8*2;
+ } else {
+ fnName = "g1m_multiexp";
+ sGIn = G.F.n8*3;
+ }
+ } else if (groupName === "G2") {
+ if (inType === "affine") {
+ fnName = "g2m_multiexpAffine";
+ sGIn = G.F.n8*2;
+ } else {
+ fnName = "g2m_multiexp";
+ sGIn = G.F.n8*3;
+ }
+ } else {
+ throw new Error("Invalid group");
+ }
+ const nPoints = Math.floor(buffBases.byteLength / sGIn);
- 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)
- )),
+ if (nPoints === 0) return G.zero;
+ const sScalar = Math.floor(buffScalars.byteLength / nPoints);
+ if( sScalar * nPoints !== buffScalars.byteLength) {
+ throw new Error("Scalar size does not match");
+ }
- 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),
+ const bitChunkSize = pTSizes[log2(nPoints)];
- c.br(0)
- )),
+ const opPromises = [];
- c.if(
- c.call(prefix + "_isNegative", R),
- c.call(prefix + "_neg", R, c.getLocal("r")),
- c.call(prefix + "_copy", R, c.getLocal("r")),
- )
+ const task = [
+ {cmd: "ALLOCSET", var: 0, buff: buffBases},
+ {cmd: "ALLOCSET", var: 1, buff: buffScalars},
+ {cmd: "ALLOC", var: 2, len: G.F.n8*3},
+ {cmd: "CALL", fnName: fnName, params: [
+ {var: 0}, //pBases
+ {var: 1}, // pScalars
+ {val: sScalar}, // scalarSize
+ {val: nPoints}, // nPoints
+ {var: 2} // pr
+ ]},
+ {cmd: "GET", out: 0, var: 2, len: G.F.n8*3}
+ ];
+ opPromises.push(
+ // transfer ownership of the buffers to the worker thread
+ G.tm.queueAction(task, [buffBases.buffer, buffScalars.buffer])
);
+
+ const result = await Promise.all(opPromises);
+
+ let res = G.zero;
+ for (let i=result.length-1; 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 c = f.getCodeBuilder();
+ let result = await Promise.all(opPromises);
- const AUX = c.i32_const(module.alloc(n8));
+ let res = G.zero;
+ for (let i=result.length-1; i>=0; i--) {
+ res = G.add(res, result[i]);
+ }
- 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")),
- );
+ return res;
}
- function buildIsOne() {
- const f = module.addFunction(prefix+"_isOne");
- f.addParam("x", "i32");
- f.setReturnType("i32");
+ 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);
+ };
+}
- const c = f.getCodeBuilder();
- f.addCode(
- c.ret(c.call(intPrefix + "_eq", c.getLocal("x"), c.i32_const(pOne)))
- );
- }
+function buildFFT$2(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;
- module.exportFunction(intPrefix + "_copy", prefix+"_copy");
- module.exportFunction(intPrefix + "_zero", prefix+"_zero");
- module.exportFunction(intPrefix + "_isZero", prefix+"_isZero");
- module.exportFunction(intPrefix + "_eq", prefix+"_eq");
+ let sIn, sMid, sOut, fnIn2Mid, fnMid2Out, fnFFTMix, fnFFTJoin, fnFFTFinal, fnReversePermutation;
+ 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";
+ fnReversePermutation = "g1m_reversePermutation";
- 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 (isPrime(q)) {
- 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.
+ if (outType == "affine") {
+ sOut = G.F.n8*2;
+ fnMid2Out = "g1m_batchToAffine";
+ } else {
+ sOut = G.F.n8*3;
+ }
- 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.
+ } 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";
+ fnReversePermutation = "g2m_reversePermutation";
+ 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";
+ fnReversePermutation = "frm_fftReversePermutation";
+ }
- You should have received a copy of the GNU General Public License
- along with wasmsnark. If not, see .
-*/
-const buildF1m$2 =build_f1m;
-const { bitLength: bitLength$3 } = bigint;
+ let returnArray = false;
+ if (Array.isArray(buff)) {
+ buff = array2buffer(buff, sIn);
+ returnArray = true;
+ } else {
+ buff = buff.slice(0, buff.byteLength);
+ }
-var build_f1 = function buildF1(module, _q, _prefix, _f1mPrefix, _intPrefix) {
+ console.log("FFT input size:", buff.byteLength, " bytes");
- const q = BigInt(_q);
- const n64 = Math.floor((bitLength$3(q - 1n) - 1)/64) +1;
- const n8 = n64*8;
+ const nPoints = buff.byteLength / sIn;
+ const bits = log2(nPoints);
- const prefix = _prefix || "f1";
- if (module.modules[prefix]) return prefix; // already builded
- module.modules[prefix] = {
- n64: n64
- };
+ console.log("FFT points:", nPoints, " bits:", bits);
- const intPrefix = _intPrefix || "int";
- const f1mPrefix = buildF1m$2(module, q, _f1mPrefix, intPrefix);
+ if ((1 << bits) != nPoints) {
+ throw new Error("fft must be multiple of 2" );
+ }
+ if (bits == Fr.s +1) {
+ let buffOut;
- const pR2 = module.modules[f1mPrefix].pR2;
- const pq = module.modules[f1mPrefix].pq;
- const pePlusOne = module.modules[f1mPrefix].pePlusOne;
+ if (inverse) {
+ buffOut = await _fftExtInv(buff, inType, outType, logger, loggerTxt);
+ } else {
+ buffOut = await _fftExt(buff, inType, outType, logger, loggerTxt);
+ }
- function buildMul() {
- const pAux1 = module.alloc(n8);
+ if (returnArray) {
+ return buffer2array(buffOut, sOut);
+ } else {
+ return buffOut;
+ }
+ }
- const f = module.addFunction(prefix+ "_mul");
- f.addParam("x", "i32");
- f.addParam("y", "i32");
- f.addParam("r", "i32");
+ let inv;
+ if (inverse) {
+ inv = Fr.inv(Fr.e(nPoints));
+ }
- 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")));
- }
+ let buffOut;
- function buildSquare() {
- const f = module.addFunction(prefix+"_square");
- f.addParam("x", "i32");
- f.addParam("r", "i32");
+ // TODO: optimize. Move to wasm?
+ //buffReverseBits(buff, sIn);
- const c = f.getCodeBuilder();
+ console.log("fnReversePermutation:", fnReversePermutation);
- f.addCode(c.call(prefix + "_mul", c.getLocal("x"), c.getLocal("x"), c.getLocal("r")));
- }
+ const task = [];
+ task.push({cmd: "ALLOC", var: 0, len: buff.byteLength});
+ task.push({cmd: "SET", var: 0, buff: buff});
+ task.push({cmd: "CALL", fnName: fnReversePermutation, params: [{var:0}, {val: bits}, {var: 0}]});
+ task.push({cmd: "GET", out:0, var: 0, len: buff.byteLength});
+ const res = await tm.queueAction(task, [buff.buffer]);
+ buff.set(res[0]);
- function buildInverse() {
+ let chunks;
+ let pointsInChunk = Math.min(1 << MAX_BITS_THREAD, nPoints);
+ let nChunks = nPoints / pointsInChunk;
- const f = module.addFunction(prefix+ "_inverse");
- f.addParam("x", "i32");
- f.addParam("r", "i32");
+ while ((nChunks < tm.concurrency)&&(pointsInChunk>=16)) {
+ nChunks *= 2;
+ pointsInChunk /= 2;
+ }
- const c = f.getCodeBuilder();
- f.addCode(c.call(intPrefix + "_inverseMod", c.getLocal("x"), c.i32_const(pq), c.getLocal("r")));
- }
+ const l2Chunk = log2(pointsInChunk);
- function buildIsNegative() {
- const f = module.addFunction(prefix+"_isNegative");
- f.addParam("x", "i32");
- f.setReturnType("i32");
+ 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}]});
+ }
- const c = f.getCodeBuilder();
+ 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, [buffChunk.buffer]).then( (r) => {
+ if (logger) logger.debug(`${loggerTxt}: fft ${bits} mix end: ${i}/${nChunks}`);
+ return r;
+ }));
+ }
- f.addCode(
- c.call(intPrefix + "_gte", c.getLocal("x"), c.i32_const(pePlusOne) )
- );
- }
+ 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;
+ }));
+ }
+ }
- return prefix;
-};
+ 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.
-*/
+ [b1, b2] = await _fftJoinExt(b1, b2, "fftJoinExt", Fr.one, Fr.shift, inType, "jacobian", logger, loggerTxt);
-const buildExp$1 = build_timesscalar;
-const buildBatchInverse$1 = build_batchinverse;
-const utils$4 = utils$6;
+ promises.push( _fft(b1, false, "jacobian", outType, logger, loggerTxt));
+ promises.push( _fft(b2, false, "jacobian", outType, logger, loggerTxt));
-var build_f2m = function buildF2m(module, mulNonResidueFn, prefix, f1mPrefix) {
+ const res1 = await Promise.all(promises);
- if (module.modules[prefix]) return prefix; // already builded
+ let buffOut;
+ if (res1[0].byteLength > (1<<28)) {
+ buffOut = new BigBuffer(res1[0].byteLength*2);
+ } else {
+ buffOut = new Uint8Array(res1[0].byteLength*2);
+ }
- const f1n8 = module.modules[f1mPrefix].n64*8;
- const q = module.modules[f1mPrefix].q;
+ buffOut.set(res1[0]);
+ buffOut.set(res1[1], res1[0].byteLength);
- module.modules[prefix] = {
- n64: module.modules[f1mPrefix].n64*2
- };
+ return buffOut;
+ }
- function buildAdd() {
- const f = module.addFunction(prefix+"_add");
- f.addParam("x", "i32");
- f.addParam("y", "i32");
- f.addParam("r", "i32");
+ 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 c = f.getCodeBuilder();
+ const promises = [];
- 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));
+ promises.push( _fft(b1, true, inType, "jacobian", logger, loggerTxt));
+ promises.push( _fft(b2, true, inType, "jacobian", logger, loggerTxt));
- f.addCode(
- c.call(f1mPrefix+"_add", x0, y0, r0),
- c.call(f1mPrefix+"_add", x1, y1, r1),
- );
- }
+ [b1, b2] = await Promise.all(promises);
- 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 res1 = await _fftJoinExt(b1, b2, "fftJoinExtInv", Fr.one, Fr.shiftInv, "jacobian", outType, logger, loggerTxt);
- const c = f.getCodeBuilder();
+ let buffOut;
+ if (res1[0].byteLength > (1<<28)) {
+ buffOut = new BigBuffer(res1[0].byteLength*2);
+ } else {
+ buffOut = new Uint8Array(res1[0].byteLength*2);
+ }
- 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));
+ buffOut.set(res1[0]);
+ buffOut.set(res1[1], res1[0].byteLength);
- 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),
- );
+ return buffOut;
}
- function buildSub() {
- const f = module.addFunction(prefix+"_sub");
- f.addParam("x", "i32");
- f.addParam("y", "i32");
- f.addParam("r", "i32");
- const c = f.getCodeBuilder();
+ async function _fftJoinExt(buff1, buff2, fn, first, inc, inType, outType, logger, loggerTxt) {
+ const MAX_CHUNK_SIZE = 1<<16;
+ const MIN_CHUNK_SIZE = 1<<4;
- 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));
+ let fnName;
+ let fnIn2Mid, fnMid2Out;
+ let sOut, sIn, sMid;
- f.addCode(
- c.call(f1mPrefix+"_sub", x0, y0, r0),
- c.call(f1mPrefix+"_sub", x1, y1, r1),
- );
- }
+ 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");
+ }
- function buildNeg() {
- const f = module.addFunction(prefix+"_neg");
- f.addParam("x", "i32");
- f.addParam("r", "i32");
+ 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");
+ }
- const c = f.getCodeBuilder();
+ 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 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 opPromises = [];
- 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();
+ for (let i=0; i {
+ if (logger) logger.debug(`${loggerTxt}: fftJoinExt End: ${i}/${nPoints}`);
+ return r;
+ })
+ );
+ }
- function buildIsNegative() {
- const f = module.addFunction(prefix+"_isNegative");
- f.addParam("x", "i32");
- f.setReturnType("i32");
+ const result = await Promise.all(opPromises);
- const c = f.getCodeBuilder();
+ 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);
+ }
- const x0 = c.getLocal("x");
- const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
+ 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");
+ }
- f.addCode(
- c.call(f1mPrefix + "_mul", x0, y, r0), // A = x0*y
- c.call(f1mPrefix + "_mul", x1, y, r1), // B = x1*y
- );
- }
+ let t0 = buff.slice(0, buff.byteLength/2);
+ let t1 = buff.slice(buff.byteLength/2, buff.byteLength);
- function buildSquare() {
- const f = module.addFunction(prefix+"_square");
- f.addParam("x", "i32");
- f.addParam("r", "i32");
- const c = f.getCodeBuilder();
+ const shiftToSmallM = Fr.exp(Fr.shift, nPoints/2);
+ const sConst = Fr.inv( Fr.sub(Fr.one, shiftToSmallM));
- 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));
+ [t0, t1] = await _fftJoinExt(t0, t1, "prepareLagrangeEvaluation", sConst, Fr.shiftInv, inType, "jacobian", logger, loggerTxt + " prep");
- 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));
+ const promises = [];
+ promises.push( _fft(t0, true, "jacobian", outType, logger, loggerTxt + " t0"));
+ promises.push( _fft(t1, true, "jacobian", outType, logger, loggerTxt + " t1"));
- f.addCode(
- // AB = x0*y1
- c.call(f1mPrefix + "_mul", x0, x1, AB),
+ [t0, t1] = await Promise.all(promises);
- // APB = x0+y1
- c.call(f1mPrefix + "_add", x0, x1, APB),
+ let buffOut;
+ if (t0.byteLength > (1<<28)) {
+ buffOut = new BigBuffer(t0.byteLength*2);
+ } else {
+ buffOut = new Uint8Array(t0.byteLength*2);
+ }
- // APBN0 = x0 + nr*x1
- c.call(mulNonResidueFn, x1, APNB),
- c.call(f1mPrefix + "_add", x0, APNB, APNB),
+ buffOut.set(t0);
+ buffOut.set(t1, t0.byteLength);
- // ABPNAB = ab + nr*ab
- c.call(mulNonResidueFn, AB, ABPNAB),
- c.call(f1mPrefix + "_add", ABPNAB, AB, ABPNAB),
+ return buffOut;
+ };
- // r0 = APB * APNB - ABPNAB
- c.call(f1mPrefix + "_mul", APB, APNB, r0),
- c.call(f1mPrefix + "_sub", r0, ABPNAB, r0),
+ 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");
+ }
- // r1 = AB + AB
- c.call(f1mPrefix + "_add", AB, AB, r1),
- );
+ const nPoints = Math.floor(buff.byteLength / sG);
+ const power = log2(nPoints);
- }
+ let nChunks = 1 << log2(tm.concurrency);
+ if (nPoints <= nChunks*2) nChunks = 1;
- function buildToMontgomery() {
- const f = module.addFunction(prefix+"_toMontgomery");
- f.addParam("x", "i32");
- f.addParam("r", "i32");
+ const pointsPerChunk = nPoints / nChunks;
- const c = f.getCodeBuilder();
+ const powerChunk = log2(pointsPerChunk);
- 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 opPromises = [];
+ for (let i=0; i=0; i--) {
+ fullBuffOut.set(result[i][0], p);
+ p+=result[i][0].byteLength;
+ }
- const c = f.getCodeBuilder();
+ return fullBuffOut;
+ };
+}
- const x0 = c.getLocal("x");
- const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
+async function buildEngine(params) {
- 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))
- );
- }
+ const tm = await buildThreadManager(params.wasm, params.singleThread);
- function buildIsOne() {
- const f = module.addFunction(prefix+"_isOne");
- f.addParam("x", "i32");
- f.setReturnType("i32");
- const c = f.getCodeBuilder();
+ const curve = {};
- const x0 = c.getLocal("x");
- const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
+ curve.q = e(params.wasm.q.toString());
+ curve.r = e(params.wasm.r.toString());
+ 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);
- f.addCode(
- c.ret(c.i32_and(
- c.call(f1mPrefix + "_isOne", x0),
- c.call(f1mPrefix + "_isZero", x1),
- ))
- );
- }
+ curve.Gt = curve.F12;
+ buildBatchApplyKey(curve, "G1");
+ buildBatchApplyKey(curve, "G2");
+ buildBatchApplyKey(curve, "Fr");
- // Check here: https://eprint.iacr.org/2012/685.pdf
- // Alg 9adj
- function buildSqrt() {
+ buildMultiexp$1(curve, "G1");
+ buildMultiexp$1(curve, "G2");
- const f = module.addFunction(prefix+"_sqrt");
- f.addParam("a", "i32");
- f.addParam("pr", "i32");
+ buildFFT$2(curve, "G1");
+ buildFFT$2(curve, "G2");
+ buildFFT$2(curve, "Fr");
- const c = f.getCodeBuilder();
+ buildPairing(curve);
- // BigInt can't take `undefined` so we use `|| 0`
- const e34 = c.i32_const(module.alloc(utils$4.bigInt2BytesLE((BigInt(q || 0) - 3n) / 4n, f1n8 )));
- // BigInt can't take `undefined` so we use `|| 0`
- const e12 = c.i32_const(module.alloc(utils$4.bigInt2BytesLE((BigInt(q || 0) - 1n) / 2n, f1n8 )));
+ curve.array2buffer = function(arr, sG) {
+ const buff = new Uint8Array(sG*arr.length);
- 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));
+ for (let i=0; i= 0) {
+ curve = await buildBn128$1(singleThread, plugins);
+ } else if (["BLS12381"].indexOf(normName) >= 0) {
+ curve = await buildBls12381$1(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 utils$6 = _utils;
+
+var bn128_wasm_gzip$1 = {};
+
+bn128_wasm_gzip$1.gzipCode = "H4sIAAAAAAAAA+x9B3wURfv/zN5ecsneJZuQBoSwF1pooYNgy4AgVRDEgo0WIAEChF4koR81oQkCAlJPQZqgIAjYT4pGQESlisJJkdA7+X+emdm7vbKX4Mvv93vf95+QsDPPtOf5zjMzO7PfvUNdBvbFCCE8B0d2FrKyUGdM/3AWxHBWZ0OW64I6G7JGZ6HOQtZo1FnMohJjFrvSKM7qHJyVxSVBaiA0y/Wj5tdkxFmdQ1zpOKuz5M6dhbOEcGxIzRgS1De1b7/M4QIqafhc2CUgLGCDQRSNCAUFm4yC0YiQESGEBAFhoynEaDSaTCYTEvRTjCASMJhuMBgQMtKcRpoXyrFSRvgJRVII/JlMBmQyCQiFmM1GoxmZLCEmWoXRiFhBAzIJQojpH9Rs9KjaK2YMgR/E2oKmBNYUbclv+zRmMrE2NT9iWLgcYQz+usIawZSWMejNbv36D0eIBkekZvZDOBiC/TJSkSEUQmkDO4FYCIJI6gAk0vSeg1KRkYa6dO+Ogmho4OCuKJiG+g7ug0y09MABg7tkpqIQizvStk93FEqzdU8bgixhtJGMIamZA1Pb9OuOwkw9avVVtYIg0yoUgi5dIEJ1gQBoINMQaBBBQxmpPVFkGCvzXGrPLoPShqSikiFM0DYjFYXTugem9cxApSQI9m2f2n1wt0GoBC0PFkTRNrkF0RZ3BCyIiYR4j8x+fdv0yxjUs1/f1MzhKE4G4aB+GlEsrZzbh0rTygHceNp+n35duqMy4bRUWt/UgR26denTJRMl0Gypw/qjirTGrl0GdevVgtdRlmk+IHMQqmRmBnVgOiZFuzK/oNVBiXXJm3kqbDX1yHSDnekGO1MLdqYKdiYDuwoNAdhVaQjArhbGyrjArhPCBAB2ZVo3BbuuBEEV7Oq0PICdTNvkYNewuCMAds1IiHuBXVsGoQfYtWjlKtj1aOUAdn3aPgW7QTgtpQH7MZoNwE6hNXqA3ZBpDmATMzOIg9042pXZA+xGsS65F9iPB/XIZPhBgMIHAYoeBACGJiGQxFp4JrRHpsuYphaIuOFtFtwjk3cchFi/QS3U3hCamfWfsUcm7T5zT+bXg9LA1gGR2uib3XoNzuiN+nsISY8eaRmpaHCcr5DnHxTa0z0qm8vuCC/6bFBPNlDbSSzQJm1YanfU1sxiPNdzpp7qiG8dpgZ5WiuaRq1rGaYGeVoL2nr3foO79klF7WV3hKc/H9yTzw4dzTzE2n/BwqM8YweaEfrhJQsP8ZQXaQp0VSczD7EqXrHwKM/4MkXOy0Nfi/MV8vyvUnU9nPeNGG8Rz/t6eE+v+WFItJeE5xzK1O+X2bdLn7QRqagbRah10zaD+nVEqe5IE9SDRjoO6te6aRvUk0aasEgv2hr1X14wzUvSBKW7JbyK3m4Jr6ePmZnDVXszjEVbdunWr2talwzUJqKne7LimbqW0MhcOftS50nLaDI4c0gq6hKhifFynemYezMzlY6VdqmZfQcP6jIorV8GGk4Hd48eg9BbdCSnQXA0nWsyuwyFyEiJ52jZLy0DZYVpYk2HDULZOMJT0iJjCBrDZsgePQa1SRuGxmIzjzVLy+jSB43DZSDePzO1f5fM1NZdemZ2yeiZ2nRIlz6DmVLjsal/vz7MqyfgcAh365cxcFDm4G6DWjdBE7F5QJf+b3YdnNanO2ncBE3CEsTT+6VlQNTGkwEl0r07moxDe9R2jcIpOITFYN6dik0QoQ1Nw8EQhulhOhPTETeDiWHuyWHivoP71EK5rFI+E81kmWAozWJBGBKzWRDGzRxWlM7wC7GF1Z6RPrhnl0GpaC6OBIHX4JiHZZB6DIG3cRDIUgeg+ViiZvDZ7x3WFExci3E4LacZDgtYVR4T97tcI5i5l2Azw4RP3UtxGIu7ZtNF2NyztmZ23IsjtXE+3e3xlHLn+wHH+Up5ie9xaE933yzDsjvGS7+Hg3oykz/AEguxGeZ9ppJrlrRjU0+101bhMDXMU1eyVNrTK1iqZqZcztTgU+VapobHXLkGB/fkPbyeNeyaLddhC4/zvB+yvNDvG1mae8LcwNLAPTazelxT5kcsr3vO3MTg9PKLjxmcfmfNLUxzD5/ZimO8ZTz3Jzi8p5en5OFoLxHP+yM3xDV1fsYg41PgLk2sCdrNYnzq+5zF+LT3BWtUO39+6S1qgr7SiHg1X2tEvK5vGIKuOXQb61jNJLoaR7gKuWbRHbiERujK+y3zL3Ue3c6Kek6kn2LJtbI0y0QHcCxE/U2shzBdGmEGPYLpIk2n1l8wXUv43HqYVadOrr/iME0UZtffcISnBGbXo6wOPrsew2YeY7PrcVwG4vqz6wlmp2rDSRwLUX82/M6cFTQ9w8YPteEs61Buwx+sOtUGJ+sDjQ1/MSA9bTjH6uA2nGcd6bLhAi4DcX0bLjJcuA28c/5mDXkKL7H1ia0G/fv3Gd4qdTjKx+7F1SW8jGN8hGxkXtF4kSv7VTau/GS/hkN71HdNajdwCIvBgnMTmyBCp6FbOBjCsODcZmI6d91hYlhw7rKK+CJzjyXAFHSfBWEWecCCMNkUsFroIpMtRELYa+4YK8gg9ZgfxghBIEsdgMYJEtWUrxDjBVozTPc2IZyW08wUE1hVHmvKJCGMmepaNyYKoT0GuddeIYTF6NormCDC1l4hGMJ07WVitvYyMV17mZitvaxSde1lmejay4J07WVBuvayomztFSysdtfaK0SCwHvtFWSQeq69QhDIYO0VJGqGuvaypujaK4TTctq1l1XlufZyjejaK5gZJuraK4SxuHvtFaK6ZtSq/diboGXX1Iy0wQPbdOlfE73vV14LfeBXXhut8Suvg9b6lddFH/qV10Pr/Mrro/V+5Q3QBr/yx9BGv/KGaJMgM3n/LmmZaRk9mw6ohbb5yGqjT31kddB2H1ldtMNHVg99Jlg8ZGinEM4FbM55thZa7i2qjVaqVfVN69MnNbN1v379kV0oyWQ9YOpqOqx/v4zUjEFpbJ7aKsTrJsLG/SO1DfDsxsNr1q6LVgmRXiLIuFqI5dJuw7v16TeoX9+0btxjtvhJajqs/5tDa6KPhdD7Jwy7hCpIwQqqbEANDDxkamAwsZDcwCCzUFwDQ5yUgBTUmOajFxO7yOwSJ9VBNGc7MYWW5VcTv6J24UaCwiX3f/BHq8S6VT7LqlRwZUPc87xeiMg8YoKIiUcQRNDz/pp5S1PPC2IKQeFGt+BFMYVgJmCVa3IwgSYHa1GTgwk0OZgancIl+gOtH8IYj1ZQPQEpuJ6ARlkNiqAYnhIQyESQiaMUQ2PF5koRIcUEKSavFBOkmCHF7JVihhQZUmSvFBlSoiAlyislClLiICXOKyUOUuIhJd4rJZ5GV0vTBA+r3mLpjQsKCgrCx3kY9xaUmDTKK4PGRv8ZNKb6z6Cx2H8GjeH+M2js959BA4P/DBSNSaulHDkSjy78n6skBS7RSKFLDBoN1YocZ1H1DrGxYgO5WoTmFhNNoyGPgSaP0qYD4InBSpBXuqCIgDZUDnKP2kyJoV5tu9KDFZNeEnRcYojiV22Tf7XNiWY9tYOVUL2kECWQseZEyb+xZv/Gyolh+saa9ZJCFF2IpIAQyYkW/xDJ/iGKSpT1IQrTh0gXWEkfWEtAYKMSw/0DG+Uf2LjESH1gZX1gdbtD0u8Oi353hAfsjrjECP/dEee/O+ITo/S7I1K/O3Q7UdLvRIt+J4brd2JEwE6MTyzhvxPjfToxWInS7yTdrpX0u9ai37Xh+l0bod+1JXy6lnad4tN1IYpur0n6vWbR77Vw/V6L0O+1Ej69RqEv7wO9pA+9RR/6cH3oI/ShL+EDPQUxyQdEiz6I4fogRuiDWMIHRApHNR84wvXhiNCHo4QPHNSwmj6GRegbVsLHMKpiXR8VS/ioSBt7TG2MFntCmhZp1rsJaIysQmMEWXmdjfFEK9xU4ImKoDbucZ8QREeyoBhc6VgR4BbBYBVZu0afSpUgfkPgVbIojaqoaEoqRlezYuHNmuhdysM2G6zoKVuIRqbCNTInhujVze50Hi1G5sI1kum9l45GesoG0sika0chysqFKxuVKOkrq2uH6R/ZEVjZqMKVjaM3mzrK6tph0rUjkLIhuiYWYkdc4XbEJ1r07dA10aRvYsg/MjGwHfEB7QhWdE0w6ZsQomtCID1D9R0xsAlKQBNM+iaE6JsQ+o9MCKxn+YB6hujrGaqrZyBlJH1HCqxnUkA9Q/X1lP6RnoGVqRZQGUlXmUAtmvX7PbAyNQMqY/5HygRusW6gFgNVa9HvpsAtPqZpUcHsbigUKfAPyybpY34ahpCCR/NDJQSnRUhU6AGJ+6wJwRkRMvmI4WQImX3EcB6EZB8xnAKhKB8xnP2gOB8xnPigeB9xvPScgEfjLAXgM1DlufWgPEBgFYQUQ4oitLNgxUDEdDWf4JPPjCRJWiMEA02U/htNaxbEFEWwGo3EgaxGSTGIKQCkkTiRVZQUpIgyUjBJkpFilDGxYRmTstYgUtYaDA2TJCU4vTpCSjAxNMu0YCWY4N7WYGiLJhFD73oINcajrCbF1Bg/L6Y0Ro1RdikJClPNRSWIVhBEgmkFQVBBEFRAk0hw78oIWUPgUCbbGqIEKcG9idjbGkoLhzTOzs7O7j+unRJK0HMDLFgJaWyyWUOUUILTraG0lhA4ChZJkmxsahEaY2sIQdZQ0C6E2LEsKSKxYyW0tyLKwaUUoxKaroTIZgrWFkFygeXxjziw1UAcgAWySsSJweWIE8uI2ASrSGyCbCDIaiZ2wWpSELELMiIOwRpEnII1mDgMXH2TLFiwYlRMYJZsUYIUkdgMskmRxBTFLKYQm0ExyEYeUELl4FIEWS1GxQACGsVWi2RUk4N43FWWyVxFoCpNWZBraoaikqQYrCGKaDUooVZRCbGGKmarpFisZsVoDVFMVqMSbDUpIayLqZ4Y3EwOLmWkVyTRUUfsoiyGS9Xo8FMEOQi8jDjVnBCkyrhkkiTFqpmD3QlBkICIQ6TDOEJaFGHgu5nJ376zIoxPLPQ4WBjN5weryAR0JBGnAcIi3Twhzfm3O1XUpvLzYXeqSZvKD4fdqWZtKj8ZdqfK2lR+LOxOjdKm8jNhd2qcNpUfCLtT47Wp8cQWRNOeEpCKh+iNh6iHh4/FYkCLTQEtNge0WA5ocVRAiz3wiIdURQ8PxY2HqOJh8sbDpIeHj8ViQItNAS02B7RYDmhxVECLPfBQILW8Hh7l3XiYVDzM3niY9fDwsVgMaLEpoMXmgBbLAS2OCmixBx7lITVJD48kNx5mFQ/ZGw9ZDw8fi8WAFpsCWmwOaLEc0OKogBZ74JEEqdX08KjmxkNW8YjyxiNKDw8fi8WAFpsCWmwOaLEc0OKogBZ74FENUmvq4VHTjUeUikecNx5xenj4WCwGtNgU0GJzQIvlgBZHBbTYA4+akFpXD4+6bjziVDzivfGI18PDx2IxoMWmgBabA1osB7Q4KqDFHnjUhdTH9PB4zI0HXXoRUdIVLMvSzrLlivI4tvB//O7G6PXgNog9uA3WO5E2urrE5BISVE9wGhJDfB5leJ9SB7HnvFLA57yh9KzUXzq0c8GQGOARn1s7c6AHid4n30HsiXG4ntHsyEP/iXGYoouXRfepEFiTb0iM0H+257ZG1j638n4k4Bdlc2IJPZBClXC9pDAlUN+YEyN1+ybQkyb9x0mAwTVDYnRRejQq0LMwvz0qJ8bq92gJvaQwRdcPIgP6gZwYE8gPAjz/0X3mFR3Qe24ZEksWxXvitN4TVxTviUosre89sfreo+tzkfo+FxPQ56ISSwXyuTh9n9N9IBat76klA3rqPUNimaJ4arzWU+OL4qlxiWX1PbW0vqfq+nekvn/H6Pt3qYD+HZeYEMi/4/X929vnNP6tOypK6o+KMgFHRbaYaC3KqFC0o0IpyqiITyynPyrK6o8K3bEUqT+WYvTHUin9sZQQcCzFJyYGGkuK/ljydmLNWNIdgSX1R2AZ/RFoDTgCx4uJFYoyAstrR2D5QkZgqFJOf4TpjstI/XEZoz8uS+mPywT9cZmoPy4t1Dydceft1ZpxpztaS+qP1jL6o9WqP1or+Cdn+LIAwxTd4RWpP7xi9IdXKf3hlaA/vBL1h1eEjy9pBoLu8CmpP3zK6A8fq/7wqeAzfHSYkJH6nh2j79ml9D07Qd+zE/U9O1rfR0vq+2gZfR+16vtoBf8kFl/yZoy+t5XS97YEfW9L1Pe2kvp+U0bfb6z6flPBx2906KGl9D0gQd8DEvU9oIx+X1r1+7KCT1/q8EUT9HslUb9XrPr4VvDBV4fvmaiPVAUfmz3plSr5cHURnkBst5b5l/fsQQ/PswpAQArS7OhVoceOXlsqMCOC7d8f5ZNerUIXDIlmfSKQ2wwpEN2iUANMutSUR83Q0Dwd16Mj8DOC8KKYHaY1O+xhzTZTjrYOx+KRPrzXmO2tpSspPCAi1wyJkUVBJEKLSMTDIiLTExQdRPTAetS8Aw1Y3gZowNLFMTIgjrfUk5dCcIzS4hj1sDhGJcbo46gLseUfQVwUHL0N0OCoC3GkPsTRASG+Z0iMKwrEsVqIYx8W4rjEkvoQ66Jv0UU/EMSybscUCX1v2zTo63ZMpH7HROt3TFzAjskWE0sXpWNKaTum1MN2THxivH7H6PaZRb/P5H/UZ0XpGG/bNB2j22eR+n0Wrd9ncfp9Vjpgn40XExOK0mdltH1W5iH6LFTR7S6LfnfJut0VqE9K6M99Rekub7M03aXbk5H6PRmt35Nx+j1ZWr8nE3x6sgjEfos+/rI+/iX+Ef6FgxyuD3KkPsjR+iDH6YNcWh/kBB+Qi/CugqyPZAldJAPBFaM/JxWOZKQ+ktH6SMbpI1laH8kEHySL8CJFCX24Yv4RXIVjEq2PSZw+JqX1MUnwwaQI72vE6BoeyLqS+oOxcMPj9A0vrW94go/hRXjBo+Q/sq5wE0rrm5DgY0Lh73YEUiZe3zML1zPBR0+fFzQYjzleMcLhBYaDCkwPL7B6eOGSSZKb7BwlScDAtIk0HE3DoTIi9lAg8IYqWC4hRYDUESrHEUcosRllo1QeKUgW6CcMSAoiTkhzsjQxhWSFSwSHc4qmHKc2HKZgBcuxUggQPhUkI2kvFlWWrCLImChWI5CXBaC7GhXcCviuRGkG/FRJjjcSm0RsIoSjJGCmSsQuyVGKQOySIsiyYiAKUJqNcDFSyikmSn8AqKmYEk5zAwc3iNYfpIjNgEGsGKoj1AjZoUYMxYPgwjjFeo0Tu+TTuhRP+ajEIclliEOCayzAJikGOUq65baUoCQBWY0EKXCwhNOJ0ie9vgCM6XgFWYO4+gRZTVRPkyJQPQFuSOutGGVkVILUcJQEj7TSXQUVE+hvovoHKUCPpjmtlHFLcG9F7JNuDVaMilEuzRpo6q6eZpWREixjFiZOCcjcvDk5SjESp6QE81ah8mBF7A31sTZMQMimjYN99QUkPWXgHYzgtI0axjrYoGAwTFSMcqwigu6iagLrCUqrLkrxuH+teKR+8TZu/0QwwqxBisEaTJBVFBgdnfaNkTKyZbV8EFyClGC4BCsi1CY+dG0Rj7S2qEJr2yQIbBg2Bda3HE/Htc0sI4goglopdK8IMw3Q8KlPGeRoxUiycVvqntmYehqxmanbu9J3I5a+G/lPV9py7/abKrNU2X+qiaWa/KeKLFX0nyqwVMF/KjfKyyaxqQVTzI5jl3fR4YNlDDOfVSAOI7EDdojYjUQhDrNcEaZJCDvNckXAkjjMlPduwRCyWeRogplvEptFTbFZaIrGJYndTOwWGcHBdW/aG6xjmlowsVsgKZr3Ep0BDFaBis1yNG3QDLpEESdUAqpE0TqdZrmkmEKcZgXLkUZ2hdLqLI/ZLC+CKRa5InEwBTl5P8wfed/iPjq3qEfnFj3yvkVD3g+ji0ZVDXkflsAikfctAcn7loDkfUtA8r4lIHnfEpC8bwlI3rcEJO9bfMn7MicTFoG8742Hj8UByPveePhYHIC8742Hj8UByPveeHgSQr3xUNx4FIG8742Hj8UByPveePhYHIC8742Hj8UByPveeHhSYL3xKO/GowjkfW88fCwOQN73xsPH4gDkfW88fCwOQN73xsOT9OuNR5IbjyKQ973x8LE4AHnfGw8fiwOQ973x8LE4AHnfGw9PmrM3HtXceBSBvO+Nh4/FAcj73nj4WByAvO+Nh4/FAcj73nh4Eru98ajpxqMI5H1vPHwsDkDe98bDx+IA5H1vPHwsDkDe98bDk8rujUddNx5FIO974+FjcQDyvjcePhYHIO974+FjcQDyvjcenuR9bzwec+NBl15O3q/yCMn77O7mkZH3Lf9L5H3LfxV531JM3r9mKSbv/0PyvqWYvP+/St63FJP3/wPI+2HF5P3/WvJ+WDF5v5i87zVQisn7xeT9YvJ+MXn/34W8H/AJxL9G3i+ge/b/JfK+5d+NvG/5/5O8bykm73sics1STN73AOufkvctxeR9Dxz/B8j7lmLyvgf6/zbk/bBi8r5Hx/wnkPfDisn7ancVk/c1SBaT94vJ+264isn7WsOLyfvF5H0vZQKR9y1u8r5FJe9bfMj7yZy8H0bDjLwfBeT9KCDvRylYrs7J+1FybeKIIrZwP+R9SHOyNB/yfm21YUber0XJ+2EPS96PlusbiS2a2MIgnEzJ+9HEHi0nA30+WhHkKoWT96MDkPejA5D3vRsn9mif1l3k/Wi5AXFEw7UWwBatGOTkopH36/8T8n7yPyfv1xOKQN6P1pL3k4G8H60E81YfFXm/1r/Gvq/9rxWv9mjI+1UeKd2+6iOtLflhyfv1GXk/hpL36wcm79fwR96PoW7vSvch73ule5H3vVK9yPteqV7kfa9UL/K+V6oXed8r1Yu8z1MLIe/HA3k/nNhjGHk/HBjvMXIKTJMQdsbI9IsIiCOG8t6BvB9DbLFyDTd5P1ZNscXSFA/yfgyxx+qQ92MhqYYPeT8WlKlBG4wBXZKJEyoBVZIZeT9GrgPk/RgFy9WM7OqHvB8GpsTKKcTBFKTLBczusVBlLCwigpzsXluasLWFTf5SCF1bYPUIo/VSJpwsDGCvAOxG6bIgWSAFsxRMq1dj8TwPltoX+at8WUhpYFBYKKmBIYmFajYw1GShxxoYHpNGPPIqWSilgSGFhZo3MDRnoXYNDO1Y6OUGhpelJLDxWeo8LWGtBhvjOUkQ7GZIIkmKw+BnCpZFTao4IFwaTBOgoFVQkNyc1vVsuAT/8xVakMPhy4MVLD8HMWKPk6MVTOxxxBHH3j+LI04IQaXEGUdsJeUoWLziZBEKgtRWEsLgCvTbfjdjNl+oDVPNgfPIFWhOFWjuoQBWkNw2HN5mU9Vpy9QpSd9PccAFEUdJ4ixJdbGXJLZSTL+SxA4hyEQcpahySjpxlCLOUqra9lLEVhpeTKGlQFcnlWi1dmIVbmi9DXVre2naLFRXGl5xKU2cTOIoTWzxskxs8XCNhqudiiIg6HQHWQYZUuGXBuPVIOst3mXQu5CoYNoBNghEuAJQp7M0cUAFjnj26xmEfKznI7jR8SzKMXDwaIQ0GV5doX0BlramlkLrKvLPh7MxHa8abysDJpYh9jJUYitDHGWgcXqNhqszHoIRELSXcQUdPKMznv7SYBlt0JbAm2AaEHuCHMVKwWdYE1sCvS2MgDqh2gRoNIH9egXLeBnvLONpfAJPJfYEYk9Q4ZaWC+4RYlBHmyLIrRSBDTd1rCjIS0qHGx8AfMDxss+Hw90lAJjAtWEo2stCNyYQW1lAsyz8OsqC7mXZL0CSAEFnWTmK2MvCr02hXgLpihxFbAqxK4C4Ar9OBRxGIc6yiiBHwANIhQZoa86yxGaFIlb2Cw0piqAIDCSB9qvColE8auWpoIczgRsrS9kGT5CaBwSptXYUK4LcAeLEbmXTipU4rHSw2q3EaXVNK1ZiS2TTilUzrSR6YEocVhiSiTCwErmRELEnEkcigAJXYisHjlOO/QI+ICL2cjD6E+HXUY5CCunlwdvKEWc56JDy8GsvD70A+Tmk9vJuSO3liIMWKc9+oaHyXpA6ynlA6iivphqIPVFFlF15LJpdid3KBRFc4FDzR0g7DNoZ1cBnVFHTF63VOdWrDzCNvxAuKaKmT16gfeIsT9/ms1Vgo7oCsVegHeIsTxwVaCc5yxMnhCATsVVU51ZbRWKv6Oq7CsRRERy2ApSCGdVeESQi16U97TqonDgrwrwAhYmtErhZRfi1V4JuqgTXaBYnjkrguZXg10lTK9AMSdCJlYgtSY4m9iT4dSRBJyQRRyXeX44kCFAVKhEnLZDEfqGaJK/eclby6C1nkqu34B45QGc5y3t1lq2Cl8BZkQuipCi+UGvmikgp0Y+Q9S+fnJAUCTdQtsryi9A7lWEoMZGTiZwgeoGJHFXkl2D0VFEEuaPaYJym7ji1QQ+hR4NxarlYTZZYtZyH0KNcrNQKudZ2PgtjozqjV5VLE3tV4qgKfQZX4qzKRnpV+EwAPo6r8tlakmoh7mPVqFfa1QuEouBqi4OgTGxUJIZL4fQIopr8JvzXOVxah42ar8eiO2oDQbCrU7fTTLWTMBYMRJHL0h2gwWpU4GuxEPs2MSWY7QKN9PY9SMZ0f0T3vnRPSGzV4b1nxQiv8sLXg9G3oG3VWTZ4j5ecpGM0iI5V1xY8GG7Xg/ku2AC74NZu9Fq6YKsOsFUnjuoAG1yJszqDrboGturuRY5OxJL0ON+qKTgd7vQNirrnMyhCc/heNkWkZxoI9g2QrtnnVXHfb7Zge7xk+VViSyaKguXuxE4D0F530F3NimnjjRA77nEkw+c48CLs9rwUyWpGZyJcHSGSjTMbISRJNZCCIL4bDdC0qBBnMi9HFGKrIXcnzmQFy69Lm9SbSthcCnRsuQsKJBsPAGOJowZ8vVkNRSBPD2iEIEgUYod67DWoF2PIEk0vEIqCqy0OgjIXVYKrvYYcCRGuvEFMgVrZbbfRFYyUjB5Jke4kADSlCCcMqYrIJ3MjvXqcMTxdhAp6aCrwPqMoigI9AynQ3lWBggnuDQOIEqNoZDfqk+6/zl4wRHrzKnt7VvmCV5W0FledJ3XrbEP1ZJWe9K6UMOfAxNRHEXozJlhLuLlXxEF0j24kWDGwINy7CcQwJD0Jvo+QBA8YohgHSHM1542Y4Gb0VBBTpQbB5om+syUw/UQ6uHtbjVxHYzM2shSD3JFOBka5o2Kg49+gzgNmtmmG+uR+9GLFtDhuSo9ijHJ7LuU5jQqSO0r7cKi/b/1TDE3prNSSKmkcZLWwiS6MICVMsVA16wsIvviPNmJWLKBjmGKmSXJLxQzgmVlb1lAFW03s2/P6pFtD+OFiCBQxAfFNMcoZ1nAFbiDClHBXP8mKDCwZuaME2dKtJiWUGsu+7DBMMcr9lDAlSG4NWsFUtxSb/X+LIc5SRLkltQpuTXpWR46aMB8T2meKMYMevNIvZFSMffhXFoYSBFOaKDdvCntJl6lG5jKi3F5jpcRufeALBuGgsobcXxGJs4Yiyh1B0psp/R/mSAP/Ax0pM4AjvaBxpN0ejjTwnztSrf9RR6opDwJHquntSGvEYC+9+PFpS7peGQbBLAdIi4poDSWI3lQoxnQybADgDUe2mCBiGEJGDUhPgh4gZQcMIXgAPccN4c8pqIZwa+LKpwSp+UwKfP6FSUxRQqhVwQSzbyOF1Z99KalRIy7QyCWjV5kCn0LIuy5JMvppDGnLYVc55NOW3zRtU9oi8PzC/SgmmLXqpaZnES+7vVQ38vK6BSQJAr2toXDfXUtuDf3Ix6xBbq+Ewk2JiZpvokMe9k61YBQb1VAn+iWyodBfrCZ+CyiCOxc7y3+rszhqy62K4CyO2opBfsGohl4J5CyNYQNTgAdUR7Z2JG6QgohpiCsuD4LTJtktMEGGOFc8PV3BQ6We2h0SVvAgq6C55aIPh2CDAHd78BwHy8PgsAG8rg/MngZFbEGfftgOIBmBZ8G3DR9ASpCMJO1t2a/Y168Vg1x5gLooDqJLIDwXhD6F4BC+GAYrxrZUjWDaaAg0D9+3DJFQ+k3RBrky9CWxUyVClRB4NH0AKaHwDNQtNighcjJNgO8WToY7dihoVEJYEs0CCZJmb6bmgUJIToZVlLfsyn0Wh/hZfGCrPJxZFkKw63kbPK+m9xDWYGKrw4EMJYgba1RC2sLDngNIrg9aDLGaNA+jTQwII3wFNZSTFEkx0ZBZMUMh4jwASkrEdhBBTxykEkWSq7jCZrkq5FRCaSPJHk+ylWD1mbh7M6gucvIIqYl69oSHUDdhdxsC3G0IVAa3G+nq7Qa1/VkxBcET9vhWLCDFwwkilkfBI6eDYCTcAiEaHilZ+T0XS24EZzB90vltElYM8khpiLpnMBAHNdG9SefOGsydFfMQLPEOsP0gok84bYcoMoeoRDECMjwcBMgcBOd20LxuJ5DGa57MOz5XfSAEzvIOMS08nsMj3itBCuahYHjCShyHkFxFCVZC6NNWeCwOT4SDoRKQQDqMHBoXadXJmif10mKP8wyNHsTpcPulgTiLqlMwZCW2n5gf2H5C9JlysBLK9QtRguRkKg8CdJQgJZRKnFQ/p7d+X/kbCAQrAh/cQ2i3CEMY/aKPNQhGAOtjybU6hSiGZvCY8ick14cvRWf3ZWzJQkqIIvZRQtNV/ZUguEU0QW7i+Il1mvMnsN7JJACwK2ySq0JORaK1J3t8HzsEQ6gVIz3u2ofQFRUPoGeYQdCuIqghIHm4B24QH5wun8X01lLdKsMxou0wNEvfIAJcD8NzcyiB+bCT5hexh+2Hi+x1IcRxmAHjOIxouCr3vKoQYz0KPniY+SBcRdqAR98m87HPLYPaBe0qYZAxp9bQ7DNwkIcTwA0L8FYwH66ceBAEtzIhShAR0+mBm2sSZNsfSKZNmXgW6HHiBN3gf8WkmOQqKl3BDaMf5oJDMPlueKySIlrNioHPFBbauMT2NZKMFbOMFQmqkhQzXNx7G4CgmqtIKCsSmiSY6AbG1AL+U0LS22bS+4Nq4GVYggzIGqaEEUTXemuEUQlj674IYVdGmlOE3ZES1AL+U4K9q4oAMXOtCEWA5mhECSXmdGL7GTovAq5KhFxFLcYe9TObjeBGfu1WzLCqedqthMKFbWdSNR7q4pQIgLbV5LpXCNH2IxBK7KAS/K8EwzD0zzQxwYW5W2stb0VUMNx9WIPoQkAdmztRMD8TUoLkKl4EHVY1rcyLSgDHxHK4Gg334hPQWLwa83Nij6TBjNHg+Bnx81f+/IPF+an1ESTL/FEksUMERBCiSVGQWxHgaBGu8MGuEGJSaIVmp0H+JEKKUz/MUG2TP7GQ+iO1UccRjQZOqgFT5hdEnynYfqF/0BboAlL43xWToRDkoCfLGGT0qSukO44gZr8slVY1kd3Wc63daRHeaREqmJEejz/8PhPx+/zB78MMxi7x4jtIr9MnAb8g9bm1E4LwP7H9CkY7WIjGImjI/iuSSyv06j5WpxH3w2NVu3jkuilKcPUFnf3kBKkUe0QKx91WrGA4mYYDbblUuFQScaeDxUQuyc650yGQI+gz/3Yjlfo3HXPuHz2d9SX/TcEqfUoxyjMwI+SxWA7WMADZ4a4/CiA/o/XmAL6DtSRA1gzLLc/ASrA8DfMocfyKQORqWs4BdqbjV1hbuA4efEDWoC8h8HtPptl0Ri6y/UZrh3hgttlM7I9u9hust6CFK4sP48w3ixfpzDeDF+/MN4MX9cw3gxf7zDeDFwHNN4MXB82VwcVC248RcRxD8nQMFxqcA1Oe4zd41GI7iuTFGC7EcRRBlTRAIzmYBm3HkDwXw8UVzeHRY0iej+H2HiqAXjruKqWm0QAmzmNIjqcK2I7DMMvBRuI4zrQ6zps8juRZLOqkuoFgMROohSQpDRHnSVrOeZIFqTW2E1DCfoKWsJ9AxHmCW+PkkRxMg/aT1Br7SeSK5vDoSa4xYvxkoDXLUzAnxkzBAxhdLRtDBD6zGsnT1NRpmA5xtwAGLM06DUvL8P8Zf4yFOjcwdGahXg0MvViofwNDfxYa1sAwTBor/NvryELZuIEhG7OwDTcw2Hg4Fzcw5PLwfNzAMJ+Hl+IGhqU8bMcNDHYe3oAbGDbw8FbcwLAV08eR8nt03pZXYGDbQQdOxx5PumdguurMwBLb0EJkvmeW+XhAuDQVs9UgGzPe3TJW73uYkjTewy7m21TMKVd2TA/6nKeo42IIEPvv4J5MSpwsghm34HdE7KepgGWbT+thT45Pc09WeW2/uNh4TB1qGeXxcLWWMbWWeakFjLz3MSWSuNR8n6t5mqppIPY/+ECz/4GI8w+uovM0IvY/VeVPI+JkEZqf2M9wxam2ZxBxntGa9ici9rNsxP7BqqHWOM8wuYdpawVXr4F2qzkX9SxXijbghAhciNOpKutExP4XnXDsf7HgTBZ0nmXR2Tzq9IiqmWdhmpH+8ehf2ih3CNUtwJFYHgWz3rXT4GxtkLZF2zvHFDuH1D9/USjFPW62CzoQUpELTfs55MolHaJoLVPRWsXQAu1c/bsGc+rfOS2E5xk+5xFxnlchPI+I/QLT5QILzmRB5zkWnc2j5z2iambA4xzL7OTRCz5R+0W3FkxT4rzIpmxWjYKpAhcpGBTE87zFv5lqfyP1z1/0gj8QL/iC+LcbRFAA/lzdKl0Q3GPd4JpDFEFeiSktIZ3dxWDVTb0T2ByiDl/XLMIrWYNdZMK/kUtL3jHOSxRXJ5h0iXXAJcT+8pmF+Uj9o5j+zaLOfDa+LiH6Z7/MnZZmvcIAvoyI8zKr8wqVEucVVsllWoEigDYCSFmQqwRVXGVVXEXqH9XlCt3wqGhzzttlxEU5LtFV5MpFNXb+jThes7B01OCJ9rJC0V7lOYUpgvwhZuy3q+pcC0pe4zMURJzXtBPSNUTs19W59prnXHsdeXUV5IDOus48/rrKNXLeYF11HRH7DQbrDcT+bjJ4biL1j6J8nUWdN1lX3UD0z35L7SrIepvhfAsR5y1W520qJc7brJJbtAJXV9327Cqo4g6r4g5S/6gut/111S3frrrj7iqA7rq7o1iAR2fyKIDLRbNVkf2GWyStFLVLlYEvVaK2n1e5Fyuf7mVcx3WYkh01Hb6Od/gd2uEisd9VZ7G7iDjvqqsWAHBPdYM7iDhZhOYn9vvaVes+Is77Wie5h4j9Aeuqu6watmrdZ/L5qrprmZPco+0S5wPmJg8Qy1nAnOQBYn8FrBcLWHAmVqXEno1ptxXQMsSZTedBWiNEx9BUZzYm9jGYlhvD/uxj2YQJwWys+oV9LAsyHbIxcY5lFYx1/dHqx2Bfr3BmY2+vcI7FGq+gB6ABfeKOr0/c9RE5H6iiHMyPROjdmGbOnIOlSjoJzKH4nD0DSzEwf9vHYXkD9YJxbFZgYud4LnaOZ77Dc0/E8kaaeyKI17u0mOfZ2DyXFj4JHlrMc1Xwtme+t10V+CR4VPA2lt5A7pu4aepKNo1SLylmk7D8DoYLsduYH7Agcdown8/gDtrt104bdi1+kpSiTl72yZhvpzQBGsmhF2I/xdLAt3jKfBwulaAvOU3B8jZML5/icGmnPjlTPfFg2u/GlJ25G8nv4sD8THowEQQIBLkQMDJSG7FPpebBaQbsmClPk55N2Keq2emGmezGjKuZ7XFY4kvW1GK+wg31VAb1VEzs0xjULEic01Sop3lCPQ1r7zPYyvWv0TfrabYwy9nNnX06lrdguJDd4FI7MXHyMG17J5ZaakpN8+Ry2meAF8NFLc03uAuxX0pnQy9KJ1diNyLOGe7SELfnMF1mACafYPcexZvcuRx7sDvtuTC64eIieNpzMW2B1whowlChmfjddi6L5PDgKVbPLHfKEhaEOuYwiWohkDuhNXX/Z9TE5mDO/tSKjB7ZgVBWBArmLlhl2FJnpFdPbmMRatitrcGHxVmUGj4PqEPHgKTNbKxH2vwCa1ib6omcbq20Hje9VLfW1UxXTjD1rvVfp/AtKBqFbzfmFD6qgi+Fbz3mHL71dCbDjMS3G3uR+L7Dfll8a7EvjW89lg4E5vGtwDpEPlBWh8gHSfIK/NBMPgf2pPJRPFQq33qs5fJhLZfvO0zJfKuwyuazB2TzrcBaOp99Fi46n28Z1iH0rcX6jL5cLO8BB3PmQhXr8aOlh/7v+tb+/1Tf2hfIt9ZpfSvbw7f2/yu+ZZvzP+xbjllY/h58yzHL17c265EAV+BiFuB/NgvQPgfO22hXuoiAa7FfJqB9DqbD2+gKb8aB2IDFXvNf6zXOuRjOtYriNc65kG8d9RoW/iig17Ct7tvwCTwIrgTeHB4iNXNTSzdjL27pZuxNLt2MvdilmzGjl6YXjV7K3vWh/NKDmBNMqUzLMP0Yy60pw7Q1hOEdAA+G6elHwjClrboopjTmyTF1UjWAY9oawkqo3NqoEQOR9ACmKcAOPYC9WaYHMCeOHsABeKYHGJOMt+8ucFGXanoIF8I1nYd1yaaf4MLIplQRxjalQUo3/QQT5ycYdJWIYyuWW8P/IFIkuaMrbJY7QVbgm36CH4Zv+hN+JITTBEY4/Rm+LtW+DbsZp9uwfBhL5VXKKcuwGPuQTg9jabiGdboN+2edch/GapDyTrdh4txGITISx6cUok+pCN7ncYWDAKJt9G5gG/Ykntq0xNOVWEs83Y79UwB561gNcurpdix35NTTA5gzADsC7287piLIQV+sAYFIq/cgAK7wpCa6dSHOtVhLTdxRZL2CITNx7KAABUFACZY7cf4pVRIIqAdoFspA7cQZqAcwlAQtd3hp6XgYCupJRDmo87AuCfUzHIiEqprhYqF+honjM2pNMLHvhO6276QiwNoVNsmdICvQUD/DujTUsTgQDxWa5kRU+vbVAeyXiko11HJR1ZfNgIy6i2rK2KgHMMQVg9xaS0d9t4h97tz1EL4YQmy7OUa23ZhGOnF/7AQx3sPA5N3FXdNJz0WgFY/OjqVr126+du1ma1ce1i5ex70Xr+M+i9dx78XrOF+8+hZt8WKnE3TxOqUuXlSmXbxO0ts+WL1WYYjRnYnH+nX2kaxftGHX+kVjnuuX4xTVBBawVRhiSqi8Chu1KbBMnWRpsO6c9FnDTqpr2MlAa9hJ5oJcB3eBfN017PfC1rDPddcw2+lC1zCqCFvDaBDWMNtpTOynMegqEecfAABcQKZI8np3xCxvpo0oobSph1jGTj/SZexPukqd0SxjZ7D8h2YZYxkcvsvYH1gapVnGzugsY9ybsRqky9gZTJxnKEpGYndSlOxOKqPnDq5IEKDkOENXsjNeK9lU7Ur2g3Ylc/6lM3twBbAaZCuZ7RyG/TJbyk6qS9l6OmH8hakM8rC9P0hE2oLHzLHKc2L7QTOxHdZObI7zRVYtGDIT53kKUxAElGB5M+ar2Ul1NTtJ89DVbDPmyxkMtvMUtPNeeu59mOVsN6bL2ef6y9nFgMuZaohrObuIieMitSeY2C7RbrddojIKuCtigm63X6Qr2kX9FW1cwBUNWucrGj0qOul/RaNKalc09XwMPvIlnyrLVjQANR8cfxXWLmlLitjztisP4ZQhxH6F42S/gmlks+qYm2mc9zMAeUX10SvQ5dCOR5ezDdlVvqhdZYvaULbW2a4xse0aE/+IpZe1RHlGwheI/RpTXp0G6Xl5MIgVEx2VGro9lRpoEe2sJr3qr2KH/4odtOID7N6XVQ1XE00w0FKF1+30X7eT1v03nZA86nbSup1Fqtt23W/dtutQ90k22bG64WqiCQZaqvC67f7rttO6L0Ew26NuO63b7l23BRHbfUYrzMGURu9BO3VxTgdQ+rk81W9auBcBdZqGgEpTpvtL8f+0fIbP0/I/Bf7iwwP380vOe7AVcJGrAHFwEX/YZ8sW4NG/SpRwsKj6kNc2xpVKy7KolvBlG8tyuLl0xEFFoA60T2zjXFFHASYOFoUUiNrGs+hYAcopAuMp2MYLnP2gCPJ1WpgGIWe2AFp6sxps49zcB9bOeCipflTXeDUVahgjgCUuvgKnMDjGCd6sBlsBdlObxtBH37YJAn3EzuFzTBAoqXqCQP9sE13w0dSJlLfhmChwtBwTGRYTBRr0Is/ZJtHKbJME+ueYxNGmaTbIDjIFAyK2CQIl1YE9Nv4RjlQ+UXB1hmovKGYT3ExHWonGh7iKWtEstSatiD7BpoydWR5u5oJW62hu4FylZvsrNdtfqdku758TkCsyB0s1XYQzeSHWvtrBn4R7vO2xEIcXmb1RVJpIZaTDM/bIOB8PkNZQD3LY3B1PbJN5hHrHZA/fsk0R1JFKU3lU6zBTmcNMFYhjKhsoNhqkUejWyQKxTaMptmkC1EijszE0DDUSxzTB1QUsz3R3M5BKHNNZI9NpkKbPYlEIXqcvJUx1ZeNZvLO9wyuYKtCJlMmnCS6KBUudpjppDpbquN/mWeCClr7PAyUWuLqBiqDMAuZpfM5VOYA8KC/C4fyzuyAoqcxaCAd8ywerb/ncdr3lg/2+5XODv+UDtz/yHfUtHxq76/GWD9Z9ywf7fctnvKB9y+eG6y0f3Fu+A/cstzCPEtsMAUSupuW7cOtkmyEowaoOnm/54CK95XObDSdHDq0d4oHf8rnn7y0fRw705F3+dsw9f2/5+Mni+ZaPnwyeb/n4yeD5lo+fDJ5v+fjJ4PmWj58Mnm/5uDO43vKpyu8hmMOyMa1ZzN0s9BmYvdhyg4pxunwDD4DPD0TyTY0knL3fcksV3eIvvNzWCDh37Q4XQXM4Xb6DpQmY3SzYZgrgHppU4pjFRExIbHME+T6/M4DUuRAFKQRp6l0MZRRBhllmpkBX6Pu0aianbbIyLMJFD7DrXT2NDjzxLpbeQm4l5nno5JhPdeJpC6BlWJMXCDQCTc0TiGMh1cixUHBF72MoCpkUDPVhkCpYfsBK2OYJHKH7WFJU1e57wOMyx53hgb8MD1zgF3iCX6DXK+6EMYJHwhhBTRjrmTBWoLeNCpbHeSaMEwZI6fQ25V0BnJOjthgicCG2pay33qVBGgUMlgrE8Z4gj4faHO9xkHjh91Rs7nJXcKutuOfoCYK7HxnhQZ4gSGX4B9PidDlb8FiJs4VwKQG5nJrO0RMFtm7jdBoMNC9nG1xvXwp8Xs42+H/7kn33QraBvn0psMmRxXIEzbxMi/udl7MN/t++9JiXp6jfwZBt6C3TGXeawKPEtlwAkatpOUeAeXk55OI6eMzLrMHC375kcNlW0dohXsjbl4K/ty9XQVHQwpXF5+1L3yxeb1/6ZvB6+9I3g9fbl74ZvN6+9M3g9falbwavty9dGVzz8o8YEdsWQYZ7kS30T55D55P3YSgT21pBhiGzViC29QLUiSBAIzkCC24S5Ln04orm8OgWQZ4vsNcv19KSW92leBoN3MLE8bEg38ZMh630BkkwEtt2pth2Xma7IM9iUccHTL3tTL3t7lKSlI6Iw0ELOhz0j1u0kxZx7KJFHLsE4viCW+T4gkVyBBb8mlrk+NodzeFRB9eav4J5mm872V27ypT1+DTe2R7LG8l1GtyU/FyngQpcVPU8J7w1y+R/GRgBnctJ3l+8JERyz0EELuzvvIHtQGkTfxlIHkvPY0EanYVpMPc8i7rbPGdg96N5fxk8tk28fl4IbpipXudZFFLPexaYrWrAanLtLN1vA6kFnfTwl6VCLZzlD3cIgppBUHc3awyuveR9TPJoFQqCgDtCK79gcO8j8mgELvQv9yIFIPeiR9T2gIsuMrRYkOT+zdBiQTWae4FF83jq3wamz9/MJLWhywbv44HcS6z8JQMNzuTByyw6mzcE5WlUQSQ3nykP+rCg2jhUP5uCAEGFvs2Rl0+z8abVoCv6t4Hf87s2XLSkek5Aa75k4HsB2IWAUZe4T0CKuusEteDPvT12RdzbYxNbk7tJTVlgLiZ5lw2KllfOK5yLSe4Vb4/z2C/OxdJ+lXQN/J90+TNMryTvigHuG/kougoRkneVvnxPF2arQJ7mX0aSdwXcaxm/+4KvoKqGHHvp153wmhRBfs+VLCkGWMwYc51/BxO0cc0grxDgQvKus+ANA/xRXEDqVQ9k8618g5E+gCK5dwzsHR42ceS5ogLYnnuXRZmA5N6iLmVg2UneTRaluNG7DJJ3i3X1LcizW1AFPI9A8u4y/75rgLpJ7m3m/fcxBEnebZZ62wB6KWpJpsptd0nIepe5MgTv6FTEW0U6ZWkztw18D0sPigSSe5Ol3TRAUC2Ze4c3c8/Vau49ljqbM0oV7FL/LlWAN8Oh5QDedGt9m8NI3/VRMEfTu2Xa6l2dlv3Yi4tkL2uVQSvoZPeqG/xeVf+WDzj6KrpbzRa8Uc69aXDXmudVK9OEKQlHUE/C3Jt3j46w3PsGOJwVSN59Fn9gYK9j5D1g8QKIQ256A5IjSIvUuzW4MWMj00Ce5jdosFWaKbjcRUkneQUGOVftO0Rys0UWzSswQARepRPcTGJ1HP/DCthNkMeXDf1DTf6pAn0ottmi9p2b3DGi12RI8qiIr6ZsQ5I7VuQ7EJYLhjwVQW+zXOD342guKpKmCP4+zB+TvHGi79wMmU7S2EnEslHdxnvrxvWC7EtpbClm2ane47315jrT2mnsJM9ObZrgbRO3h9ZOY0sFXjvYO8HbXm4rrZ3GTvLsFIuJGiwY8BM9gZ/kC/wkX+BtvsDbfIGfXBTgJxcd+CkPB/yUhwN+6sMBP/XhgJ/mA/w0T+Cn+wI/3Rf4Gb7Az/AFPqcowOcUHfjchwM+9+GAn/lwwM98OOBn+QA/yxP42b7Az/YFfo4v8HN8gZ9bFODnFh34tx8O+LcfDvh5Dwf8vIcDfr4P8PM9gX/HF/h3fIFf4Av8Al/gFxYF+IVFB37RwwG/6OGAf/fhgH/34YBfrMGC5slbLJKTcC6wWJCag2DDe6Lr6JHkLxPZAeWGFaL8jgCJECQbVouw4d+wWiQbPhDlNa4gO2AYH8TOZkHDDRtEd/fAvduGD7lgw4cijahPkoV0kr8BonBxpfL91oYNIk3NcQXVzJCRF4D7OkilOXjN/NYTusKtCuaqrBPd3rRhnUgFXoW0KvEchau0TlQLeKjkqp1t97Xo7FbRWS+6h8GG9SIVeBXSqsRzFK7SelEt4KHSehVDRf0wG/WBMch4MB+SNb7IDlLUqEtI83mL1otUM65V/gbRYxDM8jgtdglpPi/RhvWix3BTz1K8n0hDPm/ROtFjYM92UxE8noFDPi9RPivqGldMYTXqEtJ8niJpgusjm/I3ivJcGGTTBfJUNbRho5gIt+UCe++D80YE+Liq/I18CEnkSc5WhT7YQjflRSrnvTuXttDnyfmbRfljAS40OJcHPxHlLQJcSP6nLPipyKKf0RGe/5lI8nezortZcC4PfsnyfymS/G9Yhm9YcC4v9h0LgnQfC+4TWdEfWN0/0Ewk/wCLHuAt/+SOQuYjLHoE+iH/Nxb5SST5x0X5AwEuICX5p9yl/qAzUv4fVEryz0IKFD7HtDgnsgoushIXRZKfL8prBbhAbgZkFEXtqihvFuACb7gLUhtE8m+I9GkCyd0nyMvpBnm/IK8UIA5Bkn9blO0C5IMgzZ/DozdEeSsNKnBIKr2FSP69wmorYLXdEyFI8+fAaQnPbyhSfha9x1q/B283zhekDzEi+WONhTQ/wUirG2uEIM0fuHm/+UU1v7FI+Vl0rJGqOxY+H3a+IB0DdW2FqTuVVWczQpDmD6yu3/wB1PWbP0jNH1yk/CxqY+bZjIoJzJsuIJI/ozDzZrLqZhghSPMHNs9v/gDm+c0fwDy/+U1q/pAi5WfRGQyOGUYlFOCohgLBMIdVM8eoCPJWQZJsC/EwRJAk5rfCCBGTpGCE8mdfP9VkZv9tw5s76yS9/vKYMR83bbe18tJapzKf614TEadBUp69P+pIzDTliel7BvSamT5mnm8umygpk+9M6fDqvWpX7+KmhyJKnt1yI4uEFiSsebZsva17Biw5EoSIXZSUdy05X09v8vrBJ6VvryedHxZardnwYf2WZ/SocSJ4wedDQ8MQcYiSggr7IU5RUpaPfqqP1Exe3OzPxzY337J7b/La3Sm/JSYdjcqb379hpdpxiNiMkrKi0Fx2Y1Hqchgl5YNLFyMnN/+yV9tdH2T2yjJNrxVpCnl22ann7+yu/OzGw68kIuI0Skr7p8t+bCxnars8M77Tik4nU2Nf7Ly0b0RURmiv1lsXlShphm+CLgr2tjBJWd3Xuq7pma2lT7/y2umNjR50mJC9vcOT41pMW/nMc1kb82IEROxhknK3oKBtfN2311be33nJ3CH36if7ohpWJFRZrlvf3cl/r/nWo0+Uv1Zyjh9Uw6n2heSyh0vK06+UfSoqZN7CSeOfGndgQnRcr1fFCQuFUiWSzz4TZKAtOsIlZdGTP2Z3HJjR7XBB0/KDrlZddsSwKWF3laYvnr3drfKcS53j4AvDJWXp2vCyU8bv3d+k8RLy1xeh5s3Vx37RBk8PmTcwcRymddniJOXnpA/bvb8ndsQ2a8dTIz5PLzv+QO+05861qjPj3djvn+lZtgoijpqSEuH6keXwMIvFLIWGmIKDg4yiQcAYwwfJ1ipKLlsdaWlwYeAHIbR06Oet5vVc/vKvmwY0uJzs5TRTLx1dPO/JwVnKzGc3Vot9+s2MPiGDhnfdOP0H0+cN641sUPXpUR9u+b3lh7d2Ttg7ruCbztVvVp7zetX7Q355/5cFT58dlVLekFNj0Ki3Pr62r1det6PVS/dKf+lu6Us7/pz24ImPDzxfeVRM99Yv7dp4Myrxylu1btYodztp/+APN9jHD/7T0Df26Ct3x1Td1SVnzJ+G3BlfPLi1sO6uhdOe64Cf3v/30Q5PfFD5z95v51bcOHJMxZpfDQ/Nf6vDO6P2bRp5/AwRfqq05+PW+bXrP/3RCLSv5bJxT29dvyyjw+vtf+l4ZVbJYxMFU4/Bb7SoUP3rVRtHxh0vtyLx7OMdFlkyToyKfLdKd+PuBSnNBu+wjG335KbprfPR+Ahz0uaPriVUq/LGui8OjfghLnX5130eD9o6bfeJ1G1fNS+36Ye26yZbzzYP7nRr+hN3DaGhyQvP1ZvSpmBomUX7k6e9n3Twtwsf1Wh/qMyHVzvmza6S2MvZ8aePery1aGezW3O6bL0xq/Th55YO33m09eRJwQefST/eZ+6bn//2c9WP33vluX7ZC+Q/zkduPWds8+3SEp/G1FoT0e11nNxp6cpp1WYZtvw65/SDn6N3Br2w9f6rxpvPZV85933KgN6rR+yd/GBTr07f3fs26KvL9eKblakzqGHDV85+9OyP5eMtsxo16tvkzZuDno+s+96LP6X/jcuOLT3qqBh5ZKvxVzK9ZtCZKrWbV5u8eHylGfXqzfqp+uG7e8LF8VL/kBrf9KjQeeKupUMaxdW5/HK7l17JafhL3f0/Nvw+ua+x/ohlZz5Zvljc8dtTRsOZ85cOLf6+UafN5ce/Mdy2KnfcqKRSs6d/kHqo9q+LcrK7TLiRVnHCBscfzdaMLF9KODxmUo/HLU/UqH19lvVcpdV/5aT+NT5uY9ruDkt3lJvYaFXDUxXyr+ZEXil1aUdG4oyFnXunnFhzueniJ7ev/umlA9M77Fg+dphh9mOhaObi3WL55hmbKqBXvp052BKx841GwysJK+yt3//8y1Xdcc28tkfSPkv8tlpM+x8qtgzr/Nfqq01/Hp1597VKd9M2rW4f83vway8V3AlL+XpBTqsWA8t1bPDh2TEX1wz/oGFyG9PWP78p9UCZ8l3inGVL331tduqerocG3hzb9FBGy09PfTy2kXl31L2knsLk7Kjur0xqYdj9x5ZhjVqO3riq/bG2qEXkuTOpx2KbJhU+fdgbFWGYPigoKHsk6olhxxKmm/vVmL++adv792YNejNn7a5FT5bq1qBsQUFBeJ/QhB0ZOc0mfhK77+dlq0ePbvHp+mcPv/l9wvSNC8MLmVsLm33lQtJNhaSLhaQLhaTjwMnZhRRPKSS92PyAP8Xmw73A50haGjyqoODprW++VRB3vcsT7zV6ounNfs81/NOy6Mao9LTfv5z2rDnmasGSifOuvBrS+jHJ3PyDH28cXZpTeturXzZcaf2pn3OZfHLoyQK8qvOO9Ml9l/+4tWPTj+cvTN228tCJCln22II/TlTOmv16wrAbd0acv1j9t41TL21eVvNQzXaLnt4+IvdE+4HfpQl/3keNonIn7Rs3dUNm+trqd+t3PxfyYFuzRr8tfn31K10+ixJyd6x/MejY9Qo/iOUqL/qzbFaPbodSfn1j8t7pyaGHgiYlhx/p9/O04U9OlM9UOHdhT8tdHcOONO7crtfGDj2/e3FvcGvlUofYMlXXf4iux359YmW3Z/Yn7KjT6vfc13ddKtVl9cWjZ60dxYJ9B9r9vL7r3dUN8u72/0pJjri5LO6z5MO1Uud9FjSh9Mjfk1fdPNap2rcd/6xxfsXNIVkXrxz8ouf47cPGj68l7dsYcn3Y2L2lS/a4GrU4ZOCReh12HDX+MrTT2HHf9Z7Q9cSmPi2Eqd9ebJItfn12xZajyhzjk+vfWF/J8UL+3FdOdf51f/0fKoXFp8wpmPzyzeOx25/YFvHmp6TiH9bm1zp+duWr0vX2Dht/v8rNDq+1+OLomwdfS73f9PFRV9YunEq+++JpnHZtgr26KX2m+HuD3/bumTjvctVXSfmRJxY2qNWsVtIPr6Z2ivs1ZvaSlCrxt9dZfv7osytzFjS9Mr5az/wbIdXWlK+7OWxk6uCpDc58e9d6dd+3GTEj2/b7NX0YKvHh/R0rn9206siejGGbr2X9kJkr19x8cvFB4bPhBlvesLnHa93cOzry8Rb1L+7c0m3FtSanetgqh4x947Q1KuflanHNN+290uRI6NtXW5+Oyd9++ssNb66/fDw8JPLXias+srRPbhnc7LWPS+xqGEK+D6v56QynedOQ154fVq3b+47o56LvxheMbNT2i079lna7tnvt291rtPp0aNSU3+fPqTgko0PN80t3tV395wRzl58b3JWih5bLr9dsaMmlfXs//kG9sK5VrTW7GxbZl38ZN2x94rWkSy9/cPuXb+Y33LOmYf33l56oOrR99qsTRj5ztuk+xw+DVk08tWj60RT57EBhRPrTVffg+iHVJjjKvLb6jXrv9ilz9cLW9g/KJJc3by/x46a/KjW8tfGVlYahBVdHNDt5Z+iWX0la29eqPHUofk+JjS2/O1xd+mv+9RwS+2DcmlE9Z87psL8J2b1m/HMPag4xDioXrZTYLl8ct6DBONT5eNixH6qU2Nj4mQr4p6qtttcaUf7Tku90/Gha0EbH7ydGlPqq5gJbj10vd+83b/Cr3+1anVs2f2zCnC+lFo2mr/jyhZdKl0fwPU3S0uAXO3a8/snyt8dKrSo+XzN/6NfORi++WP6XKRUGRFvfbl13fvS8frcrftHreNgrqc2G/9rl4NaXnnSkjhl9N+Fg9qY905YcQu3CP03CLwtHKk7adsnR5Y/Fr/9Q/dXm4eeGLp+asKTRjmZJ33/yZ/DeGmc+rx7TdWiXydt7/F3O+cbZL8q0bp5f9snIpBPClivfZxTU6t3s0FdvlJ+7v1+JthmzV1z46d3YBs1aL5gnbyoV9tbtlHdM31X6pm9E1tr3LQuXhDYz1pv+9vfPvJvwZ6t7H+KnK5RbsuWFsusSV67+074vekDpch0KZn/eqXPJm0PqdGifizdnlcr90NwuY13N6HFXhi26vrxjqRN1P+3bLn/Rc7/Yh7aq/kTW/b+kLY+PrjWqTdDsfjH3v52beu/V4U9vdmzKTOr2W4ukF4LfeaXfpK3y0H4Xu444N/n5H2pumFFp2bj3s+t9W3vZGw/i9lVqVeFcne9GPb08/ND49zr1XdQu+N3PnosyTlj7VLYFSWW++fPO6C+ubbtXN2r//Vde+P0VcfrOSrvfnrzq/pq9X9Veu6/U+qgeL39RUKrxU+2SF31swYMNu03THo+q32prpcsP7ObDsZOrd3u3ganFphHrI04M7N2+1AL7a4ZGdTce/TtzZK/3Wmw0DLz7bbnF334yvb9l8YNqy/dPDSn9zojUn3KfsG38NuXwLSTmnh2G95x4amDQvthLJzdIYftO3/jhs/3LRqZH7B7y1uB+1dNGVdpVr4Rl/aKIgjvlr9S6ndXuwMGWeWu7rn83rellvBD3mrwuocyTMwcYxLib1hoxhqREq2nZZ7e+X1g9aOfJzY3lvt+13ZVVb8GudrsrNh59o9z3Se8sxr8Gn7asmV/24K+lnjXsL5e5beLka4O6V6rYbfTNsSueWruj4eox+y8k/DIvrc3oWjV/zTYvPvjGqejV1eefndzrwpCTd1tfbH6g1fNN5M5TX3hmRfDf6W8+8enhoV+WXCYNXXlr556tk/dvXtIt/63F2Xvif4hsahx9o0yGnNX04KasEi9e7rHx44l7p+Z0qtOk8vid5vMtKg8pVRef/qr5xaVDI4dEVa049qM5z3/+bdCx+bO/vbqmdI1VoxrEHz5SBrdRqrauePr5W3v6r+/Qv2KVJS2fvn/3VHi4Mr7BZfPqWWveO/z1xU/KbMEPVtdvOKVbsy/G33Ac61uj9tTQ1GdbRS653GHBxjkLDUs2Rey61fFu2IWCHYN7flXio9Dhc9ekXr1f+eD5B9aZGyJn1ps+5P0/Vxx7YdTwXrOf7933VP+CsmNeDS1X9qeLY5f8uKHH4nafrxoUXtt8MaTexp8Oftg9ruuihNKnn+oZjYgtD0nZAspO2a0s7XxSzm2XV3ND/3yTrbkjyd7LGTf/5SOPbR12Sxz/zFflV3T/I2rOC4fqbh50zTyt9b5qa/tciF/02tEndoy6J4xt/EXisq6/R85qf6D2pswroVNa7qnyQfq5Ugs6/dro0xF3giY2+6biqh5nYt5+8XD9j4fcCJvx3PfJ6zL+Tlj8xvGndo5+gMeQz63vdTkVMfP5H2ttHHA5ZHKL7yq/n/ZXyXde+aXhtuG3jROafl1hZeqf0XM7/lRvy+Drlult9lf/sO/FMu++fuzJz966bxjX5Mtyy7udLjG7w8E6Hw28Kk1ttbfqmt7nSy989bfHt4+8Gzzp2W8rre55NnbeSz83+GTozfCctj/UWN/vUtklb554eldWAf0CGEl5vvBDGchWhDOlE0WqzX4KSSl2YevQ04/dfvz1DnXqVyotCZ3bD26Rf/GTin3t45vU/iaqQs+Coz/uu3D2sacs389+66P81A/Q2sRjeS1+bjO9V8vvtxGMiH0WLtJBxJyiZZuHiw8sig8sig8s/t0PLBYXZZwWn1gE+inesgf8KTY/4E8RTyxW4uITi+ITi+ITi3/3E4u1uPjEovjEovjE4t/9xGIzLj6xKEDwAXfF+/TifXrxPv3ffZ/uKN6n/0fs1AL8FJsf8Oe/wXz4DNTifXrxPr14n/7vvk8/XLxPL96nF+/T/+336ceL9+mUWXAdS50Le6WlUemEqaUnfbpqZMyM888fvhz18rQr+cebHdv3xs7wuuMuRcUX/kqM/QaWOhdyo4MKraawH2K7iaXduKKyQ/hxy7gZmXhki3olzx89UWrMvGcrbr37eLu315PHXiqZ0qW1/a2Bm9d/dUR4udOxJp0n1lja/l67v0J6jzzXaFz+g6gbf/W2vXvn3S7DFi6+Pu9A1oMHb5Uu17XU4oKgxovXnR99P+nvF+O+ffHVkO7bn3irduLtl44OkevV2Vnvdsex3e/PPrN0heVft8NxC+woNN//NJ7/6g+x3cFStuH/XI//33/gxWwp5WaWhXz/bNCNiLzSB9v0e7LGj9+kNBxdp0nll+afXu2cP7dMEV5sg2oyjUFtD5zdOenP9Pgax6rcz3vG6yygCNo8wI+CWGR7X3gEg+T//Ac+wPG/wg7bzv8OOxx7BYnQfT9GwDmDP4TUAMZMhrgcsQBPQa5cCD7sT0qpuaZbU/nxoVte6P7B+46ZWXVnhiSXrzQAjbgQNTbiyI4XS7707AdLE5aMzyAzb03uOzL+g0Z7Tt7ZX+Lsx1+eH/vc9rZpFRF8MqCUUvnj+pXNx7b/sffTOqe6Xq65vUeH7rc//vH9WsduoZU7+9er8O3QB2/+Mern9377seKwiPvrg3sfHb290mcxffc9OD5BUCZVox+uJaX86ytT7phHUk3eo6kmd+yj0ebRVJM77tFo82iqyR0vPgr3y4NqZu1sND7r5y4D70bUrXSw6vaV75R7qlWtsnMWXTi4ZPuxRSeiW3x3pFX0/WOvd371mRUrK+/tuu3AW+bQSTsa3M8fUOvd0HHlEXykmZQS3CKqzturFq6f8sn6SQPL9N4zSZmS/8bFzyJGNSpbanCbq0Jm9Raty61LXPbqqddfXCGE51X87kSHZVdrHH1+7uSPYl5aLSP4qLNHMRhyJ4pSytnwNFIjrf93Uqu0Sta6Kb87X/lqXO8zO2sT24bQizs+iHx/17qUcq83t7y0r8aauLoljdflFlOkFRsOdpp1oN6W89Ya9HPTHklPTRKllEWSs8QMR7s6215847dRHb9/q+WL0R9v3Yw7n4wVhNgzYysWwW+gmo6nxv4cYZ49oFydnQWj5mxf9UzUoEPP1Kn5QZMWr1S0PP14tSJoYxOllCul7yBj9vQ9afM+6hV1+Ov8uGcsHw6IVMLOvHjk09TwyoUdqYI2UE2hb5sXrs1kUUpZc3nOV7YvfzAdGlhielT0RyVLCH323s997uUWthonXu11KqQI2kx+ND01RZRSPuz9YczNxPXfbeq6qmWVYREfXfu2+e/d1/9dcuySJqeHPlVJWTv7+5udk3avbd179cgxP9Vp2HN8n2emxp1J67gv9pm+hmahCD6VTko50bXnyJWzpzxz4tz9pOvVD+8acWhhWN71l4+8fGFI3TZPbgj6sf53O679WrLqksrXXhzx3Mr3Lq873unk33W2bFp6bHzVMeZYBJ9WJ6W89Uuz5+JiOtRf0ve7Q4sjb4ZuCZH31Fj9bmo5y7Jxk/tGmBqWXPTlzZYnNmbtGjhlkrDkyZOh66fNUhIXrnoh/1J0014wwqGahGebrQ9d3/2lz8OfmpQ8vN3RG2IZW8HAVRNbr675xOZjyVL2hNHDaoe3WLDxVsv8rL4/5lwZKXwzw9aw1evvtX+1f/IxA4JPt5NSlnT8YXBiqx0nw8+88HnTbY998cZbC2atHNswe/T/2+In33VZz4kun2m+f+97Dd1i9mtSNnWcs6ODvdYLO+rOSE5gfTyx86EK+Eg8qsRUL1Uyw4VeqmTNCX3UyeF91AmbfuqETT91XDOBhdth4+MXIWq7pH4KnZt0R/90obvp/e4/D7I23nnSPffs1IVe6t3yjRLrAv7E9MxwPm3csslbMmnrYeH4y/5WHSf093pKGjCADhzkdrh2+9aNjwomLZvO2kucFPhg6JmwXH2rQbLzk/tSH91LrgiX/Apfoezg+V5KYPVVpthJWgL6y2Y3iW5oXrxOmEdW0FKVAXQQIbdD2QQj6ab87W0i2yR9tb92O+i+bL15Yef94OWXmjJFFORYj78OKr8yZw+/yj1Rk8f/+3N3Op63+KDzaV/I/jSb/28PiDKADiikSj01iYXbYYdrmsnnh97iLLNfz1Rp/XG/VPkan9WcKl9baZO3Dh7KzK7XWcM3yjHGrGSVuLFlS6HukVlNy/Y9OlNjlJfS5/9GWQ182iFVYmoyddo31DFmwhSqVDAXqGPMhKnUcc1U6oTNNOq0/aZRp+03nYXbwWFLxtKGpy09TMKHHsj6ip29av59QnjEpGVrU4WO/2Uo1L163rjn892/Mw1fCgu9TS86bta/UFckSOHOda4VujHf98gzgM6epEo9NYOF2yHhrfD050obihrrORwLzBy3lvzb89crfmLrC/HGa60Td8rOsz03/bPeDT2zf457K8wyJmW4W3xftXD+k3O88av3Jjkxgg+ypEpMzaROzTCTOm2/WdSpGWZRJ2xmUydsZlPHNXOo0/abQ52231wWbodTymZd/0rPsr6LWTH5U3hXzwq/wu1t8zYFsU3uj335IEiD78kDEXlHxy5e7n93OTMeRdb6XvqirKon2+zt+DGG8w8nA+hYUarUU/NYuB1WLF+b9MUhJbr2icxy740eV//devZO4LCYxeo/Pi9dPKdJLUh2lYyc851P6vBs39A35X8YWc0vLWJRVjhmr/PvwZEmbvAZpdwPmBQ+tp1K8Z7WtkTZ9en290scdnu9mFaxsr5ZYuemnduYBM1uTQr7fK/x3oGE44eXvTjOsq9+d8HVkz/TrjtKhDX7Tjc4tDhz3+EMsV3RU5KCBI4IWtTLLL97q/bdLk2GlbEivdaN+3Vm2Tvd3yWdEnfmlcurLdwrah7/FfFISz17aSJTxM4UZq+7H9Q4Nt6f/E7FPfBo722n7FZzfm7n8wK7xZwa8h38PB1+r/q8hv3h+dD2da8fNLzpUFhgvljwgl1Wy9RAKzmvqCUeYnxH72e4pj19fYTHR9Mxa/Wt4xmXmK5daOo6YvN2lktG2p9Yxk38Z5MCLm6+u3GFg2a9R4qSltW2r+XrnJ8kCld8+Hfi2NUOvvbyn6uy0+WXpTBXLr639pze8/aIAulZC5KflgtvOnxD+t37EJ7vN1SuRl08bBdrZbEpLeTjrQP/puwu5nr88FG1fTxjoUzW/42ZyfuddVv2KNQK3L/1V6HgZK63Pjgpb9jIwm0PGrz6zwAd54Isc2Fk+A8Z9YIsegFx/0OFoNR/mHJGAN6Zbh9JUgEA";
+ bn128_wasm_gzip$1.pq = 488;
+ bn128_wasm_gzip$1.pr = 1768;
+ bn128_wasm_gzip$1.pG1gen = 31432;
+ bn128_wasm_gzip$1.pG1zero = 31528;
+ bn128_wasm_gzip$1.pG1b = 3080;
+ bn128_wasm_gzip$1.pG2gen = 31624;
+ bn128_wasm_gzip$1.pG2zero = 31816;
+ bn128_wasm_gzip$1.pG2b = 12456;
+ bn128_wasm_gzip$1.pOneT = 32008;
+ bn128_wasm_gzip$1.prePSize = 192;
+ bn128_wasm_gzip$1.preQSize = 19776;
+ bn128_wasm_gzip$1.n8q = 32;
+ bn128_wasm_gzip$1.n8r = 32;
+ bn128_wasm_gzip$1.q = "21888242871839275222246405745257275088696311157297823662689037894645226208583";
+ bn128_wasm_gzip$1.r = "21888242871839275222246405745257275088548364400416034343698204186575808495617";
+
+var utils$5 = {};
/*
Copyright 2019 0KIMS association.
@@ -6272,1276 +6297,1124 @@ var build_f2m = function buildF2m(module, mulNonResidueFn, prefix, f1mPrefix) {
along with wasmsnark. If not, see .
*/
-const buildExp = build_timesscalar;
-const buildBatchInverse = build_batchinverse;
+utils$5.bigInt2BytesLE = function bigInt2BytesLE(_a, len) {
+ const b = Array(len);
+ let v = BigInt(_a);
+ for (let i=0; i> 8n;
+ }
+ return b;
+};
-var build_f3m = function buildF3m(module, mulNonResidueFn, prefix, f1mPrefix) {
+utils$5.bigInt2U32LE = function bigInt2BytesLE(_a, len) {
+ const b = Array(len);
+ let v = BigInt(_a);
+ for (let i=0; i> 32n;
+ }
+ return b;
+};
+
+utils$5.isOcamNum = function(a) {
+ if (!Array.isArray(a)) return false;
+ if (a.length != 3) return false;
+ if (typeof a[0] !== "number") return false;
+ if (typeof a[1] !== "number") return false;
+ if (!Array.isArray(a[2])) return false;
+ return true;
+};
+
+/*
+ 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_int = function buildInt(module, n64, _prefix) {
+ const prefix = _prefix || "int";
if (module.modules[prefix]) return prefix; // already builded
+ module.modules[prefix] = {};
- const f1n8 = module.modules[f1mPrefix].n64*8;
- module.modules[prefix] = {
- n64: module.modules[f1mPrefix].n64*3
- };
+ const n32 = n64*2;
+ const n8 = n64*8;
- function buildAdd() {
- const f = module.addFunction(prefix+"_add");
- f.addParam("x", "i32");
- f.addParam("y", "i32");
- f.addParam("r", "i32");
+ function buildCopy() {
+ const f = module.addFunction(prefix+"_copy");
+ f.addParam("px", "i32");
+ f.addParam("pr", "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),
- );
+ for (let i=0; i>1) )&&(i>1, k>>1)
+ )
+ )
+ );
- 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(c1,
+ c.i64_add(
+ c.getLocal(c1),
+ c.i64_shr_u(
+ c.getLocal(c0),
+ c.i64_const(32)
+ )
+ )
+ )
+ );
+ }
- 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))
- );
- }
+ // Add the old carry
- function buildIsOne() {
- const f = module.addFunction(prefix+"_isOne");
- f.addParam("x", "i32");
- f.setReturnType("i32");
+ 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)
+ ),
+ )
+ )
+ );
- const c = f.getCodeBuilder();
+ 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)
+ )
+ )
+ );
+ }
- 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.i64_store32(
+ c.getLocal("r"),
+ k*4,
+ c.getLocal(c0)
+ )
+ );
- 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)
+ 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)
)
);
+
}
- 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");
+ function buildSquareOld() {
+ const f = module.addFunction(prefix+"_squareOld");
+ f.addParam("x", "i32");
+ f.addParam("r", "i32");
- return prefix;
-};
+ const c = f.getCodeBuilder();
-/*
- Copyright 2019 0KIMS association.
+ f.addCode(c.call(prefix + "_mul", c.getLocal("x"), c.getLocal("x"), c.getLocal("r")));
+ }
- This file is part of wasmsnark (Web Assembly zkSnark Prover).
+ function _buildMul1() {
+ const f = module.addFunction(prefix+"__mul1");
+ f.addParam("px", "i32");
+ f.addParam("y", "i64");
+ f.addParam("pr", "i32");
+ f.addLocal("c", "i64");
- 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.
+ const c = f.getCodeBuilder();
- 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.
+ f.addCode(c.setLocal(
+ "c",
+ c.i64_mul(
+ c.i64_load32_u(c.getLocal("px"), 0, 0),
+ c.getLocal("y")
+ )
+ ));
- You should have received a copy of the GNU General Public License
- along with wasmsnark. If not, see .
-*/
+ f.addCode(c.i64_store32(
+ c.getLocal("pr"),
+ 0,
+ 0,
+ c.getLocal("c"),
+ ));
-var build_timesscalarnaf = function buildTimesScalarNAF(module, fnName, elementLen, opAB, opAA, opAmB, opCopy, opInit) {
+ 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.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.setLocal("eY", c.i32_sub(c.getLocal("eY"), 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.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.getLocal("startBit")
+ c.i64_const(1)
)
- ),
+ )
+ );
+
+ // Force a divide by 0 if quotien is 0
+ f.addCode(
c.if(
- c.i32_gt_s(
- c.getLocal("chunkSize"),
- c.getLocal("bitsToEnd")
+ c.i64_eq(
+ c.getLocal("sy"),
+ c.i64_const(1)
),
- c.setLocal(
- "mask",
- c.i32_sub(
- c.i32_shl(
- c.i32_const(1),
- c.getLocal("bitsToEnd")
+ 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_const(1)
+ c.i32_eq(
+ c.getLocal("eX"),
+ c.i32_const(7)
+ )
)
),
- c.setLocal(
- "mask",
+ 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_shl(
- c.i32_const(1),
- c.getLocal("chunkSize")
- ),
- c.i32_const(1)
- )
+ c.i32_add( R, c.getLocal("eX")),
+ c.i32_const(7)
+ ),
+ 0,
+ 0
)
),
- 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")
+ "sx",
+ c.i64_div_u(
+ c.getLocal("sx"),
+ c.getLocal("sy")
)
),
- 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)
- )
+ c.setLocal(
+ "ec",
+ c.i32_sub(
+ c.i32_sub(
+ c.getLocal("eX"),
+ c.getLocal("eY")
+ ),
+ c.i32_const(4)
)
),
- // Reset Table
- c.setLocal("j", c.i32_const(0)),
+ // While greater than 32 bits or ec is neg, shr and inc exp
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.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("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(
+ "sx",
+ c.i64_shr_u(
+ c.getLocal("sx"),
+ c.i64_const(8)
)
),
c.setLocal(
- "idx",
- c.call(fnName + "_getChunk",
- c.getLocal("itScalar"),
- c.getLocal("scalarSize"),
- c.getLocal("startBit"),
- c.getLocal("chunkSize")
+ "ec",
+ c.i32_add(
+ c.getLocal("ec"),
+ c.i32_const(1)
)
),
-
- 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.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.i32_store(
- c.i32_const(0),
- c.getLocal("pTable")
- )
-
- );
+ 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 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
+ function buildInverseMod() {
+
+ const f = module.addFunction(prefix+"_inverseMod");
+ f.addParam("px", "i32");
+ f.addParam("pm", "i32");
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");
+ 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 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
- ]);
+ 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.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)
- )
- ),
-
+ c.setLocal("t", aux1),
+ c.call(prefix + "_zero", aux1),
+ c.setLocal("signt", c.i32_const(0)),
+ );
- // Allocate memory
+ f.addCode(
+ c.setLocal("r", aux2),
+ c.call(prefix + "_copy", c.getLocal("pm"), aux2)
+ );
- 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)
- )
- ),
+ f.addCode(
+ c.setLocal("newt", aux3),
+ c.call(prefix + "_one", aux3),
+ c.setLocal("signnewt", 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")
- )
- ),
+ f.addCode(
+ c.setLocal("newr", aux4),
+ c.call(prefix + "_copy", c.getLocal("px"), aux4)
+ );
- 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)
- ))
- );
- }
+ f.addCode(c.setLocal("qq", aux5));
+ f.addCode(c.setLocal("qr", aux6));
+ f.addCode(c.setLocal("x", aux7));
- 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");
+ 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")),
- const c = f.getCodeBuilder();
+ c.call(prefix + "_mul", c.getLocal("qq"), c.getLocal("newt"), mulBuff),
- 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.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.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.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("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();
+ c.setLocal("swp", c.getLocal("t")),
+ c.setLocal("t", c.getLocal("newt")),
+ c.setLocal("newt", c.getLocal("x")),
+ c.setLocal("x", c.getLocal("swp")),
- module.exportFunction(fnName);
- module.exportFunction(fnName +"_chunk");
+ 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)
+ )));
-/*
- Copyright 2019 0KIMS association.
+ 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"))
+ ));
+ }
- 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
+ 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.
@@ -7554,2865 +7427,2924 @@ var build_multiexp = function buildMultiexp(module, prefix, fnName, opAdd, n8b)
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
- };
+var build_timesscalar = function buildTimesScalar(module, fnName, elementLen, opAB, opAA, opCopy, opInit) {
- function buildIsZero() {
- const f = module.addFunction(prefix + "_isZero");
- f.addParam("p1", "i32");
- f.setReturnType("i32");
+ 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 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 aux = c.i32_const(module.alloc(elementLen));
- const c = f.getCodeBuilder();
+ 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))),
- 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)
- )
+ c.setLocal(
+ "b",
+ c.i32_load8_u(
+ c.i32_add(
+ c.getLocal("scalar"),
+ c.getLocal("i")
)
)
- );
- }
-
- function buildCopy() {
- const f = module.addFunction(prefix + "_copy");
- f.addParam("ps", "i32");
- f.addParam("pd", "i32");
+ ),
+ ...innerLoop(),
+ c.br_if(1, c.i32_eqz ( c.getLocal("i") )),
+ c.br(0)
+ )));
- const c = f.getCodeBuilder();
- for (let i=0; i> 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;
}
+};
- function buildCopyAffine() {
- const f = module.addFunction(prefix + "_copyAffine");
- f.addParam("ps", "i32");
- f.addParam("pd", "i32");
-
- const c = f.getCodeBuilder();
+var build_batchinverse = buildBatchInverse$3;
- for (let i=0; i b ? 1 : -1;
+}
- const XX = c.i32_const(module.alloc(n8));
- const YY = c.i32_const(module.alloc(n8));
- const YYYY = c.i32_const(module.alloc(n8));
- const S = c.i32_const(module.alloc(n8));
- const M = c.i32_const(module.alloc(n8));
- const eightYYYY = c.i32_const(module.alloc(n8));
+function square$1(n) {
+ return n * n;
+}
- f.addCode(
- c.if(
- c.call(prefix + "_isZeroAffine", c.getLocal("p1")),
- [
- ...c.call(prefix + "_toJacobian", c.getLocal("p1"), c.getLocal("pr")),
- ...c.ret([])
- ]
- ),
+function isOdd$4(n) {
+ return n % 2n !== 0n;
+}
- // XX = X1^2
- c.call(prefixField + "_square", x, XX),
+function isEven(n) {
+ return n % 2n === 0n;
+}
- // YY = Y1^2
- c.call(prefixField + "_square", y, YY),
+function isNegative$3(n) {
+ return n < 0n;
+}
- // YYYY = YY^2
- c.call(prefixField + "_square", YY, YYYY),
+function isPositive(n) {
+ return n > 0n;
+}
- // S = 2*((X1+YY)^2-XX-YYYY)
- c.call(prefixField + "_add", x, YY, S),
- c.call(prefixField + "_square", S, S),
- c.call(prefixField + "_sub", S, XX, S),
- c.call(prefixField + "_sub", S, YYYY, S),
- c.call(prefixField + "_add", S, S, S),
+function bitLength$5(n) {
+ if (isNegative$3(n)) {
+ return n.toString(2).length - 1; // discard the - sign
+ } else {
+ return n.toString(2).length;
+ }
+}
- // M = 3*XX+a (Hera a=0)
- c.call(prefixField + "_add", XX, XX, M),
- c.call(prefixField + "_add", M, XX, M),
+function abs(n) {
+ return n < 0n ? -n : n;
+}
- // Z3 = 2*Y1
- c.call(prefixField + "_add", y, y, z3),
+function isUnit(n) {
+ return abs(n) === 1n;
+}
- // T = M^2-2*S
- // X3 = T
- c.call(prefixField + "_square", M, x3),
- c.call(prefixField + "_sub", x3, S, x3),
- c.call(prefixField + "_sub", x3, S, x3),
+function modInv$3(a, n) {
+ var t = 0n, newT = 1n, r = n, newR = abs(a), q, lastT, lastR;
+ while (newR !== 0n) {
+ q = r / newR;
+ lastT = t;
+ lastR = r;
+ t = newT;
+ r = newR;
+ newT = lastT - (q * newT);
+ newR = lastR - (q * newR);
+ }
+ if (!isUnit(r)) throw new Error(a.toString() + " and " + n.toString() + " are not co-prime");
+ if (compare(t, 0n) === -1) {
+ t = t + n;
+ }
+ if (isNegative$3(a)) {
+ return -t;
+ }
+ return t;
+}
- // Y3 = M*(S-T)-8*YYYY
- c.call(prefixField + "_add", YYYY, YYYY, eightYYYY),
- c.call(prefixField + "_add", eightYYYY, eightYYYY, eightYYYY),
- c.call(prefixField + "_add", eightYYYY, eightYYYY, eightYYYY),
- c.call(prefixField + "_sub", S, x3, y3),
- c.call(prefixField + "_mul", y3, M, y3),
- c.call(prefixField + "_sub", y3, eightYYYY, y3),
- );
+function modPow$2(n, exp, mod) {
+ if (mod === 0n) throw new Error("Cannot take modPow with modulus 0");
+ var r = 1n,
+ base = n % mod;
+ if (isNegative$3(exp)) {
+ exp = exp * -1n;
+ base = modInv$3(base, mod);
+ }
+ while (isPositive(exp)) {
+ if (base === 0n) return 0n;
+ if (isOdd$4(exp)) r = r * base % mod;
+ exp = exp / 2n;
+ base = square$1(base) % mod;
}
+ return r;
+}
+function compareAbs(a, b) {
+ a = a >= 0n ? a : -a;
+ b = b >= 0n ? b : -b;
+ return a === b ? 0 : a > b ? 1 : -1;
+}
- function buildEqAffine() {
- const f = module.addFunction(prefix + "_eqAffine");
- f.addParam("p1", "i32");
- f.addParam("p2", "i32");
- f.setReturnType("i32");
- f.addLocal("z1", "i32");
+function isDivisibleBy(a, n) {
+ if (n === 0n) return false;
+ if (isUnit(n)) return true;
+ if (compareAbs(n, 2n) === 0) return isEven(a);
+ return a % n === 0n;
+}
- const c = f.getCodeBuilder();
+function isBasicPrime(v) {
+ var n = abs(v);
+ if (isUnit(n)) return false;
+ if (n === 2n || n === 3n || n === 5n) return true;
+ if (isEven(n) || isDivisibleBy(n, 3n) || isDivisibleBy(n, 5n)) return false;
+ if (n < 49n) return true;
+ // we don't know if it's prime: let the other functions figure it out
+}
- f.addCode(
- c.ret(c.i32_and(
- c.call(
- prefixField + "_eq",
- c.getLocal("p1"),
- c.getLocal("p2")
- ),
- c.call(
- prefixField + "_eq",
- c.i32_add(c.getLocal("p1"), c.i32_const(n8)),
- c.i32_add(c.getLocal("p2"), c.i32_const(n8))
- )
- ))
- );
+function prev(n) {
+ return n - 1n;
+}
+
+function millerRabinTest(n, a) {
+ var nPrev = prev(n),
+ b = nPrev,
+ r = 0,
+ d, i, x;
+ while (isEven(b)) b = b / 2n, r++;
+ next: for (i = 0; i < a.length; i++) {
+ if (n < a[i]) continue;
+ x = modPow$2(BigInt(a[i]), b, n);
+ if (isUnit(x) || x === nPrev) continue;
+ for (d = r - 1; d != 0; d--) {
+ x = square$1(x) % n;
+ if (isUnit(x)) return false;
+ if (x === nPrev) continue next;
+ }
+ return false;
}
+ return true;
+}
- function buildToMontgomery() {
- const f = module.addFunction(prefix + "_toMontgomery");
- f.addParam("p1", "i32");
+function isPrime$1(p) {
+ var isPrime = isBasicPrime(p);
+ if (isPrime !== undefined) return isPrime;
+ var n = abs(p);
+ var bits = bitLength$5(n);
+ if (bits <= 64)
+ return millerRabinTest(n, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]);
+ var logN = Math.log(2) * Number(bits);
+ var t = Math.ceil(logN);
+ for (var a = [], i = 0; i < t; i++) {
+ a.push(BigInt(i + 2));
+ }
+ return millerRabinTest(n, a);
+}
+
+bigint.bitLength = bitLength$5;
+bigint.isOdd = isOdd$4;
+bigint.isNegative = isNegative$3;
+bigint.abs = abs;
+bigint.isUnit = isUnit;
+bigint.compare = compare;
+bigint.modInv = modInv$3;
+bigint.modPow = modPow$2;
+bigint.isPrime = isPrime$1;
+bigint.square = square$1;
+
+/*
+ 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 buildInt = build_int;
+const utils$4 = utils$5;
+const buildExp$2 = build_timesscalar;
+const buildBatchInverse$2 = build_batchinverse;
+const buildBatchConvertion$1 = build_batchconvertion;
+const buildBatchOp = build_batchop;
+const { bitLength: bitLength$4, modInv: modInv$2, modPow: modPow$1, isPrime, isOdd: isOdd$3, square } = bigint;
+
+var build_f1m = function buildF1m(module, _q, _prefix, _intPrefix) {
+ const q = BigInt(_q);
+ const n64 = Math.floor((bitLength$4(q - 1n) - 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$4.bigInt2BytesLE(q, n8));
+
+ const pR2 = module.alloc(utils$4.bigInt2BytesLE(square(1n << BigInt(n64*64)) % q, n8));
+ const pOne = module.alloc(utils$4.bigInt2BytesLE((1n << BigInt(n64*64)) % q, n8));
+ const pZero = module.alloc(utils$4.bigInt2BytesLE(0n, n8));
+ const _minusOne = q - 1n;
+ const _e = _minusOne >> 1n; // e = (p-1)/2
+ const pe = module.alloc(n8, utils$4.bigInt2BytesLE(_e, n8));
+
+ const _ePlusOne = _e + 1n; // e = (p-1)/2
+ const pePlusOne = module.alloc(n8, utils$4.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(
- prefixField + "_toMontgomery",
- c.getLocal("p1"),
- c.getLocal("pr")
- ));
- for (let i=1; i<3; i++) {
- f.addCode(c.call(
- prefixField + "_toMontgomery",
- c.i32_add(c.getLocal("p1"), c.i32_const(i*n8)),
- c.i32_add(c.getLocal("pr"), c.i32_const(i*n8))
- ));
- }
+ f.addCode(c.call(intPrefix + "_copy", c.i32_const(pOne), c.getLocal("pr")));
}
- function buildToMontgomeryAffine() {
- const f = module.addFunction(prefix + "_toMontgomeryAffine");
- f.addParam("p1", "i32");
- f.addParam("pr", "i32");
+ 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.call(
- prefixField + "_toMontgomery",
- c.getLocal("p1"),
- c.getLocal("pr")
- ));
- for (let i=1; i<2; i++) {
- f.addCode(c.call(
- prefixField + "_toMontgomery",
- c.i32_add(c.getLocal("p1"), c.i32_const(i*n8)),
- c.i32_add(c.getLocal("pr"), c.i32_const(i*n8))
- ));
- }
+ 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 buildFromMontgomery() {
- const f = module.addFunction(prefix + "_fromMontgomery");
- f.addParam("p1", "i32");
- f.addParam("pr", "i32");
+ 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.call(
- prefixField + "_fromMontgomery",
- c.getLocal("p1"),
- c.getLocal("pr")
- ));
- for (let i=1; i<3; i++) {
- f.addCode(c.call(
- prefixField + "_fromMontgomery",
- c.i32_add(c.getLocal("p1"), c.i32_const(i*n8)),
- c.i32_add(c.getLocal("pr"), c.i32_const(i*n8))
- ));
- }
+ 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 buildFromMontgomeryAffine() {
- const f = module.addFunction(prefix + "_fromMontgomeryAffine");
- f.addParam("p1", "i32");
- f.addParam("pr", "i32");
+ function buildNeg() {
+ const f = module.addFunction(prefix+"_neg");
+ f.addParam("x", "i32");
+ f.addParam("r", "i32");
const c = f.getCodeBuilder();
- f.addCode(c.call(
- prefixField + "_fromMontgomery",
- c.getLocal("p1"),
- c.getLocal("pr")
- ));
- for (let i=1; i<2; i++) {
- f.addCode(c.call(
- prefixField + "_fromMontgomery",
- c.i32_add(c.getLocal("p1"), c.i32_const(i*n8)),
- c.i32_add(c.getLocal("pr"), c.i32_const(i*n8))
- ));
- }
+ f.addCode(
+ c.call(prefix + "_sub", c.i32_const(pZero), c.getLocal("x"), c.getLocal("r"))
+ );
}
- function buildAdd() {
- const f = module.addFunction(prefix + "_add");
- f.addParam("p1", "i32");
- f.addParam("p2", "i32");
- f.addParam("pr", "i32");
- f.addLocal("z1", "i32");
- f.addLocal("z2", "i32");
+ function buildIsNegative() {
+ const f = module.addFunction(prefix+"_isNegative");
+ f.addParam("x", "i32");
+ f.setReturnType("i32");
const c = f.getCodeBuilder();
- const x1 = c.getLocal("p1");
- const y1 = c.i32_add(c.getLocal("p1"), c.i32_const(n8));
- f.addCode(c.setLocal("z1", c.i32_add(c.getLocal("p1"), c.i32_const(n8*2))));
- const z1 = c.getLocal("z1");
- const x2 = c.getLocal("p2");
- const y2 = c.i32_add(c.getLocal("p2"), c.i32_const(n8));
- f.addCode(c.setLocal("z2", c.i32_add(c.getLocal("p2"), c.i32_const(n8*2))));
- const z2 = c.getLocal("z2");
- const x3 = c.getLocal("pr");
- const y3 = c.i32_add(c.getLocal("pr"), c.i32_const(n8));
- const z3 = c.i32_add(c.getLocal("pr"), c.i32_const(n8*2));
-
- const Z1Z1 = c.i32_const(module.alloc(n8));
- const Z2Z2 = c.i32_const(module.alloc(n8));
- const U1 = c.i32_const(module.alloc(n8));
- const U2 = c.i32_const(module.alloc(n8));
- const Z1_cubed = c.i32_const(module.alloc(n8));
- const Z2_cubed = c.i32_const(module.alloc(n8));
- const S1 = c.i32_const(module.alloc(n8));
- const S2 = c.i32_const(module.alloc(n8));
- const H = c.i32_const(module.alloc(n8));
- const S2_minus_S1 = c.i32_const(module.alloc(n8));
- const I = c.i32_const(module.alloc(n8));
- const J = c.i32_const(module.alloc(n8));
- const r = c.i32_const(module.alloc(n8));
- const r2 = c.i32_const(module.alloc(n8));
- const V = c.i32_const(module.alloc(n8));
- const V2 = c.i32_const(module.alloc(n8));
- const S1_J2 = c.i32_const(module.alloc(n8));
+ const AUX = c.i32_const(module.alloc(n8));
f.addCode(
- c.if(
- c.call(prefix + "_isZero", c.getLocal("p1")),
- [
- ...c.call(prefix + "_copy", c.getLocal("p2"), c.getLocal("pr")),
- ...c.ret([])
- ]
- ),
- c.if(
- c.call(prefix + "_isZero", c.getLocal("p2")),
- [
- ...c.call(prefix + "_copy", c.getLocal("p1"), c.getLocal("pr")),
- ...c.ret([])
- ]
- ),
- c.if(
- c.call(prefixField + "_isOne", z1),
- [
- ...c.call(prefix + "_addMixed", x2, x1, x3),
- ...c.ret([])
- ]
- ),
- c.if(
- c.call(prefixField + "_isOne", z2),
- [
- ...c.call(prefix + "_addMixed", x1, x2, x3),
- ...c.ret([])
- ]
- ),
- c.call(prefixField + "_square", z1, Z1Z1),
- c.call(prefixField + "_square", z2, Z2Z2),
- c.call(prefixField + "_mul", x1, Z2Z2, U1),
- c.call(prefixField + "_mul", x2, Z1Z1, U2),
- c.call(prefixField + "_mul", z1, Z1Z1, Z1_cubed),
- c.call(prefixField + "_mul", z2, Z2Z2, Z2_cubed),
- c.call(prefixField + "_mul", y1, Z2_cubed, S1),
- c.call(prefixField + "_mul", y2, Z1_cubed, S2),
-
- c.if(
- c.call(prefixField + "_eq", U1, U2),
- c.if(
- c.call(prefixField + "_eq", S1, S2),
- [
- ...c.call(prefix + "_double", c.getLocal("p1"), c.getLocal("pr")),
- ...c.ret([])
- ]
- )
- ),
-
- c.call(prefixField + "_sub", U2, U1, H),
- c.call(prefixField + "_sub", S2, S1, S2_minus_S1),
- c.call(prefixField + "_add", H, H, I),
- c.call(prefixField + "_square", I, I),
- c.call(prefixField + "_mul", H, I, J),
- c.call(prefixField + "_add", S2_minus_S1, S2_minus_S1, r),
- c.call(prefixField + "_mul", U1, I, V),
- c.call(prefixField + "_square", r, r2),
- c.call(prefixField + "_add", V, V, V2),
+ c.call(prefix + "_fromMontgomery", c.getLocal("x"), AUX),
+ c.call(intPrefix + "_gte", AUX, c.i32_const(pePlusOne) )
+ );
+ }
- c.call(prefixField + "_sub", r2, J, x3),
- c.call(prefixField + "_sub", x3, V2, x3),
+ function buildSign() {
+ const f = module.addFunction(prefix+"_sign");
+ f.addParam("x", "i32");
+ f.setReturnType("i32");
- c.call(prefixField + "_mul", S1, J, S1_J2),
- c.call(prefixField + "_add", S1_J2, S1_J2, S1_J2),
+ const c = f.getCodeBuilder();
- c.call(prefixField + "_sub", V, x3, y3),
- c.call(prefixField + "_mul", y3, r, y3),
- c.call(prefixField + "_sub", y3, S1_J2, y3),
+ const AUX = c.i32_const(module.alloc(n8));
- c.call(prefixField + "_add", z1, z2, z3),
- c.call(prefixField + "_square", z3, z3),
- c.call(prefixField + "_sub", z3, Z1Z1, z3),
- c.call(prefixField + "_sub", z3, Z2Z2, z3),
- c.call(prefixField + "_mul", z3, H, z3),
+ 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 buildAddMixed() {
+ function buildMReduct() {
+ const carries = module.alloc(n32*n32*8);
- const f = module.addFunction(prefix + "_addMixed");
- f.addParam("p1", "i32");
- f.addParam("p2", "i32");
- f.addParam("pr", "i32");
- f.addLocal("z1", "i32");
+ 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 x1 = c.getLocal("p1");
- const y1 = c.i32_add(c.getLocal("p1"), c.i32_const(n8));
- f.addCode(c.setLocal("z1", c.i32_add(c.getLocal("p1"), c.i32_const(n8*2))));
- const z1 = c.getLocal("z1");
- const x2 = c.getLocal("p2");
- const y2 = c.i32_add(c.getLocal("p2"), c.i32_const(n8));
- const x3 = c.getLocal("pr");
- const y3 = c.i32_add(c.getLocal("pr"), c.i32_const(n8));
- const z3 = c.i32_add(c.getLocal("pr"), c.i32_const(n8*2));
+ const np32 = Number(0x100000000n - modInv$2(q, 0x100000000n));
- const Z1Z1 = c.i32_const(module.alloc(n8));
- const U2 = c.i32_const(module.alloc(n8));
- const Z1_cubed = c.i32_const(module.alloc(n8));
- const S2 = c.i32_const(module.alloc(n8));
- const H = c.i32_const(module.alloc(n8));
- const HH = c.i32_const(module.alloc(n8));
- const S2_minus_y1 = c.i32_const(module.alloc(n8));
- const I = c.i32_const(module.alloc(n8));
- const J = c.i32_const(module.alloc(n8));
- const r = c.i32_const(module.alloc(n8));
- const r2 = c.i32_const(module.alloc(n8));
- const V = c.i32_const(module.alloc(n8));
- const V2 = c.i32_const(module.alloc(n8));
- const y1_J2 = c.i32_const(module.alloc(n8));
+ f.addCode(c.setLocal("np32", c.i64_const(np32)));
- f.addCode(
- c.if(
- c.call(prefix + "_isZero", c.getLocal("p1")),
- [
- ...c.call(prefix + "_copyAffine", c.getLocal("p2"), c.getLocal("pr")),
- ...c.call(prefixField + "_one", c.i32_add(c.getLocal("pr") , c.i32_const(n8*2))),
- ...c.ret([])
- ]
- ),
- c.if(
- c.call(prefix + "_isZeroAffine", c.getLocal("p2")),
- [
- ...c.call(prefix + "_copy", c.getLocal("p1"), c.getLocal("pr")),
- ...c.ret([])
- ]
- ),
- c.if(
- c.call(prefixField + "_isOne", z1),
- [
- ...c.call(prefix + "_addAffine", x1, x2, x3),
- ...c.ret([])
- ]
- ),
- c.call(prefixField + "_square", z1, Z1Z1),
- c.call(prefixField + "_mul", x2, Z1Z1, U2),
- c.call(prefixField + "_mul", z1, Z1Z1, Z1_cubed),
- c.call(prefixField + "_mul", y2, Z1_cubed, S2),
+ 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.call(prefix + "_negAffine", c.getLocal("p2"), AUX),
- c.call(prefix + "_addMixed", c.getLocal("p1"), AUX, c.getLocal("pr")),
+ c.i64_store32(
+ c.getLocal("r"),
+ n32*4-4,
+ c.getLocal(c0)
+ )
);
- }
-
-
- function buildSubAffine() {
- const f = module.addFunction(prefix + "_subAffine");
- f.addParam("p1", "i32");
- f.addParam("p2", "i32");
- f.addParam("pr", "i32");
-
- const c = f.getCodeBuilder();
-
- const AUX = c.i32_const(module.alloc(n8*3));
f.addCode(
- c.call(prefix + "_negAffine", c.getLocal("p2"), AUX),
- c.call(prefix + "_addAffine", c.getLocal("p1"), AUX, c.getLocal("pr")),
+ 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"))),
+ )
+ )
);
}
- // This sets Z to One
- function buildNormalize() {
- const f = module.addFunction(prefix + "_normalize");
- 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(n8));
- const z = c.i32_add(c.getLocal("p1"), c.i32_const(n8*2));
- const x3 = c.getLocal("pr");
- const y3 = c.i32_add(c.getLocal("pr"), c.i32_const(n8));
- const z3 = c.i32_add(c.getLocal("pr"), c.i32_const(n8*2));
+ function buildSquare() {
- const Z_inv = c.i32_const(module.alloc(n8));
- const Z2_inv = c.i32_const(module.alloc(n8));
- const Z3_inv = c.i32_const(module.alloc(n8));
-
- f.addCode(
- c.if(
- c.call(prefix + "_isZero", c.getLocal("p1")),
- c.call(prefix + "_zero", c.getLocal("pr")),
- [
- ...c.call(prefixField + "_inverse", z, Z_inv),
- ...c.call(prefixField + "_square", Z_inv, Z2_inv),
- ...c.call(prefixField + "_mul", Z_inv, Z2_inv, Z3_inv),
- ...c.call(prefixField + "_mul", x, Z2_inv, x3),
- ...c.call(prefixField + "_mul", y, Z3_inv, y3),
- ...c.call(prefixField + "_one", z3),
- ]
- )
- );
- }
+ 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");
- // Does not set Z.
- function buildToAffine() {
- const f = module.addFunction(prefix + "_toAffine");
- f.addParam("p1", "i32");
- f.addParam("pr", "i32");
+ for (let i=0;i>1) )&&(i>1, k>>1)
+ )
+ )
+ );
- c.if(
- c.call(prefixField + "_isZero", c.getLocal("itAux")),
- [
- ...c.call(prefixField + "_zero", c.getLocal("itOut")),
- ...c.call(prefixField + "_zero", c.i32_add(c.getLocal("itOut"), c.i32_const(n8)))
- ],
- [
- ...c.call(
- prefixField+"_mul",
- c.getLocal("itAux"),
- c.i32_add(c.getLocal("itIn"), c.i32_const(n8)),
- tmp,
- ),
- ...c.call(
- prefixField+"_square",
- c.getLocal("itAux"),
- c.getLocal("itAux")
- ),
- ...c.call(
- prefixField+"_mul",
- c.getLocal("itAux"),
- c.getLocal("itIn"),
- c.getLocal("itOut"),
- ),
- ...c.call(
- prefixField+"_mul",
- c.getLocal("itAux"),
- tmp,
- c.i32_add(c.getLocal("itOut"), c.i32_const(n8)),
- ),
- ]
+ 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)
+ )
+ );
- c.setLocal("itIn", c.i32_add(c.getLocal("itIn"), c.i32_const(n8*3))),
- c.setLocal("itOut", c.i32_add(c.getLocal("itOut"), c.i32_const(n8*2))),
- c.setLocal("itAux", c.i32_add(c.getLocal("itAux"), c.i32_const(n8))),
- c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
- c.br(0)
- )),
- c.i32_store(
- c.i32_const(0),
- c.getLocal("pAux")
+ 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"))),
+ )
)
);
}
- // This function is private and does not allow to OVERLAP buffers.
- function buildReverseBytes() {
- const f = module.addFunction(prefix + "__reverseBytes");
- f.addParam("pIn", "i32");
+ 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 = 2n;
+ if (isPrime(q)) {
+ while (modPow$1(_nqr, _e, q) !== _minusOne) _nqr = _nqr + 1n;
+ }
+
+ let s2 = 0;
+ let _t = _minusOne;
+
+ while ((!isOdd$3(_t))&&(_t !== 0n)) {
+ s2++;
+ _t = _t >> 1n;
+ }
+ const pt = module.alloc(n8, utils$4.bigInt2BytesLE(_t, n8));
+
+ const _nqrToT = modPow$1(_nqr, _t, q);
+ const pNqrToT = module.alloc(utils$4.bigInt2BytesLE((_nqrToT << BigInt(n64*64)) % q, n8));
+
+ const _tPlusOneOver2 = (_t + 1n) >> 1n;
+ const ptPlusOneOver2 = module.alloc(n8, utils$4.bigInt2BytesLE(_tPlusOneOver2, n8));
+
+ function buildSqrt() {
+
+ const f = module.addFunction(prefix+ "_sqrt");
f.addParam("n", "i32");
- f.addParam("pOut", "i32");
- f.addLocal("itOut", "i32");
- f.addLocal("itIn", "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(
- c.setLocal(
- "itOut",
- c.i32_sub(
- c.i32_add(
- c.getLocal("pOut"),
- c.getLocal("n")
- ),
- c.i32_const(1)
+
+ // 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(
- "itIn",
- c.getLocal("pIn")
+
+ 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_lt_s( c.getLocal("itOut"), c.getLocal("pOut") )),
+ 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("itOut"),
- c.i32_load8_u(c.getLocal("itIn")),
+ c.getLocal("j"),
+ pAux,
+ c.i32_load8_u(c.getLocal("p")),
),
- c.setLocal("itOut", c.i32_sub(c.getLocal("itOut"), c.i32_const(1))),
- c.setLocal("itIn", c.i32_add(c.getLocal("itIn"), c.i32_const(1))),
+ 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 buildLEMtoC() {
- const f = module.addFunction(prefix + "_LEMtoC");
- f.addParam("pIn", "i32");
- f.addParam("pOut", "i32");
+ 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 tmp = c.i32_const(module.alloc(n8));
+ const AUX = c.i32_const(module.alloc(n8));
f.addCode(
- c.if(
- c.call(prefix + "_isZeroAffine", c.getLocal("pIn")),
- [
- ...c.call(prefixField + "_zero", c.getLocal("pOut")),
- ...c.i32_store8(
- c.getLocal("pOut"),
- c.i32_const(0x40)
- ),
- ...c.ret([])
- ]
- ),
- c.call(prefixField + "_fromMontgomery", c.getLocal("pIn"), tmp),
- c.call(prefix + "__reverseBytes", tmp, c.i32_const(n8), c.getLocal("pOut")),
- c.if(
- c.i32_eq(
- c.call(prefixField + "_sign", c.i32_add(c.getLocal("pIn"), c.i32_const(n8))),
- c.i32_const(-1)
- ),
- c.i32_store8(
- c.getLocal("pOut"),
- c.i32_or(
- c.i32_load8_u(c.getLocal("pOut")),
- c.i32_const(0x80)
- )
- )
- ),
+ 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 buildLEMtoU() {
- const f = module.addFunction(prefix + "_LEMtoU");
- f.addParam("pIn", "i32");
- f.addParam("pOut", "i32");
+ function buildIsOne() {
+ const f = module.addFunction(prefix+"_isOne");
+ f.addParam("x", "i32");
+ f.setReturnType("i32");
const c = f.getCodeBuilder();
-
- const pTmp = module.alloc(n8*2);
- const tmp = c.i32_const(pTmp);
- const tmpX = c.i32_const(pTmp);
- const tmpY = c.i32_const(pTmp + n8);
-
f.addCode(
- c.if(
- c.call(prefix + "_isZeroAffine", c.getLocal("pIn")),
- [
- ...c.call(prefix + "_zeroAffine", c.getLocal("pOut")),
- ...c.ret([])
- ]
- ),
-
- c.call(prefix + "_fromMontgomeryAffine", c.getLocal("pIn"), tmp),
-
- c.call(prefix + "__reverseBytes", tmpX, c.i32_const(n8), c.getLocal("pOut")),
- c.call(prefix + "__reverseBytes", tmpY, c.i32_const(n8), c.i32_add(c.getLocal("pOut"), c.i32_const(n8))),
+ c.ret(c.call(intPrefix + "_eq", c.getLocal("x"), c.i32_const(pOne)))
);
}
- function buildUtoLEM() {
- const f = module.addFunction(prefix + "_UtoLEM");
- f.addParam("pIn", "i32");
- f.addParam("pOut", "i32");
- const c = f.getCodeBuilder();
+ module.exportFunction(intPrefix + "_copy", prefix+"_copy");
+ module.exportFunction(intPrefix + "_zero", prefix+"_zero");
+ module.exportFunction(intPrefix + "_isZero", prefix+"_isZero");
+ module.exportFunction(intPrefix + "_eq", prefix+"_eq");
- const pTmp = module.alloc(n8*2);
- const tmp = c.i32_const(pTmp);
- const tmpX = c.i32_const(pTmp);
- const tmpY = c.i32_const(pTmp + n8);
+ 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);
- f.addCode(
- c.if(
- c.i32_and(c.i32_load8_u(c.getLocal("pIn")), c.i32_const(0x40)),
- [
- ...c.call(prefix + "_zeroAffine", c.getLocal("pOut")),
- ...c.ret([])
- ]
- ),
- c.call(prefix + "__reverseBytes", c.getLocal("pIn"), c.i32_const(n8), tmpX),
- c.call(prefix + "__reverseBytes", c.i32_add(c.getLocal("pIn"), c.i32_const(n8)), c.i32_const(n8), tmpY),
- c.call(prefix + "_toMontgomeryAffine", tmp, c.getLocal("pOut"))
- );
+ 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 (isPrime(q)) {
+ buildSqrt();
+ buildIsSquare();
+ module.exportFunction(prefix + "_sqrt");
+ module.exportFunction(prefix + "_isSquare");
}
+ module.exportFunction(prefix + "_batchToMontgomery");
+ module.exportFunction(prefix + "_batchFromMontgomery");
+ // console.log(module.functionIdxByName);
- function buildCtoLEM() {
- const f = module.addFunction(prefix + "_CtoLEM");
- f.addParam("pIn", "i32");
- f.addParam("pOut", "i32");
- f.addLocal("firstByte", "i32");
- f.addLocal("greatest", "i32");
+ return prefix;
+};
- const c = f.getCodeBuilder();
+/*
+ Copyright 2019 0KIMS association.
- const pTmp = module.alloc(n8*2);
- const tmpX = c.i32_const(pTmp);
- const tmpY = c.i32_const(pTmp + n8);
+ This file is part of wasmsnark (Web Assembly zkSnark Prover).
- f.addCode(
- c.setLocal("firstByte", c.i32_load8_u(c.getLocal("pIn"))),
- c.if(
- c.i32_and(
- c.getLocal("firstByte"),
- c.i32_const(0x40)
- ),
- [
- ...c.call(prefix + "_zeroAffine", c.getLocal("pOut")),
- ...c.ret([])
- ]
- ),
- c.setLocal(
- "greatest",
- c.i32_and(
- c.getLocal("firstByte"),
- c.i32_const(0x80)
- )
- ),
+ 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.
- c.call(prefixField + "_copy", c.getLocal("pIn"), tmpY),
- c.i32_store8(tmpY, c.i32_and(c.getLocal("firstByte"), c.i32_const(0x3F))),
- c.call(prefix + "__reverseBytes", tmpY, c.i32_const(n8), tmpX),
- c.call(prefixField + "_toMontgomery", tmpX, c.getLocal("pOut")),
+ 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.
- c.call(prefixField + "_square", c.getLocal("pOut"), tmpY),
- c.call(prefixField + "_mul", c.getLocal("pOut"), tmpY, tmpY),
- c.call(prefixField + "_add", tmpY, c.i32_const(pB), tmpY),
+ You should have received a copy of the GNU General Public License
+ along with wasmsnark. If not, see .
+*/
- c.call(prefixField + "_sqrt", tmpY, tmpY),
- c.call(prefixField + "_neg", tmpY, tmpX),
+const buildF1m$2 =build_f1m;
+const { bitLength: bitLength$3 } = bigint;
- c.if(
- c.i32_eq(
- c.call(prefixField + "_sign", tmpY),
- c.i32_const(-1)
- ),
- c.if(
- c.getLocal("greatest"),
- c.call(prefixField + "_copy", tmpY, c.i32_add(c.getLocal("pOut"), c.i32_const(n8))),
- c.call(prefixField + "_neg", tmpY, c.i32_add(c.getLocal("pOut"), c.i32_const(n8)))
- ),
- c.if(
- c.getLocal("greatest"),
- c.call(prefixField + "_neg", tmpY, c.i32_add(c.getLocal("pOut"), c.i32_const(n8))),
- c.call(prefixField + "_copy", tmpY, c.i32_add(c.getLocal("pOut"), c.i32_const(n8)))
- ),
- )
+var build_f1 = function buildF1(module, _q, _prefix, _f1mPrefix, _intPrefix) {
+
+ const q = BigInt(_q);
+ const n64 = Math.floor((bitLength$3(q - 1n) - 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 buildInCurveAffine() {
- const f = module.addFunction(prefix + "_inCurveAffine");
- f.addParam("pIn", "i32");
- f.setReturnType("i32");
+ function buildSquare() {
+ const f = module.addFunction(prefix+"_square");
+ f.addParam("x", "i32");
+ f.addParam("r", "i32");
const c = f.getCodeBuilder();
- const x = c.getLocal("pIn");
- const y = c.i32_add(c.getLocal("pIn"), c.i32_const(n8));
+ f.addCode(c.call(prefix + "_mul", c.getLocal("x"), c.getLocal("x"), c.getLocal("r")));
+ }
- const y2 = c.i32_const(module.alloc(n8));
- const x3b = c.i32_const(module.alloc(n8));
- f.addCode(
- c.call(prefixField + "_square", y, y2),
- c.call(prefixField + "_square", x, x3b),
- c.call(prefixField + "_mul", x, x3b, x3b),
- c.call(prefixField + "_add", x3b, c.i32_const(pB), x3b),
+ function buildInverse() {
- c.ret(
- c.call(prefixField + "_eq", y2, x3b)
- )
- );
+ 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 buildInCurve() {
- const f = module.addFunction(prefix + "_inCurve");
- f.addParam("pIn", "i32");
+ 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*2));
-
f.addCode(
- c.call(prefix + "_toAffine", c.getLocal("pIn"), aux),
-
- c.ret(
- c.call(prefix + "_inCurveAffine", aux),
- )
+ c.call(intPrefix + "_gte", c.getLocal("x"), c.i32_const(pePlusOne) )
);
}
- buildIsZeroAffine();
- buildIsZero();
- buildZeroAffine();
- buildZero();
- buildCopyAffine();
- buildCopy();
- buildToJacobian();
- buildEqAffine();
- buildEqMixed();
- buildEq();
- buildDoubleAffine();
- buildDouble();
- buildAddAffine();
- buildAddMixed();
- buildAdd();
- buildNegAffine();
- buildNeg();
- buildSubAffine();
- buildSubMixed();
- buildSub();
- buildFromMontgomeryAffine();
- buildFromMontgomery();
- buildToMontgomeryAffine();
- buildToMontgomery();
- buildToAffine();
- buildInCurveAffine();
- buildInCurve();
- buildBatchToAffine();
+ 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");
- buildNormalize();
+ return prefix;
+};
+/*
+ Copyright 2019 0KIMS association.
- buildReverseBytes();
+ This file is part of wasmsnark (Web Assembly zkSnark Prover).
- buildLEMtoU();
- buildLEMtoC();
- buildUtoLEM();
- buildCtoLEM();
+ 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.
- buildBatchConvertion(module, prefix + "_batchLEMtoU", prefix + "_LEMtoU", n8*2, n8*2);
- buildBatchConvertion(module, prefix + "_batchLEMtoC", prefix + "_LEMtoC", n8*2, n8);
- buildBatchConvertion(module, prefix + "_batchUtoLEM", prefix + "_UtoLEM", n8*2, n8*2);
- buildBatchConvertion(module, prefix + "_batchCtoLEM", prefix + "_CtoLEM", n8, n8*2, true);
+ 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.
- buildBatchConvertion(module, prefix + "_batchToJacobian", prefix + "_toJacobian", n8*2, n8*3, true);
+ You should have received a copy of the GNU General Public License
+ along with wasmsnark. If not, see .
+*/
- buildMultiexp$1(module, prefix, prefix + "_multiexp", prefix + "_add", n8*3);
- buildMultiexp$1(module, prefix, prefix + "_multiexpAffine", prefix + "_addMixed", n8*2);
+const buildExp$1 = build_timesscalar;
+const buildBatchInverse$1 = build_batchinverse;
+const utils$3 = utils$5;
- /*
- buildTimesScalar(
- module,
- prefix + "_timesScalarOld",
- n8*3,
- prefix + "_add",
- prefix + "_double",
- prefix + "_copy",
- prefix + "_zero",
- );
- */
- buildTimesScalarNAF(
- module,
- prefix + "_timesScalar",
- n8*3,
- prefix + "_add",
- prefix + "_double",
- prefix + "_sub",
- prefix + "_copy",
- prefix + "_zero"
- );
+var build_f2m = function buildF2m(module, mulNonResidueFn, prefix, f1mPrefix) {
- buildTimesScalarNAF(
- module,
- prefix + "_timesScalarAffine",
- n8*2,
- prefix + "_addMixed",
- prefix + "_double",
- prefix + "_subMixed",
- prefix + "_copyAffine",
- prefix + "_zero"
- );
+ if (module.modules[prefix]) return prefix; // already builded
- module.exportFunction(prefix + "_isZero");
- module.exportFunction(prefix + "_isZeroAffine");
+ const f1n8 = module.modules[f1mPrefix].n64*8;
+ const q = module.modules[f1mPrefix].q;
- module.exportFunction(prefix + "_eq");
- module.exportFunction(prefix + "_eqMixed");
- module.exportFunction(prefix + "_eqAffine");
+ module.modules[prefix] = {
+ n64: module.modules[f1mPrefix].n64*2
+ };
- module.exportFunction(prefix + "_copy");
- module.exportFunction(prefix + "_copyAffine");
+ function buildAdd() {
+ const f = module.addFunction(prefix+"_add");
+ f.addParam("x", "i32");
+ f.addParam("y", "i32");
+ f.addParam("r", "i32");
- module.exportFunction(prefix + "_zero");
- module.exportFunction(prefix + "_zeroAffine");
+ const c = f.getCodeBuilder();
- module.exportFunction(prefix + "_double");
- module.exportFunction(prefix + "_doubleAffine");
+ 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));
- module.exportFunction(prefix + "_add");
- module.exportFunction(prefix + "_addMixed");
- module.exportFunction(prefix + "_addAffine");
+ 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));
- module.exportFunction(prefix + "_neg");
- module.exportFunction(prefix + "_negAffine");
+ f.addCode(
+ c.call(f1mPrefix+"_neg", x0, r0),
+ c.call(f1mPrefix+"_neg", x1, r1),
+ );
+ }
- module.exportFunction(prefix + "_sub");
- module.exportFunction(prefix + "_subMixed");
- module.exportFunction(prefix + "_subAffine");
+ function buildConjugate() {
+ const f = module.addFunction(prefix+"_conjugate");
+ f.addParam("x", "i32");
+ f.addParam("r", "i32");
- module.exportFunction(prefix + "_fromMontgomery");
- module.exportFunction(prefix + "_fromMontgomeryAffine");
+ const c = f.getCodeBuilder();
- module.exportFunction(prefix + "_toMontgomery");
- module.exportFunction(prefix + "_toMontgomeryAffine");
+ 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));
- module.exportFunction(prefix + "_timesScalar");
- module.exportFunction(prefix + "_timesScalarAffine");
+ f.addCode(
+ c.call(f1mPrefix+"_copy", x0, r0),
+ c.call(f1mPrefix+"_neg", x1, r1),
+ );
+ }
- module.exportFunction(prefix + "_normalize");
- // Convertion functions
- module.exportFunction(prefix + "_LEMtoU");
- module.exportFunction(prefix + "_LEMtoC");
- module.exportFunction(prefix + "_UtoLEM");
- module.exportFunction(prefix + "_CtoLEM");
+ function buildIsNegative() {
+ const f = module.addFunction(prefix+"_isNegative");
+ f.addParam("x", "i32");
+ f.setReturnType("i32");
- module.exportFunction(prefix + "_batchLEMtoU");
- module.exportFunction(prefix + "_batchLEMtoC");
- module.exportFunction(prefix + "_batchUtoLEM");
- module.exportFunction(prefix + "_batchCtoLEM");
+ const c = f.getCodeBuilder();
- module.exportFunction(prefix + "_toAffine");
- module.exportFunction(prefix + "_toJacobian");
+ const x0 = c.getLocal("x");
+ const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
- module.exportFunction(prefix + "_batchToAffine");
- module.exportFunction(prefix + "_batchToJacobian");
+ f.addCode(
+ c.if(
+ c.call(f1mPrefix+"_isZero", x1),
+ c.ret(c.call(f1mPrefix+"_isNegative", x0))
+ ),
+ c.ret(c.call(f1mPrefix+"_isNegative", x1))
+ );
+ }
- module.exportFunction(prefix + "_inCurve");
- module.exportFunction(prefix + "_inCurveAffine");
+ function buildMul() {
+ const f = module.addFunction(prefix+"_mul");
+ f.addParam("x", "i32");
+ f.addParam("y", "i32");
+ f.addParam("r", "i32");
- /*
- buildG1MulScalar(module, zq);
- module.exportFunction("g1MulScalar");
- */
+ const c = f.getCodeBuilder();
- return prefix;
-};
+ 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));
-/*
- Copyright 2019 0KIMS association.
+ 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));
- 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.
+ f.addCode(
+ c.call(f1mPrefix + "_mul", x0, y0, A), // A = x0*y0
+ c.call(f1mPrefix + "_mul", x1, y1, B), // B = x1*y1
- 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.
+ 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
- You should have received a copy of the GNU General Public License
- along with wasmsnark. If not, see .
-*/
+ // 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
+ );
-const { isOdd: isOdd$2, modInv: modInv$1, modPow } = bigint;
-const utils$3 = utils$6;
+ }
-var build_fft = function buildFFT(module, prefix, gPrefix, fPrefix, opGtimesF) {
+ function buildMul1() {
+ const f = module.addFunction(prefix+"_mul1");
+ f.addParam("x", "i32");
+ f.addParam("y", "i32");
+ f.addParam("r", "i32");
- const n64f = module.modules[fPrefix].n64;
- const n8f = n64f*8;
+ const c = f.getCodeBuilder();
- const n64g = module.modules[gPrefix].n64;
- const n8g = n64g*8;
+ 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));
- const q = module.modules[fPrefix].q;
- let rem = q - 1n;
- let maxBits = 0;
- while (!isOdd$2(rem)) {
- maxBits ++;
- rem = rem >> 1n;
+ f.addCode(
+ c.call(f1mPrefix + "_mul", x0, y, r0), // A = x0*y
+ c.call(f1mPrefix + "_mul", x1, y, r1), // B = x1*y
+ );
}
- let nr = 2n;
+ function buildSquare() {
+ const f = module.addFunction(prefix+"_square");
+ f.addParam("x", "i32");
+ f.addParam("r", "i32");
- while ( modPow(nr, q >> 1n, q) === 1n ) nr = nr + 1n;
+ const c = f.getCodeBuilder();
- // console.log(nr);
+ 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 w = new Array(maxBits+1);
- w[maxBits] = modPow(nr, rem, q);
+ 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));
- let n=maxBits-1;
- while (n>=0) {
- w[n] = modPow(w[n+1], 2n, q);
- n--;
- }
- const bytes = [];
- const R = (1n << BigInt(n8f*8)) % q;
+ f.addCode(
+ // AB = x0*y1
+ c.call(f1mPrefix + "_mul", x0, x1, AB),
- for (let i=0; i> i);
- }
- }
- return r;
- }
+ 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 rtable = Array(256);
- for (let i=0; i<256; i++) {
- rtable[i] = rev(i);
+ f.addCode(
+ c.call(f1mPrefix+"_toMontgomery", x0, r0),
+ c.call(f1mPrefix+"_toMontgomery", x1, r1)
+ );
}
- const REVTABLE = module.alloc(rtable);
+ function buildFromMontgomery() {
+ const f = module.addFunction(prefix+"_fromMontgomery");
+ f.addParam("x", "i32");
+ f.addParam("r", "i32");
+ const c = f.getCodeBuilder();
- function buildLog2() {
- const f = module.addFunction(prefix+"__log2");
- f.addParam("n", "i32");
- f.setReturnType("i32");
- f.addLocal("bits", "i32");
- f.addLocal("aux", "i32");
+ 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.setLocal(
- "aux",
- c.i32_shr_u(
- c.getLocal("n"),
- c.i32_const(1)
- )
- )
+ c.call(f1mPrefix+"_copy", x0, r0),
+ c.call(f1mPrefix+"_copy", x1, r1)
);
- 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"))
- ),
+ function buildZero() {
+ const f = module.addFunction(prefix+"_zero");
+ f.addParam("x", "i32");
- c.setLocal(
- "aux",
- c.i32_shr_u(
- c.getLocal("aux"),
- c.i32_const(1)
- )
- ),
+ const c = f.getCodeBuilder();
- c.setLocal(
- "bits",
- c.i32_add(
- c.getLocal("bits"),
- c.i32_const(1)
- )
- ),
+ const x0 = c.getLocal("x");
+ const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
- c.br(0)
- )));
+ f.addCode(
+ c.call(f1mPrefix+"_zero", x0),
+ c.call(f1mPrefix+"_zero", x1)
+ );
+ }
- f.addCode(c.if(
- c.i32_ne(
- c.getLocal("n"),
- c.i32_shl(
- c.i32_const(1),
- c.getLocal("bits")
- )
- ),
- c.unreachable()
- ));
+ function buildOne() {
+ const f = module.addFunction(prefix+"_one");
+ f.addParam("x", "i32");
- f.addCode(c.if(
- c.i32_gt_u(
- c.getLocal("bits"),
- c.i32_const(maxBits)
- ),
- c.unreachable()
- ));
+ const c = f.getCodeBuilder();
- f.addCode(c.getLocal("bits"));
- }
+ const x0 = c.getLocal("x");
+ const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
- function buildFFT() {
- const f = module.addFunction(prefix+"_fft");
- f.addParam("px", "i32");
- f.addParam("n", "i32");
+ f.addCode(
+ c.call(f1mPrefix+"_one", x0),
+ c.call(f1mPrefix+"_zero", x1)
+ );
+ }
- f.addLocal("bits", "i32");
+ function buildEq() {
+ const f = module.addFunction(prefix+"_eq");
+ f.addParam("x", "i32");
+ f.addParam("y", "i32");
+ f.setReturnType("i32");
const c = f.getCodeBuilder();
- const One = c.i32_const(module.alloc(n8f));
+ 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.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
+ c.i32_and(
+ c.call(f1mPrefix+"_eq", x0, y0),
+ c.call(f1mPrefix+"_eq", x1, y1)
)
);
-
}
- function buildIFFT() {
- const f = module.addFunction(prefix+"_ifft");
- f.addParam("px", "i32");
- f.addParam("n", "i32");
- f.addLocal("bits", "i32");
- f.addLocal("pInv2", "i32");
+ function buildIsZero() {
+ const f = module.addFunction(prefix+"_isZero");
+ f.addParam("x", "i32");
+ f.setReturnType("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)
- )
- )
- ),
+ const x0 = c.getLocal("x");
+ const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
- c.call(
- prefix+"_rawfft",
- c.getLocal("px"),
- c.getLocal("bits"),
- c.i32_const(1),
- c.getLocal("pInv2")
- ),
+ f.addCode(
+ c.i32_and(
+ c.call(f1mPrefix+"_isZero", x0),
+ c.call(f1mPrefix+"_isZero", x1)
+ )
);
}
- 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");
+ function buildInverse() {
+ const f = module.addFunction(prefix+"_inverse");
+ f.addParam("x", "i32");
+ f.addParam("r", "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),
+ 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));
- 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")
- )
- ),
+ 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));
- 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)
- )
- )
- ),
+ 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.setLocal(
- "idx2",
- c.i32_add(
- c.getLocal("idx1"),
- c.i32_mul(
- c.getLocal("mdiv2"),
- c.i32_const(n8g)
- )
- )
- ),
+ c.call(f1mPrefix+"_sub", t0, t2, t2),
+ c.call(f1mPrefix+"_inverse", t2, t3),
- c.call(
- opGtimesF,
- c.getLocal("idx2"),
- W,
- T
- ),
+ c.call(f1mPrefix+"_mul", x0, t3, r0),
+ c.call(f1mPrefix+"_mul", x1, t3, r1),
+ c.call(f1mPrefix+"_neg", r1, r1),
+ );
+ }
- c.call(
- gPrefix + "_copy",
- c.getLocal("idx1"),
- U
- ),
- c.call(
- gPrefix + "_add",
- U,
- T,
- c.getLocal("idx1"),
- ),
+ function buildSign() {
+ const f = module.addFunction(prefix+"_sign");
+ f.addParam("x", "i32");
+ f.addLocal("s", "i32");
+ f.setReturnType("i32");
- c.call(
- gPrefix + "_sub",
- U,
- T,
- c.getLocal("idx2"),
- ),
+ const c = f.getCodeBuilder();
- c.call(
- fPrefix + "_mul",
- W,
- c.getLocal("pwm"),
- W,
- ),
+ const x0 = c.getLocal("x");
+ const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
- c.setLocal("j", c.i32_add(c.getLocal("j"), c.i32_const(1))),
- c.br(0)
- )),
+ 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))
+ );
+ }
- c.setLocal("k", c.i32_add(c.getLocal("k"), c.getLocal("m"))),
- c.br(0)
- )),
+ function buildIsOne() {
+ const f = module.addFunction(prefix+"_isOne");
+ f.addParam("x", "i32");
+ f.setReturnType("i32");
- 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")
- )
+ 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),
+ ))
);
}
- 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");
+ // 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 T = c.i32_const(module.alloc(n8g));
+ // BigInt can't take `undefined` so we use `|| 0`
+ const e34 = c.i32_const(module.alloc(utils$3.bigInt2BytesLE((BigInt(q || 0) - 3n) / 4n, f1n8 )));
+ // BigInt can't take `undefined` so we use `|| 0`
+ const e12 = c.i32_const(module.alloc(utils$3.bigInt2BytesLE((BigInt(q || 0) - 1n) / 2n, 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.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.call(prefix + "_one", n1),
+ c.call(prefix + "_neg", n1, n1),
- c.setLocal("idx1",
- c.i32_add(
- c.getLocal("px"),
- c.i32_mul(
- c.getLocal("i"),
- c.i32_const(n8g)
- )
- )
- ),
+ // const a1 = F.pow(a, F.sqrt_e34);
+ c.call(prefix + "_exp", a, e34, c.i32_const(f1n8), a1),
- 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)
- )
- )
- ),
+ // const a1 = F.pow(a, F.sqrt_e34);
+ c.call(prefix + "_square", a1, alpha),
+ c.call(prefix + "_mul", a, alpha, alpha),
- 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))),
+ // const a0 = F.mul(F.frobenius(1, alfa), alfa);
+ c.call(prefix + "_conjugate", alpha, a0),
+ c.call(prefix + "_mul", a0, alpha, a0),
- c.br(0)
- )),
+ // 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(fPrefix + "_isOne", c.getLocal("mulFactor")),
+ c.call(prefix + "_eq", alpha, n1),
[
- // Do nothing (It should not be here)
+ // 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")),
],
[
- ...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"))
+ // 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();
+
+ // BigInt can't take `undefined` so we use `|| 0`
+ const e34 = c.i32_const(module.alloc(utils$3.bigInt2BytesLE((BigInt(q || 0) - 3n) / 4n, 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))
+ );
+
}
- 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();
+ buildIsZero();
+ buildIsOne();
+ buildZero();
+ buildOne();
+ buildCopy();
+ buildMul();
+ buildMul1();
+ buildSquare();
+ buildAdd();
+ buildSub();
+ buildNeg();
+ buildConjugate();
+ buildToMontgomery();
+ buildFromMontgomery();
+ buildEq();
+ buildInverse();
+ buildTimesScalar();
+ buildSign();
+ buildIsNegative();
- const T = c.i32_const(module.alloc(n8g));
+ 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();
- 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")
- )
- ),
+ module.exportFunction(prefix + "_exp");
+ module.exportFunction(prefix + "_timesScalar");
+ module.exportFunction(prefix + "_batchInverse");
+ module.exportFunction(prefix + "_sqrt");
+ module.exportFunction(prefix + "_isSquare");
+ module.exportFunction(prefix + "_isNegative");
- 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"))),
+ return prefix;
+};
- c.setLocal("idx2",
- c.i32_add(
- c.getLocal("px"),
- c.i32_mul(
- c.getLocal("ri"),
- c.i32_const(n8g)
- )
- )
- ),
+/*
+ Copyright 2019 0KIMS association.
- 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"))
- ]
- ),
+ This file is part of wasmsnark (Web Assembly zkSnark Prover).
- c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
+ 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.
- c.br(0)
- ))
- );
- }
+ 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.
- function buildRev() {
- const f = module.addFunction(prefix+"__rev");
+ 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("bits", "i32");
- f.setReturnType("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.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")
- )
+ c.call(f1mPrefix+"_add", x0, y0, r0),
+ c.call(f1mPrefix+"_add", x1, y1, r1),
+ c.call(f1mPrefix+"_add", x2, y2, r2),
);
}
-
- 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");
+ 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 W = c.i32_const(module.alloc(n8f));
- const T = c.i32_const(module.alloc(n8g));
- const U = c.i32_const(module.alloc(n8g));
+ 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( 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.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),
+ );
+ }
- 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)
- )
- )
- ),
+ function buildSub() {
+ const f = module.addFunction(prefix+"_sub");
+ f.addParam("x", "i32");
+ f.addParam("y", "i32");
+ f.addParam("r", "i32");
- c.call(
- opGtimesF,
- c.getLocal("idx2"),
- W,
- T
- ),
+ const c = f.getCodeBuilder();
- c.call(
- gPrefix + "_copy",
- c.getLocal("idx1"),
- U
- ),
+ 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));
- c.call(
- gPrefix + "_add",
- U,
- T,
- c.getLocal("idx1"),
- ),
+ f.addCode(
+ c.call(f1mPrefix+"_sub", x0, y0, r0),
+ c.call(f1mPrefix+"_sub", x1, y1, r1),
+ c.call(f1mPrefix+"_sub", x2, y2, r2),
+ );
+ }
- c.call(
- gPrefix + "_sub",
- U,
- T,
- c.getLocal("idx2"),
- ),
+ function buildNeg() {
+ const f = module.addFunction(prefix+"_neg");
+ f.addParam("x", "i32");
+ f.addParam("r", "i32");
- c.call(
- fPrefix + "_mul",
- W,
- c.getLocal("inc"),
- W,
- ),
+ const c = f.getCodeBuilder();
- c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
- c.br(0)
- ))
+ 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 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");
+ function buildIsNegative() {
+ const f = module.addFunction(prefix+"_isNegative");
+ f.addParam("x", "i32");
+ f.setReturnType("i32");
const c = f.getCodeBuilder();
- const W = c.i32_const(module.alloc(n8f));
- const U = c.i32_const(module.alloc(n8g));
+ 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("pShiftToM",
- c.i32_add(
- c.i32_const(SHIFT_TO_M),
- c.i32_mul(
- c.getLocal("totalBits"),
- c.i32_const(n8f)
- )
+ 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))
+ );
+ }
- 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")
- )
- ),
+ function buildMul() {
+ const f = module.addFunction(prefix+"_mul");
+ f.addParam("x", "i32");
+ f.addParam("y", "i32");
+ f.addParam("r", "i32");
- c.setLocal(
- "idx1",
- c.i32_add(
- c.getLocal("pBuff1"),
- c.i32_mul(
- c.getLocal("i"),
- c.i32_const(n8g)
- )
- )
- ),
+ const cd = f.getCodeBuilder();
- c.setLocal(
- "idx2",
- c.i32_add(
- c.getLocal("pBuff2"),
- c.i32_mul(
- c.getLocal("i"),
- c.i32_const(n8g)
- )
- )
- ),
+ 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));
- c.call(
- gPrefix + "_add",
- c.getLocal("idx1"),
- c.getLocal("idx2"),
- U
- ),
+ 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));
- 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")
- ),
+ f.addCode(
+ cd.call(f1mPrefix + "_mul", a, A, aA),
+ cd.call(f1mPrefix + "_mul", b, B, bB),
+ cd.call(f1mPrefix + "_mul", c, C, cC),
- c.call(
- opGtimesF,
- c.getLocal("idx2"),
- W,
- c.getLocal("idx2"),
- ),
+ 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),
- c.call(
- gPrefix + "_copy",
- U,
- c.getLocal("idx1")
- ),
+ cd.call(f1mPrefix + "_add", aA, bB, aA_bB),
+ cd.call(f1mPrefix + "_add", aA, cC, aA_cC),
+ cd.call(f1mPrefix + "_add", bB, cC, bB_cC),
- c.call(
- fPrefix + "_mul",
- W,
- c.getLocal("inc"),
- W
- ),
+ 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),
- c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
- c.br(0)
- ))
+ 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 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");
+ function buildSquare() {
+ const f = module.addFunction(prefix+"_square");
+ f.addParam("x", "i32");
+ f.addParam("r", "i32");
const c = f.getCodeBuilder();
- const W = c.i32_const(module.alloc(n8f));
- const U = c.i32_const(module.alloc(n8g));
+ 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.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(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( 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.call(f1mPrefix + "_mul", B, C, bc),
+ c.call(f1mPrefix + "_add", bc, bc, s3),
- c.setLocal(
- "idx1",
- c.i32_add(
- c.getLocal("pBuff1"),
- c.i32_mul(
- c.getLocal("i"),
- c.i32_const(n8g)
- )
- )
- ),
+ c.call(f1mPrefix + "_square", C, s4),
- c.setLocal(
- "idx2",
- c.i32_add(
- c.getLocal("pBuff2"),
- c.i32_mul(
- c.getLocal("i"),
- c.i32_const(n8g)
- )
- )
- ),
+ c.call(mulNonResidueFn, s3, r0),
+ c.call(f1mPrefix + "_add", s0, r0, r0),
- c.call(
- opGtimesF,
- c.getLocal("idx2"),
- W,
- U
- ),
+ c.call(mulNonResidueFn, s4, r1),
+ c.call(f1mPrefix + "_add", s1, r1, r1),
- c.call(
- gPrefix + "_sub",
- c.getLocal("idx1"),
- U,
- c.getLocal("idx2"),
- ),
+ 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),
+ );
- 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")
- ),
+ function buildToMontgomery() {
+ const f = module.addFunction(prefix+"_toMontgomery");
+ f.addParam("x", "i32");
+ f.addParam("r", "i32");
- c.call(
- opGtimesF,
- c.getLocal("idx1"),
- c.getLocal("pSConst"),
- c.getLocal("idx1")
- ),
+ const c = f.getCodeBuilder();
- c.call(
- fPrefix + "_mul",
- W,
- c.getLocal("inc"),
- W
- ),
+ 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));
- c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
- c.br(0)
- ))
+ 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();
- 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 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 W = c.i32_const(module.alloc(n8f));
- const U = c.i32_const(module.alloc(n8g));
+ 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),
+ );
+ }
- 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)
- )
- )
- ),
+ function buildZero() {
+ const f = module.addFunction(prefix+"_zero");
+ f.addParam("x", "i32");
+ const c = f.getCodeBuilder();
- 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")
- )
- ),
+ 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));
- c.setLocal(
- "idx1",
- c.i32_add(
- c.getLocal("pBuff1"),
- c.i32_mul(
- c.getLocal("i"),
- c.i32_const(n8g)
- )
- )
- ),
+ f.addCode(
+ c.call(f1mPrefix+"_zero", x0),
+ c.call(f1mPrefix+"_zero", x1),
+ c.call(f1mPrefix+"_zero", x2),
+ );
+ }
- c.setLocal(
- "idx2",
- c.i32_add(
- c.getLocal("pBuff2"),
- c.i32_mul(
- c.getLocal("i"),
- c.i32_const(n8g)
- )
- )
- ),
+ function buildOne() {
+ const f = module.addFunction(prefix+"_one");
+ f.addParam("x", "i32");
+ const c = f.getCodeBuilder();
- c.call(
- opGtimesF,
- c.getLocal("idx1"),
- c.getLocal("pShiftToM"),
- U
- ),
+ 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));
- c.call(
- gPrefix + "_sub",
- c.getLocal("idx2"),
- U,
- U
- ),
+ f.addCode(
+ c.call(f1mPrefix+"_one", x0),
+ c.call(f1mPrefix+"_zero", x1),
+ c.call(f1mPrefix+"_zero", x2),
+ );
+ }
- c.call(
- gPrefix + "_sub",
- c.getLocal("idx1"),
- c.getLocal("idx2"),
- c.getLocal("idx2"),
- ),
+ function buildEq() {
+ const f = module.addFunction(prefix+"_eq");
+ f.addParam("x", "i32");
+ f.addParam("y", "i32");
+ f.setReturnType("i32");
- c.call(
- opGtimesF,
- U,
- c.getLocal("pSConst"),
- c.getLocal("idx1"),
- ),
+ const c = f.getCodeBuilder();
- c.call(
- opGtimesF,
- c.getLocal("idx2"),
- W,
- c.getLocal("idx2"),
- ),
+ 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));
- c.call(
- fPrefix + "_mul",
- W,
- c.getLocal("inc"),
- W
+ f.addCode(
+ c.i32_and(
+ c.i32_and(
+ c.call(f1mPrefix+"_eq", x0, y0),
+ c.call(f1mPrefix+"_eq", x1, y1),
),
-
- c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
- c.br(0)
- ))
+ c.call(f1mPrefix+"_eq", x2, y2)
+ )
);
}
- 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");
+ function buildIsZero() {
+ const f = module.addFunction(prefix+"_isZero");
+ f.addParam("x", "i32");
+ f.setReturnType("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));
+ 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("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.i32_and(
+ c.i32_and(
+ c.call(f1mPrefix+"_isZero", x0),
+ c.call(f1mPrefix+"_isZero", x1)
),
- 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.call(f1mPrefix+"_isZero", x2)
+ )
+ );
+ }
- 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)
- )
- )
- ),
+ function buildInverse() {
+ const f = module.addFunction(prefix+"_inverse");
+ f.addParam("x", "i32");
+ f.addParam("r", "i32");
- c.setLocal(
- "idx2",
- c.i32_add(
- c.getLocal("idx1"),
- c.getLocal("pairOffset")
- )
- ),
+ const c = f.getCodeBuilder();
- c.call(
- opGtimesF,
- c.getLocal("idx2"),
- W,
- T
- ),
+ 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));
- c.call(
- gPrefix + "_copy",
- c.getLocal("idx1"),
- U
- ),
+ 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));
- c.call(
- gPrefix + "_add",
- U,
- T,
- c.getLocal("idx1"),
- ),
+ 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(
- gPrefix + "_sub",
- U,
- T,
- c.getLocal("idx2"),
- ),
+ c.call(f1mPrefix+"_inverse", t6, t6),
- 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)
- ))
+ c.call(f1mPrefix+"_mul", t6, c0, r0),
+ c.call(f1mPrefix+"_mul", t6, c1, r1),
+ c.call(f1mPrefix+"_mul", t6, c2, r2)
);
}
- // 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");
+ function buildSign() {
+ const f = module.addFunction(prefix+"_sign");
+ f.addParam("x", "i32");
+ f.addLocal("s", "i32");
+ f.setReturnType("i32");
const c = f.getCodeBuilder();
- const T = c.i32_const(module.alloc(n8g));
+ 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("ndiv2", c.i32_shr_u(c.getLocal("n"), c.i32_const(1))),
+ c.setLocal("s" , c.call( f1mPrefix + "_sign", x2)),
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.getLocal("s"),
+ c.ret(c.getLocal("s"))
),
- 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.setLocal("s" , c.call( f1mPrefix + "_sign", x1)),
+ c.if(
+ c.getLocal("s"),
+ c.ret(c.getLocal("s"))
+ ),
+ c.ret(c.call( f1mPrefix + "_sign", x0))
+ );
+ }
- c.call(
- opGtimesF,
- c.getLocal("idx2"),
- c.getLocal("factor"),
- T
- ),
+ function buildIsOne() {
+ const f = module.addFunction(prefix+"_isOne");
+ f.addParam("x", "i32");
+ f.setReturnType("i32");
- c.call(
- opGtimesF,
- c.getLocal("idx1"),
- c.getLocal("factor"),
- c.getLocal("idx2"),
- ),
+ const c = f.getCodeBuilder();
- c.call(
- gPrefix + "_copy",
- T,
- c.getLocal("idx1"),
- ),
+ 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));
- c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
- c.br(0)
- ))
+ 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)
+ )
+ )
);
}
- buildRev();
- buildReversePermutation();
- buildFinalInverse();
- buildRawFFT();
- buildLog2();
- buildFFT();
- buildIFFT();
- buildFFTJoin();
- buildFFTJoinExt();
- buildFFTJoinExtInv();
- buildFFTMix();
- buildFFTFinal();
- buildPrepareLagrangeEvaluation();
+ buildIsZero();
+ buildIsOne();
+ buildZero();
+ buildOne();
+ buildCopy();
+ buildMul();
+ buildSquare();
+ buildAdd();
+ buildSub();
+ buildNeg();
+ buildSign();
+ buildToMontgomery();
+ buildFromMontgomery();
+ buildEq();
+ buildInverse();
+ buildTimesScalar();
+ buildIsNegative();
- 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");
+ 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;
};
/*
@@ -10434,335 +10366,403 @@ var build_fft = function buildFFT(module, prefix, gPrefix, fPrefix, opGtimesF) {
along with wasmsnark. If not, see .
*/
-var build_pol = function buildPol(module, prefix, prefixField) {
-
- const n64 = module.modules[prefixField].n64;
- const n8 = n64*8;
+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");
- 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();
- const c = f.getCodeBuilder();
+ const aux = c.i32_const(module.alloc(elementLen));
- 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)
+ 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.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)
- ))
+ c.i32_const(1)
);
}
- 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");
+ 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)
+ )
+ )
+ ];
+ }
- const c = f.getCodeBuilder();
+ 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)),
- const aux = c.i32_const(module.alloc(n8));
+ c.setLocal("last",getBit(c.i32_const(0))),
+ c.setLocal("carry",c.i32_const(0)),
- 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.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.setLocal("ncoefs", c.i32_load(c.getLocal("pp"))),
- c.setLocal("pp", c.i32_add(c.getLocal("pp"), c.i32_const(4))),
+ 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("j", c.i32_const(0)),
- c.block(c.loop(
- c.br_if(
- 1,
- c.i32_eq(
- c.getLocal("j"),
- c.getLocal("ncoefs")
- )
- ),
+ c.setLocal("p", c.i32_sub(c.getLocal("p"), c.i32_const(1))),
- c.setLocal(
- "pd",
- c.i32_add(
- c.getLocal("pres"),
- c.i32_mul(
- c.i32_load(c.getLocal("pp")),
- c.i32_const(n8)
- )
- )
- ),
+ // p already points to the last bit
- c.setLocal("pp", c.i32_add(c.getLocal("pp"), c.i32_const(4))),
+ c.call(opCopy, c.getLocal("base"), aux),
+ c.call(opInit, c.getLocal("r")),
- c.call(
- prefixField + "_mul",
- c.getLocal("ps"),
- c.getLocal("pp"),
- aux
- ),
+ c.block(c.loop(
- 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.call(opAA, c.getLocal("r"), c.getLocal("r")),
- 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)
- ))
- );
- }
+ c.setLocal("cur",
+ c.i32_load8_u(
+ c.getLocal("p")
+ )
+ ),
- buildZero();
- buildConstructLC();
+ 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)
- module.exportFunction(prefix + "_zero");
- module.exportFunction(prefix + "_constructLC");
+ )),
- return prefix;
+ 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.
-var build_qap = function buildQAP(module, prefix, prefixField) {
+ You should have received a copy of the GNU General Public License
+ along with wasmsnark. If not, see .
+*/
- const n64 = module.modules[prefixField].n64;
- const n8 = n64*8;
+var build_multiexp = function buildMultiexp(module, prefix, fnName, opAdd, n8b) {
+ const n64g = module.modules[prefix].n64;
+ const n8g = n64g*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");
+ 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();
- 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.setLocal("bitsToEnd",
+ c.i32_sub(
c.i32_mul(
- c.getLocal("nOut"),
- c.i32_const(n8)
+ 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.block(c.loop(
- c.br_if(
- 1,
- c.i32_eq(
- c.getLocal("ita"),
- c.getLocal("last")
+ 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.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.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("it", c.getLocal("pCoefs")),
c.setLocal(
- "last",
+ "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("pCoefs"),
+ c.getLocal("pTable"),
c.i32_mul(
- c.getLocal("nCoefs"),
- c.i32_const(n8+12)
+ 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("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.i32_eq(
+ c.getLocal("j"),
+ c.getLocal("nTable")
)
),
+
c.call(
- prefixField + "_mul",
+ prefix + "_zero",
c.i32_add(
- c.getLocal("pWitness"),
+ c.getLocal("pTable"),
c.i32_mul(
- c.i32_sub(c.getLocal("s"), c.getLocal("offsetWitness")),
- c.i32_const(n8)
+ c.getLocal("j"),
+ c.i32_const(n8g)
)
- ),
- 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.setLocal("j", c.i32_add(c.getLocal("j"), c.i32_const(1))),
c.br(0)
)),
- c.setLocal("ita", c.getLocal("pA")),
- c.setLocal("itb", c.getLocal("pB")),
- c.setLocal("it", c.getLocal("pC")),
- c.setLocal(
- "last",
+ // Distribute elements
+ c.setLocal("itBase", c.getLocal("pBases")),
+ c.setLocal("itScalar", c.getLocal("pScalars")),
+ c.setLocal("endScalar",
c.i32_add(
- c.getLocal("pA"),
+ c.getLocal("pScalars"),
c.i32_mul(
- c.getLocal("nOut"),
- c.i32_const(n8)
+ c.getLocal("n"),
+ c.getLocal("scalarSize")
)
)
),
@@ -10770,144 +10770,287 @@ var build_qap = function buildQAP(module, prefix, prefixField) {
c.br_if(
1,
c.i32_eq(
- c.getLocal("ita"),
- c.getLocal("last")
+ c.getLocal("itScalar"),
+ c.getLocal("endScalar")
)
),
- c.call(
- prefixField + "_mul",
- c.getLocal("ita"),
- c.getLocal("itb"),
- c.getLocal("it")
+
+ c.setLocal(
+ "idx",
+ c.call(fnName + "_getChunk",
+ c.getLocal("itScalar"),
+ c.getLocal("scalarSize"),
+ c.getLocal("startBit"),
+ c.getLocal("chunkSize")
+ )
),
- 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.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 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");
+ 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(n8));
+ 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.setLocal("ita", c.getLocal("pA")),
- c.setLocal("itb", c.getLocal("pB")),
- c.setLocal("itc", c.getLocal("pC")),
- c.setLocal("itp", c.getLocal("pP")),
+ 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(
- "last",
+ "nChunks",
c.i32_add(
- c.getLocal("pA"),
- c.i32_mul(
- c.getLocal("n"),
- c.i32_const(n8)
- )
+ 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_eq(
- c.getLocal("ita"),
- c.getLocal("last")
+ 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(
- prefixField + "_mul",
- c.getLocal("ita"),
- c.getLocal("itb"),
+ fnName + "_chunk",
+ c.getLocal("pBases"),
+ c.getLocal("pScalars"),
+ c.getLocal("scalarSize"),
+ c.getLocal("n"),
+ c.getLocal("itBit"),
+ c.getLocal("chunkSize"),
aux
),
+
c.call(
- prefixField + "_sub",
+ prefix + "_add",
+ c.getLocal("pr"),
aux,
- c.getLocal("itc"),
- c.getLocal("itp"),
+ c.getLocal("pr")
),
- 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.setLocal("itBit", c.i32_sub(c.getLocal("itBit"), c.getLocal("chunkSize"))),
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");
+ 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.setLocal("ita", c.getLocal("pa")),
- c.setLocal("itb", c.getLocal("pb")),
- c.setLocal("itr", c.getLocal("pr")),
+ 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(
- "last",
+ "it2",
c.i32_add(
- c.getLocal("pa"),
+ c.getLocal("pTable"),
c.i32_mul(
- c.getLocal("n"),
- c.i32_const(n8)
+ 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("ita"),
- c.getLocal("last")
+ c.getLocal("it1"),
+ c.getLocal("pAcc")
)
),
c.call(
- prefixField + "_add",
- c.getLocal("ita"),
- c.getLocal("itb"),
- c.getLocal("itr"),
+ prefix + "_add",
+ c.getLocal("it1"),
+ c.getLocal("it2"),
+ c.getLocal("it1")
),
- 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.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"))
);
}
- buildBuildABC();
- buildJoinABC();
- buildBatchAdd();
+ buildGetChunk();
+ buildReduceTable();
+ buildMutiexpChunk();
+ buildMultiexp();
- module.exportFunction(prefix + "_buildABC");
- module.exportFunction(prefix + "_joinABC");
- module.exportFunction(prefix + "_batchAdd");
+ module.exportFunction(fnName);
+ module.exportFunction(fnName +"_chunk");
- return prefix;
};
@@ -10930,6181 +11073,6501 @@ var build_qap = function buildQAP(module, prefix, prefixField) {
along with wasmsnark. If not, see .
*/
-var build_applykey = function buildApplyKey(module, fnName, gPrefix, frPrefix, sizeGIn, sizeGOut, sizeF, opGtimesF) {
+const buildTimesScalarNAF = build_timesscalarnaf;
+//const buildTimesScalar = require("./build_timesscalar");
+const buildBatchConvertion = build_batchconvertion;
+const buildMultiexp = build_multiexp;
- 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");
+var build_curve_jacobian_a0 = function buildCurve(module, prefix, prefixField, pB) {
- const c = f.getCodeBuilder();
- const t = c.i32_const(module.alloc(sizeF));
+ const n64 = module.modules[prefixField].n64;
+ const n8 = n64*8;
- f.addCode(
- c.setLocal("pFrom", c.getLocal("pIn")),
- c.setLocal("pTo", c.getLocal("pOut")),
- );
+ if (module.modules[prefix]) return prefix; // already builded
+ module.modules[prefix] = {
+ n64: n64*3
+ };
- // 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") )),
+ function buildIsZero() {
+ const f = module.addFunction(prefix + "_isZero");
+ f.addParam("p1", "i32");
+ f.setReturnType("i32");
- 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))),
+ const c = f.getCodeBuilder();
- // 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)
- ))
- );
+ 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 acc + ( b!=0 ? 1 : 0) ,0);
- const ateNCoefs = ateNAddCoefs + ateNDblCoefs + 1;
- const prePSize = 3*2*n8;
- const preQSize = 3*n8*2 + ateNCoefs*ateCoefSize;
+ function buildFromMontgomery() {
+ const f = module.addFunction(prefix + "_fromMontgomery");
+ f.addParam("p1", "i32");
+ f.addParam("pr", "i32");
+ const c = f.getCodeBuilder();
- 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()
- };
+ f.addCode(c.call(
+ prefixField + "_fromMontgomery",
+ c.getLocal("p1"),
+ c.getLocal("pr")
+ ));
+ for (let i=1; i<3; i++) {
+ f.addCode(c.call(
+ prefixField + "_fromMontgomery",
+ c.i32_add(c.getLocal("p1"), c.i32_const(i*n8)),
+ c.i32_add(c.getLocal("pr"), c.i32_const(i*n8))
+ ));
+ }
+ }
- // console.log("PrePSize: " +prePSize);
- // console.log("PreQSize: " +preQSize);
- const finalExpZ = 4965661367192848881n;
+ function buildFromMontgomeryAffine() {
+ const f = module.addFunction(prefix + "_fromMontgomeryAffine");
+ f.addParam("p1", "i32");
+ f.addParam("pr", "i32");
- function naf(n) {
- let E = n;
- const res = [];
- while (E > 0n) {
- if (isOdd$1(E)) {
- const z = 2 - Number(E % 4n);
- res.push( z );
- E = E - BigInt(z);
- } else {
- res.push( 0 );
- }
- E = E >> 1n;
+ const c = f.getCodeBuilder();
+
+ f.addCode(c.call(
+ prefixField + "_fromMontgomery",
+ c.getLocal("p1"),
+ c.getLocal("pr")
+ ));
+ for (let i=1; i<2; i++) {
+ f.addCode(c.call(
+ prefixField + "_fromMontgomery",
+ c.i32_add(c.getLocal("p1"), c.i32_const(i*n8)),
+ c.i32_add(c.getLocal("pr"), c.i32_const(i*n8))
+ ));
}
- return res;
}
- function bits(n) {
- let E = n;
- const res = [];
- while (E > 0n) {
- if (isOdd$1(E)) {
- res.push( 1 );
- } else {
- res.push( 0 );
- }
- E = E >> 1n;
- }
- return res;
- }
+ function buildAdd() {
- function buildPrepareG1() {
- const f = module.addFunction(prefix+ "_prepareG1");
- f.addParam("pP", "i32");
- f.addParam("ppreP", "i32");
+ const f = module.addFunction(prefix + "_add");
+ f.addParam("p1", "i32");
+ f.addParam("p2", "i32");
+ f.addParam("pr", "i32");
+ f.addLocal("z1", "i32");
+ f.addLocal("z2", "i32");
const c = f.getCodeBuilder();
- f.addCode(
- c.call(g1mPrefix + "_normalize", c.getLocal("pP"), c.getLocal("ppreP")), // TODO Remove if already in affine
- );
- }
+ const x1 = c.getLocal("p1");
+ const y1 = c.i32_add(c.getLocal("p1"), c.i32_const(n8));
+ f.addCode(c.setLocal("z1", c.i32_add(c.getLocal("p1"), c.i32_const(n8*2))));
+ const z1 = c.getLocal("z1");
+ const x2 = c.getLocal("p2");
+ const y2 = c.i32_add(c.getLocal("p2"), c.i32_const(n8));
+ f.addCode(c.setLocal("z2", c.i32_add(c.getLocal("p2"), c.i32_const(n8*2))));
+ const z2 = c.getLocal("z2");
+ const x3 = c.getLocal("pr");
+ const y3 = c.i32_add(c.getLocal("pr"), c.i32_const(n8));
+ const z3 = c.i32_add(c.getLocal("pr"), c.i32_const(n8*2));
- function buildPrepAddStep() {
- const f = module.addFunction(prefix+ "_prepAddStep");
- f.addParam("pQ", "i32");
- f.addParam("pR", "i32");
- f.addParam("pCoef", "i32");
+ const Z1Z1 = c.i32_const(module.alloc(n8));
+ const Z2Z2 = c.i32_const(module.alloc(n8));
+ const U1 = c.i32_const(module.alloc(n8));
+ const U2 = c.i32_const(module.alloc(n8));
+ const Z1_cubed = c.i32_const(module.alloc(n8));
+ const Z2_cubed = c.i32_const(module.alloc(n8));
+ const S1 = c.i32_const(module.alloc(n8));
+ const S2 = c.i32_const(module.alloc(n8));
+ const H = c.i32_const(module.alloc(n8));
+ const S2_minus_S1 = c.i32_const(module.alloc(n8));
+ const I = c.i32_const(module.alloc(n8));
+ const J = c.i32_const(module.alloc(n8));
+ const r = c.i32_const(module.alloc(n8));
+ const r2 = c.i32_const(module.alloc(n8));
+ const V = c.i32_const(module.alloc(n8));
+ const V2 = c.i32_const(module.alloc(n8));
+ const S1_J2 = c.i32_const(module.alloc(n8));
- const c = f.getCodeBuilder();
+ f.addCode(
+ c.if(
+ c.call(prefix + "_isZero", c.getLocal("p1")),
+ [
+ ...c.call(prefix + "_copy", c.getLocal("p2"), c.getLocal("pr")),
+ ...c.ret([])
+ ]
+ ),
+ c.if(
+ c.call(prefix + "_isZero", c.getLocal("p2")),
+ [
+ ...c.call(prefix + "_copy", c.getLocal("p1"), c.getLocal("pr")),
+ ...c.ret([])
+ ]
+ ),
+ c.if(
+ c.call(prefixField + "_isOne", z1),
+ [
+ ...c.call(prefix + "_addMixed", x2, x1, x3),
+ ...c.ret([])
+ ]
+ ),
+ c.if(
+ c.call(prefixField + "_isOne", z2),
+ [
+ ...c.call(prefix + "_addMixed", x1, x2, x3),
+ ...c.ret([])
+ ]
+ ),
+ c.call(prefixField + "_square", z1, Z1Z1),
+ c.call(prefixField + "_square", z2, Z2Z2),
+ c.call(prefixField + "_mul", x1, Z2Z2, U1),
+ c.call(prefixField + "_mul", x2, Z1Z1, U2),
+ c.call(prefixField + "_mul", z1, Z1Z1, Z1_cubed),
+ c.call(prefixField + "_mul", z2, Z2Z2, Z2_cubed),
+ c.call(prefixField + "_mul", y1, Z2_cubed, S1),
+ c.call(prefixField + "_mul", y2, Z1_cubed, S2),
- const X2 = c.getLocal("pQ");
- const Y2 = c.i32_add(c.getLocal("pQ"), c.i32_const(f2size));
+ c.if(
+ c.call(prefixField + "_eq", U1, U2),
+ c.if(
+ c.call(prefixField + "_eq", S1, S2),
+ [
+ ...c.call(prefix + "_double", c.getLocal("p1"), c.getLocal("pr")),
+ ...c.ret([])
+ ]
+ )
+ ),
- 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));
+ c.call(prefixField + "_sub", U2, U1, H),
+ c.call(prefixField + "_sub", S2, S1, S2_minus_S1),
+ c.call(prefixField + "_add", H, H, I),
+ c.call(prefixField + "_square", I, I),
+ c.call(prefixField + "_mul", H, I, J),
+ c.call(prefixField + "_add", S2_minus_S1, S2_minus_S1, r),
+ c.call(prefixField + "_mul", U1, I, V),
+ c.call(prefixField + "_square", r, r2),
+ c.call(prefixField + "_add", V, V, V2),
- 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));
+ c.call(prefixField + "_sub", r2, J, x3),
+ c.call(prefixField + "_sub", x3, V2, x3),
- 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));
+ c.call(prefixField + "_mul", S1, J, S1_J2),
+ c.call(prefixField + "_add", S1_J2, S1_J2, S1_J2),
- f.addCode(
- // D = X1 - X2*Z1
- c.call(f2mPrefix + "_mul", X2, Z1, D),
- c.call(f2mPrefix + "_sub", X1, D, D),
+ c.call(prefixField + "_sub", V, x3, y3),
+ c.call(prefixField + "_mul", y3, r, y3),
+ c.call(prefixField + "_sub", y3, S1_J2, y3),
- // E = Y1 - Y2*Z1
- c.call(f2mPrefix + "_mul", Y2, Z1, E),
- c.call(f2mPrefix + "_sub", Y1, E, E),
+ c.call(prefixField + "_add", z1, z2, z3),
+ c.call(prefixField + "_square", z3, z3),
+ c.call(prefixField + "_sub", z3, Z1Z1, z3),
+ c.call(prefixField + "_sub", z3, Z2Z2, z3),
+ c.call(prefixField + "_mul", z3, H, z3),
+ );
- // 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),
+ function buildAddMixed() {
- // I = X1 * F
- c.call(f2mPrefix + "_mul", X1, F, I),
+ const f = module.addFunction(prefix + "_addMixed");
+ f.addParam("p1", "i32");
+ f.addParam("p2", "i32");
+ f.addParam("pr", "i32");
+ f.addLocal("z1", "i32");
- // 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),
+ const c = f.getCodeBuilder();
+ const x1 = c.getLocal("p1");
+ const y1 = c.i32_add(c.getLocal("p1"), c.i32_const(n8));
+ f.addCode(c.setLocal("z1", c.i32_add(c.getLocal("p1"), c.i32_const(n8*2))));
+ const z1 = c.getLocal("z1");
+ const x2 = c.getLocal("p2");
+ const y2 = c.i32_add(c.getLocal("p2"), c.i32_const(n8));
+ const x3 = c.getLocal("pr");
+ const y3 = c.i32_add(c.getLocal("pr"), c.i32_const(n8));
+ const z3 = c.i32_add(c.getLocal("pr"), c.i32_const(n8*2));
- // X3 (X1) = D*J
- c.call(f2mPrefix + "_mul", D, J, X1),
+ const Z1Z1 = c.i32_const(module.alloc(n8));
+ const U2 = c.i32_const(module.alloc(n8));
+ const Z1_cubed = c.i32_const(module.alloc(n8));
+ const S2 = c.i32_const(module.alloc(n8));
+ const H = c.i32_const(module.alloc(n8));
+ const HH = c.i32_const(module.alloc(n8));
+ const S2_minus_y1 = c.i32_const(module.alloc(n8));
+ const I = c.i32_const(module.alloc(n8));
+ const J = c.i32_const(module.alloc(n8));
+ const r = c.i32_const(module.alloc(n8));
+ const r2 = c.i32_const(module.alloc(n8));
+ const V = c.i32_const(module.alloc(n8));
+ const V2 = c.i32_const(module.alloc(n8));
+ const y1_J2 = c.i32_const(module.alloc(n8));
- // 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),
+ f.addCode(
+ c.if(
+ c.call(prefix + "_isZero", c.getLocal("p1")),
+ [
+ ...c.call(prefix + "_copyAffine", c.getLocal("p2"), c.getLocal("pr")),
+ ...c.call(prefixField + "_one", c.i32_add(c.getLocal("pr") , c.i32_const(n8*2))),
+ ...c.ret([])
+ ]
+ ),
+ c.if(
+ c.call(prefix + "_isZeroAffine", c.getLocal("p2")),
+ [
+ ...c.call(prefix + "_copy", c.getLocal("p1"), c.getLocal("pr")),
+ ...c.ret([])
+ ]
+ ),
+ c.if(
+ c.call(prefixField + "_isOne", z1),
+ [
+ ...c.call(prefix + "_addAffine", x1, x2, x3),
+ ...c.ret([])
+ ]
+ ),
+ c.call(prefixField + "_square", z1, Z1Z1),
+ c.call(prefixField + "_mul", x2, Z1Z1, U2),
+ c.call(prefixField + "_mul", z1, Z1Z1, Z1_cubed),
+ c.call(prefixField + "_mul", y2, Z1_cubed, S2),
- // Z3 (Z1) = Z1*H
- c.call(f2mPrefix + "_mul", Z1, H, Z1),
+ c.if(
+ c.call(prefixField + "_eq", x1, U2),
+ c.if(
+ c.call(prefixField + "_eq", y1, S2),
+ [
+ ...c.call(prefix + "_doubleAffine", c.getLocal("p2"), c.getLocal("pr")),
+ ...c.ret([])
+ ]
+ )
+ ),
- // 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),
+ c.call(prefixField + "_sub", U2, x1, H),
+ c.call(prefixField + "_sub", S2, y1, S2_minus_y1),
+ c.call(prefixField + "_square", H, HH),
+ c.call(prefixField + "_add", HH , HH, I),
+ c.call(prefixField + "_add", I , I, I),
+ c.call(prefixField + "_mul", H, I, J),
+ c.call(prefixField + "_add", S2_minus_y1, S2_minus_y1, r),
+ c.call(prefixField + "_mul", x1, I, V),
+ c.call(prefixField + "_square", r, r2),
+ c.call(prefixField + "_add", V, V, V2),
+ c.call(prefixField + "_sub", r2, J, x3),
+ c.call(prefixField + "_sub", x3, V2, x3),
- // ell_VV = - E (later: * xP)
- c.call(f2mPrefix + "_neg", E, ELL_VV),
+ c.call(prefixField + "_mul", y1, J, y1_J2),
+ c.call(prefixField + "_add", y1_J2, y1_J2, y1_J2),
- // ell_VW = D (later: * yP )
- // Already assigned
+ c.call(prefixField + "_sub", V, x3, y3),
+ c.call(prefixField + "_mul", y3, r, y3),
+ c.call(prefixField + "_sub", y3, y1_J2, y3),
+ c.call(prefixField + "_add", z1, H, z3),
+ c.call(prefixField + "_square", z3, z3),
+ c.call(prefixField + "_sub", z3, Z1Z1, z3),
+ c.call(prefixField + "_sub", z3, HH, z3),
);
}
+ function buildAddAffine() {
- function buildPrepDoubleStep() {
- const f = module.addFunction(prefix+ "_prepDblStep");
- f.addParam("pR", "i32");
- f.addParam("pCoef", "i32");
+ const f = module.addFunction(prefix + "_addAffine");
+ f.addParam("p1", "i32");
+ f.addParam("p2", "i32");
+ f.addParam("pr", "i32");
+ f.addLocal("z1", "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 x1 = c.getLocal("p1");
+ const y1 = c.i32_add(c.getLocal("p1"), c.i32_const(n8));
+ f.addCode(c.setLocal("z1", c.i32_add(c.getLocal("p1"), c.i32_const(n8*2))));
+ const x2 = c.getLocal("p2");
+ const y2 = c.i32_add(c.getLocal("p2"), c.i32_const(n8));
+ const x3 = c.getLocal("pr");
+ const y3 = c.i32_add(c.getLocal("pr"), c.i32_const(n8));
+ const z3 = c.i32_add(c.getLocal("pr"), c.i32_const(n8*2));
- 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));
+ const H = c.i32_const(module.alloc(n8));
+ const HH = c.i32_const(module.alloc(n8));
+ const y2_minus_y1 = c.i32_const(module.alloc(n8));
+ const I = c.i32_const(module.alloc(n8));
+ const J = c.i32_const(module.alloc(n8));
+ const r = c.i32_const(module.alloc(n8));
+ const r2 = c.i32_const(module.alloc(n8));
+ const V = c.i32_const(module.alloc(n8));
+ const V2 = c.i32_const(module.alloc(n8));
+ const y1_J2 = c.i32_const(module.alloc(n8));
f.addCode(
+ c.if(
+ c.call(prefix + "_isZeroAffine", c.getLocal("p1")),
+ [
+ ...c.call(prefix + "_copyAffine", c.getLocal("p2"), c.getLocal("pr")),
+ ...c.call(prefixField + "_one", c.i32_add(c.getLocal("pr") , c.i32_const(n8*2))),
+ ...c.ret([])
+ ]
+ ),
+ c.if(
+ c.call(prefix + "_isZeroAffine", c.getLocal("p2")),
+ [
+ ...c.call(prefix + "_copyAffine", c.getLocal("p1"), c.getLocal("pr")),
+ ...c.call(prefixField + "_one", c.i32_add(c.getLocal("pr") , c.i32_const(n8*2))),
+ ...c.ret([])
+ ]
+ ),
- // 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),
+ c.if(
+ c.call(prefixField + "_eq", x1, x2),
+ c.if(
+ c.call(prefixField + "_eq", y1, y2),
+ [
+ ...c.call(prefix + "_doubleAffine", c.getLocal("p2"), c.getLocal("pr")),
+ ...c.ret([])
+ ]
+ )
+ ),
- // Z3 (Z1) = B * H
- c.call(f2mPrefix + "_mul", B, H, Z1),
+ c.call(prefixField + "_sub", x2, x1, H),
+ c.call(prefixField + "_sub", y2, y1, y2_minus_y1),
+ c.call(prefixField + "_square", H, HH),
+ c.call(prefixField + "_add", HH , HH, I),
+ c.call(prefixField + "_add", I , I, I),
+ c.call(prefixField + "_mul", H, I, J),
+ c.call(prefixField + "_add", y2_minus_y1, y2_minus_y1, r),
+ c.call(prefixField + "_mul", x1, I, V),
+ c.call(prefixField + "_square", r, r2),
+ c.call(prefixField + "_add", V, V, V2),
- // ell_0 = xi * I
- c.call(f2mPrefix + "_mul", c.i32_const(pAltBn128Twist), I, ELL_0),
+ c.call(prefixField + "_sub", r2, J, x3),
+ c.call(prefixField + "_sub", x3, V2, x3),
- // ell_VW = - H (later: * yP)
- c.call(f2mPrefix + "_neg", H, ELL_VW),
+ c.call(prefixField + "_mul", y1, J, y1_J2),
+ c.call(prefixField + "_add", y1_J2, y1_J2, y1_J2),
- // ell_VV = 3*J (later: * xP)
- c.call(f2mPrefix + "_add", J, J, ELL_VV),
- c.call(f2mPrefix + "_add", J, ELL_VV, ELL_VV),
+ c.call(prefixField + "_sub", V, x3, y3),
+ c.call(prefixField + "_mul", y3, r, y3),
+ c.call(prefixField + "_sub", y3, y1_J2, y3),
+ c.call(prefixField + "_add", H, H, z3),
);
}
- function buildMulByQ() {
- const f = module.addFunction(prefix + "_mulByQ");
+ function buildNeg() {
+ const f = module.addFunction(prefix + "_neg");
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 y = c.i32_add(c.getLocal("p1"), c.i32_const(n8));
+ const z = c.i32_add(c.getLocal("p1"), c.i32_const(n8*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$2.bigInt2BytesLE( toMontgomery("21575463638280843010398324269430826099269044274347216827212613867836435027261"), f1size ),
- ...utils$2.bigInt2BytesLE( toMontgomery("10307601595873709700152284273816112264069230130616436755625194854815875713954"), f1size ),
- ]));
-
- const MulByQY = c.i32_const(module.alloc([
- ...utils$2.bigInt2BytesLE( toMontgomery("2821565182194536844548159561693502659359617185244120367078079554186484126554"), f1size ),
- ...utils$2.bigInt2BytesLE( toMontgomery("3505843767911556378687030309984248845540243509899259641013678093033130930403"), f1size ),
- ]));
+ const y3 = c.i32_add(c.getLocal("pr"), c.i32_const(n8));
+ const z3 = c.i32_add(c.getLocal("pr"), c.i32_const(n8*2));
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),
+ c.call(prefixField + "_copy", x, x3),
+ c.call(prefixField + "_neg", y, y3),
+ c.call(prefixField + "_copy", 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");
+ function buildNegAffine() {
+ const f = module.addFunction(prefix + "_negAffine");
+ f.addParam("p1", "i32");
+ f.addParam("pr", "i32");
const c = f.getCodeBuilder();
- const QX = c.getLocal("pQ");
-
- 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));
-
- const pQ1 = module.alloc(f2size*3);
- const Q1 = c.i32_const(pQ1);
-
- const pQ2 = module.alloc(f2size*3);
- const Q2 = c.i32_const(pQ2);
- const Q2Y = c.i32_const(pQ2 + f2size);
+ const x = c.getLocal("p1");
+ const y = c.i32_add(c.getLocal("p1"), c.i32_const(n8));
+ const x3 = c.getLocal("pr");
+ const y3 = c.i32_add(c.getLocal("pr"), c.i32_const(n8));
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),
+ c.call(prefixField + "_copy", x, x3),
+ c.call(prefixField + "_neg", y, y3),
);
+ }
- 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)
- ))
- );
+ function buildSub() {
+ const f = module.addFunction(prefix + "_sub");
+ f.addParam("p1", "i32");
+ f.addParam("p2", "i32");
+ f.addParam("pr", "i32");
+
+ const c = f.getCodeBuilder();
+
+ const AUX = c.i32_const(module.alloc(n8*3));
f.addCode(
- c.call(prefix + "_mulByQ", cQX, Q1),
- c.call(prefix + "_mulByQ", Q1, Q2)
+ c.call(prefix + "_neg", c.getLocal("p2"), AUX),
+ c.call(prefix + "_add", c.getLocal("p1"), AUX, c.getLocal("pr")),
);
+ }
- f.addCode(
- c.call(f2mPrefix + "_neg", Q2Y, Q2Y),
+ function buildSubMixed() {
+ const f = module.addFunction(prefix + "_subMixed");
+ f.addParam("p1", "i32");
+ f.addParam("p2", "i32");
+ f.addParam("pr", "i32");
- c.call(prefix + "_prepAddStep", Q1, R, c.getLocal("pCoef")),
- c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))),
+ const c = f.getCodeBuilder();
- c.call(prefix + "_prepAddStep", Q2, R, c.getLocal("pCoef")),
- c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))),
+ const AUX = c.i32_const(module.alloc(n8*3));
+
+ f.addCode(
+ c.call(prefix + "_negAffine", c.getLocal("p2"), AUX),
+ c.call(prefix + "_addMixed", c.getLocal("p1"), AUX, c.getLocal("pr")),
);
}
- 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");
+ function buildSubAffine() {
+ const f = module.addFunction(prefix + "_subAffine");
+ f.addParam("p1", "i32");
+ f.addParam("p2", "i32");
+ f.addParam("pr", "i32");
- const z0 = c.getLocal("pR");
+ const c = f.getCodeBuilder();
- 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);
+ const AUX = c.i32_const(module.alloc(n8*3));
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),
+ c.call(prefix + "_negAffine", c.getLocal("p2"), AUX),
+ c.call(prefix + "_addAffine", c.getLocal("p1"), AUX, c.getLocal("pr")),
);
}
- 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
+ // This sets Z to One
+ function buildNormalize() {
+ const f = module.addFunction(prefix + "_normalize");
+ f.addParam("p1", "i32");
+ f.addParam("pr", "i32");
const c = f.getCodeBuilder();
- const x0 = c.getLocal("pEll0");
- const x2 = c.getLocal("pEllVV");
- const x4 = c.getLocal("pEllVW");
+ const x = c.getLocal("p1");
+ const y = c.i32_add(c.getLocal("p1"), c.i32_const(n8));
+ const z = c.i32_add(c.getLocal("p1"), c.i32_const(n8*2));
+ const x3 = c.getLocal("pr");
+ const y3 = c.i32_add(c.getLocal("pr"), c.i32_const(n8));
+ const z3 = c.i32_add(c.getLocal("pr"), c.i32_const(n8*2));
- 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));
+ const Z_inv = c.i32_const(module.alloc(n8));
+ const Z2_inv = c.i32_const(module.alloc(n8));
+ const Z3_inv = c.i32_const(module.alloc(n8));
f.addCode(
+ c.if(
+ c.call(prefix + "_isZero", c.getLocal("p1")),
+ c.call(prefix + "_zero", c.getLocal("pr")),
+ [
+ ...c.call(prefixField + "_inverse", z, Z_inv),
+ ...c.call(prefixField + "_square", Z_inv, Z2_inv),
+ ...c.call(prefixField + "_mul", Z_inv, Z2_inv, Z3_inv),
+ ...c.call(prefixField + "_mul", x, Z2_inv, x3),
+ ...c.call(prefixField + "_mul", y, Z3_inv, y3),
+ ...c.call(prefixField + "_one", z3),
+ ]
+ )
+ );
+ }
- // 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),
+ // Does not set Z.
+ function buildToAffine() {
+ const f = module.addFunction(prefix + "_toAffine");
+ f.addParam("p1", "i32");
+ f.addParam("pr", "i32");
- // 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;
+ const c = f.getCodeBuilder();
- // 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;
+ const x = c.getLocal("p1");
+ const y = c.i32_add(c.getLocal("p1"), c.i32_const(n8));
+ const z = c.i32_add(c.getLocal("p1"), c.i32_const(n8*2));
+ const x3 = c.getLocal("pr");
+ const y3 = c.i32_add(c.getLocal("pr"), c.i32_const(n8));
+ const Z_inv = c.i32_const(module.alloc(n8));
+ const Z2_inv = c.i32_const(module.alloc(n8));
+ const Z3_inv = c.i32_const(module.alloc(n8));
- // 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),
+ f.addCode(
+ c.if(
+ c.call(prefix + "_isZero", c.getLocal("p1")),
+ [
+ ...c.call(prefixField + "_zero", x3),
+ ...c.call(prefixField + "_zero", y3),
+ ],
+ [
+ ...c.call(prefixField + "_inverse", z, Z_inv),
+ ...c.call(prefixField + "_square", Z_inv, Z2_inv),
+ ...c.call(prefixField + "_mul", Z_inv, Z2_inv, Z3_inv),
+ ...c.call(prefixField + "_mul", x, Z2_inv, x3),
+ ...c.call(prefixField + "_mul", y, Z3_inv, y3),
+ ]
+ )
+ );
+ }
- // 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;
+ function buildToJacobian() {
+ const f = module.addFunction(prefix + "_toJacobian");
+ f.addParam("p1", "i32");
+ f.addParam("pr", "i32");
- // 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;
+ const c = f.getCodeBuilder();
- // 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;
+ const x = c.getLocal("p1");
+ const y = c.i32_add(c.getLocal("p1"), c.i32_const(n8));
+ const x3 = c.getLocal("pr");
+ const y3 = c.i32_add(c.getLocal("pr"), c.i32_const(n8));
+ const z3 = c.i32_add(c.getLocal("pr"), c.i32_const(n8*2));
+ f.addCode(
+ c.if(
+ c.call(prefix + "_isZeroAffine", c.getLocal("p1")),
+ c.call(prefix + "_zero", c.getLocal("pr")),
+ [
+ ...c.call(prefixField + "_one", z3),
+ ...c.call(prefixField + "_copy", y, y3),
+ ...c.call(prefixField + "_copy", x, x3)
+ ]
+ )
);
}
-
- function buildMillerLoop() {
- const f = module.addFunction(prefix+ "_millerLoop");
- f.addParam("ppreP", "i32");
- f.addParam("ppreQ", "i32");
- f.addParam("r", "i32");
- f.addLocal("pCoef", "i32");
+ function buildBatchToAffine() {
+ const f = module.addFunction(prefix + "_batchToAffine");
+ f.addParam("pIn", "i32");
+ f.addParam("n", "i32");
+ f.addParam("pOut", "i32");
+ f.addLocal("pAux", "i32");
+ f.addLocal("itIn", "i32");
+ f.addLocal("itAux", "i32");
+ f.addLocal("itOut", "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");
-
+ const tmp = c.i32_const(module.alloc(n8));
f.addCode(
- c.call(ftmPrefix + "_one", F),
+ c.setLocal("pAux", c.i32_load( c.i32_const(0) )),
+ c.i32_store(
+ c.i32_const(0),
+ c.i32_add(
+ c.getLocal("pAux"),
+ c.i32_mul(c.getLocal("n"), c.i32_const(n8))
+ )
+ ),
- c.setLocal("pCoef", c.i32_add( c.getLocal("ppreQ"), c.i32_const(f2size*3))),
+ c.call(
+ prefixField + "_batchInverse",
+ c.i32_add(c.getLocal("pIn"), c.i32_const(n8*2)),
+ c.i32_const(n8*3),
+ c.getLocal("n"),
+ c.getLocal("pAux"),
+ c.i32_const(n8)
+ ),
- c.setLocal("i", c.i32_const(ateLoopBitBytes.length-2)),
+ c.setLocal("itIn", c.getLocal("pIn")),
+ c.setLocal("itAux", c.getLocal("pAux")),
+ c.setLocal("itOut", c.getLocal("pOut")),
+ c.setLocal("i", c.i32_const(0)),
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.br_if(1, c.i32_eq ( c.getLocal("i"), c.getLocal("n") )),
c.if(
- c.i32_load8_s(c.getLocal("i"), pAteLoopBitBytes),
+ c.call(prefixField + "_isZero", c.getLocal("itAux")),
[
- ...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(prefixField + "_zero", c.getLocal("itOut")),
+ ...c.call(prefixField + "_zero", c.i32_add(c.getLocal("itOut"), c.i32_const(n8)))
+ ],
+ [
+ ...c.call(
+ prefixField+"_mul",
+ c.getLocal("itAux"),
+ c.i32_add(c.getLocal("itIn"), c.i32_const(n8)),
+ tmp,
+ ),
+ ...c.call(
+ prefixField+"_square",
+ c.getLocal("itAux"),
+ c.getLocal("itAux")
+ ),
+ ...c.call(
+ prefixField+"_mul",
+ c.getLocal("itAux"),
+ c.getLocal("itIn"),
+ c.getLocal("itOut"),
+ ),
+ ...c.call(
+ prefixField+"_mul",
+ c.getLocal("itAux"),
+ tmp,
+ c.i32_add(c.getLocal("itOut"), c.i32_const(n8)),
+ ),
]
),
- 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))),
+ c.setLocal("itIn", c.i32_add(c.getLocal("itIn"), c.i32_const(n8*3))),
+ c.setLocal("itOut", c.i32_add(c.getLocal("itOut"), c.i32_const(n8*2))),
+ c.setLocal("itAux", c.i32_add(c.getLocal("itAux"), c.i32_const(n8))),
+ c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
+ c.br(0)
+ )),
+ c.i32_store(
+ c.i32_const(0),
+ c.getLocal("pAux")
+ )
);
-
}
- function buildFrobeniusMap(n) {
- const F12 = [
- [
- [1n, 0n],
- [1n, 0n],
- [1n, 0n],
- [1n, 0n],
- [1n, 0n],
- [1n, 0n],
- [1n, 0n],
- [1n, 0n],
- [1n, 0n],
- [1n, 0n],
- [1n, 0n],
- [1n, 0n],
- ],
- [
- [1n, 0n],
- [8376118865763821496583973867626364092589906065868298776909617916018768340080n, 16469823323077808223889137241176536799009286646108169935659301613961712198316n],
- [21888242871839275220042445260109153167277707414472061641714758635765020556617n, 0n],
- [11697423496358154304825782922584725312912383441159505038794027105778954184319n, 303847389135065887422783454877609941456349188919719272345083954437860409601n],
- [21888242871839275220042445260109153167277707414472061641714758635765020556616n, 0n],
- [3321304630594332808241809054958361220322477375291206261884409189760185844239n, 5722266937896532885780051958958348231143373700109372999374820235121374419868n],
- [21888242871839275222246405745257275088696311157297823662689037894645226208582n, 0n],
- [13512124006075453725662431877630910996106405091429524885779419978626457868503n, 5418419548761466998357268504080738289687024511189653727029736280683514010267n],
- [2203960485148121921418603742825762020974279258880205651966n, 0n],
- [10190819375481120917420622822672549775783927716138318623895010788866272024264n, 21584395482704209334823622290379665147239961968378104390343953940207365798982n],
- [2203960485148121921418603742825762020974279258880205651967n, 0n],
- [18566938241244942414004596690298913868373833782006617400804628704885040364344n, 16165975933942742336466353786298926857552937457188450663314217659523851788715n],
- ]
- ];
-
- const F6 = [
- [
- [1n, 0n],
- [1n, 0n],
- [1n, 0n],
- [1n, 0n],
- [1n, 0n],
- [1n, 0n],
- ],
- [
- [1n, 0n],
- [21575463638280843010398324269430826099269044274347216827212613867836435027261n, 10307601595873709700152284273816112264069230130616436755625194854815875713954n],
- [21888242871839275220042445260109153167277707414472061641714758635765020556616n, 0n],
- [3772000881919853776433695186713858239009073593817195771773381919316419345261n, 2236595495967245188281701248203181795121068902605861227855261137820944008926n],
- [2203960485148121921418603742825762020974279258880205651966n, 0n],
- [18429021223477853657660792034369865839114504446431234726392080002137598044644n, 9344045779998320333812420223237981029506012124075525679208581902008406485703n],
- ],
- [
- [1n, 0n],
- [2581911344467009335267311115468803099551665605076196740867805258568234346338n, 19937756971775647987995932169929341994314640652964949448313374472400716661030n],
- [2203960485148121921418603742825762020974279258880205651966n, 0n],
- [5324479202449903542726783395506214481928257762400643279780343368557297135718n, 16208900380737693084919495127334387981393726419856888799917914180988844123039n],
- [21888242871839275220042445260109153167277707414472061641714758635765020556616n, 0n],
- [13981852324922362344252311234282257507216387789820983642040889267519694726527n, 7629828391165209371577384193250820201684255241773809077146787135900891633097n],
- ]
- ];
-
- const f = module.addFunction(prefix+ "__frobeniusMap"+n);
- f.addParam("x", "i32");
- f.addParam("r", "i32");
+ // This function is private and does not allow to OVERLAP buffers.
+ function buildReverseBytes() {
+ const f = module.addFunction(prefix + "__reverseBytes");
+ f.addParam("pIn", "i32");
+ f.addParam("n", "i32");
+ f.addParam("pOut", "i32");
+ f.addLocal("itOut", "i32");
+ f.addLocal("itIn", "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$2.bigInt2BytesLE(toMontgomery(coef[0]), 32),
- ...utils$2.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(a[0]);
- const ac1 = BigInt(a[1]);
- const bc0 = BigInt(b[0]);
- const bc1 = BigInt(b[1]);
- const res = [
- (ac0 * bc0 - ( ac1 * bc1) ) % q,
- (ac0 * bc1 + ( ac1 * bc0) ) % q,
- ];
- if (isNegative$2(res[0])) res[0] = res[0] + q;
- return res;
- }
+ f.addCode(
+ c.setLocal(
+ "itOut",
+ c.i32_sub(
+ c.i32_add(
+ c.getLocal("pOut"),
+ c.getLocal("n")
+ ),
+ c.i32_const(1)
+ )
+ ),
+ c.setLocal(
+ "itIn",
+ c.getLocal("pIn")
+ ),
+ c.block(c.loop(
+ c.br_if(1, c.i32_lt_s( c.getLocal("itOut"), c.getLocal("pOut") )),
+ c.i32_store8(
+ c.getLocal("itOut"),
+ c.i32_load8_u(c.getLocal("itIn")),
+ ),
+ c.setLocal("itOut", c.i32_sub(c.getLocal("itOut"), c.i32_const(1))),
+ c.setLocal("itIn", c.i32_add(c.getLocal("itIn"), c.i32_const(1))),
+ c.br(0)
+ )),
+ );
}
+ function buildLEMtoC() {
+ const f = module.addFunction(prefix + "_LEMtoC");
+ f.addParam("pIn", "i32");
+ f.addParam("pOut", "i32");
+ const c = f.getCodeBuilder();
- function buildFinalExponentiationFirstChunk() {
+ const tmp = c.i32_const(module.alloc(n8));
- const f = module.addFunction(prefix+ "__finalExponentiationFirstChunk");
- f.addParam("x", "i32");
- f.addParam("r", "i32");
+ f.addCode(
+ c.if(
+ c.call(prefix + "_isZeroAffine", c.getLocal("pIn")),
+ [
+ ...c.call(prefixField + "_zero", c.getLocal("pOut")),
+ ...c.i32_store8(
+ c.getLocal("pOut"),
+ c.i32_const(0x40)
+ ),
+ ...c.ret([])
+ ]
+ ),
+ c.call(prefixField + "_fromMontgomery", c.getLocal("pIn"), tmp),
+ c.call(prefix + "__reverseBytes", tmp, c.i32_const(n8), c.getLocal("pOut")),
+ c.if(
+ c.i32_eq(
+ c.call(prefixField + "_sign", c.i32_add(c.getLocal("pIn"), c.i32_const(n8))),
+ c.i32_const(-1)
+ ),
+ c.i32_store8(
+ c.getLocal("pOut"),
+ c.i32_or(
+ c.i32_load8_u(c.getLocal("pOut")),
+ c.i32_const(0x80)
+ )
+ )
+ ),
+ );
+ }
+
+ function buildLEMtoU() {
+ const f = module.addFunction(prefix + "_LEMtoU");
+ f.addParam("pIn", "i32");
+ f.addParam("pOut", "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));
+ const pTmp = module.alloc(n8*2);
+ const tmp = c.i32_const(pTmp);
+ const tmpX = c.i32_const(pTmp);
+ const tmpY = c.i32_const(pTmp + n8);
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),
+ c.if(
+ c.call(prefix + "_isZeroAffine", c.getLocal("pIn")),
+ [
+ ...c.call(prefix + "_zeroAffine", c.getLocal("pOut")),
+ ...c.ret([])
+ ]
+ ),
- // const alt_bn128_Fq12 B = elt.inverse();
- c.call(ftmPrefix + "_inverse", elt, B),
+ c.call(prefix + "_fromMontgomeryAffine", c.getLocal("pIn"), tmp),
- // 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),
+ c.call(prefix + "__reverseBytes", tmpX, c.i32_const(n8), c.getLocal("pOut")),
+ c.call(prefix + "__reverseBytes", tmpY, c.i32_const(n8), c.i32_add(c.getLocal("pOut"), c.i32_const(n8))),
);
}
- function buildCyclotomicSquare() {
- const f = module.addFunction(prefix+ "__cyclotomicSquare");
- f.addParam("x", "i32");
- f.addParam("r", "i32");
+ function buildUtoLEM() {
+ const f = module.addFunction(prefix + "_UtoLEM");
+ f.addParam("pIn", "i32");
+ f.addParam("pOut", "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 pTmp = module.alloc(n8*2);
+ const tmp = c.i32_const(pTmp);
+ const tmpX = c.i32_const(pTmp);
+ const tmpY = c.i32_const(pTmp + n8);
- 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));
+ f.addCode(
+ c.if(
+ c.i32_and(c.i32_load8_u(c.getLocal("pIn")), c.i32_const(0x40)),
+ [
+ ...c.call(prefix + "_zeroAffine", c.getLocal("pOut")),
+ ...c.ret([])
+ ]
+ ),
+ c.call(prefix + "__reverseBytes", c.getLocal("pIn"), c.i32_const(n8), tmpX),
+ c.call(prefix + "__reverseBytes", c.i32_add(c.getLocal("pIn"), c.i32_const(n8)), c.i32_const(n8), tmpY),
+ c.call(prefix + "_toMontgomeryAffine", tmp, c.getLocal("pOut"))
+ );
+ }
- 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));
+ function buildCtoLEM() {
+ const f = module.addFunction(prefix + "_CtoLEM");
+ f.addParam("pIn", "i32");
+ f.addParam("pOut", "i32");
+ f.addLocal("firstByte", "i32");
+ f.addLocal("greatest", "i32");
+ const c = f.getCodeBuilder();
- f.addCode(
- // // 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),
+ const pTmp = module.alloc(n8*2);
+ const tmpX = c.i32_const(pTmp);
+ const tmpY = c.i32_const(pTmp + n8);
- // // 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),
+ f.addCode(
+ c.setLocal("firstByte", c.i32_load8_u(c.getLocal("pIn"))),
+ c.if(
+ c.i32_and(
+ c.getLocal("firstByte"),
+ c.i32_const(0x40)
+ ),
+ [
+ ...c.call(prefix + "_zeroAffine", c.getLocal("pOut")),
+ ...c.ret([])
+ ]
+ ),
+ c.setLocal(
+ "greatest",
+ c.i32_and(
+ c.getLocal("firstByte"),
+ c.i32_const(0x80)
+ )
+ ),
- // // 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),
+ c.call(prefixField + "_copy", c.getLocal("pIn"), tmpY),
+ c.i32_store8(tmpY, c.i32_and(c.getLocal("firstByte"), c.i32_const(0x3F))),
+ c.call(prefix + "__reverseBytes", tmpY, c.i32_const(n8), tmpX),
+ c.call(prefixField + "_toMontgomery", tmpX, c.getLocal("pOut")),
- // 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),
+ c.call(prefixField + "_square", c.getLocal("pOut"), tmpY),
+ c.call(prefixField + "_mul", c.getLocal("pOut"), tmpY, tmpY),
+ c.call(prefixField + "_add", tmpY, c.i32_const(pB), tmpY),
- // 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),
+ c.call(prefixField + "_sqrt", tmpY, tmpY),
+ c.call(prefixField + "_neg", tmpY, tmpX),
- // 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),
+ c.if(
+ c.i32_eq(
+ c.call(prefixField + "_sign", tmpY),
+ c.i32_const(-1)
+ ),
+ c.if(
+ c.getLocal("greatest"),
+ c.call(prefixField + "_copy", tmpY, c.i32_add(c.getLocal("pOut"), c.i32_const(n8))),
+ c.call(prefixField + "_neg", tmpY, c.i32_add(c.getLocal("pOut"), c.i32_const(n8)))
+ ),
+ c.if(
+ c.getLocal("greatest"),
+ c.call(prefixField + "_neg", tmpY, c.i32_add(c.getLocal("pOut"), c.i32_const(n8))),
+ c.call(prefixField + "_copy", tmpY, c.i32_add(c.getLocal("pOut"), c.i32_const(n8)))
+ ),
+ )
);
}
+ function buildInCurveAffine() {
+ const f = module.addFunction(prefix + "_inCurveAffine");
+ f.addParam("pIn", "i32");
+ f.setReturnType("i32");
- function buildCyclotomicExp(exponent, fnName) {
- const exponentNafBytes = naf(exponent).map( (b) => (b==-1 ? 0xFF: b) );
- const pExponentNafBytes = module.alloc(exponentNafBytes);
+ const c = f.getCodeBuilder();
- const f = module.addFunction(prefix+ "__cyclotomicExp_"+fnName);
- f.addParam("x", "i32");
- f.addParam("r", "i32");
- f.addLocal("bit", "i32");
- f.addLocal("i", "i32");
+ const x = c.getLocal("pIn");
+ const y = c.i32_add(c.getLocal("pIn"), c.i32_const(n8));
- const c = f.getCodeBuilder();
+ const y2 = c.i32_const(module.alloc(n8));
+ const x3b = c.i32_const(module.alloc(n8));
- const x = c.getLocal("x");
+ f.addCode(
+ c.call(prefixField + "_square", y, y2),
+ c.call(prefixField + "_square", x, x3b),
+ c.call(prefixField + "_mul", x, x3b, x3b),
+ c.call(prefixField + "_add", x3b, c.i32_const(pB), x3b),
- const res = c.getLocal("r");
+ c.ret(
+ c.call(prefixField + "_eq", y2, x3b)
+ )
+ );
+ }
- const inverse = c.i32_const(module.alloc(ftsize));
+ function buildInCurve() {
+ const f = module.addFunction(prefix + "_inCurve");
+ f.addParam("pIn", "i32");
+ f.setReturnType("i32");
+ const c = f.getCodeBuilder();
- f.addCode(
- c.call(ftmPrefix + "_conjugate", x, inverse),
- c.call(ftmPrefix + "_one", res),
+ const aux = c.i32_const(module.alloc(n8*2));
- 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),
- )
- ),
+ f.addCode(
+ c.call(prefix + "_toAffine", c.getLocal("pIn"), aux),
- c.setLocal("i", c.i32_const(exponentNafBytes.length-2)),
- c.block(c.loop(
- 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)
- ))
+ c.ret(
+ c.call(prefix + "_inCurveAffine", aux),
+ )
);
}
+ buildIsZeroAffine();
+ buildIsZero();
+ buildZeroAffine();
+ buildZero();
+ buildCopyAffine();
+ buildCopy();
+ buildToJacobian();
+ buildEqAffine();
+ buildEqMixed();
+ buildEq();
+ buildDoubleAffine();
+ buildDouble();
+ buildAddAffine();
+ buildAddMixed();
+ buildAdd();
+ buildNegAffine();
+ buildNeg();
+ buildSubAffine();
+ buildSubMixed();
+ buildSub();
+ buildFromMontgomeryAffine();
+ buildFromMontgomery();
+ buildToMontgomeryAffine();
+ buildToMontgomery();
+ buildToAffine();
+ buildInCurveAffine();
+ buildInCurve();
+ buildBatchToAffine();
- function buildFinalExponentiationLastChunk() {
- buildCyclotomicSquare();
- buildCyclotomicExp(finalExpZ, "w0");
-
- const f = module.addFunction(prefix+ "__finalExponentiationLastChunk");
- f.addParam("x", "i32");
- f.addParam("r", "i32");
-
- const c = f.getCodeBuilder();
+ buildNormalize();
- 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(
+ buildReverseBytes();
+ buildLEMtoU();
+ buildLEMtoC();
+ buildUtoLEM();
+ buildCtoLEM();
- // 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),
+ buildBatchConvertion(module, prefix + "_batchLEMtoU", prefix + "_LEMtoU", n8*2, n8*2);
+ buildBatchConvertion(module, prefix + "_batchLEMtoC", prefix + "_LEMtoC", n8*2, n8);
+ buildBatchConvertion(module, prefix + "_batchUtoLEM", prefix + "_UtoLEM", n8*2, n8*2);
+ buildBatchConvertion(module, prefix + "_batchCtoLEM", prefix + "_CtoLEM", n8, n8*2, true);
- // N = M * elt // = elt^(12*z^3 + 12*z^2 + 6*z + 1)
- c.call(ftmPrefix + "_mul", M, elt, N),
+ buildBatchConvertion(module, prefix + "_batchToJacobian", prefix + "_toJacobian", n8*2, n8*3, true);
- // 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
- );
- }
+ buildMultiexp(module, prefix, prefix + "_multiexp", prefix + "_add", n8*3);
+ buildMultiexp(module, prefix, prefix + "_multiexpAffine", prefix + "_addMixed", n8*2);
+ /*
+ buildTimesScalar(
+ module,
+ prefix + "_timesScalarOld",
+ n8*3,
+ prefix + "_add",
+ prefix + "_double",
+ prefix + "_copy",
+ prefix + "_zero",
+ );
+ */
+ buildTimesScalarNAF(
+ module,
+ prefix + "_timesScalar",
+ n8*3,
+ prefix + "_add",
+ prefix + "_double",
+ prefix + "_sub",
+ prefix + "_copy",
+ prefix + "_zero"
+ );
- function buildFinalExponentiation() {
- buildFinalExponentiationFirstChunk();
- buildFinalExponentiationLastChunk();
- const f = module.addFunction(prefix+ "_finalExponentiation");
- f.addParam("x", "i32");
- f.addParam("r", "i32");
+ buildTimesScalarNAF(
+ module,
+ prefix + "_timesScalarAffine",
+ n8*2,
+ prefix + "_addMixed",
+ prefix + "_double",
+ prefix + "_subMixed",
+ prefix + "_copyAffine",
+ prefix + "_zero"
+ );
- const c = f.getCodeBuilder();
+ module.exportFunction(prefix + "_isZero");
+ module.exportFunction(prefix + "_isZeroAffine");
- const elt = c.getLocal("x");
- const result = c.getLocal("r");
- const eltToFirstChunk = c.i32_const(module.alloc(ftsize));
+ module.exportFunction(prefix + "_eq");
+ module.exportFunction(prefix + "_eqMixed");
+ module.exportFunction(prefix + "_eqAffine");
- f.addCode(
- c.call(prefix + "__finalExponentiationFirstChunk", elt, eltToFirstChunk ),
- c.call(prefix + "__finalExponentiationLastChunk", eltToFirstChunk, result )
- );
- }
+ module.exportFunction(prefix + "_copy");
+ module.exportFunction(prefix + "_copyAffine");
+ module.exportFunction(prefix + "_zero");
+ module.exportFunction(prefix + "_zeroAffine");
- function buildFinalExponentiationOld() {
- const f = module.addFunction(prefix+ "_finalExponentiationOld");
- f.addParam("x", "i32");
- f.addParam("r", "i32");
+ module.exportFunction(prefix + "_double");
+ module.exportFunction(prefix + "_doubleAffine");
- const exponent = 552484233613224096312617126783173147097382103762957654188882734314196910839907541213974502761540629817009608548654680343627701153829446747810907373256841551006201639677726139946029199968412598804882391702273019083653272047566316584365559776493027495458238373902875937659943504873220554161550525926302303331747463515644711876653177129578303191095900909191624817826566688241804408081892785725967931714097716709526092261278071952560171111444072049229123565057483750161460024353346284167282452756217662335528813519139808291170539072125381230815729071544861602750936964829313608137325426383735122175229541155376346436093930287402089517426973178917569713384748081827255472576937471496195752727188261435633271238710131736096299798168852925540549342330775279877006784354801422249722573783561685179618816480037695005515426162362431072245638324744480n;
+ module.exportFunction(prefix + "_add");
+ module.exportFunction(prefix + "_addMixed");
+ module.exportFunction(prefix + "_addAffine");
- const pExponent = module.alloc(utils$2.bigInt2BytesLE( exponent, 352 ));
+ module.exportFunction(prefix + "_neg");
+ module.exportFunction(prefix + "_negAffine");
- const c = f.getCodeBuilder();
+ module.exportFunction(prefix + "_sub");
+ module.exportFunction(prefix + "_subMixed");
+ module.exportFunction(prefix + "_subAffine");
- f.addCode(
- c.call(ftmPrefix + "_exp", c.getLocal("x"), c.i32_const(pExponent), c.i32_const(352), c.getLocal("r")),
- );
- }
+ module.exportFunction(prefix + "_fromMontgomery");
+ module.exportFunction(prefix + "_fromMontgomeryAffine");
+ module.exportFunction(prefix + "_toMontgomery");
+ module.exportFunction(prefix + "_toMontgomeryAffine");
+ module.exportFunction(prefix + "_timesScalar");
+ module.exportFunction(prefix + "_timesScalarAffine");
+ module.exportFunction(prefix + "_normalize");
- const pPreP = module.alloc(prePSize);
- const pPreQ = module.alloc(preQSize);
+ // Convertion functions
+ module.exportFunction(prefix + "_LEMtoU");
+ module.exportFunction(prefix + "_LEMtoC");
+ module.exportFunction(prefix + "_UtoLEM");
+ module.exportFunction(prefix + "_CtoLEM");
- function buildPairingEquation(nPairings) {
+ module.exportFunction(prefix + "_batchLEMtoU");
+ module.exportFunction(prefix + "_batchLEMtoC");
+ module.exportFunction(prefix + "_batchUtoLEM");
+ module.exportFunction(prefix + "_batchCtoLEM");
- const f = module.addFunction(prefix+ "_pairingEq"+nPairings);
- for (let i=0; i.
+*/
+const { isOdd: isOdd$2, modInv: modInv$1, modPow } = bigint;
+const utils$2 = utils$5;
- function buildPairing() {
+var build_fft = function buildFFT(module, prefix, gPrefix, fPrefix, opGtimesF) {
- const f = module.addFunction(prefix+ "_pairing");
- f.addParam("p", "i32");
- f.addParam("q", "i32");
- f.addParam("r", "i32");
+ const n64f = module.modules[fPrefix].n64;
+ const n8f = n64f*8;
- const c = f.getCodeBuilder();
+ const n64g = module.modules[gPrefix].n64;
+ const n8g = n64g*8;
- const resT = c.i32_const(module.alloc(ftsize));
+ const q = module.modules[fPrefix].q;
- f.addCode(c.call(prefix + "_prepareG1", c.getLocal("p"), c.i32_const(pPreP) ));
- f.addCode(c.call(prefix + "_prepareG2", c.getLocal("q"), c.i32_const(pPreQ) ));
- f.addCode(c.call(prefix + "_millerLoop", c.i32_const(pPreP), c.i32_const(pPreQ), resT ));
- f.addCode(c.call(prefix + "_finalExponentiation", resT, c.getLocal("r") ));
+ let rem = q - 1n;
+ let maxBits = 0;
+ while (!isOdd$2(rem)) {
+ maxBits ++;
+ rem = rem >> 1n;
}
+ let nr = 2n;
- buildPrepAddStep();
- buildPrepDoubleStep();
-
- buildPrepareG1();
- buildPrepareG2();
+ while ( modPow(nr, q >> 1n, q) === 1n ) nr = nr + 1n;
- buildMulBy024();
- buildMulBy024Old();
- buildMillerLoop();
+ // console.log(nr);
+ const w = new Array(maxBits+1);
+ w[maxBits] = modPow(nr, rem, q);
- for (let i=0; i<10; i++) {
- buildFrobeniusMap(i);
- module.exportFunction(prefix + "__frobeniusMap"+i);
+ let n=maxBits-1;
+ while (n>=0) {
+ w[n] = modPow(w[n+1], 2n, q);
+ n--;
}
- buildFinalExponentiationOld();
- buildFinalExponentiation();
+ const bytes = [];
+ const R = (1n << BigInt(n8f*8)) % q;
- for (let i=1; i<=5; i++) {
- buildPairingEquation(i);
- module.exportFunction(prefix + "_pairingEq"+i);
+ for (let i=0; i> i);
+ }
+ }
+ return r;
+ }
-var build_bls12381 = function buildBLS12381(module, _prefix) {
+ const rtable = Array(256);
+ for (let i=0; i<256; i++) {
+ rtable[i] = rev(i);
+ }
- const prefix = _prefix || "bls12381";
+ const REVTABLE = module.alloc(rtable);
- if (module.modules[prefix]) return prefix; // already builded
- const q = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaabn;
- const r = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001n;
+ function buildLog2() {
+ const f = module.addFunction(prefix+"__log2");
+ f.addParam("n", "i32");
+ f.setReturnType("i32");
+ f.addLocal("bits", "i32");
+ f.addLocal("aux", "i32");
- const n64q = Math.floor((bitLength$1(q - 1n) - 1)/64) +1;
- const n8q = n64q*8;
- const f1size = n8q;
- const f2size = f1size * 2;
- const ftsize = f1size * 12;
+ const c = f.getCodeBuilder();
- const n64r = Math.floor((bitLength$1(r - 1n) - 1)/64) +1;
- const n8r = n64r*8;
- const frsize = n8r;
+ 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)
+ )
+ ),
- const pr = module.alloc(utils$1.bigInt2BytesLE( r, frsize ));
+ c.setLocal(
+ "bits",
+ c.i32_add(
+ c.getLocal("bits"),
+ c.i32_const(1)
+ )
+ ),
- const f1mPrefix = buildF1m(module, q, "f1m", "intq");
- buildF1(module, r, "fr", "frm", "intr");
- const pG1b = module.alloc(utils$1.bigInt2BytesLE( toMontgomery(4n), f1size ));
- const g1mPrefix = buildCurve(module, "g1m", "f1m", pG1b);
+ c.br(0)
+ )));
- buildFFT$1(module, "frm", "frm", "frm", "frm_mul");
+ f.addCode(c.if(
+ c.i32_ne(
+ c.getLocal("n"),
+ c.i32_shl(
+ c.i32_const(1),
+ c.getLocal("bits")
+ )
+ ),
+ c.unreachable()
+ ));
- buildPol(module, "pol", "frm");
- buildQAP(module, "qap", "frm");
+ f.addCode(c.if(
+ c.i32_gt_u(
+ c.getLocal("bits"),
+ c.i32_const(maxBits)
+ ),
+ c.unreachable()
+ ));
- const f2mPrefix = buildF2m(module, "f1m_neg", "f2m", "f1m");
- const pG2b = module.alloc([
- ...utils$1.bigInt2BytesLE( toMontgomery(4n), f1size ),
- ...utils$1.bigInt2BytesLE( toMontgomery(4n), f1size )
- ]);
- const g2mPrefix = buildCurve(module, "g2m", "f2m", pG2b);
+ f.addCode(c.getLocal("bits"));
+ }
+ function buildFFT() {
+ const f = module.addFunction(prefix+"_fft");
+ f.addParam("px", "i32");
+ f.addParam("n", "i32");
- function buildGTimesFr(fnName, opMul) {
- const f = module.addFunction(fnName);
- f.addParam("pG", "i32");
- f.addParam("pFr", "i32");
- f.addParam("pr", "i32");
+ f.addLocal("bits", "i32");
const c = f.getCodeBuilder();
- const AUX = c.i32_const(module.alloc(n8r));
+ const One = c.i32_const(module.alloc(n8f));
f.addCode(
- c.call("frm_fromMontgomery", c.getLocal("pFr"), AUX),
+ c.setLocal(
+ "bits",
+ c.call(
+ prefix + "__log2",
+ c.getLocal("n")
+ )
+ ),
+ c.call(fPrefix + "_one", One),
c.call(
- opMul,
- c.getLocal("pG"),
- AUX,
- c.i32_const(n8r),
- c.getLocal("pr")
+ prefix+"_rawfft",
+ c.getLocal("px"),
+ c.getLocal("bits"),
+ c.i32_const(0),
+ One
)
);
- module.exportFunction(fnName);
}
- buildGTimesFr("g1m_timesFr", "g1m_timesScalar");
- buildFFT$1(module, "g1m", "g1m", "frm", "g1m_timesFr");
-
- buildGTimesFr("g2m_timesFr", "g2m_timesScalar");
- buildFFT$1(module, "g2m", "g2m", "frm", "g2m_timesFr");
- buildGTimesFr("g1m_timesFrAffine", "g1m_timesScalarAffine");
- buildGTimesFr("g2m_timesFrAffine", "g2m_timesScalarAffine");
+ function buildIFFT() {
+ const f = module.addFunction(prefix+"_ifft");
+ f.addParam("px", "i32");
+ f.addParam("n", "i32");
+ f.addLocal("bits", "i32");
+ f.addLocal("pInv2", "i32");
- buildApplyKey(module, "frm_batchApplyKey", "fmr", "frm", n8r, n8r, n8r, "frm_mul");
- buildApplyKey(module, "g1m_batchApplyKey", "g1m", "frm", n8q*3, n8q*3, n8r, "g1m_timesFr");
- buildApplyKey(module, "g1m_batchApplyKeyMixed", "g1m", "frm", n8q*2, n8q*3, n8r, "g1m_timesFrAffine");
- buildApplyKey(module, "g2m_batchApplyKey", "g2m", "frm", n8q*2*3, n8q*3*2, n8r, "g2m_timesFr");
- buildApplyKey(module, "g2m_batchApplyKeyMixed", "g2m", "frm", n8q*2*2, n8q*3*2, n8r, "g2m_timesFrAffine");
+ 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)
+ )
+ )
+ ),
- function toMontgomery(a) {
- return BigInt(a) * (1n << BigInt(f1size*8)) % q;
+ c.call(
+ prefix+"_rawfft",
+ c.getLocal("px"),
+ c.getLocal("bits"),
+ c.i32_const(1),
+ c.getLocal("pInv2")
+ ),
+ );
}
- const G1gen = [
- 3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507n,
- 1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569n,
- 1n
- ];
+ 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");
- const pG1gen = module.alloc(
- [
- ...utils$1.bigInt2BytesLE( toMontgomery(G1gen[0]), f1size ),
- ...utils$1.bigInt2BytesLE( toMontgomery(G1gen[1]), f1size ),
- ...utils$1.bigInt2BytesLE( toMontgomery(G1gen[2]), f1size ),
- ]
- );
+ 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 G1zero = [
- 0n,
- 1n,
- 0n
- ];
+ const c = f.getCodeBuilder();
- const pG1zero = module.alloc(
- [
- ...utils$1.bigInt2BytesLE( toMontgomery(G1zero[0]), f1size ),
- ...utils$1.bigInt2BytesLE( toMontgomery(G1zero[1]), f1size ),
- ...utils$1.bigInt2BytesLE( toMontgomery(G1zero[2]), f1size )
- ]
- );
+ const W = c.i32_const(module.alloc(n8f));
+ const T = c.i32_const(module.alloc(n8g));
+ const U = c.i32_const(module.alloc(n8g));
- const G2gen = [
- [
- 352701069587466618187139116011060144890029952792775240219908644239793785735715026873347600343865175952761926303160n,
- 3059144344244213709971259814753781636986470325476647558659373206291635324768958432433509563104347017837885763365758n,
- ],[
- 1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905n,
- 927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582n,
- ],[
- 1n,
- 0n,
- ]
- ];
+ 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")
+ )
+ ),
- const pG2gen = module.alloc(
- [
- ...utils$1.bigInt2BytesLE( toMontgomery(G2gen[0][0]), f1size ),
- ...utils$1.bigInt2BytesLE( toMontgomery(G2gen[0][1]), f1size ),
- ...utils$1.bigInt2BytesLE( toMontgomery(G2gen[1][0]), f1size ),
- ...utils$1.bigInt2BytesLE( toMontgomery(G2gen[1][1]), f1size ),
- ...utils$1.bigInt2BytesLE( toMontgomery(G2gen[2][0]), f1size ),
- ...utils$1.bigInt2BytesLE( toMontgomery(G2gen[2][1]), f1size ),
- ]
- );
+ c.call(fPrefix + "_one", W),
- const G2zero = [
- [
- 0n,
- 0n,
- ],[
- 1n,
- 0n,
- ],[
- 0n,
- 0n,
- ]
- ];
+ 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")
+ )
+ ),
- const pG2zero = module.alloc(
- [
- ...utils$1.bigInt2BytesLE( toMontgomery(G2zero[0][0]), f1size ),
- ...utils$1.bigInt2BytesLE( toMontgomery(G2zero[0][1]), f1size ),
- ...utils$1.bigInt2BytesLE( toMontgomery(G2zero[1][0]), f1size ),
- ...utils$1.bigInt2BytesLE( toMontgomery(G2zero[1][1]), f1size ),
- ...utils$1.bigInt2BytesLE( toMontgomery(G2zero[2][0]), f1size ),
- ...utils$1.bigInt2BytesLE( toMontgomery(G2zero[2][1]), f1size ),
- ]
- );
+ 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
+ ),
- const pOneT = module.alloc([
- ...utils$1.bigInt2BytesLE( toMontgomery(1n), f1size ),
- ...utils$1.bigInt2BytesLE( toMontgomery(0n), f1size ),
- ...utils$1.bigInt2BytesLE( toMontgomery(0n), f1size ),
- ...utils$1.bigInt2BytesLE( toMontgomery(0n), f1size ),
- ...utils$1.bigInt2BytesLE( toMontgomery(0n), f1size ),
- ...utils$1.bigInt2BytesLE( toMontgomery(0n), f1size ),
- ...utils$1.bigInt2BytesLE( toMontgomery(0n), f1size ),
- ...utils$1.bigInt2BytesLE( toMontgomery(0n), f1size ),
- ...utils$1.bigInt2BytesLE( toMontgomery(0n), f1size ),
- ...utils$1.bigInt2BytesLE( toMontgomery(0n), f1size ),
- ...utils$1.bigInt2BytesLE( toMontgomery(0n), f1size ),
- ...utils$1.bigInt2BytesLE( toMontgomery(0n), f1size ),
- ]);
+ c.call(
+ gPrefix + "_copy",
+ c.getLocal("idx1"),
+ U
+ ),
- const pBls12381Twist = module.alloc([
- ...utils$1.bigInt2BytesLE( toMontgomery(1n), f1size ),
- ...utils$1.bigInt2BytesLE( toMontgomery(1n), f1size ),
- ]);
+ c.call(
+ gPrefix + "_add",
+ U,
+ T,
+ c.getLocal("idx1"),
+ ),
- function build_mulNR2() {
- const f = module.addFunction(f2mPrefix + "_mulNR");
- f.addParam("x", "i32");
- f.addParam("pr", "i32");
+ c.call(
+ gPrefix + "_sub",
+ U,
+ T,
+ c.getLocal("idx2"),
+ ),
- const c = f.getCodeBuilder();
+ c.call(
+ fPrefix + "_mul",
+ W,
+ c.getLocal("pwm"),
+ W,
+ ),
- const x0c = c.i32_const(module.alloc(f1size));
- const x0 = c.getLocal("x");
- const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1size));
- const r0 = c.getLocal("pr");
- const r1 = c.i32_add(c.getLocal("pr"), c.i32_const(f1size));
+ c.setLocal("j", c.i32_add(c.getLocal("j"), c.i32_const(1))),
+ c.br(0)
+ )),
- f.addCode(
- c.call(f1mPrefix+"_copy", x0, x0c),
- c.call(f1mPrefix+"_sub", x0, x1, r0),
- c.call(f1mPrefix+"_add", x0c, x1, r1),
+ 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")
+ )
);
}
- build_mulNR2();
- const f6mPrefix = buildF3m(module, f2mPrefix+"_mulNR", "f6m", "f2m");
- function build_mulNR6() {
- const f = module.addFunction(f6mPrefix + "_mulNR");
- f.addParam("x", "i32");
- f.addParam("pr", "i32");
+ 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 c0copy = c.i32_const(module.alloc(f1size*2));
+ const T = c.i32_const(module.alloc(n8g));
f.addCode(
- c.call(
- f2mPrefix + "_copy",
- c.getLocal("x"),
- c0copy
- ),
- c.call(
- f2mPrefix + "_mulNR",
- c.i32_add(c.getLocal("x"), c.i32_const(n8q*4)),
- c.getLocal("pr")
- ),
- c.call(
- f2mPrefix + "_copy",
- c.i32_add(c.getLocal("x"), c.i32_const(n8q*2)),
- c.i32_add(c.getLocal("pr"), c.i32_const(n8q*4)),
+ c.if(
+ c.i32_and(
+ c.i32_eqz(c.getLocal("reverse")),
+ c.call(fPrefix + "_isOne", c.getLocal("mulFactor"))
+ ),
+ c.ret([])
),
- c.call(
- f2mPrefix + "_copy",
- c0copy,
- c.i32_add(c.getLocal("pr"), c.i32_const(n8q*2)),
+ 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"))
+ ]
+ )
);
}
- build_mulNR6();
- const ftmPrefix = buildF2m(module, f6mPrefix+"_mulNR", "ftm", f6mPrefix);
-
- const ateLoopCount = 0xd201000000010000n;
- const ateLoopBitBytes = bits(ateLoopCount);
- const pAteLoopBitBytes = module.alloc(ateLoopBitBytes);
+ 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 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*n8q;
- const preQSize = 3*n8q*2 + ateNCoefs*ateCoefSize;
- const finalExpIsNegative = true;
+ const c = f.getCodeBuilder();
- const finalExpZ = 15132376222941642752n;
+ 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")
+ )
+ ),
- 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
- };
+ 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"))),
- function naf(n) {
- let E = n;
- const res = [];
- while (E > 0n) {
- if (isOdd(E)) {
- const z = 2 - Number(E % 4n);
- res.push( z );
- E = E - BigInt(z);
- } else {
- res.push( 0 );
- }
- E = E >> 1n;
- }
- return res;
- }
+ c.setLocal("idx2",
+ c.i32_add(
+ c.getLocal("px"),
+ c.i32_mul(
+ c.getLocal("ri"),
+ c.i32_const(n8g)
+ )
+ )
+ ),
- function bits(n) {
- let E = n;
- const res = [];
- while (E > 0n) {
- if (isOdd(E)) {
- res.push( 1 );
- } else {
- res.push( 0 );
- }
- E = E >> 1n;
- }
- return res;
+ 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 buildPrepareG1() {
- const f = module.addFunction(prefix+ "_prepareG1");
- f.addParam("pP", "i32");
- f.addParam("ppreP", "i32");
+ 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.call(g1mPrefix + "_normalize", c.getLocal("pP"), c.getLocal("ppreP")), // TODO Remove if already in affine
+ 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 buildPrepDoubleStep() {
- const f = module.addFunction(prefix+ "_prepDblStep");
- f.addParam("R", "i32");
- f.addParam("r", "i32");
+ 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 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));
+ 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")
+ )
+ ),
- // tmp0 = r.x.square();
- c.call(f2mPrefix + "_square", Rx, t0),
-
- // tmp1 = r.y.square();
- c.call(f2mPrefix + "_square", Ry, t1),
+ c.setLocal(
+ "idx1",
+ c.i32_add(
+ c.getLocal("pBuff1"),
+ c.i32_mul(
+ c.getLocal("i"),
+ c.i32_const(n8g)
+ )
+ )
+ ),
- // tmp2 = tmp1.square();
- c.call(f2mPrefix + "_square", t1, t2),
+ c.setLocal(
+ "idx2",
+ c.i32_add(
+ c.getLocal("pBuff2"),
+ c.i32_mul(
+ c.getLocal("i"),
+ c.i32_const(n8g)
+ )
+ )
+ ),
- // 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),
+ c.call(
+ opGtimesF,
+ c.getLocal("idx2"),
+ W,
+ T
+ ),
- // tmp3 = tmp3 + tmp3;
- c.call(f2mPrefix + "_add", t3, t3, t3),
+ c.call(
+ gPrefix + "_copy",
+ c.getLocal("idx1"),
+ U
+ ),
- // tmp4 = tmp0 + tmp0 + tmp0;
- c.call(f2mPrefix + "_add", t0, t0, t4),
- c.call(f2mPrefix + "_add", t4, t0, t4),
+ c.call(
+ gPrefix + "_add",
+ U,
+ T,
+ c.getLocal("idx1"),
+ ),
- // tmp6 = r.x + tmp4;
- c.call(f2mPrefix + "_add", Rx, t4, t6),
+ c.call(
+ gPrefix + "_sub",
+ U,
+ T,
+ c.getLocal("idx2"),
+ ),
- // tmp5 = tmp4.square();
- c.call(f2mPrefix + "_square", t4, t5),
+ c.call(
+ fPrefix + "_mul",
+ W,
+ c.getLocal("inc"),
+ W,
+ ),
- // zsquared = r.z.square();
- c.call(f2mPrefix + "_square", Rz, zsquared),
+ c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
+ c.br(0)
+ ))
+ );
+ }
- // 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),
+ 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");
- // r.y = (tmp3 - r.x) * tmp4;
- c.call(f2mPrefix + "_sub", t3, Rx, Ry),
- c.call(f2mPrefix + "_mul", Ry, t4, Ry),
+ const c = f.getCodeBuilder();
- // tmp2 = tmp2 + tmp2;
- c.call(f2mPrefix + "_add", t2, t2, t2),
+ const W = c.i32_const(module.alloc(n8f));
+ const U = c.i32_const(module.alloc(n8g));
- // tmp2 = tmp2 + tmp2;
- c.call(f2mPrefix + "_add", t2, t2, t2),
+ f.addCode(
- // tmp2 = tmp2 + tmp2;
- c.call(f2mPrefix + "_add", t2, t2, t2),
+ c.setLocal("pShiftToM",
+ c.i32_add(
+ c.i32_const(SHIFT_TO_M),
+ c.i32_mul(
+ c.getLocal("totalBits"),
+ c.i32_const(n8f)
+ )
+ )
+ ),
- // r.y -= tmp2;
- c.call(f2mPrefix + "_sub", Ry, t2, Ry),
- // tmp3 = tmp4 * zsquared;
- c.call(f2mPrefix + "_mul", t4, zsquared, t3),
+ 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")
+ )
+ ),
- // tmp3 = tmp3 + tmp3;
- c.call(f2mPrefix + "_add", t3, t3, t3),
+ c.setLocal(
+ "idx1",
+ c.i32_add(
+ c.getLocal("pBuff1"),
+ c.i32_mul(
+ c.getLocal("i"),
+ c.i32_const(n8g)
+ )
+ )
+ ),
- // tmp3 = -tmp3;
- c.call(f2mPrefix + "_neg", t3, t3),
+ c.setLocal(
+ "idx2",
+ c.i32_add(
+ c.getLocal("pBuff2"),
+ c.i32_mul(
+ c.getLocal("i"),
+ c.i32_const(n8g)
+ )
+ )
+ ),
- // 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),
+ c.call(
+ gPrefix + "_add",
+ c.getLocal("idx1"),
+ c.getLocal("idx2"),
+ U
+ ),
- // tmp1 = tmp1 + tmp1;
- c.call(f2mPrefix + "_add", t1, t1, t1),
+ c.call(
+ opGtimesF,
+ c.getLocal("idx2"),
+ c.getLocal("pShiftToM"),
+ c.getLocal("idx2")
+ ),
- // tmp1 = tmp1 + tmp1;
- c.call(f2mPrefix + "_add", t1, t1, t1),
+ c.call(
+ gPrefix + "_add",
+ c.getLocal("idx1"),
+ c.getLocal("idx2"),
+ c.getLocal("idx2")
+ ),
- // tmp6 = tmp6 - tmp1;
- c.call(f2mPrefix + "_sub", t6, t1, t6),
+ c.call(
+ opGtimesF,
+ c.getLocal("idx2"),
+ W,
+ c.getLocal("idx2"),
+ ),
- // tmp0 = r.z * zsquared;
- c.call(f2mPrefix + "_mul", Rz, zsquared, t0),
+ c.call(
+ gPrefix + "_copy",
+ U,
+ c.getLocal("idx1")
+ ),
- // tmp0 = tmp0 + tmp0;
- c.call(f2mPrefix + "_add", t0, t0, t0),
+ 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 buildPrepAddStep() {
- const f = module.addFunction(prefix+ "_prepAddStep");
- f.addParam("R", "i32");
- f.addParam("Q", "i32");
- f.addParam("r", "i32");
+ 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 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 W = c.i32_const(module.alloc(n8f));
+ const U = c.i32_const(module.alloc(n8g));
- const Qx = c.getLocal("Q");
- const Qy = c.i32_add(c.getLocal("Q"), c.i32_const(2*n8q));
+ f.addCode(
- 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));
+ 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)
+ )
+ )
+ ),
- 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(
+ 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")
+ )
+ ),
- // zsquared = r.z.square();
- c.call(f2mPrefix + "_square", Rz, zsquared),
+ c.setLocal(
+ "idx1",
+ c.i32_add(
+ c.getLocal("pBuff1"),
+ c.i32_mul(
+ c.getLocal("i"),
+ c.i32_const(n8g)
+ )
+ )
+ ),
- // ysquared = q.y.square();
- c.call(f2mPrefix + "_square", Qy, ysquared),
+ c.setLocal(
+ "idx2",
+ c.i32_add(
+ c.getLocal("pBuff2"),
+ c.i32_mul(
+ c.getLocal("i"),
+ c.i32_const(n8g)
+ )
+ )
+ ),
- // t0 = zsquared * q.x;
- c.call(f2mPrefix + "_mul", zsquared, Qx, t0),
+ c.call(
+ opGtimesF,
+ c.getLocal("idx2"),
+ W,
+ U
+ ),
- // 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),
+ c.call(
+ gPrefix + "_sub",
+ c.getLocal("idx1"),
+ U,
+ c.getLocal("idx2"),
+ ),
- // t2 = t0 - r.x;
- c.call(f2mPrefix + "_sub", t0, Rx, t2),
+ 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")
+ ),
- // t3 = t2.square();
- c.call(f2mPrefix + "_square", t2, t3),
+ c.call(
+ opGtimesF,
+ c.getLocal("idx1"),
+ c.getLocal("pSConst"),
+ c.getLocal("idx1")
+ ),
- // t4 = t3 + t3;
- c.call(f2mPrefix + "_add", t3, t3, t4),
+ c.call(
+ fPrefix + "_mul",
+ W,
+ c.getLocal("inc"),
+ W
+ ),
- // t4 = t4 + t4;
- c.call(f2mPrefix + "_add", t4, t4, t4),
+ c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
+ c.br(0)
+ ))
+ );
+ }
- // 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),
+ 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");
- // t7 = t4 * r.x;
- c.call(f2mPrefix + "_mul", t4, Rx, t7),
+ const c = f.getCodeBuilder();
- // 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),
+ const W = c.i32_const(module.alloc(n8f));
+ const U = c.i32_const(module.alloc(n8g));
- // 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),
+ f.addCode(
- // t10 = q.y + r.z;
- c.call(f2mPrefix + "_add", Qy, Rz, t10),
+ 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)
+ )
+ )
+ ),
- // 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),
+ 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")
+ )
+ ),
- // t0 = t0 + t0;
- c.call(f2mPrefix + "_add", t0, t0, t0),
+ c.setLocal(
+ "idx1",
+ c.i32_add(
+ c.getLocal("pBuff1"),
+ c.i32_mul(
+ c.getLocal("i"),
+ c.i32_const(n8g)
+ )
+ )
+ ),
- // r.y = t8 - t0;
- c.call(f2mPrefix + "_sub", t8, t0, Ry),
+ c.setLocal(
+ "idx2",
+ c.i32_add(
+ c.getLocal("pBuff2"),
+ c.i32_mul(
+ c.getLocal("i"),
+ c.i32_const(n8g)
+ )
+ )
+ ),
- // 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),
+ c.call(
+ opGtimesF,
+ c.getLocal("idx1"),
+ c.getLocal("pShiftToM"),
+ U
+ ),
- // t10 = t10 - ztsquared;
- c.call(f2mPrefix + "_sub", t10, ztsquared, t10),
+ c.call(
+ gPrefix + "_sub",
+ c.getLocal("idx2"),
+ U,
+ U
+ ),
- // t9 = t9 + t9 - t10;
- c.call(f2mPrefix + "_add", t9, t9, t9),
- c.call(f2mPrefix + "_sub", t9, t10, t9),
+ c.call(
+ gPrefix + "_sub",
+ c.getLocal("idx1"),
+ c.getLocal("idx2"),
+ c.getLocal("idx2"),
+ ),
- // t10 = r.z + r.z;
- c.call(f2mPrefix + "_add", Rz, Rz, t10),
+ c.call(
+ opGtimesF,
+ U,
+ c.getLocal("pSConst"),
+ c.getLocal("idx1"),
+ ),
- // t6 = -t6;
- c.call(f2mPrefix + "_neg", t6, t6),
+ c.call(
+ opGtimesF,
+ c.getLocal("idx2"),
+ W,
+ c.getLocal("idx2"),
+ ),
- // t1 = t6 + t6;
- c.call(f2mPrefix + "_add", t6, t6, t1),
+ 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 buildPrepareG2() {
- const f = module.addFunction(prefix+ "_prepareG2");
- f.addParam("pQ", "i32");
- f.addParam("ppreQ", "i32");
- f.addLocal("pCoef", "i32");
+ 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));
- const Q = c.getLocal("pQ");
+ 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")
+ )
+ ),
- const pR = module.alloc(f2size*3);
- const R = c.i32_const(pR);
+ 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")
+ )
+ ),
- const base = c.getLocal("ppreQ");
+ c.call(
+ opGtimesF,
+ c.getLocal("idx2"),
+ W,
+ T
+ ),
- 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))),
- );
+ c.call(
+ gPrefix + "_copy",
+ c.getLocal("idx1"),
+ U
+ ),
- f.addCode(
- c.setLocal("i", c.i32_const(ateLoopBitBytes.length-2)),
- c.block(c.loop(
+ c.call(
+ gPrefix + "_add",
+ U,
+ T,
+ c.getLocal("idx1"),
+ ),
- c.call(prefix + "_prepDblStep", R, c.getLocal("pCoef")),
- c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))),
+ c.call(
+ gPrefix + "_sub",
+ U,
+ T,
+ c.getLocal("idx2"),
+ ),
- 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.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)
))
);
}
- function buildF6Mul1() {
- const f = module.addFunction(f6mPrefix+ "_mul1");
- f.addParam("pA", "i32"); // F6
- f.addParam("pC1", "i32"); // F2
- f.addParam("pR", "i32"); // F6
+ // 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 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));
+ 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.call(f2mPrefix + "_add", A_c0, A_c1, Ac0_Ac1),
- c.call(f2mPrefix + "_add", A_c1, A_c2, Ac1_Ac2),
+ c.setLocal(
+ "idx1",
+ c.i32_add(
+ c.getLocal("pBuff"),
+ c.i32_mul(
+ c.getLocal("i"),
+ c.i32_const(n8g)
+ )
+ )
+ ),
- // let b_b = self.c1 * c1;
- c.call(f2mPrefix + "_mul", A_c1, c1, b_b),
+ 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)
+ )
+ )
+ ),
- // 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),
+ c.call(
+ opGtimesF,
+ c.getLocal("idx2"),
+ c.getLocal("factor"),
+ T
+ ),
- // let t1 = t1.mul_by_nonresidue();
- c.call(f2mPrefix + "_mulNR", t1, t1),
+ c.call(
+ opGtimesF,
+ c.getLocal("idx1"),
+ c.getLocal("factor"),
+ c.getLocal("idx2"),
+ ),
- // 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),
+ c.call(
+ gPrefix + "_copy",
+ T,
+ c.getLocal("idx1"),
+ ),
+
+ c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
+ c.br(0)
+ ))
);
}
- 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),
+ buildRev();
+ buildReversePermutation();
+ buildFinalInverse();
+ buildRawFFT();
+ buildLog2();
+ buildFFT();
+ buildIFFT();
+ buildFFTJoin();
+ buildFFTJoinExt();
+ buildFFTJoinExtInv();
+ buildFFTMix();
+ buildFFTFinal();
+ buildPrepareLagrangeEvaluation();
- // 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),
+ module.exportFunction(prefix+"__reversePermutation");
+ 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");
+};
- );
- }
- buildF6Mul01();
+/*
+ Copyright 2019 0KIMS association.
+ This file is part of wasmsnark (Web Assembly zkSnark Prover).
- function buildF12Mul014() {
+ 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.
- 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
+ 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.
- const c = f.getCodeBuilder();
+ 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 A_c0 = c.getLocal("pA");
- const A_c1 = c.i32_add(c.getLocal("pA"), c.i32_const(f1size*6));
+ const n64 = module.modules[prefixField].n64;
+ const n8 = n64*8;
- 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));
+ 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 R_c0 = c.getLocal("pR");
- const R_c1 = c.i32_add(c.getLocal("pR"), c.i32_const(f1size*6));
+ const c = f.getCodeBuilder();
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),
+ 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)
+ ))
+ );
+ }
- // let o = c1 + c4;
- c.call(f2mPrefix + "_add", c1, c4, o),
+ 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");
- // let c1 = self.c1 + self.c0;
- c.call(f6mPrefix + "_add", A_c1, A_c0, R_c1),
+ const c = f.getCodeBuilder();
- // let c1 = c1.mul_by_01(c0, &o);
- c.call(f6mPrefix + "_mul01", R_c1, c0, o, R_c1),
+ const aux = c.i32_const(module.alloc(n8));
- // let c1 = c1 - aa - bb;
- c.call(f6mPrefix + "_sub", R_c1, aa, R_c1),
- c.call(f6mPrefix + "_sub", R_c1, bb, R_c1),
+ 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")
+ )
+ ),
- // let c0 = bb;
- c.call(f6mPrefix + "_copy", bb, R_c0),
+ c.setLocal("ncoefs", c.i32_load(c.getLocal("pp"))),
+ c.setLocal("pp", c.i32_add(c.getLocal("pp"), c.i32_const(4))),
- // let c0 = c0.mul_by_nonresidue();
- c.call(f6mPrefix + "_mulNR", R_c0, R_c0),
+ c.setLocal("j", c.i32_const(0)),
+ c.block(c.loop(
+ c.br_if(
+ 1,
+ c.i32_eq(
+ c.getLocal("j"),
+ c.getLocal("ncoefs")
+ )
+ ),
- // let c0 = c0 + aa;
- c.call(f6mPrefix + "_add", R_c0, aa, R_c0),
- );
- }
- buildF12Mul014();
+ 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))),
- function buildELL() {
- const f = module.addFunction(prefix+ "_ell");
- f.addParam("pP", "i32");
- f.addParam("pCoefs", "i32");
- f.addParam("pF", "i32");
- const c = f.getCodeBuilder();
+ c.call(
+ prefixField + "_mul",
+ c.getLocal("ps"),
+ c.getLocal("pp"),
+ aux
+ ),
- const Px = c.getLocal("pP");
- const Py = c.i32_add(c.getLocal("pP"), c.i32_const(n8q));
+ c.call(
+ prefixField + "_add",
+ aux,
+ c.getLocal("pd"),
+ c.getLocal("pd")
+ ),
- const F = c.getLocal("pF");
+ 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)
+ )),
- 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));
+ 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)
+ ))
+ );
- 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)
+ buildZero();
+ buildConstructLC();
- 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),
+ module.exportFunction(prefix + "_zero");
+ module.exportFunction(prefix + "_constructLC");
- );
+ return prefix;
- }
- 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");
+};
- const coefs = c.getLocal("pCoef");
+var build_qap = function buildQAP(module, prefix, prefixField) {
- const F = c.getLocal("r");
+ const n64 = module.modules[prefixField].n64;
+ const n8 = n64*8;
- f.addCode(
- c.call(ftmPrefix + "_one", F),
+ 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");
- 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))),
+ const c = f.getCodeBuilder();
- c.setLocal("i", c.i32_const(ateLoopBitBytes.length-2)),
+ 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.call(prefix + "_ell", preP, coefs, F),
- c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))),
+ 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_load8_s(c.getLocal("i"), pAteLoopBitBytes),
+ 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.call(prefix + "_ell", preP, coefs, F),
- ...c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))),
+ ...c.setLocal("it", c.i32_add(c.getLocal("it"), c.i32_const(n8+12))),
+ ...c.br(1)
]
),
- c.call(ftmPrefix + "_square", F, F),
+ 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.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.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)
)),
- c.call(prefix + "_ell", preP, coefs, F),
);
-
-
- {
- f.addCode(
- c.call(ftmPrefix + "_conjugate", F, F),
- );
- }
}
-
- function buildFrobeniusMap(n) {
- const F12 = [
- [
- [1n, 0n],
- [1n, 0n],
- [1n, 0n],
- [1n, 0n],
- [1n, 0n],
- [1n, 0n],
- [1n, 0n],
- [1n, 0n],
- [1n, 0n],
- [1n, 0n],
- [1n, 0n],
- [1n, 0n],
- ],
- [
- [1n, 0n],
- [3850754370037169011952147076051364057158807420970682438676050522613628423219637725072182697113062777891589506424760n, 151655185184498381465642749684540099398075398968325446656007613510403227271200139370504932015952886146304766135027n],
- [793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620351n, 0n],
- [2973677408986561043442465346520108879172042883009249989176415018091420807192182638567116318576472649347015917690530n, 1028732146235106349975324479215795277384839936929757896155643118032610843298655225875571310552543014690878354869257n],
- [793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350n, 0n],
- [3125332594171059424908108096204648978570118281977575435832422631601824034463382777937621250592425535493320683825557n, 877076961050607968509681729531255177986764537961432449499635504522207616027455086505066378536590128544573588734230n],
- [4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559786n, 0n],
- [151655185184498381465642749684540099398075398968325446656007613510403227271200139370504932015952886146304766135027n, 3850754370037169011952147076051364057158807420970682438676050522613628423219637725072182697113062777891589506424760n],
- [4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436n, 0n],
- [1028732146235106349975324479215795277384839936929757896155643118032610843298655225875571310552543014690878354869257n, 2973677408986561043442465346520108879172042883009249989176415018091420807192182638567116318576472649347015917690530n],
- [4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437n, 0n],
- [877076961050607968509681729531255177986764537961432449499635504522207616027455086505066378536590128544573588734230n, 3125332594171059424908108096204648978570118281977575435832422631601824034463382777937621250592425535493320683825557n],
- ]
- ];
-
- const F6 = [
- [
- [1n, 0n],
- [1n, 0n],
- [1n, 0n],
- [1n, 0n],
- [1n, 0n],
- [1n, 0n],
- ],
- [
- [1n, 0n],
- [0n, 4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436n],
- [793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350n, 0n],
- [0n, 1n],
- [4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436n, 0n],
- [0n, 793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350n],
- ],
- [
- [1n, 0n],
- [4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437n, 0n],
- [4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436n, 0n],
- [4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559786n, 0n],
- [793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350n, 0n],
- [793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620351n, 0n],
- ]
- ];
-
- const f = module.addFunction(ftmPrefix + "_frobeniusMap"+n);
- f.addParam("x", "i32");
- f.addParam("r", "i32");
+ 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();
- 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$1.bigInt2BytesLE(toMontgomery(coef[0]), n8q),
- ...utils$1.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 = a[0];
- const ac1 = a[1];
- const bc0 = b[0];
- const bc1 = b[1];
- const res = [
- (ac0 * bc0 - (ac1 * bc1)) % q,
- (ac0 * bc1 + (ac1 * bc0)) % q,
- ];
- if (isNegative$1(res[0])) res[0] = res[0] + q;
- return res;
- }
+ 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 buildCyclotomicSquare() {
- const f = module.addFunction(prefix+ "__cyclotomicSquare");
- f.addParam("x", "i32");
- f.addParam("r", "i32");
+ 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();
- 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));
+ 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)
+ ))
+ );
+ }
- 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));
+ buildBuildABC();
+ buildJoinABC();
+ buildBatchAdd();
- 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));
+ module.exportFunction(prefix + "_buildABC");
+ module.exportFunction(prefix + "_joinABC");
+ module.exportFunction(prefix + "_batchAdd");
+ return prefix;
- f.addCode(
- // // 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),
+/*
+ Copyright 2019 0KIMS association.
- // // 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),
+ This file is part of wasmsnark (Web Assembly zkSnark Prover).
- // 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),
+ 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.
- // 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),
+ 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.
- // 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),
+ 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));
- 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));
+ f.addCode(
+ c.setLocal("pFrom", c.getLocal("pIn")),
+ c.setLocal("pTo", c.getLocal("pOut")),
+ );
- const f = module.addFunction(prefix+ "__cyclotomicExp_"+fnName);
- f.addParam("x", "i32");
- f.addParam("r", "i32");
- f.addLocal("bit", "i32");
- f.addLocal("i", "i32");
+ // 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") )),
- const c = f.getCodeBuilder();
+ 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))),
- const x = c.getLocal("x");
+ // 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)
+ ))
+ );
- const res = c.getLocal("r");
+ module.exportFunction(fnName);
- const inverse = c.i32_const(module.alloc(ftsize));
+};
+const utils$1 = utils$5;
- f.addCode(
- c.call(ftmPrefix + "_conjugate", x, inverse),
- c.call(ftmPrefix + "_one", res),
+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$1 = build_fft;
+const buildPol$1 = build_pol;
+const buildQAP$1 = build_qap;
+const buildApplyKey$1 = build_applykey;
+const { bitLength: bitLength$2, modInv, isOdd: isOdd$1, isNegative: isNegative$2 } = bigint;
- 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),
- )
- ),
+var build_bn128 = function buildBN128(module, _prefix) {
- c.setLocal("i", c.i32_const(exponentNafBytes.length-2)),
- c.block(c.loop(
- 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)
- ))
- );
+ const prefix = _prefix || "bn128";
- if (isExpNegative) {
- f.addCode(
- c.call(ftmPrefix + "_conjugate", res, res),
- );
- }
+ if (module.modules[prefix]) return prefix; // already builded
- }
+ const q = 21888242871839275222246405745257275088696311157297823662689037894645226208583n;
+ const r = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
- function buildFinalExponentiation() {
- buildCyclotomicSquare();
- buildCyclotomicExp(finalExpZ, finalExpIsNegative, "w0");
- const f = module.addFunction(prefix+ "_finalExponentiation");
- f.addParam("x", "i32");
- f.addParam("r", "i32");
+ const n64 = Math.floor((bitLength$2(q - 1n) - 1)/64) +1;
+ const n8 = n64*8;
+ const frsize = n8;
+ const f1size = n8;
+ const f2size = f1size * 2;
+ const ftsize = f1size * 12;
- const c = f.getCodeBuilder();
+ const pr = module.alloc(utils$1.bigInt2BytesLE( r, frsize ));
- 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));
+ const f1mPrefix = buildF1m$1(module, q, "f1m");
+ buildF1$1(module, r, "fr", "frm");
- f.addCode(
+ const pG1b = module.alloc(utils$1.bigInt2BytesLE( toMontgomery(3n), f1size ));
+ const g1mPrefix = buildCurve$1(module, "g1m", "f1m", pG1b);
- // let mut t0 = f.frobenius_map(6)
- c.call(ftmPrefix + "_frobeniusMap6", elt, t0),
+ buildFFT$1(module, "frm", "frm", "frm", "frm_mul");
- // let t1 = f.invert()
- c.call(ftmPrefix + "_inverse", elt, t1),
+ buildPol$1(module, "pol", "frm");
+ buildQAP$1(module, "qap", "frm");
- // let mut t2 = t0 * t1;
- c.call(ftmPrefix + "_mul", t0, t1, t2),
+ const f2mPrefix = buildF2m$1(module, "f1m_neg", "f2m", "f1m");
+ const pG2b = module.alloc([
+ ...utils$1.bigInt2BytesLE( toMontgomery(19485874751759354771024239261021720505790618469301721065564631296452457478373n), f1size ),
+ ...utils$1.bigInt2BytesLE( toMontgomery(266929791119991161246907387137283842545076965332900288569378510910307636690n), f1size )
+ ]);
+ const g2mPrefix = buildCurve$1(module, "g2m", "f2m", pG2b);
- // t1 = t2.clone();
- c.call(ftmPrefix + "_copy", t2, t1),
- // t2 = t2.frobenius_map().frobenius_map();
- c.call(ftmPrefix + "_frobeniusMap2", t2, t2),
+ function buildGTimesFr(fnName, opMul) {
+ const f = module.addFunction(fnName);
+ f.addParam("pG", "i32");
+ f.addParam("pFr", "i32");
+ f.addParam("pr", "i32");
- // t2 *= t1;
- c.call(ftmPrefix + "_mul", t2, t1, t2),
+ const c = f.getCodeBuilder();
+ const AUX = c.i32_const(module.alloc(n8));
- // t1 = cyclotomic_square(t2).conjugate();
- c.call(prefix + "__cyclotomicSquare", t2, t1),
- c.call(ftmPrefix + "_conjugate", t1, t1),
+ f.addCode(
+ c.call("frm_fromMontgomery", c.getLocal("pFr"), AUX),
+ c.call(
+ opMul,
+ c.getLocal("pG"),
+ AUX,
+ c.i32_const(n8),
+ c.getLocal("pr")
+ )
+ );
- // let mut t3 = cycolotomic_exp(t2);
- c.call(prefix + "__cyclotomicExp_w0", t2, t3),
+ module.exportFunction(fnName);
+ }
+ buildGTimesFr("g1m_timesFr", "g1m_timesScalar");
+ buildFFT$1(module, "g1m", "g1m", "frm", "g1m_timesFr");
- // let mut t4 = cyclotomic_square(t3);
- c.call(prefix + "__cyclotomicSquare", t3, t4),
+ buildGTimesFr("g2m_timesFr", "g2m_timesScalar");
+ buildFFT$1(module, "g2m", "g2m", "frm", "g2m_timesFr");
- // let mut t5 = t1 * t3;
- c.call(ftmPrefix + "_mul", t1, t3, t5),
+ buildGTimesFr("g1m_timesFrAffine", "g1m_timesScalarAffine");
+ buildGTimesFr("g2m_timesFrAffine", "g2m_timesScalarAffine");
- // t1 = cycolotomic_exp(t5);
- c.call(prefix + "__cyclotomicExp_w0", t5, t1),
+ 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");
- // t0 = cycolotomic_exp(t1);
- c.call(prefix + "__cyclotomicExp_w0", t1, t0),
+ function toMontgomery(a) {
+ return BigInt(a) * ( 1n << BigInt(f1size*8)) % q;
+ }
- // let mut t6 = cycolotomic_exp(t0);
- c.call(prefix + "__cyclotomicExp_w0", t0, t6),
+ const G1gen = [
+ 1n,
+ 2n,
+ 1n
+ ];
- // t6 *= t4;
- c.call(ftmPrefix + "_mul", t6, t4, t6),
+ const pG1gen = module.alloc(
+ [
+ ...utils$1.bigInt2BytesLE( toMontgomery(G1gen[0]), f1size ),
+ ...utils$1.bigInt2BytesLE( toMontgomery(G1gen[1]), f1size ),
+ ...utils$1.bigInt2BytesLE( toMontgomery(G1gen[2]), f1size ),
+ ]
+ );
- // t4 = cycolotomic_exp(t6);
- c.call(prefix + "__cyclotomicExp_w0", t6, t4),
+ const G1zero = [
+ 0n,
+ 1n,
+ 0n
+ ];
- // t5 = t5.conjugate();
- c.call(ftmPrefix + "_conjugate", t5, t5),
+ const pG1zero = module.alloc(
+ [
+ ...utils$1.bigInt2BytesLE( toMontgomery(G1zero[0]), f1size ),
+ ...utils$1.bigInt2BytesLE( toMontgomery(G1zero[1]), f1size ),
+ ...utils$1.bigInt2BytesLE( toMontgomery(G1zero[2]), f1size )
+ ]
+ );
- // t4 *= t5 * t2;
- c.call(ftmPrefix + "_mul", t4, t5, t4),
- c.call(ftmPrefix + "_mul", t4, t2, t4),
+ const G2gen = [
+ [
+ 10857046999023057135944570762232829481370756359578518086990519993285655852781n,
+ 11559732032986387107991004021392285783925812861821192530917403151452391805634n,
+ ],[
+ 8495653923123431417604973247489272438418190587263600148770280649306958101930n,
+ 4082367875863433681332203403145435568316851327593401208105741076214120093531n,
+ ],[
+ 1n,
+ 0n,
+ ]
+ ];
- // t5 = t2.conjugate();
- c.call(ftmPrefix + "_conjugate", t2, t5),
+ const pG2gen = module.alloc(
+ [
+ ...utils$1.bigInt2BytesLE( toMontgomery(G2gen[0][0]), f1size ),
+ ...utils$1.bigInt2BytesLE( toMontgomery(G2gen[0][1]), f1size ),
+ ...utils$1.bigInt2BytesLE( toMontgomery(G2gen[1][0]), f1size ),
+ ...utils$1.bigInt2BytesLE( toMontgomery(G2gen[1][1]), f1size ),
+ ...utils$1.bigInt2BytesLE( toMontgomery(G2gen[2][0]), f1size ),
+ ...utils$1.bigInt2BytesLE( toMontgomery(G2gen[2][1]), f1size ),
+ ]
+ );
- // t1 *= t2;
- c.call(ftmPrefix + "_mul", t1, t2, t1),
+ const G2zero = [
+ [
+ 0n,
+ 0n,
+ ],[
+ 1n,
+ 0n,
+ ],[
+ 0n,
+ 0n,
+ ]
+ ];
- // t1 = t1.frobenius_map().frobenius_map().frobenius_map();
- c.call(ftmPrefix + "_frobeniusMap3", t1, t1),
+ const pG2zero = module.alloc(
+ [
+ ...utils$1.bigInt2BytesLE( toMontgomery(G2zero[0][0]), f1size ),
+ ...utils$1.bigInt2BytesLE( toMontgomery(G2zero[0][1]), f1size ),
+ ...utils$1.bigInt2BytesLE( toMontgomery(G2zero[1][0]), f1size ),
+ ...utils$1.bigInt2BytesLE( toMontgomery(G2zero[1][1]), f1size ),
+ ...utils$1.bigInt2BytesLE( toMontgomery(G2zero[2][0]), f1size ),
+ ...utils$1.bigInt2BytesLE( toMontgomery(G2zero[2][1]), f1size ),
+ ]
+ );
- // t6 *= t5;
- c.call(ftmPrefix + "_mul", t6, t5, t6),
+ const pOneT = module.alloc([
+ ...utils$1.bigInt2BytesLE( toMontgomery(1), f1size ),
+ ...utils$1.bigInt2BytesLE( toMontgomery(0), f1size ),
+ ...utils$1.bigInt2BytesLE( toMontgomery(0), f1size ),
+ ...utils$1.bigInt2BytesLE( toMontgomery(0), f1size ),
+ ...utils$1.bigInt2BytesLE( toMontgomery(0), f1size ),
+ ...utils$1.bigInt2BytesLE( toMontgomery(0), f1size ),
+ ...utils$1.bigInt2BytesLE( toMontgomery(0), f1size ),
+ ...utils$1.bigInt2BytesLE( toMontgomery(0), f1size ),
+ ...utils$1.bigInt2BytesLE( toMontgomery(0), f1size ),
+ ...utils$1.bigInt2BytesLE( toMontgomery(0), f1size ),
+ ...utils$1.bigInt2BytesLE( toMontgomery(0), f1size ),
+ ...utils$1.bigInt2BytesLE( toMontgomery(0), f1size ),
+ ]);
- // t6 = t6.frobenius_map();
- c.call(ftmPrefix + "_frobeniusMap1", t6, t6),
+ const pNonResidueF6 = module.alloc([
+ ...utils$1.bigInt2BytesLE( toMontgomery(9), f1size ),
+ ...utils$1.bigInt2BytesLE( toMontgomery(1), f1size ),
+ ]);
- // t3 *= t0;
- c.call(ftmPrefix + "_mul", t3, t0, t3),
+ const pTwoInv = module.alloc([
+ ...utils$1.bigInt2BytesLE( toMontgomery( modInv(2n, q)), f1size ),
+ ...utils$1.bigInt2BytesLE( 0n, f1size )
+ ]);
- // t3 = t3.frobenius_map().frobenius_map();
- c.call(ftmPrefix + "_frobeniusMap2", t3, t3),
+ const pAltBn128Twist = pNonResidueF6;
- // t3 *= t1;
- c.call(ftmPrefix + "_mul", t3, t1, t3),
+ const pTwistCoefB = module.alloc([
+ ...utils$1.bigInt2BytesLE( toMontgomery(19485874751759354771024239261021720505790618469301721065564631296452457478373n), f1size ),
+ ...utils$1.bigInt2BytesLE( toMontgomery(266929791119991161246907387137283842545076965332900288569378510910307636690n), f1size ),
+ ]);
- // t3 *= t6;
- c.call(ftmPrefix + "_mul", t3, t6, t3),
+ function build_mulNR6() {
+ const f = module.addFunction(prefix + "_mulNR6");
+ f.addParam("x", "i32");
+ f.addParam("pr", "i32");
- // f = t3 * t4;
- c.call(ftmPrefix + "_mul", t3, t4, res),
+ 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 buildFinalExponentiationOld() {
- const f = module.addFunction(prefix+ "_finalExponentiationOld");
+ function build_mulNR12() {
+ const f = module.addFunction(prefix + "_mulNR12");
f.addParam("x", "i32");
- f.addParam("r", "i32");
-
- const exponent = 322277361516934140462891564586510139908379969514828494218366688025288661041104682794998680497580008899973249814104447692778988208376779573819485263026159588510513834876303014016798809919343532899164848730280942609956670917565618115867287399623286813270357901731510188149934363360381614501334086825442271920079363289954510565375378443704372994881406797882676971082200626541916413184642520269678897559532260949334760604962086348898118982248842634379637598665468817769075878555493752214492790122785850202957575200176084204422751485957336465472324810982833638490904279282696134323072515220044451592646885410572234451732790590013479358343841220074174848221722017083597872017638514103174122784843925578370430843522959600095676285723737049438346544753168912974976791528535276317256904336520179281145394686565050419250614107803233314658825463117900250701199181529205942363159325765991819433914303908860460720581408201373164047773794825411011922305820065611121544561808414055302212057471395719432072209245600258134364584636810093520285711072578721435517884103526483832733289802426157301542744476740008494780363354305116978805620671467071400711358839553375340724899735460480144599782014906586543813292157922220645089192130209334926661588737007768565838519456601560804957985667880395221049249803753582637708560n;
-
- const pExponent = module.alloc(utils$1.bigInt2BytesLE( exponent, 544 ));
+ f.addParam("pr", "i32");
const c = f.getCodeBuilder();
f.addCode(
- c.call(ftmPrefix + "_exp", c.getLocal("x"), c.i32_const(pExponent), c.i32_const(544), c.getLocal("r")),
+ 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 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*n8;
+ const preQSize = 3*n8*2 + ateNCoefs*ateCoefSize;
- for (let i=0; i 0n) {
+ if (isOdd$1(E)) {
+ const z = 2 - Number(E % 4n);
+ res.push( z );
+ E = E - BigInt(z);
+ } else {
+ res.push( 0 );
+ }
+ E = E >> 1n;
}
-
- f.addCode(c.call(prefix + "_finalExponentiation", resT, resT ));
-
- f.addCode(c.call(ftmPrefix + "_eq", resT, c.getLocal("c")));
+ return res;
}
-
- function buildPairing() {
-
- const f = module.addFunction(prefix+ "_pairing");
- f.addParam("p", "i32");
- f.addParam("q", "i32");
- f.addParam("r", "i32");
-
- const c = f.getCodeBuilder();
-
- const resT = c.i32_const(module.alloc(ftsize));
-
- f.addCode(c.call(prefix + "_prepareG1", c.getLocal("p"), c.i32_const(pPreP) ));
- f.addCode(c.call(prefix + "_prepareG2", c.getLocal("q"), c.i32_const(pPreQ) ));
- f.addCode(c.call(prefix + "_millerLoop", c.i32_const(pPreP), c.i32_const(pPreQ), resT ));
- f.addCode(c.call(prefix + "_finalExponentiation", resT, c.getLocal("r") ));
+ function bits(n) {
+ let E = n;
+ const res = [];
+ while (E > 0n) {
+ if (isOdd$1(E)) {
+ res.push( 1 );
+ } else {
+ res.push( 0 );
+ }
+ E = E >> 1n;
+ }
+ return res;
}
-
- function buildInGroupG2() {
- const f = module.addFunction(g2mPrefix+ "_inGroupAffine");
- f.addParam("p", "i32");
- f.setReturnType("i32");
+ function buildPrepareG1() {
+ const f = module.addFunction(prefix+ "_prepareG1");
+ f.addParam("pP", "i32");
+ f.addParam("ppreP", "i32");
const c = f.getCodeBuilder();
- const WINV = [
- 2001204777610833696708894912867952078278441409969503942666029068062015825245418932221343814564507832018947136279894n,
- 2001204777610833696708894912867952078278441409969503942666029068062015825245418932221343814564507832018947136279893n
- ];
-
- const FROB2X = 4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436n;
- const FROB3Y = [
- 2973677408986561043442465346520108879172042883009249989176415018091420807192182638567116318576472649347015917690530n,
- 2973677408986561043442465346520108879172042883009249989176415018091420807192182638567116318576472649347015917690530n
- ];
-
- const wInv = c.i32_const(module.alloc([
- ...utils$1.bigInt2BytesLE(toMontgomery(WINV[0]), n8q),
- ...utils$1.bigInt2BytesLE(toMontgomery(WINV[1]), n8q),
- ]));
-
- const frob2X = c.i32_const(module.alloc(utils$1.bigInt2BytesLE(toMontgomery(FROB2X), n8q)));
- const frob3Y = c.i32_const(module.alloc([
- ...utils$1.bigInt2BytesLE(toMontgomery(FROB3Y[0]), n8q),
- ...utils$1.bigInt2BytesLE(toMontgomery(FROB3Y[1]), n8q),
- ]));
-
- const z = c.i32_const(module.alloc(utils$1.bigInt2BytesLE(finalExpZ, 8)));
-
- const px = c.getLocal("p");
- const py = c.i32_add(c.getLocal("p"), c.i32_const(f2size));
-
- const aux = c.i32_const(module.alloc(f1size));
+ f.addCode(
+ c.call(g1mPrefix + "_normalize", c.getLocal("pP"), c.getLocal("ppreP")), // TODO Remove if already in affine
+ );
+ }
- const x_winv = c.i32_const(module.alloc(f2size));
- const y_winv = c.i32_const(module.alloc(f2size));
- const pf2 = module.alloc(f2size*2);
- const f2 = c.i32_const(pf2);
- const f2x = c.i32_const(pf2);
- const f2x_c1 = c.i32_const(pf2);
- const f2x_c2 = c.i32_const(pf2+f1size);
- const f2y = c.i32_const(pf2+f2size);
- const f2y_c1 = c.i32_const(pf2+f2size);
- const f2y_c2 = c.i32_const(pf2+f2size+f1size);
- const pf3 = module.alloc(f2size*3);
- const f3 = c.i32_const(pf3);
- const f3x = c.i32_const(pf3);
- const f3x_c1 = c.i32_const(pf3);
- const f3x_c2 = c.i32_const(pf3+f1size);
- const f3y = c.i32_const(pf3+f2size);
- const f3y_c1 = c.i32_const(pf3+f2size);
- const f3y_c2 = c.i32_const(pf3+f2size+f1size);
- const f3z = c.i32_const(pf3+f2size*2);
+ 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(
- c.if(
- c.call(g2mPrefix + "_isZeroAffine", c.getLocal("p")),
- c.ret( c.i32_const(1)),
- ),
- c.if(
- c.i32_eqz(c.call(g2mPrefix + "_inCurveAffine", c.getLocal("p"))),
- c.ret( c.i32_const(0)),
- ),
- c.call(f2mPrefix + "_mul", px, wInv, x_winv),
- c.call(f2mPrefix + "_mul", py, wInv, y_winv),
+ // D = X1 - X2*Z1
+ c.call(f2mPrefix + "_mul", X2, Z1, D),
+ c.call(f2mPrefix + "_sub", X1, D, D),
- c.call(f2mPrefix + "_mul1", x_winv, frob2X, f2x),
- c.call(f2mPrefix + "_neg", y_winv, f2y),
+ // E = Y1 - Y2*Z1
+ c.call(f2mPrefix + "_mul", Y2, Z1, E),
+ c.call(f2mPrefix + "_sub", Y1, E, E),
- c.call(f2mPrefix + "_neg", x_winv, f3x),
- c.call(f2mPrefix + "_mul", y_winv, frob3Y, f3y),
+ // F = D^2
+ c.call(f2mPrefix + "_square", D, F),
- c.call(f1mPrefix + "_sub", f2x_c1, f2x_c2, aux),
- c.call(f1mPrefix + "_add", f2x_c1, f2x_c2, f2x_c2),
- c.call(f1mPrefix + "_copy", aux, f2x_c1),
+ // G = E^2
+ c.call(f2mPrefix + "_square", E, G),
- c.call(f1mPrefix + "_sub", f2y_c1, f2y_c2, aux),
- c.call(f1mPrefix + "_add", f2y_c1, f2y_c2, f2y_c2),
- c.call(f1mPrefix + "_copy", aux, f2y_c1),
+ // H = D*F
+ c.call(f2mPrefix + "_mul", D, F, H),
- c.call(f1mPrefix + "_add", f3x_c1, f3x_c2, aux),
- c.call(f1mPrefix + "_sub", f3x_c1, f3x_c2, f3x_c2),
- c.call(f1mPrefix + "_copy", aux, f3x_c1),
+ // I = X1 * F
+ c.call(f2mPrefix + "_mul", X1, F, I),
- c.call(f1mPrefix + "_sub", f3y_c2, f3y_c1, aux),
- c.call(f1mPrefix + "_add", f3y_c1, f3y_c2, f3y_c2),
- c.call(f1mPrefix + "_copy", aux, f3y_c1),
+ // 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),
- c.call(f2mPrefix + "_one", f3z),
- c.call(g2mPrefix + "_timesScalar", f3, z, c.i32_const(8), f3),
- c.call(g2mPrefix + "_addMixed", f3, f2, f3),
+ // X3 (X1) = D*J
+ c.call(f2mPrefix + "_mul", D, J, X1),
- c.ret(
- c.call(g2mPrefix + "_eqMixed", f3, c.getLocal("p"))
- )
- );
+ // 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),
- const fInGroup = module.addFunction(g2mPrefix + "_inGroup");
- fInGroup.addParam("pIn", "i32");
- fInGroup.setReturnType("i32");
+ // Z3 (Z1) = Z1*H
+ c.call(f2mPrefix + "_mul", Z1, H, Z1),
- const c2 = fInGroup.getCodeBuilder();
+ // 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),
- const aux2 = c2.i32_const(module.alloc(f2size*2));
- fInGroup.addCode(
- c2.call(g2mPrefix + "_toAffine", c2.getLocal("pIn"), aux2),
+ // ell_VV = - E (later: * xP)
+ c.call(f2mPrefix + "_neg", E, ELL_VV),
- c2.ret(
- c2.call(g2mPrefix + "_inGroupAffine", aux2),
- )
- );
+ // ell_VW = D (later: * yP )
+ // Already assigned
+ );
}
- function buildInGroupG1() {
- const f = module.addFunction(g1mPrefix+ "_inGroupAffine");
- f.addParam("p", "i32");
- f.setReturnType("i32");
+
+
+ function buildPrepDoubleStep() {
+ const f = module.addFunction(prefix+ "_prepDblStep");
+ f.addParam("pR", "i32");
+ f.addParam("pCoef", "i32");
const c = f.getCodeBuilder();
- const BETA = 4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436n;
- const BETA2 = 793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350n;
- const Z2M1D3 = (finalExpZ * finalExpZ - 1n) / 3n;
+ 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));
- const beta = c.i32_const(module.alloc(utils$1.bigInt2BytesLE(toMontgomery(BETA), n8q)));
- const beta2 = c.i32_const(module.alloc(utils$1.bigInt2BytesLE(toMontgomery(BETA2), n8q)));
+ f.addCode(
- const z2m1d3 = c.i32_const(module.alloc(utils$1.bigInt2BytesLE(Z2M1D3, 16)));
+ // 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),
- const px = c.getLocal("p");
- const py = c.i32_add(c.getLocal("p"), c.i32_const(f1size));
+ // C = Z1^2
+ c.call(f2mPrefix + "_square", Z1, C),
- const psp = module.alloc(f1size*3);
- const sp = c.i32_const(psp);
- const spx = c.i32_const(psp);
- const spy = c.i32_const(psp+f1size);
+ // D = 3 * C
+ c.call(f2mPrefix + "_add", C, C, D),
+ c.call(f2mPrefix + "_add", D, C, D),
- const ps2p = module.alloc(f1size*2);
- const s2p = c.i32_const(ps2p);
- const s2px = c.i32_const(ps2p);
- const s2py = c.i32_const(ps2p+f1size);
+ // E = twist_b * D
+ c.call(f2mPrefix + "_mul", c.i32_const(pTwistCoefB), D, E),
- f.addCode(
- c.if(
- c.call(g1mPrefix + "_isZeroAffine", c.getLocal("p")),
- c.ret( c.i32_const(1)),
- ),
- c.if(
- c.i32_eqz(c.call(g1mPrefix + "_inCurveAffine", c.getLocal("p"))),
- c.ret( c.i32_const(0)),
- ),
+ // F = 3 * E
+ c.call(f2mPrefix + "_add", E, E, F),
+ c.call(f2mPrefix + "_add", E, F, F),
- c.call(f1mPrefix + "_mul", px, beta, spx),
- c.call(f1mPrefix + "_copy", py, spy),
+ // G = (B+F)/2
+ c.call(f2mPrefix + "_add", B, F, G),
+ c.call(f2mPrefix + "_mul", G, c.i32_const(pTwoInv), G),
- c.call(f1mPrefix + "_mul", px, beta2, s2px),
- c.call(f1mPrefix + "_copy", py, s2py),
+ // 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),
- c.call(g1mPrefix + "_doubleAffine", sp, sp),
- c.call(g1mPrefix + "_subMixed", sp, c.getLocal("p"), sp),
- c.call(g1mPrefix + "_subMixed", sp, s2p, sp),
+ // J = X1^2
+ c.call(f2mPrefix + "_square", X1, J),
- c.call(g1mPrefix + "_timesScalar", sp, z2m1d3, c.i32_const(16), sp),
+ // E_squared = E^2
+ c.call(f2mPrefix + "_square", E, E2),
- c.ret(
- c.call(g1mPrefix + "_eqMixed", sp, s2p)
- )
+ // 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),
- const fInGroup = module.addFunction(g1mPrefix + "_inGroup");
- fInGroup.addParam("pIn", "i32");
- fInGroup.setReturnType("i32");
+ // Z3 (Z1) = B * H
+ c.call(f2mPrefix + "_mul", B, H, Z1),
- const c2 = fInGroup.getCodeBuilder();
+ // ell_0 = xi * I
+ c.call(f2mPrefix + "_mul", c.i32_const(pAltBn128Twist), I, ELL_0),
- const aux2 = c2.i32_const(module.alloc(f1size*2));
+ // ell_VW = - H (later: * yP)
+ c.call(f2mPrefix + "_neg", H, ELL_VW),
- fInGroup.addCode(
- c2.call(g1mPrefix + "_toAffine", c2.getLocal("pIn"), aux2),
+ // ell_VV = 3*J (later: * xP)
+ c.call(f2mPrefix + "_add", J, J, ELL_VV),
+ c.call(f2mPrefix + "_add", J, ELL_VV, ELL_VV),
- c2.ret(
- c2.call(g1mPrefix + "_inGroupAffine", aux2),
- )
);
}
- for (let i=0; i<10; i++) {
- buildFrobeniusMap(i);
- module.exportFunction(ftmPrefix + "_frobeniusMap"+i);
- }
-
-
- buildInGroupG1();
- buildInGroupG2();
+ function buildMulByQ() {
+ const f = module.addFunction(prefix + "_mulByQ");
+ f.addParam("p1", "i32");
+ f.addParam("pr", "i32");
- buildPrepAddStep();
- buildPrepDoubleStep();
+ const c = f.getCodeBuilder();
- buildPrepareG1();
- buildPrepareG2();
+ 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));
- buildMillerLoop();
+ const MulByQX = c.i32_const(module.alloc([
+ ...utils$1.bigInt2BytesLE( toMontgomery("21575463638280843010398324269430826099269044274347216827212613867836435027261"), f1size ),
+ ...utils$1.bigInt2BytesLE( toMontgomery("10307601595873709700152284273816112264069230130616436755625194854815875713954"), f1size ),
+ ]));
- buildFinalExponentiationOld();
- buildFinalExponentiation();
+ const MulByQY = c.i32_const(module.alloc([
+ ...utils$1.bigInt2BytesLE( toMontgomery("2821565182194536844548159561693502659359617185244120367078079554186484126554"), f1size ),
+ ...utils$1.bigInt2BytesLE( toMontgomery("3505843767911556378687030309984248845540243509899259641013678093033130930403"), f1size ),
+ ]));
- for (let i=1; i<=5; i++) {
- buildPairingEquation(i);
- module.exportFunction(prefix + "_pairingEq"+i);
+ 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),
+ );
}
- buildPairing();
- module.exportFunction(prefix + "_pairing");
+ 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();
- module.exportFunction(prefix + "_prepareG1");
- module.exportFunction(prefix + "_prepareG2");
- module.exportFunction(prefix + "_millerLoop");
- module.exportFunction(prefix + "_finalExponentiation");
- module.exportFunction(prefix + "_finalExponentiationOld");
- module.exportFunction(prefix + "__cyclotomicSquare");
- module.exportFunction(prefix + "__cyclotomicExp_w0");
+ const QX = c.getLocal("pQ");
- module.exportFunction(f6mPrefix + "_mul1");
- module.exportFunction(f6mPrefix + "_mul01");
- module.exportFunction(ftmPrefix + "_mul014");
+ 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);
- module.exportFunction(g1mPrefix + "_inGroupAffine");
- module.exportFunction(g1mPrefix + "_inGroup");
- module.exportFunction(g2mPrefix + "_inGroupAffine");
- module.exportFunction(g2mPrefix + "_inGroup");
+ const cQX = c.i32_add( c.getLocal("ppreQ"), c.i32_const(0));
+ const cQY = c.i32_add( c.getLocal("ppreQ"), c.i32_const(f2size));
- // console.log(module.functionIdxByName);
-};
+ const pQ1 = module.alloc(f2size*3);
+ const Q1 = c.i32_const(pQ1);
-/*
- Copyright 2019 0KIMS association.
+ const pQ2 = module.alloc(f2size*3);
+ const Q2 = c.i32_const(pQ2);
+ const Q2Y = c.i32_const(pQ2 + f2size);
- This file is part of wasmsnark (Web Assembly zkSnark Prover).
+ 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),
+ );
- 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.
+ 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(
- 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.
+ c.call(prefix + "_prepDblStep", R, c.getLocal("pCoef")),
+ c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))),
- You should have received a copy of the GNU General Public License
- along with wasmsnark. If not, see .
-*/
+ 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)
+ ))
+ );
-// 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");
+ f.addCode(
+ c.call(prefix + "_mulByQ", cQX, Q1),
+ c.call(prefix + "_mulByQ", Q1, Q2)
+ );
-var buildBn128$1 = build_bn128;
-var buildBls12381$1 = build_bls12381;
+ f.addCode(
+ c.call(f2mPrefix + "_neg", Q2Y, Q2Y),
-/* global BigInt */
+ c.call(prefix + "_prepAddStep", Q1, R, c.getLocal("pCoef")),
+ c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))),
-function stringifyBigInts(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);
- } else if (typeof o == "object") {
- const res = {};
- const keys = Object.keys(o);
- keys.forEach((k) => {
- res[k] = stringifyBigInts(o[k]);
- });
- return res;
- } else {
- return o;
+ c.call(prefix + "_prepAddStep", Q2, R, c.getLocal("pCoef")),
+ c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))),
+ );
}
-}
-function unstringifyBigInts(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);
- } else if (typeof o == "object") {
- if (o === null) return null;
- const res = {};
- const keys = Object.keys(o);
- keys.forEach((k) => {
- res[k] = unstringifyBigInts(o[k]);
- });
- return res;
- } else {
- return o;
- }
-}
+ 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
-function beBuff2int(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;
-}
+ const c = f.getCodeBuilder();
-function beInt2Buff(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;
-}
+ const x0 = c.getLocal("pEll0");
+ const x2 = c.getLocal("pEllVV");
+ const x4 = c.getLocal("pEllVW");
-function leBuff2int(buff) {
- let res = BigInt(0);
- let i = 0;
- const buffV = new DataView(buff.buffer, buff.byteOffset, buff.byteLength);
- while (i < buff.length) {
- if (i + 4 <= buff.length) {
- res += BigInt(buffV.getUint32(i, true)) << BigInt(i * 8);
- i += 4;
- } else if (i + 2 <= buff.length) {
- res += BigInt(buffV.getUint16(i, true)) << BigInt(i * 8);
- i += 2;
- } else {
- res += BigInt(buffV.getUint8(i, true)) << BigInt(i * 8);
- i += 1;
- }
- }
- return res;
-}
+ const z0 = c.getLocal("pR");
-function leInt2Buff(n, len) {
- let r = n;
- if (typeof len === "undefined") {
- len = Math.floor((bitLength$6(n) - 1) / 8) + 1;
- if (len == 0) len = 1;
- }
- const buff = new Uint8Array(len);
- const buffV = new DataView(buff.buffer);
- let o = 0;
- while (o < len) {
- if (o + 4 <= len) {
- buffV.setUint32(o, Number(r & BigInt(0xffffffff)), true);
- o += 4;
- r = r >> BigInt(32);
- } else if (o + 2 <= len) {
- buffV.setUint16(o, Number(r & BigInt(0xffff)), true);
- o += 2;
- r = r >> BigInt(16);
- } else {
- buffV.setUint8(o, Number(r & BigInt(0xff)), true);
- o += 1;
- r = r >> BigInt(8);
- }
- }
- if (r) {
- throw new Error("Number does not fit in this length");
- }
- return buff;
-}
+ 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(
-function stringifyFElements(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.bind(this, F));
- } else if (typeof o == "object") {
- const res = {};
- const keys = Object.keys(o);
- keys.forEach((k) => {
- res[k] = stringifyFElements(F, o[k]);
- });
- return res;
- } else {
- return o;
+ 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 unstringifyFElements(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.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(F, o[k]);
- });
- return res;
- } else {
- return o;
- }
-}
+ 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 _revTable = [];
-for (let i = 0; i < 256; i++) {
- _revTable[i] = _revSlow(i, 8);
-}
+ const c = f.getCodeBuilder();
-function _revSlow(idx, bits) {
- let res = 0;
- let a = idx;
- for (let i = 0; i < bits; i++) {
- res <<= 1;
- res = res | (a & 1);
- a >>= 1;
- }
- return res;
-}
+ const x0 = c.getLocal("pEll0");
+ const x2 = c.getLocal("pEllVV");
+ const x4 = c.getLocal("pEllVW");
-function bitReverse(idx, bits) {
- return (
- (_revTable[idx >>> 24] |
- (_revTable[(idx >>> 16) & 0xff] << 8) |
- (_revTable[(idx >>> 8) & 0xff] << 16) |
- (_revTable[idx & 0xff] << 24)) >>>
- (32 - bits)
- );
-}
+ 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));
-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)
- );
-}
+ 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));
-function buffReverseBits(buff, eSize) {
- const n = buff.byteLength / eSize;
- const bits = log2(n);
- if (n != 1 << bits) {
- throw new Error("Invalid number of pointers");
- }
- for (let i = 0; i < n; i++) {
- const r = bitReverse(i, bits);
- if (i > r) {
- 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);
- }
- }
-}
+ f.addCode(
-function array2buffer(arr, sG) {
- const buff = new Uint8Array(sG * arr.length);
+ // 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 (let i = 0; i < arr.length; i++) {
- buff.set(arr[i], i * sG);
- }
- return buff;
-}
+ // 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;
-function buffer2array(buff, sG) {
- const n = buff.byteLength / sG;
- const arr = new Array(n);
- for (let i = 0; i < n; i++) {
- arr[i] = buff.slice(i * sG, i * sG + sG);
+ // 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;
+
+ );
}
- return arr;
-}
-var _utils = /*#__PURE__*/Object.freeze({
- __proto__: null,
- array2buffer: array2buffer,
- beBuff2int: beBuff2int,
- beInt2Buff: beInt2Buff,
- bitReverse: bitReverse,
- buffReverseBits: buffReverseBits,
- buffer2array: buffer2array,
- leBuff2int: leBuff2int,
- leInt2Buff: leInt2Buff,
- log2: log2,
- stringifyBigInts: stringifyBigInts,
- stringifyFElements: stringifyFElements,
- unstringifyBigInts: unstringifyBigInts,
- unstringifyFElements: unstringifyFElements
-});
-const PAGE_SIZE = 1<<30;
+ 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();
-class BigBuffer {
+ const preP_PX = c.getLocal("ppreP");
+ const preP_PY = c.i32_add(c.getLocal("ppreP"), c.i32_const(f1size));
- constructor(size) {
- this.buffers = [];
- this.byteLength = size;
- 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;
- }
+ c.setLocal("pCoef", c.i32_add( c.getLocal("ppreQ"), c.i32_const(f2size*3))),
- return buff;
- }
+ c.setLocal("i", c.i32_const(ateLoopBitBytes.length-2)),
+ c.block(c.loop(
- set(buff, offset) {
- if (offset === undefined) offset = 0;
- const len = buff.byteLength;
+ c.call(ftmPrefix + "_square", F, F),
- if (len==0) return;
+ 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))),
- const firstPage = Math.floor(offset / PAGE_SIZE);
- const lastPage = Math.floor((offset+len-1) / PAGE_SIZE);
+ 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),
- 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);
- }
+ ...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)
+ ))
+ );
- 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;
- }
+ 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 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]);
- }
+ // // 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),
- if (!this.eq(this.w[0], this.one)) {
- throw new Error("Error calculating roots of unity");
- }
+ // // 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),
- this.batchToMontgomery = buildBatchConvert(tm, prefix + "_batchToMontgomery", this.n8, this.n8);
- this.batchFromMontgomery = buildBatchConvert(tm, prefix + "_batchFromMontgomery", this.n8, this.n8);
- }
+ // 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),
- 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);
- }
+ // 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),
- 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);
- }
+ function buildCyclotomicExp(exponent, fnName) {
+ const exponentNafBytes = naf(exponent).map( (b) => (b==-1 ? 0xFF: b) );
+ const pExponentNafBytes = module.alloc(exponentNafBytes);
- add(a,b) {
- return this.op2("_add", a, b);
- }
+ 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();
- eq(a,b) {
- return this.op2Bool("_eq", a, b);
- }
+ const x = c.getLocal("x");
- isZero(a) {
- return this.op1Bool("_isZero", a);
- }
+ const res = c.getLocal("r");
- sub(a,b) {
- return this.op2("_sub", a, b);
- }
+ const inverse = c.i32_const(module.alloc(ftsize));
- neg(a) {
- return this.op1("_neg", a);
- }
- inv(a) {
- return this.op1("_inverse", a);
- }
+ f.addCode(
+ c.call(ftmPrefix + "_conjugate", x, inverse),
+ c.call(ftmPrefix + "_one", res),
- toMontgomery(a) {
- return this.op1("_toMontgomery", a);
- }
+ 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),
+ )
+ ),
- fromMontgomery(a) {
- return this.op1("_fromMontgomery", a);
+ c.setLocal("i", c.i32_const(exponentNafBytes.length-2)),
+ c.block(c.loop(
+ 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)
+ ))
+ );
}
- 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);
- }
+ function buildFinalExponentiationLastChunk() {
+ buildCyclotomicSquare();
+ buildCyclotomicExp(finalExpZ, "w0");
- isSquare(a) {
- return this.op1Bool("_isSquare", a);
- }
+ const f = module.addFunction(prefix+ "__finalExponentiationLastChunk");
+ f.addParam("x", "i32");
+ f.addParam("r", "i32");
- sqrt(a) {
- return this.op1("_sqrt", a);
- }
+ const c = f.getCodeBuilder();
- 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);
- }
+ 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));
- isNegative(a) {
- return this.op1Bool("_isNegative", a);
- }
+ f.addCode(
- e(a, b) {
- if (a instanceof Uint8Array) return a;
- let ra = e(a, b);
- if (isNegative$4(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);
- }
+ // 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),
- fromRng(rng) {
- let v;
- const buff = new Uint8Array(this.n8);
- do {
- v = zero;
- 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;
- op1Bool(opName, a) {
- this.tm.setBuff(this.pOp1, a);
- return !!this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp3);
- }
+ const finalExpZ = 15132376222941642752n;
- add(a,b) {
- if (a.byteLength == this.F.n8*3) {
- if (b.byteLength == this.F.n8*3) {
- return this.op2("_add", a, b);
- } else if (b.byteLength == this.F.n8*2) {
- return this.op2("_addMixed", a, b);
- } else {
- throw new Error("invalid point size");
- }
- } else if (a.byteLength == this.F.n8*2) {
- if (b.byteLength == this.F.n8*3) {
- return this.op2("_addMixed", b, a);
- } else if (b.byteLength == this.F.n8*2) {
- return this.op2("_addAffine", a, b);
+
+ 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 > 0n) {
+ if (isOdd(E)) {
+ const z = 2 - Number(E % 4n);
+ res.push( z );
+ E = E - BigInt(z);
} else {
- throw new Error("invalid point size");
+ res.push( 0 );
}
- } else {
- throw new Error("invalid point size");
+ E = E >> 1n;
}
+ return res;
}
- sub(a,b) {
- if (a.byteLength == this.F.n8*3) {
- if (b.byteLength == this.F.n8*3) {
- return this.op2("_sub", a, b);
- } else if (b.byteLength == this.F.n8*2) {
- return this.op2("_subMixed", a, b);
- } else {
- throw new Error("invalid point size");
- }
- } else if (a.byteLength == this.F.n8*2) {
- if (b.byteLength == this.F.n8*3) {
- return this.op2("_subMixed", b, a);
- } else if (b.byteLength == this.F.n8*2) {
- return this.op2("_subAffine", a, b);
+ function bits(n) {
+ let E = n;
+ const res = [];
+ while (E > 0n) {
+ if (isOdd(E)) {
+ res.push( 1 );
} else {
- throw new Error("invalid point size");
+ res.push( 0 );
}
- } else {
- throw new Error("invalid point size");
+ E = E >> 1n;
}
+ return res;
}
- neg(a) {
- if (a.byteLength == this.F.n8*3) {
- return this.op1("_neg", a);
- } else if (a.byteLength == this.F.n8*2) {
- return this.op1Affine("_negAffine", a);
- } else {
- throw new Error("invalid point size");
- }
- }
+ function buildPrepareG1() {
+ const f = module.addFunction(prefix+ "_prepareG1");
+ f.addParam("pP", "i32");
+ f.addParam("ppreP", "i32");
- double(a) {
- if (a.byteLength == this.F.n8*3) {
- return this.op1("_double", a);
- } else if (a.byteLength == this.F.n8*2) {
- return this.op1("_doubleAffine", a);
- } else {
- throw new Error("invalid point size");
- }
- }
+ const c = f.getCodeBuilder();
- isZero(a) {
- if (a.byteLength == this.F.n8*3) {
- return this.op1Bool("_isZero", a);
- } else if (a.byteLength == this.F.n8*2) {
- return this.op1Bool("_isZeroAffine", a);
- } else {
- throw new Error("invalid point size");
- }
+ f.addCode(
+ c.call(g1mPrefix + "_normalize", c.getLocal("pP"), c.getLocal("ppreP")), // TODO Remove if already in affine
+ );
}
- timesScalar(a, s) {
- if (!(s instanceof Uint8Array)) {
- s = toLEBuff(e(s));
- }
- let fnName;
- if (a.byteLength == this.F.n8*3) {
- fnName = this.prefix + "_timesScalar";
- } else if (a.byteLength == this.F.n8*2) {
- fnName = this.prefix + "_timesScalarAffine";
- } else {
- throw new Error("invalid point size");
- }
- this.tm.setBuff(this.pOp1, a);
- this.tm.setBuff(this.pOp2, s);
- this.tm.instance.exports[fnName](this.pOp1, this.pOp2, s.byteLength, this.pOp3);
- return this.tm.getBuff(this.pOp3, this.F.n8*3);
- }
- timesFr(a, s) {
- let fnName;
- if (a.byteLength == this.F.n8*3) {
- fnName = this.prefix + "_timesFr";
- } else if (a.byteLength == this.F.n8*2) {
- fnName = this.prefix + "_timesFrAffine";
- } else {
- throw new Error("invalid point size");
- }
- this.tm.setBuff(this.pOp1, a);
- this.tm.setBuff(this.pOp2, s);
- this.tm.instance.exports[fnName](this.pOp1, this.pOp2, this.pOp3);
- return this.tm.getBuff(this.pOp3, this.F.n8*3);
- }
- eq(a,b) {
- if (a.byteLength == this.F.n8*3) {
- if (b.byteLength == this.F.n8*3) {
- return this.op2bool("_eq", a, b);
- } else if (b.byteLength == this.F.n8*2) {
- return this.op2bool("_eqMixed", a, b);
- } else {
- throw new Error("invalid point size");
- }
- } else if (a.byteLength == this.F.n8*2) {
- if (b.byteLength == this.F.n8*3) {
- return this.op2bool("_eqMixed", b, a);
- } else if (b.byteLength == this.F.n8*2) {
- return this.op2bool("_eqAffine", a, b);
- } else {
- throw new Error("invalid point size");
- }
- } else {
- throw new Error("invalid point size");
- }
- }
+ function buildPrepDoubleStep() {
+ const f = module.addFunction(prefix+ "_prepDblStep");
+ f.addParam("R", "i32");
+ f.addParam("r", "i32");
- toAffine(a) {
- if (a.byteLength == this.F.n8*3) {
- return this.op1Affine("_toAffine", a);
- } else if (a.byteLength == this.F.n8*2) {
- return a;
- } else {
- throw new Error("invalid point size");
- }
- }
+ 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));
- toJacobian(a) {
- if (a.byteLength == this.F.n8*3) {
- return a;
- } else if (a.byteLength == this.F.n8*2) {
- return this.op1("_toJacobian", a);
- } else {
- throw new Error("invalid point size");
- }
- }
+ 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));
- toRprUncompressed(arr, offset, a) {
- this.tm.setBuff(this.pOp1, a);
- if (a.byteLength == this.F.n8*3) {
- this.tm.instance.exports[this.prefix + "_toAffine"](this.pOp1, this.pOp1);
- } else if (a.byteLength != this.F.n8*2) {
- throw new Error("invalid point size");
- }
- this.tm.instance.exports[this.prefix + "_LEMtoU"](this.pOp1, this.pOp1);
- const res = this.tm.getBuff(this.pOp1, this.F.n8*2);
- arr.set(res, offset);
- }
- fromRprUncompressed(arr, offset) {
- const buff = arr.slice(offset, offset + this.F.n8*2);
- this.tm.setBuff(this.pOp1, buff);
- this.tm.instance.exports[this.prefix + "_UtoLEM"](this.pOp1, this.pOp1);
- return this.tm.getBuff(this.pOp1, this.F.n8*2);
- }
+ 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));
- toRprCompressed(arr, offset, a) {
- this.tm.setBuff(this.pOp1, a);
- if (a.byteLength == this.F.n8*3) {
- this.tm.instance.exports[this.prefix + "_toAffine"](this.pOp1, this.pOp1);
- } else if (a.byteLength != this.F.n8*2) {
- throw new Error("invalid point size");
- }
- this.tm.instance.exports[this.prefix + "_LEMtoC"](this.pOp1, this.pOp1);
- const res = this.tm.getBuff(this.pOp1, this.F.n8);
- arr.set(res, offset);
- }
+ f.addCode(
- fromRprCompressed(arr, offset) {
- const buff = arr.slice(offset, offset + this.F.n8);
- this.tm.setBuff(this.pOp1, buff);
- this.tm.instance.exports[this.prefix + "_CtoLEM"](this.pOp1, this.pOp2);
- return this.tm.getBuff(this.pOp2, this.F.n8*2);
- }
+ // tmp0 = r.x.square();
+ c.call(f2mPrefix + "_square", Rx, t0),
- toUncompressed(a) {
- const buff = new Uint8Array(this.F.n8*2);
- this.toRprUncompressed(buff, 0, a);
- return buff;
- }
+ // tmp1 = r.y.square();
+ c.call(f2mPrefix + "_square", Ry, t1),
- toRprLEM(arr, offset, a) {
- if (a.byteLength == this.F.n8*2) {
- arr.set(a, offset);
- return;
- } else if (a.byteLength == this.F.n8*3) {
- this.tm.setBuff(this.pOp1, a);
- this.tm.instance.exports[this.prefix + "_toAffine"](this.pOp1, this.pOp1);
- const res = this.tm.getBuff(this.pOp1, this.F.n8*2);
- arr.set(res, offset);
- } else {
- throw new Error("invalid point size");
- }
- }
+ // tmp2 = tmp1.square();
+ c.call(f2mPrefix + "_square", t1, t2),
- fromRprLEM(arr, offset) {
- offset = offset || 0;
- return arr.slice(offset, offset+this.F.n8*2);
- }
+ // 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),
- toString(a, radix) {
- if (a.byteLength == this.F.n8*3) {
- const x = this.F.toString(a.slice(0, this.F.n8), radix);
- const y = this.F.toString(a.slice(this.F.n8, this.F.n8*2), radix);
- const z = this.F.toString(a.slice(this.F.n8*2), radix);
- return `[ ${x}, ${y}, ${z} ]`;
- } else if (a.byteLength == this.F.n8*2) {
- const x = this.F.toString(a.slice(0, this.F.n8), radix);
- const y = this.F.toString(a.slice(this.F.n8), radix);
- return `[ ${x}, ${y} ]`;
- } else {
- throw new Error("invalid point size");
- }
- }
+ // tmp3 = tmp3 + tmp3;
+ c.call(f2mPrefix + "_add", t3, t3, t3),
- isValid(a) {
- if (this.isZero(a)) return true;
- const F = this.F;
- const aa = this.toAffine(a);
- const x = aa.slice(0, this.F.n8);
- const y = aa.slice(this.F.n8, this.F.n8*2);
- const x3b = F.add(F.mul(F.square(x),x), this.b);
- const y2 = F.square(y);
- return F.eq(x3b, y2);
- }
+ // tmp4 = tmp0 + tmp0 + tmp0;
+ c.call(f2mPrefix + "_add", t0, t0, t4),
+ c.call(f2mPrefix + "_add", t4, t0, t4),
- fromRng(rng) {
- const F = this.F;
- let P = [];
- let greatest;
- let x3b;
- do {
- P[0] = F.fromRng(rng);
- greatest = rng.nextBool();
- x3b = F.add(F.mul(F.square(P[0]), P[0]), this.b);
- } while (!F.isSquare(x3b));
+ // tmp6 = r.x + tmp4;
+ c.call(f2mPrefix + "_add", Rx, t4, t6),
- P[1] = F.sqrt(x3b);
+ // tmp5 = tmp4.square();
+ c.call(f2mPrefix + "_square", t4, t5),
- const s = F.isNegative(P[1]);
- if (greatest ^ s) P[1] = F.neg(P[1]);
+ // zsquared = r.z.square();
+ c.call(f2mPrefix + "_square", Rz, zsquared),
- let Pbuff = new Uint8Array(this.F.n8*2);
- Pbuff.set(P[0]);
- Pbuff.set(P[1], this.F.n8);
+ // r.x = tmp5 - tmp3 - tmp3;
+ c.call(f2mPrefix + "_sub", t5, t3, Rx),
+ c.call(f2mPrefix + "_sub", Rx, t3, Rx),
- if (this.cofactor) {
- Pbuff = this.timesScalar(Pbuff, this.cofactor);
- }
+ // 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),
- return Pbuff;
- }
+ // 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),
- toObject(a) {
- if (this.isZero(a)) {
- return [
- this.F.toObject(this.F.zero),
- this.F.toObject(this.F.one),
- this.F.toObject(this.F.zero),
- ];
- }
- const x = this.F.toObject(a.slice(0, this.F.n8));
- const y = this.F.toObject(a.slice(this.F.n8, this.F.n8*2));
- let z;
- if (a.byteLength == this.F.n8*3) {
- z = this.F.toObject(a.slice(this.F.n8*2, this.F.n8*3));
- } else {
- z = this.F.toObject(this.F.one);
- }
- return [x, y, z];
- }
+ // tmp2 = tmp2 + tmp2;
+ c.call(f2mPrefix + "_add", t2, t2, t2),
- fromObject(a) {
- const x = this.F.fromObject(a[0]);
- const y = this.F.fromObject(a[1]);
- let z;
- if (a.length==3) {
- z = this.F.fromObject(a[2]);
- } else {
- z = this.F.one;
- }
- if (this.F.isZero(z, this.F.one)) {
- return this.zeroAffine;
- } else if (this.F.eq(z, this.F.one)) {
- const buff = new Uint8Array(this.F.n8*2);
- buff.set(x);
- buff.set(y, this.F.n8);
- return buff;
- } else {
- const buff = new Uint8Array(this.F.n8*3);
- buff.set(x);
- buff.set(y, this.F.n8);
- buff.set(z, this.F.n8*2);
- return buff;
- }
- }
+ // r.y -= tmp2;
+ c.call(f2mPrefix + "_sub", Ry, t2, Ry),
- e(a) {
- if (a instanceof Uint8Array) return a;
- return this.fromObject(a);
- }
+ // tmp3 = tmp4 * zsquared;
+ c.call(f2mPrefix + "_mul", t4, zsquared, t3),
- x(a) {
- const tmp = this.toAffine(a);
- return tmp.slice(0, this.F.n8);
- }
+ // tmp3 = tmp3 + tmp3;
+ c.call(f2mPrefix + "_add", t3, t3, t3),
- y(a) {
- const tmp = this.toAffine(a);
- return tmp.slice(this.F.n8);
- }
+ // 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),
-/* global WebAssembly */
+ // tmp1 = tmp1 + tmp1;
+ c.call(f2mPrefix + "_add", t1, t1, t1),
-function thread(self) {
- const MAXMEM = 32767;
- let instance;
- let memory;
+ // tmp1 = tmp1 + tmp1;
+ c.call(f2mPrefix + "_add", t1, t1, t1),
- if (self) {
- self.onmessage = function(e) {
- let data;
- if (e.data) {
- data = e.data;
- } else {
- data = e;
- }
+ // tmp6 = tmp6 - tmp1;
+ c.call(f2mPrefix + "_sub", t6, t1, t6),
- if (data[0].cmd == "INIT") {
- init(data[0]).then(function() {
- self.postMessage(data.result);
- });
- } else if (data[0].cmd == "TERMINATE") {
- self.close();
- } else {
- const res = runTask(data);
- self.postMessage(res);
- }
- };
+ // tmp0 = r.z * zsquared;
+ c.call(f2mPrefix + "_mul", Rz, zsquared, t0),
+
+ // tmp0 = tmp0 + tmp0;
+ c.call(f2mPrefix + "_add", t0, t0, t0),
+
+ );
}
- async function init(data) {
- const code = new Uint8Array(data.code);
- const wasmModule = await WebAssembly.compile(code);
- memory = new WebAssembly.Memory({initial:data.init, maximum: MAXMEM});
+ function buildPrepAddStep() {
+ const f = module.addFunction(prefix+ "_prepAddStep");
+ f.addParam("R", "i32");
+ f.addParam("Q", "i32");
+ f.addParam("r", "i32");
- instance = await WebAssembly.instantiate(wasmModule, {
- env: {
- "memory": memory
- }
- });
- }
+ 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));
- function alloc(length) {
- const u32 = new Uint32Array(memory.buffer, 0, 1);
- while (u32[0] & 3) u32[0]++; // Return always aligned pointers
- const res = u32[0];
- u32[0] += length;
- if (u32[0] + length > 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;
- }
+ 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));
- function allocBuffer(buffer) {
- const p = alloc(buffer.byteLength);
- setBuffer(p, buffer);
- return p;
- }
+ 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));
- function getBuffer(pointer, length) {
- const u8 = new Uint8Array(memory.buffer);
- return new Uint8Array(u8.buffer, u8.byteOffset + pointer, length);
- }
+ f.addCode(
- function setBuffer(pointer, buffer) {
- const u8 = new Uint8Array(memory.buffer);
- u8.set(new Uint8Array(buffer), pointer);
- }
+ // zsquared = r.z.square();
+ c.call(f2mPrefix + "_square", Rz, zsquared),
- 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.
-*/
+ // t5 = t4 * t2;
+ c.call(f2mPrefix + "_mul", t4, t2, t5),
-// const MEM_SIZE = 1000; // Memory size in 64K Pakes (512Mb)
-const MEM_SIZE = 25; // Memory size in 64K Pakes (1600Kb)
+ // t6 = t1 - r.y - r.y;
+ c.call(f2mPrefix + "_sub", t1, Ry, t6),
+ c.call(f2mPrefix + "_sub", t6, Ry, t6),
-class Deferred {
- constructor() {
- this.promise = new Promise((resolve, reject)=> {
- this.reject = reject;
- this.resolve = resolve;
- });
- }
-}
+ // t9 = t6 * q.x;
+ c.call(f2mPrefix + "_mul", t6, Qx, t9),
-function sleep(ms) {
- return new Promise(resolve => setTimeout(resolve, ms));
-}
+ // t7 = t4 * r.x;
+ c.call(f2mPrefix + "_mul", t4, Rx, t7),
-let workerSource;
+ // 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),
-const threadStr = `(${"function thread(self) {\n const MAXMEM = 32767;\n let instance;\n let memory;\n\n if (self) {\n self.onmessage = function(e) {\n let data;\n if (e.data) {\n data = e.data;\n } else {\n data = e;\n }\n\n if (data[0].cmd == \"INIT\") {\n init(data[0]).then(function() {\n self.postMessage(data.result);\n });\n } else if (data[0].cmd == \"TERMINATE\") {\n self.close();\n } else {\n const res = runTask(data);\n self.postMessage(res);\n }\n };\n }\n\n async function init(data) {\n const code = new Uint8Array(data.code);\n const wasmModule = await WebAssembly.compile(code);\n memory = new WebAssembly.Memory({initial:data.init, maximum: MAXMEM});\n\n instance = await WebAssembly.instantiate(wasmModule, {\n env: {\n \"memory\": memory\n }\n });\n }\n\n\n\n function alloc(length) {\n const u32 = new Uint32Array(memory.buffer, 0, 1);\n while (u32[0] & 3) u32[0]++; // Return always aligned pointers\n const res = u32[0];\n u32[0] += length;\n if (u32[0] + length > memory.buffer.byteLength) {\n const currentPages = memory.buffer.byteLength / 0x10000;\n let requiredPages = Math.floor((u32[0] + length) / 0x10000)+1;\n if (requiredPages>MAXMEM) requiredPages=MAXMEM;\n memory.grow(requiredPages-currentPages);\n }\n return res;\n }\n\n function allocBuffer(buffer) {\n const p = alloc(buffer.byteLength);\n setBuffer(p, buffer);\n return p;\n }\n\n function getBuffer(pointer, length) {\n const u8 = new Uint8Array(memory.buffer);\n return new Uint8Array(u8.buffer, u8.byteOffset + pointer, length);\n }\n\n function setBuffer(pointer, buffer) {\n const u8 = new Uint8Array(memory.buffer);\n u8.set(new Uint8Array(buffer), pointer);\n }\n\n function runTask(task) {\n if (task[0].cmd == \"INIT\") {\n return init(task[0]);\n }\n const ctx = {\n vars: [],\n out: []\n };\n const u32a = new Uint32Array(memory.buffer, 0, 1);\n const oldAlloc = u32a[0];\n for (let i=0; i64) concurrency=64;
- tm.concurrency = concurrency;
+ function buildPrepareG2() {
+ const f = module.addFunction(prefix+ "_prepareG2");
+ f.addParam("pQ", "i32");
+ f.addParam("ppreQ", "i32");
+ f.addLocal("pCoef", "i32");
+ f.addLocal("i", "i32");
- 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);
- }
- }
- }
+ f.addCode(
- queueAction(actionData, transfers) {
- const d = new Deferred();
+ c.call(f2mPrefix + "_add", A_c0, A_c1, Ac0_Ac1),
+ c.call(f2mPrefix + "_add", A_c1, A_c2, Ac1_Ac2),
- 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;
- }
+ // let b_b = self.c1 * c1;
+ c.call(f2mPrefix + "_mul", A_c1, c1, b_b),
- resetMemory() {
- this.u32[0] = this.initalPFree;
- }
+ // 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),
- allocBuff(buff) {
- const pointer = this.alloc(buff.byteLength);
- this.setBuff(pointer, buff);
- return pointer;
- }
+ // let t1 = t1.mul_by_nonresidue();
+ c.call(f2mPrefix + "_mulNR", t1, t1),
- getBuff(pointer, length) {
- return this.u8.slice(pointer, pointer+ length);
+ // 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();
- setBuff(pointer, buffer) {
- this.u8.set(new Uint8Array(buffer), pointer);
- }
+ 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
- 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;
- }
+ const c = f.getCodeBuilder();
- 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;
- }));
- }
+ // 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),
- const result = await Promise.all(opPromises);
+ // 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),
- let res = G.zero;
- for (let i=result.length-1; i>=0; i--) {
- res = G.add(res, result[i]);
- }
+ // 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),
- 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;
+ 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));
- 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";
+ const f = module.addFunction(prefix+ "__cyclotomicExp_"+fnName);
+ f.addParam("x", "i32");
+ f.addParam("r", "i32");
+ f.addLocal("bit", "i32");
+ f.addLocal("i", "i32");
- if (outType == "affine") {
- sOut = G.F.n8*2;
- fnMid2Out = "g1m_batchToAffine";
- } else {
- sOut = G.F.n8*3;
- }
+ const c = f.getCodeBuilder();
- } 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";
- }
+ const x = c.getLocal("x");
+ const res = c.getLocal("r");
- let returnArray = false;
- if (Array.isArray(buff)) {
- buff = array2buffer(buff, sIn);
- returnArray = true;
- } else {
- buff = buff.slice(0, buff.byteLength);
- }
+ const inverse = c.i32_const(module.alloc(ftsize));
- const nPoints = buff.byteLength / sIn;
- const bits = log2(nPoints);
- if ((1 << bits) != nPoints) {
- throw new Error("fft must be multiple of 2" );
- }
+ f.addCode(
+ c.call(ftmPrefix + "_conjugate", x, inverse),
+ c.call(ftmPrefix + "_one", res),
- if (bits == Fr.s +1) {
- let buffOut;
+ 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),
+ )
+ ),
- if (inverse) {
- buffOut = await _fftExtInv(buff, inType, outType, logger, loggerTxt);
- } else {
- buffOut = await _fftExt(buff, inType, outType, logger, loggerTxt);
- }
+ c.setLocal("i", c.i32_const(exponentNafBytes.length-2)),
+ c.block(c.loop(
+ 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 (returnArray) {
- return buffer2array(buffOut, sOut);
- } else {
- return buffOut;
- }
+ if (isExpNegative) {
+ f.addCode(
+ c.call(ftmPrefix + "_conjugate", res, res),
+ );
}
- let inv;
- if (inverse) {
- inv = Fr.inv(Fr.e(nPoints));
- }
+ }
- let buffOut;
+ function buildFinalExponentiation() {
+ buildCyclotomicSquare();
+ buildCyclotomicExp(finalExpZ, finalExpIsNegative, "w0");
- buffReverseBits(buff, sIn);
+ const f = module.addFunction(prefix+ "_finalExponentiation");
+ f.addParam("x", "i32");
+ f.addParam("r", "i32");
- let chunks;
- let pointsInChunk = Math.min(1 << MAX_BITS_THREAD, nPoints);
- let nChunks = nPoints / pointsInChunk;
+ const c = f.getCodeBuilder();
- while ((nChunks < tm.concurrency)&&(pointsInChunk>=16)) {
- nChunks *= 2;
- pointsInChunk /= 2;
- }
+ 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));
- const l2Chunk = log2(pointsInChunk);
+ f.addCode(
- 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}]});
- }
+ // let mut t0 = f.frobenius_map(6)
+ c.call(ftmPrefix + "_frobeniusMap6", elt, t0),
+
+ // let t1 = f.invert()
+ c.call(ftmPrefix + "_inverse", elt, t1),
- 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;
- }));
- }
+ // let mut t2 = t0 * t1;
+ c.call(ftmPrefix + "_mul", t0, t1, t2),
- chunks = await Promise.all(promises);
- for (let i = 0; i< nChunks; i++) chunks[i] = chunks[i][0];
+ // t1 = t2.clone();
+ c.call(ftmPrefix + "_copy", t2, t1),
- 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;
- }));
- }
- }
+ // t2 *= t1;
+ c.call(ftmPrefix + "_mul", t2, t1, t2),
- 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);
- }
+ // t6 *= t4;
+ c.call(ftmPrefix + "_mul", t6, t4, t6),
- buffOut.set(res1[0]);
- buffOut.set(res1[1], res1[0].byteLength);
+ // t4 = cycolotomic_exp(t6);
+ c.call(prefix + "__cyclotomicExp_w0", t6, t4),
- return buffOut;
- }
+ // t5 = t5.conjugate();
+ c.call(ftmPrefix + "_conjugate", t5, t5),
- 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);
+ // t4 *= t5 * t2;
+ c.call(ftmPrefix + "_mul", t4, t5, t4),
+ c.call(ftmPrefix + "_mul", t4, t2, t4),
- const promises = [];
+ // t5 = t2.conjugate();
+ c.call(ftmPrefix + "_conjugate", t2, t5),
- promises.push( _fft(b1, true, inType, "jacobian", logger, loggerTxt));
- promises.push( _fft(b2, true, inType, "jacobian", logger, loggerTxt));
+ // t1 *= t2;
+ c.call(ftmPrefix + "_mul", t1, t2, t1),
- [b1, b2] = await Promise.all(promises);
+ // t1 = t1.frobenius_map().frobenius_map().frobenius_map();
+ c.call(ftmPrefix + "_frobeniusMap3", t1, t1),
- const res1 = await _fftJoinExt(b1, b2, "fftJoinExtInv", Fr.one, Fr.shiftInv, "jacobian", outType, logger, loggerTxt);
+ // t6 *= t5;
+ c.call(ftmPrefix + "_mul", t6, t5, t6),
- let buffOut;
- if (res1[0].byteLength > (1<<28)) {
- buffOut = new BigBuffer(res1[0].byteLength*2);
- } else {
- buffOut = new Uint8Array(res1[0].byteLength*2);
- }
+ // t6 = t6.frobenius_map();
+ c.call(ftmPrefix + "_frobeniusMap1", t6, t6),
- buffOut.set(res1[0]);
- buffOut.set(res1[1], res1[0].byteLength);
+ // t3 *= t0;
+ c.call(ftmPrefix + "_mul", t3, t0, t3),
- return buffOut;
- }
+ // t3 = t3.frobenius_map().frobenius_map();
+ c.call(ftmPrefix + "_frobeniusMap2", t3, t3),
+ // t3 *= t1;
+ c.call(ftmPrefix + "_mul", t3, t1, t3),
- async function _fftJoinExt(buff1, buff2, fn, first, inc, inType, outType, logger, loggerTxt) {
- const MAX_CHUNK_SIZE = 1<<16;
- const MIN_CHUNK_SIZE = 1<<4;
+ // t3 *= t6;
+ c.call(ftmPrefix + "_mul", t3, t6, t3),
- let fnName;
- let fnIn2Mid, fnMid2Out;
- let sOut, sIn, sMid;
+ // f = t3 * t4;
+ c.call(ftmPrefix + "_mul", t3, t4, res),
- 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");
- }
+ );
+ }
+
+
+ function buildFinalExponentiationOld() {
+ const f = module.addFunction(prefix+ "_finalExponentiationOld");
+ f.addParam("x", "i32");
+ f.addParam("r", "i32");
+
+ const exponent = 322277361516934140462891564586510139908379969514828494218366688025288661041104682794998680497580008899973249814104447692778988208376779573819485263026159588510513834876303014016798809919343532899164848730280942609956670917565618115867287399623286813270357901731510188149934363360381614501334086825442271920079363289954510565375378443704372994881406797882676971082200626541916413184642520269678897559532260949334760604962086348898118982248842634379637598665468817769075878555493752214492790122785850202957575200176084204422751485957336465472324810982833638490904279282696134323072515220044451592646885410572234451732790590013479358343841220074174848221722017083597872017638514103174122784843925578370430843522959600095676285723737049438346544753168912974976791528535276317256904336520179281145394686565050419250614107803233314658825463117900250701199181529205942363159325765991819433914303908860460720581408201373164047773794825411011922305820065611121544561808414055302212057471395719432072209245600258134364584636810093520285711072578721435517884103526483832733289802426157301542744476740008494780363354305116978805620671467071400711358839553375340724899735460480144599782014906586543813292157922220645089192130209334926661588737007768565838519456601560804957985667880395221049249803753582637708560n;
- 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");
+ const pExponent = module.alloc(utils.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 MAX_CHUNK_SIZE) chunkSize = MAX_CHUNK_SIZE;
- const opPromises = [];
+ const c = f.getCodeBuilder();
- for (let i=0; i {
- if (logger) logger.debug(`${loggerTxt}: fftJoinExt End: ${i}/${nPoints}`);
- return r;
- })
+ f.addCode(c.call(prefix + "_prepareG1", c.getLocal("p_"+i), c.i32_const(pPreP) ));
+ f.addCode(c.call(prefix + "_prepareG2", c.getLocal("q_"+i), c.i32_const(pPreQ) ));
+
+ // Checks
+ f.addCode(
+ c.if(
+ c.i32_eqz(c.call(g1mPrefix + "_inGroupAffine", c.i32_const(pPreP))),
+ c.ret(c.i32_const(0))
+ ),
+ c.if(
+ c.i32_eqz(c.call(g2mPrefix + "_inGroupAffine", c.i32_const(pPreQ))),
+ c.ret(c.i32_const(0))
+ )
);
- }
- const result = await Promise.all(opPromises);
+ f.addCode(c.call(prefix + "_millerLoop", c.i32_const(pPreP), c.i32_const(pPreQ), auxT ));
- 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);
+ f.addCode(c.call(ftmPrefix + "_mul", resT, auxT, resT ));
}
- 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");
- }
+ const c = f.getCodeBuilder();
- let t0 = buff.slice(0, buff.byteLength/2);
- let t1 = buff.slice(buff.byteLength/2, buff.byteLength);
+ const WINV = [
+ 2001204777610833696708894912867952078278441409969503942666029068062015825245418932221343814564507832018947136279894n,
+ 2001204777610833696708894912867952078278441409969503942666029068062015825245418932221343814564507832018947136279893n
+ ];
+ const FROB2X = 4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436n;
+ const FROB3Y = [
+ 2973677408986561043442465346520108879172042883009249989176415018091420807192182638567116318576472649347015917690530n,
+ 2973677408986561043442465346520108879172042883009249989176415018091420807192182638567116318576472649347015917690530n
+ ];
- const shiftToSmallM = Fr.exp(Fr.shift, nPoints/2);
- const sConst = Fr.inv( Fr.sub(Fr.one, shiftToSmallM));
+ const wInv = c.i32_const(module.alloc([
+ ...utils.bigInt2BytesLE(toMontgomery(WINV[0]), n8q),
+ ...utils.bigInt2BytesLE(toMontgomery(WINV[1]), n8q),
+ ]));
- [t0, t1] = await _fftJoinExt(t0, t1, "prepareLagrangeEvaluation", sConst, Fr.shiftInv, inType, "jacobian", logger, loggerTxt + " prep");
+ const frob2X = c.i32_const(module.alloc(utils.bigInt2BytesLE(toMontgomery(FROB2X), n8q)));
+ const frob3Y = c.i32_const(module.alloc([
+ ...utils.bigInt2BytesLE(toMontgomery(FROB3Y[0]), n8q),
+ ...utils.bigInt2BytesLE(toMontgomery(FROB3Y[1]), n8q),
+ ]));
- const promises = [];
+ const z = c.i32_const(module.alloc(utils.bigInt2BytesLE(finalExpZ, 8)));
- promises.push( _fft(t0, true, "jacobian", outType, logger, loggerTxt + " t0"));
- promises.push( _fft(t1, true, "jacobian", outType, logger, loggerTxt + " t1"));
+ const px = c.getLocal("p");
+ const py = c.i32_add(c.getLocal("p"), c.i32_const(f2size));
- [t0, t1] = await Promise.all(promises);
+ const aux = c.i32_const(module.alloc(f1size));
- let buffOut;
- if (t0.byteLength > (1<<28)) {
- buffOut = new BigBuffer(t0.byteLength*2);
- } else {
- buffOut = new Uint8Array(t0.byteLength*2);
- }
+ const x_winv = c.i32_const(module.alloc(f2size));
+ const y_winv = c.i32_const(module.alloc(f2size));
+ const pf2 = module.alloc(f2size*2);
+ const f2 = c.i32_const(pf2);
+ const f2x = c.i32_const(pf2);
+ const f2x_c1 = c.i32_const(pf2);
+ const f2x_c2 = c.i32_const(pf2+f1size);
+ const f2y = c.i32_const(pf2+f2size);
+ const f2y_c1 = c.i32_const(pf2+f2size);
+ const f2y_c2 = c.i32_const(pf2+f2size+f1size);
+ const pf3 = module.alloc(f2size*3);
+ const f3 = c.i32_const(pf3);
+ const f3x = c.i32_const(pf3);
+ const f3x_c1 = c.i32_const(pf3);
+ const f3x_c2 = c.i32_const(pf3+f1size);
+ const f3y = c.i32_const(pf3+f2size);
+ const f3y_c1 = c.i32_const(pf3+f2size);
+ const f3y_c2 = c.i32_const(pf3+f2size+f1size);
+ const f3z = c.i32_const(pf3+f2size*2);
- buffOut.set(t0);
- buffOut.set(t1, t0.byteLength);
- return buffOut;
- };
+ f.addCode(
+ c.if(
+ c.call(g2mPrefix + "_isZeroAffine", c.getLocal("p")),
+ c.ret( c.i32_const(1)),
+ ),
+ c.if(
+ c.i32_eqz(c.call(g2mPrefix + "_inCurveAffine", c.getLocal("p"))),
+ c.ret( c.i32_const(0)),
+ ),
+ c.call(f2mPrefix + "_mul", px, wInv, x_winv),
+ c.call(f2mPrefix + "_mul", py, wInv, y_winv),
- 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");
- }
+ c.call(f2mPrefix + "_mul1", x_winv, frob2X, f2x),
+ c.call(f2mPrefix + "_neg", y_winv, f2y),
+
+ c.call(f2mPrefix + "_neg", x_winv, f3x),
+ c.call(f2mPrefix + "_mul", y_winv, frob3Y, f3y),
+
+ c.call(f1mPrefix + "_sub", f2x_c1, f2x_c2, aux),
+ c.call(f1mPrefix + "_add", f2x_c1, f2x_c2, f2x_c2),
+ c.call(f1mPrefix + "_copy", aux, f2x_c1),
+
+ c.call(f1mPrefix + "_sub", f2y_c1, f2y_c2, aux),
+ c.call(f1mPrefix + "_add", f2y_c1, f2y_c2, f2y_c2),
+ c.call(f1mPrefix + "_copy", aux, f2y_c1),
+
+ c.call(f1mPrefix + "_add", f3x_c1, f3x_c2, aux),
+ c.call(f1mPrefix + "_sub", f3x_c1, f3x_c2, f3x_c2),
+ c.call(f1mPrefix + "_copy", aux, f3x_c1),
- const nPoints = Math.floor(buff.byteLength / sG);
- const power = log2(nPoints);
+ c.call(f1mPrefix + "_sub", f3y_c2, f3y_c1, aux),
+ c.call(f1mPrefix + "_add", f3y_c1, f3y_c2, f3y_c2),
+ c.call(f1mPrefix + "_copy", aux, f3y_c1),
- let nChunks = 1 << log2(tm.concurrency);
+ c.call(f2mPrefix + "_one", f3z),
- if (nPoints <= nChunks*2) nChunks = 1;
+ c.call(g2mPrefix + "_timesScalar", f3, z, c.i32_const(8), f3),
+ c.call(g2mPrefix + "_addMixed", f3, f2, f3),
- const pointsPerChunk = nPoints / nChunks;
+ c.ret(
+ c.call(g2mPrefix + "_eqMixed", f3, c.getLocal("p"))
+ )
+ );
- const powerChunk = log2(pointsPerChunk);
+ const fInGroup = module.addFunction(g2mPrefix + "_inGroup");
+ fInGroup.addParam("pIn", "i32");
+ fInGroup.setReturnType("i32");
- const opPromises = [];
- for (let i=0; i=0; i--) {
- fullBuffOut.set(result[i][0], p);
- p+=result[i][0].byteLength;
- }
+ buildPrepareG1();
+ buildPrepareG2();
- return fullBuffOut;
- };
-}
+ buildMillerLoop();
-async function buildEngine(params) {
+ buildFinalExponentiationOld();
+ buildFinalExponentiation();
- const tm = await buildThreadManager(params.wasm, params.singleThread);
+ for (let i=1; i<=5; i++) {
+ buildPairingEquation(i);
+ module.exportFunction(prefix + "_pairingEq"+i);
+ }
+ buildPairing();
- const curve = {};
+ module.exportFunction(prefix + "_pairing");
- curve.q = e(params.wasm.q.toString());
- curve.r = e(params.wasm.r.toString());
- 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;
+ module.exportFunction(prefix + "_prepareG1");
+ module.exportFunction(prefix + "_prepareG2");
+ module.exportFunction(prefix + "_millerLoop");
+ module.exportFunction(prefix + "_finalExponentiation");
+ module.exportFunction(prefix + "_finalExponentiationOld");
+ module.exportFunction(prefix + "__cyclotomicSquare");
+ module.exportFunction(prefix + "__cyclotomicExp_w0");
- buildBatchApplyKey(curve, "G1");
- buildBatchApplyKey(curve, "G2");
- buildBatchApplyKey(curve, "Fr");
+ module.exportFunction(f6mPrefix + "_mul1");
+ module.exportFunction(f6mPrefix + "_mul01");
+ module.exportFunction(ftmPrefix + "_mul014");
- buildMultiexp(curve, "G1");
- buildMultiexp(curve, "G2");
+ module.exportFunction(g1mPrefix + "_inGroupAffine");
+ module.exportFunction(g1mPrefix + "_inGroup");
+ module.exportFunction(g2mPrefix + "_inGroupAffine");
+ module.exportFunction(g2mPrefix + "_inGroup");
- buildFFT(curve, "G1");
- buildFFT(curve, "G2");
- buildFFT(curve, "Fr");
+ // console.log(module.functionIdxByName);
+};
- buildPairing(curve);
+/*
+ Copyright 2019 0KIMS association.
- curve.array2buffer = function(arr, sG) {
- const buff = new Uint8Array(sG*arr.length);
+ This file is part of wasmsnark (Web Assembly zkSnark Prover).
- for (let i=0; i.
+*/
- return curve;
-}
+// module.exports.bn128_wasm = require("./build/bn128_wasm.js");
+var bn128_wasm_gzip = bn128_wasm_gzip$1;
+// module.exports.bls12381_wasm = require("./build/bls12381_wasm.js");
+// module.exports.mnt6753_wasm = require("./build/mnt6753_wasm.js");
+
+var buildBn128 = build_bn128;
+var buildBls12381 = build_bls12381;
+
+var index = /*#__PURE__*/Object.freeze({
+ __proto__: null,
+ bn128_wasm_gzip: bn128_wasm_gzip,
+ buildBls12381: buildBls12381,
+ buildBn128: buildBn128
+});
/*
Copyright 2019 0KIMS association.
@@ -18026,169 +18489,28 @@ class ModuleBuilder {
}
-globalThis.curve_bn128 = null;
-
-async function buildBn128(singleThread, plugins) {
- if ((!singleThread) && (globalThis.curve_bn128)) return globalThis.curve_bn128;
-
- 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;
-
- 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) {
- if ((!singleThread) && (globalThis.curve_bls12381)) return globalThis.curve_bls12381;
-
- 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.bls12381.q;
- bls12381wasm.r = moduleBuilder.modules.bls12381.r;
-
-
- 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;
-}
-
-const bls12381r = e("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", 16);
-const bn128r = e("21888242871839275222246405745257275088548364400416034343698204186575808495617");
-
-const bls12381q = e("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", 16);
-const bn128q = e("21888242871839275222246405745257275088696311157297823662689037894645226208583");
-
-async function getCurveFromR(r, singleThread, plugins) {
- let curve;
- if (eq(r, bn128r)) {
- curve = await buildBn128(singleThread, plugins);
- } else if (eq(r, bls12381r)) {
- curve = await buildBls12381(singleThread, plugins);
- } else {
- throw new Error(`Curve not supported: ${toString(r)}`);
- }
- return curve;
-}
+/*
+ Copyright 2019 0KIMS association.
-async function getCurveFromQ(q, singleThread, plugins) {
- let curve;
- if (eq(q, bn128q)) {
- curve = await buildBn128(singleThread, plugins);
- } else if (eq(q, bls12381q)) {
- curve = await buildBls12381(singleThread, plugins);
- } else {
- throw new Error(`Curve not supported: ${toString(q, 16)}`);
- }
- return curve;
-}
+ This file is part of wasmbuilder
-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;
+ 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.
- function normalizeName(n) {
- return n.toUpperCase().match(/[A-Za-z0-9]+/g).join("");
- }
+ 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 Scalar=_Scalar;
-const utils = _utils;
+var main = /*#__PURE__*/Object.freeze({
+ __proto__: null,
+ ModuleBuilder: ModuleBuilder
+});
-export { BigBuffer, ChaCha, EC, ZqField as F1Field, F2Field, F3Field, PolField, Scalar, ZqField, buildBls12381, buildBn128, getCurveFromName, getCurveFromQ, getCurveFromR, utils };
+export { BigBuffer, ChaCha, EC, ZqField as F1Field, F2Field, F3Field, PolField, Scalar, ZqField, buildBls12381$1 as buildBls12381, buildBn128$1 as buildBn128, getCurveFromName, getCurveFromQ, getCurveFromR, utils$6 as utils };
diff --git a/build/main.cjs b/build/main.cjs
index 5bb247b..4448871 100644
--- a/build/main.cjs
+++ b/build/main.cjs
@@ -1,10 +1,8 @@
'use strict';
var crypto = require('crypto');
-var wasmcurves = require('wasmcurves');
var os = require('os');
var Worker = require('web-worker');
-var wasmbuilder = require('wasmbuilder');
/* global BigInt */
const hexLen = [ 0, 1, 2, 2, 3, 3, 3, 3, 4 ,4 ,4 ,4 ,4 ,4 ,4 ,4];
@@ -3034,7 +3032,7 @@ var _utils = /*#__PURE__*/Object.freeze({
unstringifyFElements: unstringifyFElements
});
-const PAGE_SIZE = 1<<30;
+const PAGE_SIZE = ( typeof Buffer !== "undefined" && Buffer.constants && Buffer.constants.MAX_LENGTH ) ? Buffer.constants.MAX_LENGTH : (1 << 30);
class BigBuffer {
@@ -3044,7 +3042,11 @@ class BigBuffer {
for (let i=0; iMAXMEM) requiredPages=MAXMEM;
memory.grow(requiredPages-currentPages);
+ console.log("Growing memory to", memory.buffer.byteLength / 1024 / 1024, "MB");
}
return res;
}
@@ -4310,8 +4367,9 @@ function thread(self) {
}
function getBuffer(pointer, length) {
- const u8 = new Uint8Array(memory.buffer);
- return new Uint8Array(u8.buffer, u8.byteOffset + pointer, length);
+ // const u8 = new Uint8Array(memory.buffer);
+ // return new Uint8Array(u8.buffer, u8.byteOffset + pointer, length);
+ return new Uint8Array(memory.buffer, pointer, length);
}
function setBuffer(pointer, buffer) {
@@ -4320,7 +4378,8 @@ function thread(self) {
}
function runTask(task) {
- if (task[0].cmd == "INIT") {
+ clearTimeout(terminationTimer);
+ if (task[0].cmd === "INIT") {
return init(task[0]);
}
const ctx = {
@@ -4362,9 +4421,31 @@ function thread(self) {
}
const u32b = new Uint32Array(memory.buffer, 0, 1);
u32b[0] = oldAlloc;
+
+ //console.log(ctx.out);
+
return ctx.out;
}
+ function scheduleTermination() {
+ if (terminationTimeout>0) {
+ terminationTimer = setTimeout( () => {
+ console.log("Shutting down thread due to inactivity");
+ terminate();
+ }, terminationTimeout);
+ }
+ }
+
+ function terminate() {
+ clearTimeout(terminationTimer);
+ instance = null;
+ memory = null;
+ if (self) {
+ console.log("TERMINATE");
+ self.postMessage({status: "terminated"});
+ self.close();
+ }
+ }
return runTask;
}
@@ -4400,10 +4481,6 @@ class Deferred {
}
}
-function sleep(ms) {
- return new Promise(resolve => setTimeout(resolve, ms));
-}
-
let workerSource;
const threadStr = `(${thread.toString()})(self)`;
@@ -4435,7 +4512,7 @@ async function buildThreadManager(wasm, singleThread) {
"memory": tm.memory
}
});
-
+
if(process.browser && !globalThis?.Worker) {
singleThread = true;
}
@@ -4450,11 +4527,13 @@ async function buildThreadManager(wasm, singleThread) {
tm.pG2zero = wasm.pG2zero;
tm.pOneT = wasm.pOneT;
+ tm.code = wasm.code;
+ tm.wasmModule = wasmModule;
+
// 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",
@@ -4466,6 +4545,8 @@ async function buildThreadManager(wasm, singleThread) {
tm.workers = [];
tm.pendingDeferreds = [];
tm.working = [];
+ tm.initialized = [];
+ tm.initializing = [];
let concurrency = 2;
if (process.browser) {
@@ -4476,39 +4557,69 @@ async function buildThreadManager(wasm, singleThread) {
concurrency = os.cpus().length;
}
- if(concurrency == 0){
+ if(concurrency === 0){
concurrency = 2;
}
+ //concurrency = 10; // For testing
+
// Limit to 64 threads for memory reasons.
if (concurrency>64) concurrency=64;
tm.concurrency = concurrency;
- for (let i = 0; i {
+ this.initialized[i] = true;
+ });
}
startSyncOp() {
- if (this.oldPFree != 0) throw new Error("Sync operation in progress");
+ if (this.oldPFree !== 0) throw new Error("Sync operation in progress");
this.oldPFree = this.u32[0];
}
endSyncOp() {
- if (this.oldPFree == 0) throw new Error("No sync operation in progress");
+ if (this.oldPFree === 0) throw new Error("No sync operation in progress");
this.u32[0] = this.oldPFree;
this.oldPFree = 0;
}
- postAction(workerId, e, transfers, _deferred) {
+ async postAction(workerId, e, transfers, _deferred) {
if (this.working[workerId]) {
- throw new Error("Posting a job t a working worker");
+ throw new Error("Posting a job to a working worker");
}
this.working[workerId] = true;
this.pendingDeferreds[workerId] = _deferred ? _deferred : new Deferred();
- this.workers[workerId].postMessage(e, transfers);
+ await this.workers[workerId].postMessage(e, transfers);
return this.pendingDeferreds[workerId].promise;
}
- processWorks() {
- for (let i=0; (i 0); i++) {
- if (this.working[i] == false) {
+ async processWorks() {
+ for (let i=0; (i 0); i++) {
+ if (this.workers[i] && this.initialized[i] && !this.working[i]) {
const work = this.actionQueue.shift();
this.postAction(i, work.data, work.transfers, work.deferred);
}
}
+
+ // Initialize more workers if needed
+ if (this.actionQueue.length > 0) {
+ // Find a worker that is not initialized yet
+ let initializingCount = 0;
+ for (let i=0; i= this.actionQueue.length) break;
+
+ // Initialize this worker
+ console.log(`Worker ${i} not initialized yet. Initializing...`);
+ initializingCount++;
+ await this.startWorker(i);
+ //this.startWorker(i);
+ }
+ }
}
queueAction(actionData, transfers) {
@@ -4606,10 +4789,12 @@ class ThreadManager {
}
async terminate() {
+ console.log("terminate!!!");
for (let i=0; iMAX_CHUNK_SIZE) chunkSize = MAX_CHUNK_SIZE;
if (chunkSize {
+
+ opPromises.push(_multiExpChunk(buffBasesChunk, buffScalarsChunk, inType, logger, logText).then((r) => {
if (logger) logger.debug(`Multiexp end: ${logText}: ${i}/${nPoints}`);
return r;
}));
}
- const result = await Promise.all(opPromises);
+ let result = await Promise.all(opPromises);
let res = G.zero;
for (let i=result.length-1; i>=0; i--) {
@@ -5027,7 +5235,7 @@ function buildFFT(curve, groupName) {
outType = outType || "affine";
const MAX_BITS_THREAD = 14;
- let sIn, sMid, sOut, fnIn2Mid, fnMid2Out, fnFFTMix, fnFFTJoin, fnFFTFinal;
+ let sIn, sMid, sOut, fnIn2Mid, fnMid2Out, fnFFTMix, fnFFTJoin, fnFFTFinal, fnReversePermutation;
if (groupName == "G1") {
if (inType == "affine") {
sIn = G.F.n8*2;
@@ -5041,6 +5249,7 @@ function buildFFT(curve, groupName) {
}
fnFFTJoin = "g1m_fftJoin";
fnFFTMix = "g1m_fftMix";
+ fnReversePermutation = "g1m_reversePermutation";
if (outType == "affine") {
sOut = G.F.n8*2;
@@ -5062,6 +5271,7 @@ function buildFFT(curve, groupName) {
}
fnFFTJoin = "g2m_fftJoin";
fnFFTMix = "g2m_fftMix";
+ fnReversePermutation = "g2m_reversePermutation";
if (outType == "affine") {
sOut = G.F.n8*2;
fnMid2Out = "g2m_batchToAffine";
@@ -5077,6 +5287,7 @@ function buildFFT(curve, groupName) {
}
fnFFTMix = "frm_fftMix";
fnFFTJoin = "frm_fftJoin";
+ fnReversePermutation = "frm_fftReversePermutation";
}
@@ -5088,9 +5299,13 @@ function buildFFT(curve, groupName) {
buff = buff.slice(0, buff.byteLength);
}
+ console.log("FFT input size:", buff.byteLength, " bytes");
+
const nPoints = buff.byteLength / sIn;
const bits = log2(nPoints);
+ console.log("FFT points:", nPoints, " bits:", bits);
+
if ((1 << bits) != nPoints) {
throw new Error("fft must be multiple of 2" );
}
@@ -5118,7 +5333,19 @@ function buildFFT(curve, groupName) {
let buffOut;
- buffReverseBits(buff, sIn);
+ // TODO: optimize. Move to wasm?
+ //buffReverseBits(buff, sIn);
+
+ console.log("fnReversePermutation:", fnReversePermutation);
+
+ const task = [];
+ task.push({cmd: "ALLOC", var: 0, len: buff.byteLength});
+ task.push({cmd: "SET", var: 0, buff: buff});
+ task.push({cmd: "CALL", fnName: fnReversePermutation, params: [{var:0}, {val: bits}, {var: 0}]});
+ task.push({cmd: "GET", out:0, var: 0, len: buff.byteLength});
+ const res = await tm.queueAction(task, [buff.buffer]);
+
+ buff.set(res[0]);
let chunks;
let pointsInChunk = Math.min(1 << MAX_BITS_THREAD, nPoints);
@@ -5161,7 +5388,7 @@ function buildFFT(curve, groupName) {
} else {
task.push({cmd: "GET", out:0, var: 0, len: sMid*pointsInChunk});
}
- promises.push(tm.queueAction(task).then( (r) => {
+ promises.push(tm.queueAction(task, [buffChunk.buffer]).then( (r) => {
if (logger) logger.debug(`${loggerTxt}: fft ${bits} mix end: ${i}/${nChunks}`);
return r;
}));
@@ -5218,7 +5445,7 @@ function buildFFT(curve, groupName) {
task.push({cmd: "GET", out: 0, var: 0, len: pointsInChunk*sMid});
task.push({cmd: "GET", out: 1, var: 1, len: pointsInChunk*sMid});
}
- opPromises.push(tm.queueAction(task).then( (r) => {
+ opPromises.push(tm.queueAction(task, [chunks[o1].buffer, chunks[o2].buffer, first.buffer ]).then( (r) => {
if (logger) logger.debug(`${loggerTxt}: fft ${bits} join ${i}/${bits} ${j+1}/${nGroups} ${k}/${nChunksPerGroup/2}`);
return r;
}));
@@ -5417,7 +5644,7 @@ function buildFFT(curve, groupName) {
task.push({cmd: "GET", out: 0, var: 0, len: n*sOut});
task.push({cmd: "GET", out: 1, var: 1, len: n*sOut});
opPromises.push(
- tm.queueAction(task).then( (r) => {
+ tm.queueAction(task, [b1.buffer, b2.buffer, firstChunk.buffer]).then((r) => {
if (logger) logger.debug(`${loggerTxt}: fftJoinExt End: ${i}/${nPoints}`);
return r;
})
@@ -5565,7 +5792,7 @@ function buildFFT(curve, groupName) {
}
task.push({cmd: "GET", out: 0, var: 0, len: pointsPerChunk*sG});
opPromises.push(
- tm.queueAction(task)
+ tm.queueAction(task, [b.buffer])
);
}
@@ -5600,7 +5827,7 @@ function buildFFT(curve, groupName) {
]});
task.push({cmd: "GET", out: 0, var: 0, len: pointsPerChunk*sG});
task.push({cmd: "GET", out: 1, var: 1, len: pointsPerChunk*sG});
- opPromises.push(tm.queueAction(task));
+ opPromises.push(tm.queueAction(task, [chunks[o1].buffer, chunks[o2].buffer, first.buffer]));
}
}
@@ -5679,7 +5906,7 @@ function buildFFT(curve, groupName) {
task.push({cmd: "GET", out: 0, var: 0, len: pointsPerChunk*sG});
task.push({cmd: "GET", out: 1, var: 1, len: pointsPerChunk*sG});
opPromises.push(
- tm.queueAction(task)
+ tm.queueAction(task, [b1.buffer, b2.buffer, firstChunk.buffer])
);
}
@@ -5755,7 +5982,7 @@ function buildFFT(curve, groupName) {
]});
task.push({cmd: "GET", out: 0, var: 0, len: n*sGout});
opPromises.push(
- tm.queueAction(task)
+ tm.queueAction(task, [b.buffer])
);
}
@@ -5837,35 +6064,79 @@ async function buildEngine(params) {
return curve;
}
+//import { bn128_wasm_gzip as bn128wasmPrebuilt } from "wasmcurves";
+
globalThis.curve_bn128 = null;
async function buildBn128(singleThread, plugins) {
if ((!singleThread) && (globalThis.curve_bn128)) return globalThis.curve_bn128;
- const moduleBuilder = new wasmbuilder.ModuleBuilder();
- moduleBuilder.setMemory(25);
- wasmcurves.buildBn128(moduleBuilder);
+ let bn128wasm = {};
- if (plugins) plugins(moduleBuilder);
+ if (!plugins) {
+
+ console.log("Using prebuilt bn128 wasm");
- 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;
+ //import { bn128_wasm_gzip as bn128wasmPrebuilt } from "wasmcurves";
+ const { bn128_wasm_gzip: bn128wasmPrebuilt } = await import('wasmcurves');
+ //const { default: bn128wasmPrebuilt } = await import("wasmcurves/build/bn128_wasm_gzip.js");
+
+ //console.log(bn128wasmPrebuilt);
+ bn128wasm.pq = bn128wasmPrebuilt.pq;
+ bn128wasm.pr = bn128wasmPrebuilt.pq;
+ bn128wasm.pG1gen = bn128wasmPrebuilt.pG1gen;
+ bn128wasm.pG1zero = bn128wasmPrebuilt.pG1zero;
+ bn128wasm.pG1b = bn128wasmPrebuilt.pG1b;
+ bn128wasm.pG2gen = bn128wasmPrebuilt.pG2gen;
+ bn128wasm.pG2zero = bn128wasmPrebuilt.pG2zero;
+ bn128wasm.pG2b = bn128wasmPrebuilt.pG2b;
+ bn128wasm.pOneT = bn128wasmPrebuilt.pOneT;
+ bn128wasm.prePSize = bn128wasmPrebuilt.prePSize;
+ bn128wasm.preQSize = bn128wasmPrebuilt.preQSize;
+ bn128wasm.n8q = 32;
+ bn128wasm.n8r = 32;
+ bn128wasm.q = bn128wasmPrebuilt.q;
+ bn128wasm.r = bn128wasmPrebuilt.r;
+
+ const compressedCode = new Uint8Array(Buffer.from(bn128wasmPrebuilt.gzipCode, "base64"));
+ const blob = new Blob([compressedCode]);
+
+ const ds = new DecompressionStream("gzip");
+ const decompressedStream = blob.stream().pipeThrough(ds);
+
+ bn128wasm.code = await new Response(decompressedStream).bytes();
+ } else {
+
+ //import { ModuleBuilder } from "wasmbuilder";
+ //import { buildBn128 as buildBn128wasm } from "wasmcurves";
+ const { ModuleBuilder } = await import('wasmbuilder');
+ const { buildBn128: buildBn128wasm } = await import('wasmcurves');
+
+ const moduleBuilder = new ModuleBuilder();
+ moduleBuilder.setMemory(25);
+ buildBn128wasm(moduleBuilder);
+
+ if (plugins) plugins(moduleBuilder);
+
+ 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;
+ }
+
+ //console.log("bn128wasm:", bn128wasm);
const params = {
name: "bn128",
@@ -5898,9 +6169,12 @@ globalThis.curve_bls12381 = null;
async function buildBls12381(singleThread, plugins) {
if ((!singleThread) && (globalThis.curve_bls12381)) return globalThis.curve_bls12381;
- const moduleBuilder = new wasmbuilder.ModuleBuilder();
+ const { ModuleBuilder } = await import('wasmbuilder');
+ const { buildBls12381: buildBls12381wasm } = await import('wasmcurves');
+
+ const moduleBuilder = new ModuleBuilder();
moduleBuilder.setMemory(25);
- wasmcurves.buildBls12381(moduleBuilder);
+ buildBls12381wasm(moduleBuilder);
if (plugins) plugins(moduleBuilder);
diff --git a/package-lock.json b/package-lock.json
index 5880f3d..977eaa4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,7 +10,7 @@
"license": "GPL-3.0",
"dependencies": {
"wasmbuilder": "0.0.16",
- "wasmcurves": "0.2.2",
+ "wasmcurves": "file:../wasmcurves",
"web-worker": "1.5.0"
},
"devDependencies": {
@@ -23,6 +23,17 @@
"rollup": "^3.29.4"
}
},
+ "../wasmcurves": {
+ "version": "0.2.2",
+ "license": "GPL-3.0",
+ "dependencies": {
+ "wasmbuilder": "0.0.16"
+ },
+ "devDependencies": {
+ "eslint": "^8.17.0",
+ "mocha": "^10.0.0"
+ }
+ },
"node_modules/@aashutoshrathi/word-wrap": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
@@ -329,6 +340,7 @@
"integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==",
"dev": true,
"license": "MIT",
+ "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -740,6 +752,7 @@
"integrity": "sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.11.0",
@@ -1734,6 +1747,7 @@
"integrity": "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==",
"dev": true,
"license": "MIT",
+ "peer": true,
"bin": {
"rollup": "dist/bin/rollup"
},
@@ -1906,12 +1920,8 @@
"integrity": "sha512-Qx3lEFqaVvp1cEYW7Bfi+ebRJrOiwz2Ieu7ZG2l7YyeSJIok/reEQCQCuicj/Y32ITIJuGIM9xZQppGx5LrQdA=="
},
"node_modules/wasmcurves": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/wasmcurves/-/wasmcurves-0.2.2.tgz",
- "integrity": "sha512-JRY908NkmKjFl4ytnTu5ED6AwPD+8VJ9oc94kdq7h5bIwbj0L4TDJ69mG+2aLs2SoCmGfqIesMWTEJjtYsoQXQ==",
- "dependencies": {
- "wasmbuilder": "0.0.16"
- }
+ "resolved": "../wasmcurves",
+ "link": true
},
"node_modules/web-worker": {
"version": "1.5.0",
diff --git a/package.json b/package.json
index a3ad475..358c4e9 100644
--- a/package.json
+++ b/package.json
@@ -40,7 +40,7 @@
"homepage": "https://github.com/iden3/ffjavascript",
"dependencies": {
"wasmbuilder": "0.0.16",
- "wasmcurves": "0.2.2",
+ "wasmcurves": "file:../wasmcurves",
"web-worker": "1.5.0"
},
"devDependencies": {
diff --git a/rollup.browser.esm.config.js b/rollup.browser.esm.config.js
index 104a1e1..bc07d5d 100644
--- a/rollup.browser.esm.config.js
+++ b/rollup.browser.esm.config.js
@@ -10,6 +10,7 @@ export default [
{
format: "es",
file: "build/browser.esm.js",
+ inlineDynamicImports: true,
},
],
plugins: [
diff --git a/src/bigbuffer.js b/src/bigbuffer.js
index 1064a02..47c1a7c 100644
--- a/src/bigbuffer.js
+++ b/src/bigbuffer.js
@@ -1,5 +1,5 @@
-const PAGE_SIZE = 1<<30;
+const PAGE_SIZE = ( typeof Buffer !== "undefined" && Buffer.constants && Buffer.constants.MAX_LENGTH ) ? Buffer.constants.MAX_LENGTH : (1 << 30);
export default class BigBuffer {
diff --git a/src/bls12381.js b/src/bls12381.js
index ce012b8..737f6a2 100644
--- a/src/bls12381.js
+++ b/src/bls12381.js
@@ -1,13 +1,14 @@
-import { buildBls12381 as buildBls12381wasm } from "wasmcurves";
import buildEngine from "./engine.js";
import * as Scalar from "./scalar.js";
-import { ModuleBuilder } from "wasmbuilder";
globalThis.curve_bls12381 = null;
export default async function buildBls12381(singleThread, plugins) {
if ((!singleThread) && (globalThis.curve_bls12381)) return globalThis.curve_bls12381;
+ const { ModuleBuilder } = await import("wasmbuilder");
+ const { buildBls12381: buildBls12381wasm } = await import("wasmcurves");
+
const moduleBuilder = new ModuleBuilder();
moduleBuilder.setMemory(25);
buildBls12381wasm(moduleBuilder);
diff --git a/src/bn128.js b/src/bn128.js
index 7a421c1..371d286 100644
--- a/src/bn128.js
+++ b/src/bn128.js
@@ -1,37 +1,78 @@
-import { buildBn128 as buildBn128wasm } from "wasmcurves";
+//import { bn128_wasm_gzip as bn128wasmPrebuilt } from "wasmcurves";
import buildEngine from "./engine.js";
import * as Scalar from "./scalar.js";
-import { ModuleBuilder } from "wasmbuilder";
globalThis.curve_bn128 = null;
export default async function buildBn128(singleThread, plugins) {
if ((!singleThread) && (globalThis.curve_bn128)) return globalThis.curve_bn128;
- const moduleBuilder = new ModuleBuilder();
- moduleBuilder.setMemory(25);
- buildBn128wasm(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;
+ let bn128wasm = {};
+
+ if (!plugins) {
+
+ console.log("Using prebuilt bn128 wasm");
+
+ //import { bn128_wasm_gzip as bn128wasmPrebuilt } from "wasmcurves";
+ //const { bn128_wasm_gzip: bn128wasmPrebuilt } = await import("wasmcurves");
+ const { default: bn128wasmPrebuilt } = await import("wasmcurves/build/bn128_wasm_gzip.js");
+
+ //console.log(bn128wasmPrebuilt);
+ bn128wasm.pq = bn128wasmPrebuilt.pq;
+ bn128wasm.pr = bn128wasmPrebuilt.pq;
+ bn128wasm.pG1gen = bn128wasmPrebuilt.pG1gen;
+ bn128wasm.pG1zero = bn128wasmPrebuilt.pG1zero;
+ bn128wasm.pG1b = bn128wasmPrebuilt.pG1b;
+ bn128wasm.pG2gen = bn128wasmPrebuilt.pG2gen;
+ bn128wasm.pG2zero = bn128wasmPrebuilt.pG2zero;
+ bn128wasm.pG2b = bn128wasmPrebuilt.pG2b;
+ bn128wasm.pOneT = bn128wasmPrebuilt.pOneT;
+ bn128wasm.prePSize = bn128wasmPrebuilt.prePSize;
+ bn128wasm.preQSize = bn128wasmPrebuilt.preQSize;
+ bn128wasm.n8q = 32;
+ bn128wasm.n8r = 32;
+ bn128wasm.q = bn128wasmPrebuilt.q;
+ bn128wasm.r = bn128wasmPrebuilt.r;
+
+ const compressedCode = new Uint8Array(Buffer.from(bn128wasmPrebuilt.gzipCode, "base64"));
+ const blob = new Blob([compressedCode]);
+
+ const ds = new DecompressionStream("gzip");
+ const decompressedStream = blob.stream().pipeThrough(ds);
+
+ bn128wasm.code = await new Response(decompressedStream).bytes();
+ } else {
+
+ //import { ModuleBuilder } from "wasmbuilder";
+ //import { buildBn128 as buildBn128wasm } from "wasmcurves";
+ const { ModuleBuilder } = await import("wasmbuilder");
+ const { buildBn128: buildBn128wasm } = await import("wasmcurves");
+
+ const moduleBuilder = new ModuleBuilder();
+ moduleBuilder.setMemory(25);
+ buildBn128wasm(moduleBuilder);
+
+ if (plugins) plugins(moduleBuilder);
+
+ 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;
+ }
+
+ //console.log("bn128wasm:", bn128wasm);
const params = {
name: "bn128",
diff --git a/src/engine_applykey.js b/src/engine_applykey.js
index 5857d8c..294c9ff 100644
--- a/src/engine_applykey.js
+++ b/src/engine_applykey.js
@@ -64,10 +64,12 @@ export default function buildBatchApplyKey(curve, groupName) {
const task = [];
+ const b = buff.slice(i*pointsPerChunk*sGin, i*pointsPerChunk*sGin + n*sGin);
+
task.push({
cmd: "ALLOCSET",
var: 0,
- buff: buff.slice(i*pointsPerChunk*sGin, i*pointsPerChunk*sGin + n*sGin)
+ buff: b
});
task.push({cmd: "ALLOCSET", var: 1, buff: t});
task.push({cmd: "ALLOCSET", var: 2, buff: inc});
@@ -96,7 +98,7 @@ export default function buildBatchApplyKey(curve, groupName) {
}
task.push({cmd: "GET", out: 0, var: 3, len: n*sGout});
- opPromises.push(tm.queueAction(task));
+ opPromises.push(tm.queueAction(task, [b.buffer]));
t = Fr.mul(t, Fr.exp(inc, n));
}
diff --git a/src/engine_batchconvert.js b/src/engine_batchconvert.js
index 0acf524..1adb3bf 100644
--- a/src/engine_batchconvert.js
+++ b/src/engine_batchconvert.js
@@ -29,7 +29,7 @@ export default function buildBatchConvert(tm, fnName, sIn, sOut) {
{cmd: "GET", out: 0, var: 1, len:sOut * n},
];
opPromises.push(
- tm.queueAction(task)
+ tm.queueAction(task, [buffChunk.buffer])
);
}
diff --git a/src/engine_fft.js b/src/engine_fft.js
index 5ae955b..2a862df 100644
--- a/src/engine_fft.js
+++ b/src/engine_fft.js
@@ -12,7 +12,7 @@ export default function buildFFT(curve, groupName) {
outType = outType || "affine";
const MAX_BITS_THREAD = 14;
- let sIn, sMid, sOut, fnIn2Mid, fnMid2Out, fnFFTMix, fnFFTJoin, fnFFTFinal;
+ let sIn, sMid, sOut, fnIn2Mid, fnMid2Out, fnFFTMix, fnFFTJoin, fnFFTFinal, fnReversePermutation;
if (groupName == "G1") {
if (inType == "affine") {
sIn = G.F.n8*2;
@@ -26,6 +26,7 @@ export default function buildFFT(curve, groupName) {
}
fnFFTJoin = "g1m_fftJoin";
fnFFTMix = "g1m_fftMix";
+ fnReversePermutation = "g1m__reversePermutation";
if (outType == "affine") {
sOut = G.F.n8*2;
@@ -47,6 +48,7 @@ export default function buildFFT(curve, groupName) {
}
fnFFTJoin = "g2m_fftJoin";
fnFFTMix = "g2m_fftMix";
+ fnReversePermutation = "g2m__reversePermutation";
if (outType == "affine") {
sOut = G.F.n8*2;
fnMid2Out = "g2m_batchToAffine";
@@ -62,6 +64,7 @@ export default function buildFFT(curve, groupName) {
}
fnFFTMix = "frm_fftMix";
fnFFTJoin = "frm_fftJoin";
+ fnReversePermutation = "frm__reversePermutation";
}
@@ -73,9 +76,13 @@ export default function buildFFT(curve, groupName) {
buff = buff.slice(0, buff.byteLength);
}
+ console.log("FFT input size:", buff.byteLength, " bytes");
+
const nPoints = buff.byteLength / sIn;
const bits = log2(nPoints);
+ console.log("FFT points:", nPoints, " bits:", bits);
+
if ((1 << bits) != nPoints) {
throw new Error("fft must be multiple of 2" );
}
@@ -103,7 +110,26 @@ export default function buildFFT(curve, groupName) {
let buffOut;
- buffReverseBits(buff, sIn);
+ // TODO: optimize. Move to wasm
+ // buffReverseBits(buff, sIn);
+
+ console.log("fnReversePermutation:", fnReversePermutation);
+
+ // TODO: try to do reversing for each batch separately and inside of the task
+ const task = [];
+ task.push({cmd: "ALLOCSET", var: 0, buff: buff});
+ task.push({cmd: "CALL", fnName: fnReversePermutation, params: [{var:0}, {val: bits}]});
+ task.push({cmd: "GET", out:0, var: 0, len: nPoints*sOut});
+ const reversedBuff = await tm.queueAction(task, [buff.buffer]);
+ //const reversedBuff = await tm.queueAction(task, []);
+
+ //console.log("wasm buffReverseBits:", reversedBuff[0]);
+ //buffReverseBits(buff, sIn);
+ //console.log("js buffReverseBits:", buff);
+
+ //exit(1);
+
+ buff = reversedBuff[0];
let chunks;
let pointsInChunk = Math.min(1 << MAX_BITS_THREAD, nPoints);
@@ -117,8 +143,8 @@ export default function buildFFT(curve, groupName) {
const l2Chunk = log2(pointsInChunk);
const promises = [];
+ if (logger) logger.debug(`${loggerTxt}: fft ${bits} mix start: ${nChunks}`);
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);
@@ -146,17 +172,15 @@ export default function buildFFT(curve, groupName) {
} 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;
- }));
+ promises.push(tm.queueAction(task, [buffChunk.buffer]));
}
chunks = await Promise.all(promises);
+ if (logger) logger.debug(`${loggerTxt}: fft ${bits} mix end: ${nChunks}`);
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}`);
+ if (logger) logger.debug(`${loggerTxt}: fft ${bits} join: ${i}/${bits}`);
const nGroups = 1 << (bits - i);
const nChunksPerGroup = nChunks / nGroups;
const opPromises = [];
@@ -203,10 +227,7 @@ export default function buildFFT(curve, groupName) {
task.push({cmd: "GET", out: 0, var: 0, len: pointsInChunk*sMid});
task.push({cmd: "GET", out: 1, var: 1, len: pointsInChunk*sMid});
}
- opPromises.push(tm.queueAction(task).then( (r) => {
- if (logger) logger.debug(`${loggerTxt}: fft ${bits} join ${i}/${bits} ${j+1}/${nGroups} ${k}/${nChunksPerGroup/2}`);
- return r;
- }));
+ opPromises.push(tm.queueAction(task, [chunks[o1].buffer, chunks[o2].buffer, first.buffer ]));
}
}
@@ -402,7 +423,7 @@ export default function buildFFT(curve, groupName) {
task.push({cmd: "GET", out: 0, var: 0, len: n*sOut});
task.push({cmd: "GET", out: 1, var: 1, len: n*sOut});
opPromises.push(
- tm.queueAction(task).then( (r) => {
+ tm.queueAction(task, [b1.buffer, b2.buffer, firstChunk.buffer]).then((r) => {
if (logger) logger.debug(`${loggerTxt}: fftJoinExt End: ${i}/${nPoints}`);
return r;
})
@@ -550,7 +571,7 @@ export default function buildFFT(curve, groupName) {
}
task.push({cmd: "GET", out: 0, var: 0, len: pointsPerChunk*sG});
opPromises.push(
- tm.queueAction(task)
+ tm.queueAction(task, [b.buffer])
);
}
@@ -585,7 +606,7 @@ export default function buildFFT(curve, groupName) {
]});
task.push({cmd: "GET", out: 0, var: 0, len: pointsPerChunk*sG});
task.push({cmd: "GET", out: 1, var: 1, len: pointsPerChunk*sG});
- opPromises.push(tm.queueAction(task));
+ opPromises.push(tm.queueAction(task, [chunks[o1].buffer, chunks[o2].buffer, first.buffer]));
}
}
@@ -664,7 +685,7 @@ export default function buildFFT(curve, groupName) {
task.push({cmd: "GET", out: 0, var: 0, len: pointsPerChunk*sG});
task.push({cmd: "GET", out: 1, var: 1, len: pointsPerChunk*sG});
opPromises.push(
- tm.queueAction(task)
+ tm.queueAction(task, [b1.buffer, b2.buffer, firstChunk.buffer])
);
}
@@ -740,7 +761,7 @@ export default function buildFFT(curve, groupName) {
]});
task.push({cmd: "GET", out: 0, var: 0, len: n*sGout});
opPromises.push(
- tm.queueAction(task)
+ tm.queueAction(task, [b.buffer])
);
}
diff --git a/src/engine_multiexp.js b/src/engine_multiexp.js
index 38d813f..96d52f4 100644
--- a/src/engine_multiexp.js
+++ b/src/engine_multiexp.js
@@ -10,6 +10,7 @@ const pTSizes = [
export default function buildMultiexp(curve, groupName) {
const G = curve[groupName];
const tm = G.tm;
+
async function _multiExpChunk(buffBases, buffScalars, inType, logger, logText) {
if ( ! (buffBases instanceof Uint8Array) ) {
if (logger) logger.error(`${logText} _multiExpChunk buffBases is not Uint8Array`);
@@ -23,20 +24,20 @@ export default function buildMultiexp(curve, groupName) {
let sGIn;
let fnName;
- if (groupName == "G1") {
- if (inType == "affine") {
- fnName = "g1m_multiexpAffine_chunk";
+ if (groupName === "G1") {
+ if (inType === "affine") {
+ fnName = "g1m_multiexpAffine";
sGIn = G.F.n8*2;
} else {
- fnName = "g1m_multiexp_chunk";
+ fnName = "g1m_multiexp";
sGIn = G.F.n8*3;
}
- } else if (groupName == "G2") {
- if (inType == "affine") {
- fnName = "g2m_multiexpAffine_chunk";
+ } else if (groupName === "G2") {
+ if (inType === "affine") {
+ fnName = "g2m_multiexpAffine";
sGIn = G.F.n8*2;
} else {
- fnName = "g2m_multiexp_chunk";
+ fnName = "g2m_multiexp";
sGIn = G.F.n8*3;
}
} else {
@@ -44,36 +45,33 @@ export default function buildMultiexp(curve, groupName) {
}
const nPoints = Math.floor(buffBases.byteLength / sGIn);
- if (nPoints == 0) return G.zero;
+ if (nPoints === 0) return G.zero;
const sScalar = Math.floor(buffScalars.byteLength / nPoints);
- if( sScalar * nPoints != buffScalars.byteLength) {
+ if( sScalar * nPoints !== buffScalars.byteLength) {
throw new Error("Scalar size does not match");
}
const bitChunkSize = pTSizes[log2(nPoints)];
- const nChunks = Math.floor((sScalar*8 - 1) / bitChunkSize) +1;
const opPromises = [];
- for (let i=0; iMAX_CHUNK_SIZE) chunkSize = MAX_CHUNK_SIZE;
if (chunkSize {
+
+ opPromises.push(_multiExpChunk(buffBasesChunk, buffScalarsChunk, inType, logger, logText).then((r) => {
if (logger) logger.debug(`Multiexp end: ${logText}: ${i}/${nPoints}`);
return r;
}));
}
- const result = await Promise.all(opPromises);
+ result = await Promise.all(opPromises);
let res = G.zero;
for (let i=result.length-1; i>=0; i--) {
@@ -147,9 +163,9 @@ export default function buildMultiexp(curve, groupName) {
}
G.multiExp = async function multiExpAffine(buffBases, buffScalars, logger, logText) {
- return await _multiExp(buffBases, buffScalars, "jacobian", logger, logText);
+ return _multiExp(buffBases, buffScalars, "jacobian", logger, logText);
};
G.multiExpAffine = async function multiExpAffine(buffBases, buffScalars, logger, logText) {
- return await _multiExp(buffBases, buffScalars, "affine", logger, logText);
+ return _multiExp(buffBases, buffScalars, "affine", logger, logText);
};
}
diff --git a/src/engine_pairing.js b/src/engine_pairing.js
index 5a802ce..39095d2 100644
--- a/src/engine_pairing.js
+++ b/src/engine_pairing.js
@@ -60,7 +60,7 @@ export default function buildPairing(curve) {
task.push({cmd: "GET", out: 0, var: 4, len: curve.Gt.n8});
opPromises.push(
- tm.queueAction(task)
+ tm.queueAction(task, [g1Buff.buffer, g2Buff.buffer])
);
}
diff --git a/src/threadman.js b/src/threadman.js
index f80901b..60bbf09 100644
--- a/src/threadman.js
+++ b/src/threadman.js
@@ -84,11 +84,13 @@ export default async function buildThreadManager(wasm, singleThread) {
tm.pG2zero = wasm.pG2zero;
tm.pOneT = wasm.pOneT;
+ tm.code = wasm.code;
+ tm.wasmModule = wasmModule;
+
// 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",
@@ -100,6 +102,9 @@ export default async function buildThreadManager(wasm, singleThread) {
tm.workers = [];
tm.pendingDeferreds = [];
tm.working = [];
+ tm.initialized = [];
+ tm.initializing = [];
+ tm.terminating = [];
let concurrency = 2;
if (process.browser) {
@@ -110,40 +115,70 @@ export default async function buildThreadManager(wasm, singleThread) {
concurrency = os.cpus().length;
}
- if(concurrency == 0){
+ if(concurrency === 0){
concurrency = 2;
}
+ //concurrency = 10; // For testing
+
// Limit to 64 threads for memory reasons.
if (concurrency>64) concurrency=64;
tm.concurrency = concurrency;
- for (let i = 0; i {
+ this.initialized[i] = true;
+ });
}
startSyncOp() {
- if (this.oldPFree != 0) throw new Error("Sync operation in progress");
+ if (this.oldPFree !== 0) throw new Error("Sync operation in progress");
this.oldPFree = this.u32[0];
}
endSyncOp() {
- if (this.oldPFree == 0) throw new Error("No sync operation in progress");
+ if (this.oldPFree === 0) throw new Error("No sync operation in progress");
this.u32[0] = this.oldPFree;
this.oldPFree = 0;
}
- postAction(workerId, e, transfers, _deferred) {
+ async postAction(workerId, e, transfers, _deferred) {
if (this.working[workerId]) {
- throw new Error("Posting a job t a working worker");
+ throw new Error("Posting a job to a working worker");
}
this.working[workerId] = true;
this.pendingDeferreds[workerId] = _deferred ? _deferred : new Deferred();
- this.workers[workerId].postMessage(e, transfers);
+ await this.workers[workerId].postMessage(e, transfers);
return this.pendingDeferreds[workerId].promise;
}
- processWorks() {
- for (let i=0; (i 0); i++) {
- if (this.working[i] == false) {
+ async processWorks() {
+
+ //console.log("this.actionQueue.length:", this.actionQueue.length);
+
+ for (let i=0; (i 0); i++) {
+ if (this.workers[i] && this.initialized[i] && !this.working[i]) {
const work = this.actionQueue.shift();
- this.postAction(i, work.data, work.transfers, work.deferred);
+ await this.postAction(i, work.data, work.transfers, work.deferred);
+ }
+ }
+
+ // Initialize more workers if needed
+ if (this.actionQueue.length > 0) {
+ // Find a worker that is not initialized yet
+ let initializingCount = 0;
+ for (let i=0; i= this.actionQueue.length) break;
+
+ // Initialize this worker
+ console.log(`Worker ${i} not initialized yet. Initializing...`);
+ initializingCount++;
+ await this.startWorker(i);
+ //this.startWorker(i);
}
}
}
- queueAction(actionData, transfers) {
+ async queueAction(actionData, transfers) {
const d = new Deferred();
if (this.singleThread) {
const res = this.taskManager(actionData);
d.resolve(res);
} else {
+ // Wait if queue is too large
+ // while (this.actionQueue.length >= this.concurrency * 2) {
+ // await sleep(10);
+ // }
this.actionQueue.push({
data: actionData,
transfers: transfers,
deferred: d
});
- this.processWorks();
+ await this.processWorks();
}
return d.promise;
}
@@ -240,10 +367,12 @@ export class ThreadManager {
}
async terminate() {
+ //console.log("terminate!!!");
for (let i=0; iMAXMEM) requiredPages=MAXMEM;
memory.grow(requiredPages-currentPages);
+ console.log("Growing memory to", memory.buffer.byteLength / 1024 / 1024, "MB");
}
return res;
}
@@ -62,8 +119,9 @@ export default function thread(self) {
}
function getBuffer(pointer, length) {
- const u8 = new Uint8Array(memory.buffer);
- return new Uint8Array(u8.buffer, u8.byteOffset + pointer, length);
+ // const u8 = new Uint8Array(memory.buffer);
+ // return new Uint8Array(u8.buffer, u8.byteOffset + pointer, length);
+ return new Uint8Array(memory.buffer, pointer, length);
}
function setBuffer(pointer, buffer) {
@@ -72,7 +130,8 @@ export default function thread(self) {
}
function runTask(task) {
- if (task[0].cmd == "INIT") {
+ clearTimeout(terminationTimer);
+ if (task[0].cmd === "INIT") {
return init(task[0]);
}
const ctx = {
@@ -84,9 +143,17 @@ export default function thread(self) {
for (let i=0; i 25) {
+ console.log("tasks", task);
+ console.trace();
+ }
ctx.vars[task[i].var] = allocBuffer(task[i].buff);
break;
case "ALLOC":
+ if (task[i].len / 1024 / 1024 > 25) {
+ console.log("tasks", task);
+ console.trace();
+ }
ctx.vars[task[i].var] = alloc(task[i].len);
break;
case "SET":
@@ -114,9 +181,32 @@ export default function thread(self) {
}
const u32b = new Uint32Array(memory.buffer, 0, 1);
u32b[0] = oldAlloc;
+
+ //console.log(ctx.out);
+
return ctx.out;
}
+ function scheduleTermination() {
+ clearTimeout(terminationTimer);
+ if (terminationTimeout>0) {
+ terminationTimer = setTimeout( () => {
+ console.log("Shutting down thread due to inactivity");
+ terminate();
+ }, terminationTimeout);
+ }
+ }
+
+ function terminate() {
+ clearTimeout(terminationTimer);
+ //instance = null;
+ //memory = null;
+ if (self) {
+ console.log("TERMINATE");
+ self.postMessage({status: "terminated"});
+ self.close();
+ }
+ }
return runTask;
}
diff --git a/src/wasm_field1.js b/src/wasm_field1.js
index e5c3b64..7dbd8bb 100644
--- a/src/wasm_field1.js
+++ b/src/wasm_field1.js
@@ -282,7 +282,7 @@ export default class WasmField1 {
{cmd: "GET", out: 0, var: 1, len:sOut * n},
];
opPromises.push(
- this.tm.queueAction(task)
+ this.tm.queueAction(task, [buffChunk.buffer])
);
}
diff --git a/test/utils.js b/test/utils.js
index 693557c..8ff0af1 100644
--- a/test/utils.js
+++ b/test/utils.js
@@ -30,7 +30,7 @@ describe("Utils native", () => {
it("Should generate buffer little-endian without trailing non-zero element", () => {
for (let i = 1; i < 33; i++) {
- var buff = utilsN.leInt2Buff(BigInt(42), i);
+ let buff = utilsN.leInt2Buff(BigInt(42), i);
for (let t = 1; t < buff.length; t++){
assert(buff[t] === 0, true);
}
@@ -39,7 +39,7 @@ describe("Utils native", () => {
it("Should generate buffer big-endian without trailing non-zero element", () => {
for (let i = 1; i < 33; i++) {
- var buff = utilsN.beInt2Buff(BigInt(42), i);
+ let buff = utilsN.beInt2Buff(BigInt(42), i);
for (let t = 0; t < buff.length - 1; t++){
assert(buff[t] === 0, true);
}