ffjavascript/build/browser.esm.js
Oleksandr Brezhniev d5dae76856
Release 0.3.1 prep (#162)
* Bump deps and package version. Rebuild

* Update chai
2024-10-12 17:12:41 +01:00

18195 lines
562 KiB
JavaScript

/* global BigInt */
const hexLen = [ 0, 1, 2, 2, 3, 3, 3, 3, 4 ,4 ,4 ,4 ,4 ,4 ,4 ,4];
function fromString(s, radix) {
if ((!radix)||(radix==10)) {
return BigInt(s);
} else if (radix==16) {
if (s.slice(0,2) == "0x") {
return BigInt(s);
} else {
return BigInt("0x"+s);
}
}
}
const e = fromString;
function fromArray(a, radix) {
let acc =BigInt(0);
radix = BigInt(radix);
for (let i=0; i<a.length; i++) {
acc = acc*radix + BigInt(a[i]);
}
return acc;
}
function bitLength$6(a) {
const aS =a.toString(16);
return (aS.length-1)*4 +hexLen[parseInt(aS[0], 16)];
}
function isNegative$4(a) {
return BigInt(a) < BigInt(0);
}
function isZero$1(a) {
return !a;
}
function shiftLeft(a, n) {
return BigInt(a) << BigInt(n);
}
function shiftRight(a, n) {
return BigInt(a) >> BigInt(n);
}
const shl = shiftLeft;
const shr = shiftRight;
function isOdd$5(a) {
return (BigInt(a) & BigInt(1)) == BigInt(1);
}
function naf(n) {
let E = BigInt(n);
const res = [];
while (E) {
if (E & BigInt(1)) {
const z = 2 - Number(E % BigInt(4));
res.push( z );
E = E - BigInt(z);
} else {
res.push( 0 );
}
E = E >> BigInt(1);
}
return res;
}
function bits(n) {
let E = BigInt(n);
const res = [];
while (E) {
if (E & BigInt(1)) {
res.push(1);
} else {
res.push( 0 );
}
E = E >> BigInt(1);
}
return res;
}
function toNumber$1(s) {
if (s>BigInt(Number.MAX_SAFE_INTEGER )) {
throw new Error("Number too big");
}
return Number(s);
}
function toArray(s, radix) {
const res = [];
let rem = BigInt(s);
radix = BigInt(radix);
while (rem) {
res.unshift( Number(rem % radix));
rem = rem / radix;
}
return res;
}
function add(a, b) {
return BigInt(a) + BigInt(b);
}
function sub(a, b) {
return BigInt(a) - BigInt(b);
}
function neg(a) {
return -BigInt(a);
}
function mul(a, b) {
return BigInt(a) * BigInt(b);
}
function square$2(a) {
return BigInt(a) * BigInt(a);
}
function pow(a, b) {
return BigInt(a) ** BigInt(b);
}
function exp$1(a, b) {
return BigInt(a) ** BigInt(b);
}
function abs$1(a) {
return BigInt(a) >= 0 ? BigInt(a) : -BigInt(a);
}
function div(a, b) {
return BigInt(a) / BigInt(b);
}
function mod(a, b) {
return BigInt(a) % BigInt(b);
}
function eq(a, b) {
return BigInt(a) == BigInt(b);
}
function neq(a, b) {
return BigInt(a) != BigInt(b);
}
function lt(a, b) {
return BigInt(a) < BigInt(b);
}
function gt(a, b) {
return BigInt(a) > BigInt(b);
}
function leq(a, b) {
return BigInt(a) <= BigInt(b);
}
function geq(a, b) {
return BigInt(a) >= BigInt(b);
}
function band(a, b) {
return BigInt(a) & BigInt(b);
}
function bor(a, b) {
return BigInt(a) | BigInt(b);
}
function bxor(a, b) {
return BigInt(a) ^ BigInt(b);
}
function land(a, b) {
return BigInt(a) && BigInt(b);
}
function lor(a, b) {
return BigInt(a) || BigInt(b);
}
function lnot(a) {
return !BigInt(a);
}
// Returns a buffer with Little Endian Representation
function toRprLE(buff, o, e, n8) {
const s = "0000000" + e.toString(16);
const v = new Uint32Array(buff.buffer, buff.byteOffset + o, n8/4);
const l = (((s.length-7)*4 - 1) >> 5)+1; // Number of 32bit words;
for (let i=0; i<l; i++) v[i] = parseInt(s.substring(s.length-8*i-8, s.length-8*i), 16);
for (let i=l; i<v.length; i++) v[i] = 0;
for (let i=v.length*4; i<n8; i++) buff[i] = toNumber$1(band(shiftRight(e, i*8), 0xFF));
}
// Returns a buffer with Big Endian Representation
function toRprBE(buff, o, e, n8) {
const s = "0000000" + e.toString(16);
const v = new DataView(buff.buffer, buff.byteOffset + o, n8);
const l = (((s.length-7)*4 - 1) >> 5)+1; // Number of 32bit words;
for (let i=0; i<l; i++) v.setUint32(n8-i*4 -4, parseInt(s.substring(s.length-8*i-8, s.length-8*i), 16), false);
for (let i=0; i<n8/4-l; i++) v[i] = 0;
}
// Pases a buffer with Little Endian Representation
function fromRprLE(buff, o, n8) {
n8 = n8 || buff.byteLength;
o = o || 0;
const v = new Uint32Array(buff.buffer, buff.byteOffset + o, n8/4);
const a = new Array(n8/4);
v.forEach( (ch,i) => a[a.length-i-1] = ch.toString(16).padStart(8,"0") );
return fromString(a.join(""), 16);
}
// Pases a buffer with Big Endian Representation
function fromRprBE(buff, o, n8) {
n8 = n8 || buff.byteLength;
o = o || 0;
const v = new DataView(buff.buffer, buff.byteOffset + o, n8);
const a = new Array(n8/4);
for (let i=0; i<n8/4; i++) {
a[i] = v.getUint32(i*4, false).toString(16).padStart(8, "0");
}
return fromString(a.join(""), 16);
}
function toString(a, radix) {
return a.toString(radix);
}
function toLEBuff(a) {
const buff = new Uint8Array(Math.floor((bitLength$6(a) - 1) / 8) +1);
toRprLE(buff, 0, a, buff.byteLength);
return buff;
}
const zero = e(0);
const one = e(1);
var _Scalar = /*#__PURE__*/Object.freeze({
__proto__: null,
abs: abs$1,
add: add,
band: band,
bitLength: bitLength$6,
bits: bits,
bor: bor,
bxor: bxor,
div: div,
e: e,
eq: eq,
exp: exp$1,
fromArray: fromArray,
fromRprBE: fromRprBE,
fromRprLE: fromRprLE,
fromString: fromString,
geq: geq,
gt: gt,
isNegative: isNegative$4,
isOdd: isOdd$5,
isZero: isZero$1,
land: land,
leq: leq,
lnot: lnot,
lor: lor,
lt: lt,
mod: mod,
mul: mul,
naf: naf,
neg: neg,
neq: neq,
one: one,
pow: pow,
shiftLeft: shiftLeft,
shiftRight: shiftRight,
shl: shl,
shr: shr,
square: square$2,
sub: sub,
toArray: toArray,
toLEBuff: toLEBuff,
toNumber: toNumber$1,
toRprBE: toRprBE,
toRprLE: toRprLE,
toString: toString,
zero: zero
});
/*
Copyright 2018 0kims association.
This file is part of snarkjs.
snarkjs 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.
snarkjs 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
snarkjs. If not, see <https://www.gnu.org/licenses/>.
*/
/*
This library does operations on polynomials with coefficients in a field F.
A polynomial P(x) = p0 + p1 * x + p2 * x^2 + ... + pn * x^n is represented
by the array [ p0, p1, p2, ... , pn ].
*/
class PolField {
constructor (F) {
this.F = F;
let rem = F.sqrt_t;
let s = F.sqrt_s;
const five = this.F.add(this.F.add(this.F.two, this.F.two), this.F.one);
this.w = new Array(s+1);
this.wi = new Array(s+1);
this.w[s] = this.F.pow(five, rem);
this.wi[s] = this.F.inv(this.w[s]);
let n=s-1;
while (n>=0) {
this.w[n] = this.F.square(this.w[n+1]);
this.wi[n] = this.F.square(this.wi[n+1]);
n--;
}
this.roots = [];
/* for (let i=0; i<16; i++) {
let r = this.F.one;
n = 1 << i;
const rootsi = new Array(n);
for (let j=0; j<n; j++) {
rootsi[j] = r;
r = this.F.mul(r, this.w[i]);
}
this.roots.push(rootsi);
}
*/
this._setRoots(15);
}
_setRoots(n) {
if (n > this.F.sqrt_s) n = this.s;
for (let i=n; (i>=0) && (!this.roots[i]); i--) {
let r = this.F.one;
const nroots = 1 << i;
const rootsi = new Array(nroots);
for (let j=0; j<nroots; j++) {
rootsi[j] = r;
r = this.F.mul(r, this.w[i]);
}
this.roots[i] = rootsi;
}
}
add(a, b) {
const m = Math.max(a.length, b.length);
const res = new Array(m);
for (let i=0; i<m; i++) {
res[i] = this.F.add(a[i] || this.F.zero, b[i] || this.F.zero);
}
return this.reduce(res);
}
double(a) {
return this.add(a,a);
}
sub(a, b) {
const m = Math.max(a.length, b.length);
const res = new Array(m);
for (let i=0; i<m; i++) {
res[i] = this.F.sub(a[i] || this.F.zero, b[i] || this.F.zero);
}
return this.reduce(res);
}
mulScalar(p, b) {
if (this.F.eq(b, this.F.zero)) return [];
if (this.F.eq(b, this.F.one)) return p;
const res = new Array(p.length);
for (let i=0; i<p.length; i++) {
res[i] = this.F.mul(p[i], b);
}
return res;
}
mul(a, b) {
if (a.length == 0) return [];
if (b.length == 0) return [];
if (a.length == 1) return this.mulScalar(b, a[0]);
if (b.length == 1) return this.mulScalar(a, b[0]);
if (b.length > a.length) {
[b, a] = [a, b];
}
if ((b.length <= 2) || (b.length < log2$2(a.length))) {
return this.mulNormal(a,b);
} else {
return this.mulFFT(a,b);
}
}
mulNormal(a, b) {
let res = [];
for (let i=0; i<b.length; i++) {
res = this.add(res, this.scaleX(this.mulScalar(a, b[i]), i) );
}
return res;
}
mulFFT(a,b) {
const longestN = Math.max(a.length, b.length);
const bitsResult = log2$2(longestN-1)+2;
this._setRoots(bitsResult);
const m = 1 << bitsResult;
const ea = this.extend(a,m);
const eb = this.extend(b,m);
const ta = __fft$1(this, ea, bitsResult, 0, 1);
const tb = __fft$1(this, eb, bitsResult, 0, 1);
const tres = new Array(m);
for (let i=0; i<m; i++) {
tres[i] = this.F.mul(ta[i], tb[i]);
}
const res = __fft$1(this, tres, bitsResult, 0, 1);
const twoinvm = this.F.inv( this.F.mulScalar(this.F.one, m) );
const resn = new Array(m);
for (let i=0; i<m; i++) {
resn[i] = this.F.mul(res[(m-i)%m], twoinvm);
}
return this.reduce(resn);
}
square(a) {
return this.mul(a,a);
}
scaleX(p, n) {
if (n==0) {
return p;
} else if (n>0) {
const z = new Array(n).fill(this.F.zero);
return z.concat(p);
} else {
if (-n >= p.length) return [];
return p.slice(-n);
}
}
eval2(p, x) {
let v = this.F.zero;
let ix = this.F.one;
for (let i=0; i<p.length; i++) {
v = this.F.add(v, this.F.mul(p[i], ix));
ix = this.F.mul(ix, x);
}
return v;
}
evaluate(p,x) {
const F = this.F;
if (p.length == 0) return F.zero;
const m = this._next2Power(p.length);
const ep = this.extend(p, m);
return _eval(ep, x, 0, 1, m);
function _eval(p, x, offset, step, n) {
if (n==1) return p[offset];
const newX = F.square(x);
const res= F.add(
_eval(p, newX, offset, step << 1, n >> 1),
F.mul(
x,
_eval(p, newX, offset+step , step << 1, n >> 1)));
return res;
}
}
lagrange(points) {
let roots = [this.F.one];
for (let i=0; i<points.length; i++) {
roots = this.mul(roots, [this.F.neg(points[i][0]), this.F.one]);
}
let sum = [];
for (let i=0; i<points.length; i++) {
let mpol = this.ruffini(roots, points[i][0]);
const factor =
this.F.mul(
this.F.inv(this.evaluate(mpol, points[i][0])),
points[i][1]);
mpol = this.mulScalar(mpol, factor);
sum = this.add(sum, mpol);
}
return sum;
}
fft(p) {
if (p.length <= 1) return p;
const bits = log2$2(p.length-1)+1;
this._setRoots(bits);
const m = 1 << bits;
const ep = this.extend(p, m);
const res = __fft$1(this, ep, bits, 0, 1);
return res;
}
fft2(p) {
if (p.length <= 1) return p;
const bits = log2$2(p.length-1)+1;
this._setRoots(bits);
const m = 1 << bits;
const ep = this.extend(p, m);
__bitReverse(ep, bits);
const res = __fft2(this, ep, bits);
return res;
}
ifft(p) {
if (p.length <= 1) return p;
const bits = log2$2(p.length-1)+1;
this._setRoots(bits);
const m = 1 << bits;
const ep = this.extend(p, m);
const res = __fft$1(this, ep, bits, 0, 1);
const twoinvm = this.F.inv( this.F.mulScalar(this.F.one, m) );
const resn = new Array(m);
for (let i=0; i<m; i++) {
resn[i] = this.F.mul(res[(m-i)%m], twoinvm);
}
return resn;
}
ifft2(p) {
if (p.length <= 1) return p;
const bits = log2$2(p.length-1)+1;
this._setRoots(bits);
const m = 1 << bits;
const ep = this.extend(p, m);
__bitReverse(ep, bits);
const res = __fft2(this, ep, bits);
const twoinvm = this.F.inv( this.F.mulScalar(this.F.one, m) );
const resn = new Array(m);
for (let i=0; i<m; i++) {
resn[i] = this.F.mul(res[(m-i)%m], twoinvm);
}
return resn;
}
_fft(pall, bits, offset, step) {
const n = 1 << bits;
if (n==1) {
return [ pall[offset] ];
}
const ndiv2 = n >> 1;
const p1 = this._fft(pall, bits-1, offset, step*2);
const p2 = this._fft(pall, bits-1, offset+step, step*2);
const out = new Array(n);
let m= this.F.one;
for (let i=0; i<ndiv2; i++) {
out[i] = this.F.add(p1[i], this.F.mul(m, p2[i]));
out[i+ndiv2] = this.F.sub(p1[i], this.F.mul(m, p2[i]));
m = this.F.mul(m, this.w[bits]);
}
return out;
}
extend(p, e) {
if (e == p.length) return p;
const z = new Array(e-p.length).fill(this.F.zero);
return p.concat(z);
}
reduce(p) {
if (p.length == 0) return p;
if (! this.F.eq(p[p.length-1], this.F.zero) ) return p;
let i=p.length-1;
while( i>0 && this.F.eq(p[i], this.F.zero) ) i--;
return p.slice(0, i+1);
}
eq(a, b) {
const pa = this.reduce(a);
const pb = this.reduce(b);
if (pa.length != pb.length) return false;
for (let i=0; i<pb.length; i++) {
if (!this.F.eq(pa[i], pb[i])) return false;
}
return true;
}
ruffini(p, r) {
const res = new Array(p.length-1);
res[res.length-1] = p[p.length-1];
for (let i = res.length-2; i>=0; i--) {
res[i] = this.F.add(this.F.mul(res[i+1], r), p[i+1]);
}
return res;
}
_next2Power(v) {
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;
return v;
}
toString(p) {
const ap = this.normalize(p);
let S = "";
for (let i=ap.length-1; i>=0; i--) {
if (!this.F.eq(p[i], this.F.zero)) {
if (S!="") S += " + ";
S = S + p[i].toString(10);
if (i>0) {
S = S + "x";
if (i>1) {
S = S + "^" +i;
}
}
}
}
return S;
}
normalize(p) {
const res = new Array(p.length);
for (let i=0; i<p.length; i++) {
res[i] = this.F.normalize(p[i]);
}
return res;
}
_reciprocal(p, bits) {
const k = 1 << bits;
if (k==1) {
return [ this.F.inv(p[0]) ];
}
const np = this.scaleX(p, -k/2);
const q = this._reciprocal(np, bits-1);
const a = this.scaleX(this.double(q), 3*k/2-2);
const b = this.mul( this.square(q), p);
return this.scaleX(this.sub(a,b), -(k-2));
}
// divides x^m / v
_div2(m, v) {
const kbits = log2$2(v.length-1)+1;
const k = 1 << kbits;
const scaleV = k - v.length;
// rec = x^(k - 2) / v* x^scaleV =>
// rec = x^(k-2-scaleV)/ v
//
// res = x^m/v = x^(m + (2*k-2 - scaleV) - (2*k-2 - scaleV)) /v =>
// res = rec * x^(m - (2*k-2 - scaleV)) =>
// res = rec * x^(m - 2*k + 2 + scaleV)
const rec = this._reciprocal(this.scaleX(v, scaleV), kbits);
const res = this.scaleX(rec, m - 2*k + 2 + scaleV);
return res;
}
div(_u, _v) {
if (_u.length < _v.length) return [];
const kbits = log2$2(_v.length-1)+1;
const k = 1 << kbits;
const u = this.scaleX(_u, k-_v.length);
const v = this.scaleX(_v, k-_v.length);
const n = v.length-1;
let m = u.length-1;
const s = this._reciprocal(v, kbits);
let t;
if (m>2*n) {
t = this.sub(this.scaleX([this.F.one], 2*n), this.mul(s, v));
}
let q = [];
let rem = u;
let us, ut;
let finish = false;
while (!finish) {
us = this.mul(rem, s);
q = this.add(q, this.scaleX(us, -2*n));
if ( m > 2*n ) {
ut = this.mul(rem, t);
rem = this.scaleX(ut, -2*n);
m = rem.length-1;
} else {
finish = true;
}
}
return q;
}
// returns the ith nth-root of one
oneRoot(n, i) {
let nbits = log2$2(n-1)+1;
let res = this.F.one;
let r = i;
if(i>=n) {
throw new Error("Given 'i' should be lower than 'n'");
}
else if (1<<nbits !== n) {
throw new Error(`Internal errlr: ${n} should equal ${1<<nbits}`);
}
while (r>0) {
if (r & 1 == 1) {
res = this.F.mul(res, this.w[nbits]);
}
r = r >> 1;
nbits --;
}
return res;
}
computeVanishingPolinomial(bits, t) {
const m = 1 << bits;
return this.F.sub(this.F.pow(t, m), this.F.one);
}
evaluateLagrangePolynomials(bits, t) {
const m= 1 << bits;
const tm = this.F.pow(t, m);
const u= new Array(m).fill(this.F.zero);
this._setRoots(bits);
const omega = this.w[bits];
if (this.F.eq(tm, this.F.one)) {
for (let i = 0; i < m; i++) {
if (this.F.eq(this.roots[bits][0],t)) { // i.e., t equals omega^i
u[i] = this.F.one;
return u;
}
}
}
const z = this.F.sub(tm, this.F.one);
// let l = this.F.mul(z, this.F.pow(this.F.twoinv, m));
let l = this.F.mul(z, this.F.inv(this.F.e(m)));
for (let i = 0; i < m; i++) {
u[i] = this.F.mul(l, this.F.inv(this.F.sub(t,this.roots[bits][i])));
l = this.F.mul(l, omega);
}
return u;
}
log2(V) {
return log2$2(V);
}
}
function log2$2( 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 ) );
}
function __fft$1(PF, pall, bits, offset, step) {
const n = 1 << bits;
if (n==1) {
return [ pall[offset] ];
} else if (n==2) {
return [
PF.F.add(pall[offset], pall[offset + step]),
PF.F.sub(pall[offset], pall[offset + step])];
}
const ndiv2 = n >> 1;
const p1 = __fft$1(PF, pall, bits-1, offset, step*2);
const p2 = __fft$1(PF, pall, bits-1, offset+step, step*2);
const out = new Array(n);
for (let i=0; i<ndiv2; i++) {
out[i] = PF.F.add(p1[i], PF.F.mul(PF.roots[bits][i], p2[i]));
out[i+ndiv2] = PF.F.sub(p1[i], PF.F.mul(PF.roots[bits][i], p2[i]));
}
return out;
}
function __fft2(PF, pall, bits) {
const n = 1 << bits;
if (n==1) {
return [ pall[0] ];
}
const ndiv2 = n >> 1;
const p1 = __fft2(PF, pall.slice(0, ndiv2), bits-1);
const p2 = __fft2(PF, pall.slice(ndiv2), bits-1);
const out = new Array(n);
for (let i=0; i<ndiv2; i++) {
out[i] = PF.F.add(p1[i], PF.F.mul(PF.roots[bits][i], p2[i]));
out[i+ndiv2] = PF.F.sub(p1[i], PF.F.mul(PF.roots[bits][i], p2[i]));
}
return out;
}
const _revTable$1 = [];
for (let i=0; i<256; i++) {
_revTable$1[i] = _revSlow$1(i, 8);
}
function _revSlow$1(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;
}
function rev(idx, bits) {
return (
_revTable$1[idx >>> 24] |
(_revTable$1[(idx >>> 16) & 0xFF] << 8) |
(_revTable$1[(idx >>> 8) & 0xFF] << 16) |
(_revTable$1[idx & 0xFF] << 24)
) >>> (32-bits);
}
function __bitReverse(p, bits) {
for (let k=0; k<p.length; k++) {
const r = rev(k, bits);
if (r>k) {
const tmp= p[k];
p[k] = p[r];
p[r] = tmp;
}
}
}
/*
Copyright 2018 0kims association.
This file is part of snarkjs.
snarkjs 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.
snarkjs 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
snarkjs. If not, see <https://www.gnu.org/licenses/>.
*/
function mulScalar(F, base, e) {
let res;
if (isZero$1(e)) return F.zero;
const n = naf(e);
if (n[n.length-1] == 1) {
res = base;
} else if (n[n.length-1] == -1) {
res = F.neg(base);
} else {
throw new Error("invlaud NAF");
}
for (let i=n.length-2; i>=0; i--) {
res = F.double(res);
if (n[i] == 1) {
res = F.add(res, base);
} else if (n[i] == -1) {
res = F.sub(res, base);
}
}
return res;
}
/*
exports.mulScalar = (F, base, e) =>{
let res = F.zero;
let rem = bigInt(e);
let exp = base;
while (! rem.eq(bigInt.zero)) {
if (rem.and(bigInt.one).eq(bigInt.one)) {
res = F.add(res, exp);
}
exp = F.double(exp);
rem = rem.shiftRight(1);
}
return res;
};
*/
function exp(F, base, e) {
if (isZero$1(e)) return F.one;
const n = bits(e);
if (n.length==0) return F.one;
let res = base;
for (let i=n.length-2; i>=0; i--) {
res = F.square(res);
if (n[i]) {
res = F.mul(res, base);
}
}
return res;
}
// Check here: https://eprint.iacr.org/2012/685.pdf
function buildSqrt (F) {
if ((F.m % 2) == 1) {
if (eq(mod(F.p, 4), 1 )) {
if (eq(mod(F.p, 8), 1 )) {
if (eq(mod(F.p, 16), 1 )) {
// alg7_muller(F);
alg5_tonelliShanks(F);
} else if (eq(mod(F.p, 16), 9 )) {
alg4_kong(F);
} else {
throw new Error("Field withot sqrt");
}
} else if (eq(mod(F.p, 8), 5 )) {
alg3_atkin(F);
} else {
throw new Error("Field withot sqrt");
}
} else if (eq(mod(F.p, 4), 3 )) {
alg2_shanks(F);
}
} else {
const pm2mod4 = mod(pow(F.p, F.m/2), 4);
if (pm2mod4 == 1) {
alg10_adj(F);
} else if (pm2mod4 == 3) {
alg9_adj(F);
} else {
alg8_complex(F);
}
}
}
function alg5_tonelliShanks(F) {
F.sqrt_q = pow(F.p, F.m);
F.sqrt_s = 0;
F.sqrt_t = sub(F.sqrt_q, 1);
while (!isOdd$5(F.sqrt_t)) {
F.sqrt_s = F.sqrt_s + 1;
F.sqrt_t = div(F.sqrt_t, 2);
}
let c0 = F.one;
while (F.eq(c0, F.one)) {
const c = F.random();
F.sqrt_z = F.pow(c, F.sqrt_t);
c0 = F.pow(F.sqrt_z, 2 ** (F.sqrt_s-1) );
}
F.sqrt_tm1d2 = div(sub(F.sqrt_t, 1),2);
F.sqrt = function(a) {
const F=this;
if (F.isZero(a)) return F.zero;
let w = F.pow(a, F.sqrt_tm1d2);
const a0 = F.pow( F.mul(F.square(w), a), 2 ** (F.sqrt_s-1) );
if (F.eq(a0, F.negone)) return null;
let v = F.sqrt_s;
let x = F.mul(a, w);
let b = F.mul(x, w);
let z = F.sqrt_z;
while (!F.eq(b, F.one)) {
let b2k = F.square(b);
let k=1;
while (!F.eq(b2k, F.one)) {
b2k = F.square(b2k);
k++;
}
w = z;
for (let i=0; i<v-k-1; i++) {
w = F.square(w);
}
z = F.square(w);
b = F.mul(b, z);
x = F.mul(x, w);
v = k;
}
return F.geq(x, F.zero) ? x : F.neg(x);
};
}
function alg4_kong(F) {
F.sqrt = function() {
throw new Error("Sqrt alg 4 not implemented");
};
}
function alg3_atkin(F) {
F.sqrt = function() {
throw new Error("Sqrt alg 3 not implemented");
};
}
function alg2_shanks(F) {
F.sqrt_q = pow(F.p, F.m);
F.sqrt_e1 = div( sub(F.sqrt_q, 3) , 4);
F.sqrt = function(a) {
if (this.isZero(a)) return this.zero;
// Test that have solution
const a1 = this.pow(a, this.sqrt_e1);
const a0 = this.mul(this.square(a1), a);
if ( this.eq(a0, this.negone) ) return null;
const x = this.mul(a1, a);
return F.geq(x, F.zero) ? x : F.neg(x);
};
}
function alg10_adj(F) {
F.sqrt = function() {
throw new Error("Sqrt alg 10 not implemented");
};
}
function alg9_adj(F) {
F.sqrt_q = pow(F.p, F.m/2);
F.sqrt_e34 = div( sub(F.sqrt_q, 3) , 4);
F.sqrt_e12 = div( sub(F.sqrt_q, 1) , 2);
F.frobenius = function(n, x) {
if ((n%2) == 1) {
return F.conjugate(x);
} else {
return x;
}
};
F.sqrt = function(a) {
const F = this;
const a1 = F.pow(a, F.sqrt_e34);
const alfa = F.mul(F.square(a1), a);
const a0 = F.mul(F.frobenius(1, alfa), alfa);
if (F.eq(a0, F.negone)) return null;
const x0 = F.mul(a1, a);
let x;
if (F.eq(alfa, F.negone)) {
x = F.mul(x0, [F.F.zero, F.F.one]);
} else {
const b = F.pow(F.add(F.one, alfa), F.sqrt_e12);
x = F.mul(b, x0);
}
return F.geq(x, F.zero) ? x : F.neg(x);
};
}
function alg8_complex(F) {
F.sqrt = function() {
throw new Error("Sqrt alg 8 not implemented");
};
}
function quarterRound(st, a, b, c, d) {
st[a] = (st[a] + st[b]) >>> 0;
st[d] = (st[d] ^ st[a]) >>> 0;
st[d] = ((st[d] << 16) | ((st[d]>>>16) & 0xFFFF)) >>> 0;
st[c] = (st[c] + st[d]) >>> 0;
st[b] = (st[b] ^ st[c]) >>> 0;
st[b] = ((st[b] << 12) | ((st[b]>>>20) & 0xFFF)) >>> 0;
st[a] = (st[a] + st[b]) >>> 0;
st[d] = (st[d] ^ st[a]) >>> 0;
st[d] = ((st[d] << 8) | ((st[d]>>>24) & 0xFF)) >>> 0;
st[c] = (st[c] + st[d]) >>> 0;
st[b] = (st[b] ^ st[c]) >>> 0;
st[b] = ((st[b] << 7) | ((st[b]>>>25) & 0x7F)) >>> 0;
}
function doubleRound(st) {
quarterRound(st, 0, 4, 8,12);
quarterRound(st, 1, 5, 9,13);
quarterRound(st, 2, 6,10,14);
quarterRound(st, 3, 7,11,15);
quarterRound(st, 0, 5,10,15);
quarterRound(st, 1, 6,11,12);
quarterRound(st, 2, 7, 8,13);
quarterRound(st, 3, 4, 9,14);
}
class ChaCha {
constructor(seed) {
seed = seed || [0,0,0,0,0,0,0,0];
this.state = [
0x61707865,
0x3320646E,
0x79622D32,
0x6B206574,
seed[0],
seed[1],
seed[2],
seed[3],
seed[4],
seed[5],
seed[6],
seed[7],
0,
0,
0,
0
];
this.idx = 16;
this.buff = new Array(16);
}
nextU32() {
if (this.idx == 16) this.update();
return this.buff[this.idx++];
}
nextU64() {
return add(mul(this.nextU32(), 0x100000000), this.nextU32());
}
nextBool() {
return (this.nextU32() & 1) == 1;
}
update() {
// Copy the state
for (let i=0; i<16; i++) this.buff[i] = this.state[i];
// Apply the rounds
for (let i=0; i<10; i++) doubleRound(this.buff);
// Add to the initial
for (let i=0; i<16; i++) this.buff[i] = (this.buff[i] + this.state[i]) >>> 0;
this.idx = 0;
this.state[12] = (this.state[12] + 1) >>> 0;
if (this.state[12] != 0) return;
this.state[13] = (this.state[13] + 1) >>> 0;
if (this.state[13] != 0) return;
this.state[14] = (this.state[14] + 1) >>> 0;
if (this.state[14] != 0) return;
this.state[15] = (this.state[15] + 1) >>> 0;
}
}
function getRandomBytes(n) {
let array = new Uint8Array(n);
{ // Browser
if (typeof globalThis.crypto !== "undefined") { // Supported
globalThis.crypto.getRandomValues(array);
} else { // fallback
for (let i=0; i<n; i++) {
array[i] = (Math.random()*4294967296)>>>0;
}
}
}
return array;
}
function getRandomSeed() {
const arr = getRandomBytes(32);
const arrV = new Uint32Array(arr.buffer);
const seed = [];
for (let i=0; i<8; i++) {
seed.push(arrV[i]);
}
return seed;
}
let threadRng = null;
function getThreadRng() {
if (threadRng) return threadRng;
threadRng = new ChaCha(getRandomSeed());
return threadRng;
}
/*
Copyright 2018 0kims association.
This file is part of snarkjs.
snarkjs 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.
snarkjs 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
snarkjs. If not, see <https://www.gnu.org/licenses/>.
*/
/*
This library does operations on polynomials with coefficients in a field F.
A polynomial P(x) = p0 + p1 * x + p2 * x^2 + ... + pn * x^n is represented
by the array [ p0, p1, p2, ... , pn ].
*/
class FFT {
constructor (G, F, opMulGF) {
this.F = F;
this.G = G;
this.opMulGF = opMulGF;
let rem = F.sqrt_t || F.t;
let s = F.sqrt_s || F.s;
let nqr = F.one;
while (F.eq(F.pow(nqr, F.half), F.one)) nqr = F.add(nqr, F.one);
this.w = new Array(s+1);
this.wi = new Array(s+1);
this.w[s] = this.F.pow(nqr, rem);
this.wi[s] = this.F.inv(this.w[s]);
let n=s-1;
while (n>=0) {
this.w[n] = this.F.square(this.w[n+1]);
this.wi[n] = this.F.square(this.wi[n+1]);
n--;
}
this.roots = [];
/*
for (let i=0; i<16; i++) {
let r = this.F.one;
n = 1 << i;
const rootsi = new Array(n);
for (let j=0; j<n; j++) {
rootsi[j] = r;
r = this.F.mul(r, this.w[i]);
}
this.roots.push(rootsi);
}
*/
this._setRoots(Math.min(s, 15));
}
_setRoots(n) {
for (let i=n; (i>=0) && (!this.roots[i]); i--) {
let r = this.F.one;
const nroots = 1 << i;
const rootsi = new Array(nroots);
for (let j=0; j<nroots; j++) {
rootsi[j] = r;
r = this.F.mul(r, this.w[i]);
}
this.roots[i] = rootsi;
}
}
fft(p) {
if (p.length <= 1) return p;
const bits = log2$1(p.length-1)+1;
this._setRoots(bits);
const m = 1 << bits;
if (p.length != m) {
throw new Error("Size must be multiple of 2");
}
const res = __fft(this, p, bits, 0, 1);
return res;
}
ifft(p) {
if (p.length <= 1) return p;
const bits = log2$1(p.length-1)+1;
this._setRoots(bits);
const m = 1 << bits;
if (p.length != m) {
throw new Error("Size must be multiple of 2");
}
const res = __fft(this, p, bits, 0, 1);
const twoinvm = this.F.inv( this.F.mulScalar(this.F.one, m) );
const resn = new Array(m);
for (let i=0; i<m; i++) {
resn[i] = this.opMulGF(res[(m-i)%m], twoinvm);
}
return resn;
}
}
function log2$1( 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 ) );
}
function __fft(PF, pall, bits, offset, step) {
const n = 1 << bits;
if (n==1) {
return [ pall[offset] ];
} else if (n==2) {
return [
PF.G.add(pall[offset], pall[offset + step]),
PF.G.sub(pall[offset], pall[offset + step])];
}
const ndiv2 = n >> 1;
const p1 = __fft(PF, pall, bits-1, offset, step*2);
const p2 = __fft(PF, pall, bits-1, offset+step, step*2);
const out = new Array(n);
for (let i=0; i<ndiv2; i++) {
out[i] = PF.G.add(p1[i], PF.opMulGF(p2[i], PF.roots[bits][i]));
out[i+ndiv2] = PF.G.sub(p1[i], PF.opMulGF(p2[i], PF.roots[bits][i]));
}
return out;
}
/* global BigInt */
class ZqField {
constructor(p) {
this.type="F1";
this.one = BigInt(1);
this.zero = BigInt(0);
this.p = BigInt(p);
this.m = 1;
this.negone = this.p-this.one;
this.two = BigInt(2);
this.half = this.p >> this.one;
this.bitLength = bitLength$6(this.p);
this.mask = (this.one << BigInt(this.bitLength)) - this.one;
this.n64 = Math.floor((this.bitLength - 1) / 64)+1;
this.n32 = this.n64*2;
this.n8 = this.n64*8;
this.R = this.e(this.one << BigInt(this.n64*64));
this.Ri = this.inv(this.R);
const e = this.negone >> this.one;
this.nqr = this.two;
let r = this.pow(this.nqr, e);
while (!this.eq(r, this.negone)) {
this.nqr = this.nqr + this.one;
r = this.pow(this.nqr, e);
}
this.s = 0;
this.t = this.negone;
while ((this.t & this.one) == this.zero) {
this.s = this.s + 1;
this.t = this.t >> this.one;
}
this.nqr_to_t = this.pow(this.nqr, this.t);
buildSqrt(this);
this.FFT = new FFT(this, this, this.mul.bind(this));
this.fft = this.FFT.fft.bind(this.FFT);
this.ifft = this.FFT.ifft.bind(this.FFT);
this.w = this.FFT.w;
this.wi = this.FFT.wi;
this.shift = this.square(this.nqr);
this.k = this.exp(this.nqr, 2**this.s);
}
e(a,b) {
let res;
if (!b) {
res = BigInt(a);
} else if (b==16) {
res = BigInt("0x"+a);
}
if (res < 0) {
let nres = -res;
if (nres >= this.p) nres = nres % this.p;
return this.p - nres;
} else {
return (res>= this.p) ? res%this.p : res;
}
}
add(a, b) {
const res = a + b;
return res >= this.p ? res-this.p : res;
}
sub(a, b) {
return (a >= b) ? a-b : this.p-b+a;
}
neg(a) {
return a ? this.p-a : a;
}
mul(a, b) {
return (a*b)%this.p;
}
mulScalar(base, s) {
return (base * this.e(s)) % this.p;
}
square(a) {
return (a*a) % this.p;
}
eq(a, b) {
return a==b;
}
neq(a, b) {
return a!=b;
}
lt(a, b) {
const aa = (a > this.half) ? a - this.p : a;
const bb = (b > this.half) ? b - this.p : b;
return aa < bb;
}
gt(a, b) {
const aa = (a > this.half) ? a - this.p : a;
const bb = (b > this.half) ? b - this.p : b;
return aa > bb;
}
leq(a, b) {
const aa = (a > this.half) ? a - this.p : a;
const bb = (b > this.half) ? b - this.p : b;
return aa <= bb;
}
geq(a, b) {
const aa = (a > this.half) ? a - this.p : a;
const bb = (b > this.half) ? b - this.p : b;
return aa >= bb;
}
div(a, b) {
return this.mul(a, this.inv(b));
}
idiv(a, b) {
if (!b) throw new Error("Division by zero");
return a / b;
}
inv(a) {
if (!a) throw new Error("Division by zero");
let t = this.zero;
let r = this.p;
let newt = this.one;
let newr = a % this.p;
while (newr) {
let q = r/newr;
[t, newt] = [newt, t-q*newt];
[r, newr] = [newr, r-q*newr];
}
if (t<this.zero) t += this.p;
return t;
}
mod(a, b) {
return a % b;
}
pow(b, e) {
return exp(this, b, e);
}
exp(b, e) {
return exp(this, b, e);
}
band(a, b) {
const res = ((a & b) & this.mask);
return res >= this.p ? res-this.p : res;
}
bor(a, b) {
const res = ((a | b) & this.mask);
return res >= this.p ? res-this.p : res;
}
bxor(a, b) {
const res = ((a ^ b) & this.mask);
return res >= this.p ? res-this.p : res;
}
bnot(a) {
const res = a ^ this.mask;
return res >= this.p ? res-this.p : res;
}
shl(a, b) {
if (Number(b) < this.bitLength) {
const res = (a << b) & this.mask;
return res >= this.p ? res-this.p : res;
} else {
const nb = this.p - b;
if (Number(nb) < this.bitLength) {
return a >> nb;
} else {
return this.zero;
}
}
}
shr(a, b) {
if (Number(b) < this.bitLength) {
return a >> b;
} else {
const nb = this.p - b;
if (Number(nb) < this.bitLength) {
const res = (a << nb) & this.mask;
return res >= this.p ? res-this.p : res;
} else {
return 0;
}
}
}
land(a, b) {
return (a && b) ? this.one : this.zero;
}
lor(a, b) {
return (a || b) ? this.one : this.zero;
}
lnot(a) {
return (a) ? this.zero : this.one;
}
sqrt_old(n) {
if (n == this.zero) return this.zero;
// Test that have solution
const res = this.pow(n, this.negone >> this.one);
if ( res != this.one ) return null;
let m = this.s;
let c = this.nqr_to_t;
let t = this.pow(n, this.t);
let r = this.pow(n, this.add(this.t, this.one) >> this.one );
while ( t != this.one ) {
let sq = this.square(t);
let i = 1;
while (sq != this.one ) {
i++;
sq = this.square(sq);
}
// b = c ^ m-i-1
let b = c;
for (let j=0; j< m-i-1; j ++) b = this.square(b);
m = i;
c = this.square(b);
t = this.mul(t, c);
r = this.mul(r, b);
}
if (r > (this.p >> this.one)) {
r = this.neg(r);
}
return r;
}
normalize(a, b) {
a = BigInt(a,b);
if (a < 0) {
let na = -a;
if (na >= this.p) na = na % this.p;
return this.p - na;
} else {
return (a>= this.p) ? a%this.p : a;
}
}
random() {
const nBytes = (this.bitLength*2 / 8);
let res =this.zero;
for (let i=0; i<nBytes; i++) {
res = (res << BigInt(8)) + BigInt(getRandomBytes(1)[0]);
}
return res % this.p;
}
toString(a, base) {
base = base || 10;
let vs;
if ((a > this.half)&&(base == 10)) {
const v = this.p-a;
vs = "-"+v.toString(base);
} else {
vs = a.toString(base);
}
return vs;
}
isZero(a) {
return a == this.zero;
}
fromRng(rng) {
let v;
do {
v=this.zero;
for (let i=0; i<this.n64; i++) {
v += rng.nextU64() << BigInt(64 *i);
}
v &= this.mask;
} while (v >= this.p);
v = (v * this.Ri) % this.p; // Convert from montgomery
return v;
}
fft(a) {
return this.FFT.fft(a);
}
ifft(a) {
return this.FFT.ifft(a);
}
// Returns a buffer with Little Endian Representation
toRprLE(buff, o, e) {
toRprLE(buff, o, e, this.n64*8);
}
// Returns a buffer with Big Endian Representation
toRprBE(buff, o, e) {
toRprBE(buff, o, e, this.n64*8);
}
// Returns a buffer with Big Endian Montgomery Representation
toRprBEM(buff, o, e) {
return this.toRprBE(buff, o, this.mul(this.R, e));
}
toRprLEM(buff, o, e) {
return this.toRprLE(buff, o, this.mul(this.R, e));
}
// Pases a buffer with Little Endian Representation
fromRprLE(buff, o) {
return fromRprLE(buff, o, this.n8);
}
// Pases a buffer with Big Endian Representation
fromRprBE(buff, o) {
return fromRprBE(buff, o, this.n8);
}
fromRprLEM(buff, o) {
return this.mul(this.fromRprLE(buff, o), this.Ri);
}
fromRprBEM(buff, o) {
return this.mul(this.fromRprBE(buff, o), this.Ri);
}
toObject(a) {
return a;
}
}
/*
Copyright 2018 0kims association.
This file is part of snarkjs.
snarkjs 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.
snarkjs 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
snarkjs. If not, see <https://www.gnu.org/licenses/>.
*/
class F2Field {
constructor(F, nonResidue) {
this.type="F2";
this.F = F;
this.zero = [this.F.zero, this.F.zero];
this.one = [this.F.one, this.F.zero];
this.negone = this.neg(this.one);
this.nonResidue = nonResidue;
this.m = F.m*2;
this.p = F.p;
this.n64 = F.n64*2;
this.n32 = this.n64*2;
this.n8 = this.n64*8;
buildSqrt(this);
}
_mulByNonResidue(a) {
return this.F.mul(this.nonResidue, a);
}
copy(a) {
return [this.F.copy(a[0]), this.F.copy(a[1])];
}
add(a, b) {
return [
this.F.add(a[0], b[0]),
this.F.add(a[1], b[1])
];
}
double(a) {
return this.add(a,a);
}
sub(a, b) {
return [
this.F.sub(a[0], b[0]),
this.F.sub(a[1], b[1])
];
}
neg(a) {
return this.sub(this.zero, a);
}
conjugate(a) {
return [
a[0],
this.F.neg(a[1])
];
}
mul(a, b) {
const aA = this.F.mul(a[0] , b[0]);
const bB = this.F.mul(a[1] , b[1]);
return [
this.F.add( aA , this._mulByNonResidue(bB)),
this.F.sub(
this.F.mul(
this.F.add(a[0], a[1]),
this.F.add(b[0], b[1])),
this.F.add(aA, bB))];
}
inv(a) {
const t0 = this.F.square(a[0]);
const t1 = this.F.square(a[1]);
const t2 = this.F.sub(t0, this._mulByNonResidue(t1));
const t3 = this.F.inv(t2);
return [
this.F.mul(a[0], t3),
this.F.neg(this.F.mul( a[1], t3)) ];
}
div(a, b) {
return this.mul(a, this.inv(b));
}
square(a) {
const ab = this.F.mul(a[0] , a[1]);
/*
[
(a + b) * (a + non_residue * b) - ab - non_residue * ab,
ab + ab
];
*/
return [
this.F.sub(
this.F.mul(
this.F.add(a[0], a[1]) ,
this.F.add(
a[0] ,
this._mulByNonResidue(a[1]))),
this.F.add(
ab,
this._mulByNonResidue(ab))),
this.F.add(ab, ab)
];
}
isZero(a) {
return this.F.isZero(a[0]) && this.F.isZero(a[1]);
}
eq(a, b) {
return this.F.eq(a[0], b[0]) && this.F.eq(a[1], b[1]);
}
mulScalar(base, e) {
return mulScalar(this, base, e);
}
pow(base, e) {
return exp(this, base, e);
}
exp(base, e) {
return exp(this, base, e);
}
toString(a) {
return `[ ${this.F.toString(a[0])} , ${this.F.toString(a[1])} ]`;
}
fromRng(rng) {
const c0 = this.F.fromRng(rng);
const c1 = this.F.fromRng(rng);
return [c0, c1];
}
gt(a, b) {
if (this.F.gt(a[0], b[0])) return true;
if (this.F.gt(b[0], a[0])) return false;
if (this.F.gt(a[1], b[1])) return true;
return false;
}
geq(a, b) {
return this.gt(a, b) || this.eq(a, b);
}
lt(a, b) {
return !this.geq(a,b);
}
leq(a, b) {
return !this.gt(a,b);
}
neq(a, b) {
return !this.eq(a,b);
}
random() {
return [this.F.random(), this.F.random()];
}
toRprLE(buff, o, e) {
this.F.toRprLE(buff, o, e[0]);
this.F.toRprLE(buff, o+this.F.n8, e[1]);
}
toRprBE(buff, o, e) {
this.F.toRprBE(buff, o, e[1]);
this.F.toRprBE(buff, o+this.F.n8, e[0]);
}
toRprLEM(buff, o, e) {
this.F.toRprLEM(buff, o, e[0]);
this.F.toRprLEM(buff, o+this.F.n8, e[1]);
}
toRprBEM(buff, o, e) {
this.F.toRprBEM(buff, o, e[1]);
this.F.toRprBEM(buff, o+this.F.n8, e[0]);
}
fromRprLE(buff, o) {
o = o || 0;
const c0 = this.F.fromRprLE(buff, o);
const c1 = this.F.fromRprLE(buff, o+this.F.n8);
return [c0, c1];
}
fromRprBE(buff, o) {
o = o || 0;
const c1 = this.F.fromRprBE(buff, o);
const c0 = this.F.fromRprBE(buff, o+this.F.n8);
return [c0, c1];
}
fromRprLEM(buff, o) {
o = o || 0;
const c0 = this.F.fromRprLEM(buff, o);
const c1 = this.F.fromRprLEM(buff, o+this.F.n8);
return [c0, c1];
}
fromRprBEM(buff, o) {
o = o || 0;
const c1 = this.F.fromRprBEM(buff, o);
const c0 = this.F.fromRprBEM(buff, o+this.F.n8);
return [c0, c1];
}
toObject(a) {
return a;
}
}
/*
Copyright 2018 0kims association.
This file is part of snarkjs.
snarkjs 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.
snarkjs 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
snarkjs. If not, see <https://www.gnu.org/licenses/>.
*/
class F3Field {
constructor(F, nonResidue) {
this.type="F3";
this.F = F;
this.zero = [this.F.zero, this.F.zero, this.F.zero];
this.one = [this.F.one, this.F.zero, this.F.zero];
this.negone = this.neg(this.one);
this.nonResidue = nonResidue;
this.m = F.m*3;
this.p = F.p;
this.n64 = F.n64*3;
this.n32 = this.n64*2;
this.n8 = this.n64*8;
}
_mulByNonResidue(a) {
return this.F.mul(this.nonResidue, a);
}
copy(a) {
return [this.F.copy(a[0]), this.F.copy(a[1]), this.F.copy(a[2])];
}
add(a, b) {
return [
this.F.add(a[0], b[0]),
this.F.add(a[1], b[1]),
this.F.add(a[2], b[2])
];
}
double(a) {
return this.add(a,a);
}
sub(a, b) {
return [
this.F.sub(a[0], b[0]),
this.F.sub(a[1], b[1]),
this.F.sub(a[2], b[2])
];
}
neg(a) {
return this.sub(this.zero, a);
}
mul(a, b) {
const aA = this.F.mul(a[0] , b[0]);
const bB = this.F.mul(a[1] , b[1]);
const cC = this.F.mul(a[2] , b[2]);
return [
this.F.add(
aA,
this._mulByNonResidue(
this.F.sub(
this.F.mul(
this.F.add(a[1], a[2]),
this.F.add(b[1], b[2])),
this.F.add(bB, cC)))), // aA + non_residue*((b+c)*(B+C)-bB-cC),
this.F.add(
this.F.sub(
this.F.mul(
this.F.add(a[0], a[1]),
this.F.add(b[0], b[1])),
this.F.add(aA, bB)),
this._mulByNonResidue( cC)), // (a+b)*(A+B)-aA-bB+non_residue*cC
this.F.add(
this.F.sub(
this.F.mul(
this.F.add(a[0], a[2]),
this.F.add(b[0], b[2])),
this.F.add(aA, cC)),
bB)]; // (a+c)*(A+C)-aA+bB-cC)
}
inv(a) {
const t0 = this.F.square(a[0]); // t0 = a^2 ;
const t1 = this.F.square(a[1]); // t1 = b^2 ;
const t2 = this.F.square(a[2]); // t2 = c^2;
const t3 = this.F.mul(a[0],a[1]); // t3 = ab
const t4 = this.F.mul(a[0],a[2]); // t4 = ac
const t5 = this.F.mul(a[1],a[2]); // t5 = bc;
// c0 = t0 - non_residue * t5;
const c0 = this.F.sub(t0, this._mulByNonResidue(t5));
// c1 = non_residue * t2 - t3;
const c1 = this.F.sub(this._mulByNonResidue(t2), t3);
const c2 = this.F.sub(t1, t4); // c2 = t1-t4
// t6 = (a * c0 + non_residue * (c * c1 + b * c2)).inv();
const t6 =
this.F.inv(
this.F.add(
this.F.mul(a[0], c0),
this._mulByNonResidue(
this.F.add(
this.F.mul(a[2], c1),
this.F.mul(a[1], c2)))));
return [
this.F.mul(t6, c0), // t6*c0
this.F.mul(t6, c1), // t6*c1
this.F.mul(t6, c2)]; // t6*c2
}
div(a, b) {
return this.mul(a, this.inv(b));
}
square(a) {
const s0 = this.F.square(a[0]); // s0 = a^2
const ab = this.F.mul(a[0], a[1]); // ab = a*b
const s1 = this.F.add(ab, ab); // s1 = 2ab;
const s2 = this.F.square(
this.F.add(this.F.sub(a[0],a[1]), a[2])); // s2 = (a - b + c)^2;
const bc = this.F.mul(a[1],a[2]); // bc = b*c
const s3 = this.F.add(bc, bc); // s3 = 2*bc
const s4 = this.F.square(a[2]); // s4 = c^2
return [
this.F.add(
s0,
this._mulByNonResidue(s3)), // s0 + non_residue * s3,
this.F.add(
s1,
this._mulByNonResidue(s4)), // s1 + non_residue * s4,
this.F.sub(
this.F.add( this.F.add(s1, s2) , s3 ),
this.F.add(s0, s4))]; // s1 + s2 + s3 - s0 - s4
}
isZero(a) {
return this.F.isZero(a[0]) && this.F.isZero(a[1]) && this.F.isZero(a[2]);
}
eq(a, b) {
return this.F.eq(a[0], b[0]) && this.F.eq(a[1], b[1]) && this.F.eq(a[2], b[2]);
}
affine(a) {
return [this.F.affine(a[0]), this.F.affine(a[1]), this.F.affine(a[2])];
}
mulScalar(base, e) {
return mulScalar(this, base, e);
}
pow(base, e) {
return exp(this, base, e);
}
exp(base, e) {
return exp(this, base, e);
}
toString(a) {
return `[ ${this.F.toString(a[0])} , ${this.F.toString(a[1])}, ${this.F.toString(a[2])} ]`;
}
fromRng(rng) {
const c0 = this.F.fromRng(rng);
const c1 = this.F.fromRng(rng);
const c2 = this.F.fromRng(rng);
return [c0, c1, c2];
}
gt(a, b) {
if (this.F.gt(a[0], b[0])) return true;
if (this.F.gt(b[0], a[0])) return false;
if (this.F.gt(a[1], b[1])) return true;
if (this.F.gt(b[1], a[1])) return false;
if (this.F.gt(a[2], b[2])) return true;
return false;
}
geq(a, b) {
return this.gt(a, b) || this.eq(a, b);
}
lt(a, b) {
return !this.geq(a,b);
}
leq(a, b) {
return !this.gt(a,b);
}
neq(a, b) {
return !this.eq(a,b);
}
random() {
return [this.F.random(), this.F.random(), this.F.random()];
}
toRprLE(buff, o, e) {
this.F.toRprLE(buff, o, e[0]);
this.F.toRprLE(buff, o+this.F.n8, e[1]);
this.F.toRprLE(buff, o+this.F.n8*2, e[2]);
}
toRprBE(buff, o, e) {
this.F.toRprBE(buff, o, e[2]);
this.F.toRprBE(buff, o+this.F.n8, e[1]);
this.F.toRprBE(buff, o+this.F.n8*2, e[0]);
}
toRprLEM(buff, o, e) {
this.F.toRprLEM(buff, o, e[0]);
this.F.toRprLEM(buff, o+this.F.n8, e[1]);
this.F.toRprLEM(buff, o+this.F.n8*2, e[2]);
}
toRprBEM(buff, o, e) {
this.F.toRprBEM(buff, o, e[2]);
this.F.toRprBEM(buff, o+this.F.n8, e[1]);
this.F.toRprBEM(buff, o+this.F.n8*2, e[0]);
}
fromRprLE(buff, o) {
o = o || 0;
const c0 = this.F.fromRprLE(buff, o);
const c1 = this.F.fromRprLE(buff, o+this.n8);
const c2 = this.F.fromRprLE(buff, o+this.n8*2);
return [c0, c1, c2];
}
fromRprBE(buff, o) {
o = o || 0;
const c2 = this.F.fromRprBE(buff, o);
const c1 = this.F.fromRprBE(buff, o+this.n8);
const c0 = this.F.fromRprBE(buff, o+this.n8*2);
return [c0, c1, c2];
}
fromRprLEM(buff, o) {
o = o || 0;
const c0 = this.F.fromRprLEM(buff, o);
const c1 = this.F.fromRprLEM(buff, o+this.n8);
const c2 = this.F.fromRprLEM(buff, o+this.n8*2);
return [c0, c1, c2];
}
fromRprBEM(buff, o) {
o = o || 0;
const c2 = this.F.fromRprBEM(buff, o);
const c1 = this.F.fromRprBEM(buff, o+this.n8);
const c0 = this.F.fromRprBEM(buff, o+this.n8*2);
return [c0, c1, c2];
}
toObject(a) {
return a;
}
}
/*
Copyright 2018 0kims association.
This file is part of snarkjs.
snarkjs 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.
snarkjs 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
snarkjs. If not, see <https://www.gnu.org/licenses/>.
*/
function isGreatest(F, a) {
if (Array.isArray(a)) {
for (let i=a.length-1; i>=0; i--) {
if (!F.F.isZero(a[i])) {
return isGreatest(F.F, a[i]);
}
}
return 0;
} else {
const na = F.neg(a);
return gt(a, na);
}
}
class EC {
constructor(F, g) {
this.F = F;
this.g = g;
if (this.g.length == 2) this.g[2] = this.F.one;
this.zero = [this.F.zero, this.F.one, this.F.zero];
}
add(p1, p2) {
const F = this.F;
if (this.eq(p1, this.zero)) return p2;
if (this.eq(p2, this.zero)) return p1;
const res = new Array(3);
const Z1Z1 = F.square( p1[2] );
const Z2Z2 = F.square( p2[2] );
const U1 = F.mul( p1[0] , Z2Z2 ); // U1 = X1 * Z2Z2
const U2 = F.mul( p2[0] , Z1Z1 ); // U2 = X2 * Z1Z1
const Z1_cubed = F.mul( p1[2] , Z1Z1);
const Z2_cubed = F.mul( p2[2] , Z2Z2);
const S1 = F.mul( p1[1] , Z2_cubed); // S1 = Y1 * Z2 * Z2Z2
const S2 = F.mul( p2[1] , Z1_cubed); // S2 = Y2 * Z1 * Z1Z1
if (F.eq(U1,U2) && F.eq(S1,S2)) {
return this.double(p1);
}
const H = F.sub( U2 , U1 ); // H = U2-U1
const S2_minus_S1 = F.sub( S2 , S1 );
const I = F.square( F.add(H,H) ); // I = (2 * H)^2
const J = F.mul( H , I ); // J = H * I
const r = F.add( S2_minus_S1 , S2_minus_S1 ); // r = 2 * (S2-S1)
const V = F.mul( U1 , I ); // V = U1 * I
res[0] =
F.sub(
F.sub( F.square(r) , J ),
F.add( V , V )); // X3 = r^2 - J - 2 * V
const S1_J = F.mul( S1 , J );
res[1] =
F.sub(
F.mul( r , F.sub(V,res[0])),
F.add( S1_J,S1_J )); // Y3 = r * (V-X3)-2 S1 J
res[2] =
F.mul(
H,
F.sub(
F.square( F.add(p1[2],p2[2]) ),
F.add( Z1Z1 , Z2Z2 ))); // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H
return res;
}
neg(p) {
return [p[0], this.F.neg(p[1]), p[2]];
}
sub(a, b) {
return this.add(a, this.neg(b));
}
double(p) {
const F = this.F;
const res = new Array(3);
if (this.eq(p, this.zero)) return p;
const A = F.square( p[0] ); // A = X1^2
const B = F.square( p[1] ); // B = Y1^2
const C = F.square( B ); // C = B^2
let D =
F.sub(
F.square( F.add(p[0] , B )),
F.add( A , C));
D = F.add(D,D); // D = 2 * ((X1 + B)^2 - A - C)
const E = F.add( F.add(A,A), A); // E = 3 * A
const FF =F.square( E ); // F = E^2
res[0] = F.sub( FF , F.add(D,D) ); // X3 = F - 2 D
let eightC = F.add( C , C );
eightC = F.add( eightC , eightC );
eightC = F.add( eightC , eightC );
res[1] =
F.sub(
F.mul(
E,
F.sub( D, res[0] )),
eightC); // Y3 = E * (D - X3) - 8 * C
const Y1Z1 = F.mul( p[1] , p[2] );
res[2] = F.add( Y1Z1 , Y1Z1 ); // Z3 = 2 * Y1 * Z1
return res;
}
timesScalar(base, e) {
return mulScalar(this, base, e);
}
mulScalar(base, e) {
return mulScalar(this, base, e);
}
affine(p) {
const F = this.F;
if (this.isZero(p)) {
return this.zero;
} else if (F.eq(p[2], F.one)) {
return p;
} else {
const Z_inv = F.inv(p[2]);
const Z2_inv = F.square(Z_inv);
const Z3_inv = F.mul(Z2_inv, Z_inv);
const res = new Array(3);
res[0] = F.mul(p[0],Z2_inv);
res[1] = F.mul(p[1],Z3_inv);
res[2] = F.one;
return res;
}
}
multiAffine(arr) {
const keys = Object.keys(arr);
const F = this.F;
const accMul = new Array(keys.length+1);
accMul[0] = F.one;
for (let i = 0; i< keys.length; i++) {
if (F.eq(arr[keys[i]][2], F.zero)) {
accMul[i+1] = accMul[i];
} else {
accMul[i+1] = F.mul(accMul[i], arr[keys[i]][2]);
}
}
accMul[keys.length] = F.inv(accMul[keys.length]);
for (let i = keys.length-1; i>=0; i--) {
if (F.eq(arr[keys[i]][2], F.zero)) {
accMul[i] = accMul[i+1];
arr[keys[i]] = this.zero;
} else {
const Z_inv = F.mul(accMul[i], accMul[i+1]);
accMul[i] = F.mul(arr[keys[i]][2], accMul[i+1]);
const Z2_inv = F.square(Z_inv);
const Z3_inv = F.mul(Z2_inv, Z_inv);
arr[keys[i]][0] = F.mul(arr[keys[i]][0],Z2_inv);
arr[keys[i]][1] = F.mul(arr[keys[i]][1],Z3_inv);
arr[keys[i]][2] = F.one;
}
}
}
eq(p1, p2) {
const F = this.F;
if (this.F.eq(p1[2], this.F.zero)) return this.F.eq(p2[2], this.F.zero);
if (this.F.eq(p2[2], this.F.zero)) return false;
const Z1Z1 = F.square( p1[2] );
const Z2Z2 = F.square( p2[2] );
const U1 = F.mul( p1[0] , Z2Z2 );
const U2 = F.mul( p2[0] , Z1Z1 );
const Z1_cubed = F.mul( p1[2] , Z1Z1);
const Z2_cubed = F.mul( p2[2] , Z2Z2);
const S1 = F.mul( p1[1] , Z2_cubed);
const S2 = F.mul( p2[1] , Z1_cubed);
return (F.eq(U1,U2) && F.eq(S1,S2));
}
isZero(p) {
return this.F.isZero(p[2]);
}
toString(p) {
const cp = this.affine(p);
return `[ ${this.F.toString(cp[0])} , ${this.F.toString(cp[1])} ]`;
}
fromRng(rng) {
const F = this.F;
let P = [];
let greatest;
do {
P[0] = F.fromRng(rng);
greatest = rng.nextBool();
const x3b = F.add(F.mul(F.square(P[0]), P[0]), this.b);
P[1] = F.sqrt(x3b);
} while ((P[1] == null)||(F.isZero[P]));
const s = isGreatest(F, P[1]);
if (greatest ^ s) P[1] = F.neg(P[1]);
P[2] = F.one;
if (this.cofactor) {
P = this.mulScalar(P, this.cofactor);
}
P = this.affine(P);
return P;
}
toRprLE(buff, o, p) {
p = this.affine(p);
if (this.isZero(p)) {
const BuffV = new Uint8Array(buff, o, this.F.n8*2);
BuffV.fill(0);
return;
}
this.F.toRprLE(buff, o, p[0]);
this.F.toRprLE(buff, o+this.F.n8, p[1]);
}
toRprBE(buff, o, p) {
p = this.affine(p);
if (this.isZero(p)) {
const BuffV = new Uint8Array(buff, o, this.F.n8*2);
BuffV.fill(0);
return;
}
this.F.toRprBE(buff, o, p[0]);
this.F.toRprBE(buff, o+this.F.n8, p[1]);
}
toRprLEM(buff, o, p) {
p = this.affine(p);
if (this.isZero(p)) {
const BuffV = new Uint8Array(buff, o, this.F.n8*2);
BuffV.fill(0);
return;
}
this.F.toRprLEM(buff, o, p[0]);
this.F.toRprLEM(buff, o+this.F.n8, p[1]);
}
toRprLEJM(buff, o, p) {
p = this.affine(p);
if (this.isZero(p)) {
const BuffV = new Uint8Array(buff, o, this.F.n8*2);
BuffV.fill(0);
return;
}
this.F.toRprLEM(buff, o, p[0]);
this.F.toRprLEM(buff, o+this.F.n8, p[1]);
this.F.toRprLEM(buff, o+2*this.F.n8, p[2]);
}
toRprBEM(buff, o, p) {
p = this.affine(p);
if (this.isZero(p)) {
const BuffV = new Uint8Array(buff, o, this.F.n8*2);
BuffV.fill(0);
return;
}
this.F.toRprBEM(buff, o, p[0]);
this.F.toRprBEM(buff, o+this.F.n8, p[1]);
}
fromRprLE(buff, o) {
o = o || 0;
const x = this.F.fromRprLE(buff, o);
const y = this.F.fromRprLE(buff, o+this.F.n8);
if (this.F.isZero(x) && this.F.isZero(y)) {
return this.zero;
}
return [x, y, this.F.one];
}
fromRprBE(buff, o) {
o = o || 0;
const x = this.F.fromRprBE(buff, o);
const y = this.F.fromRprBE(buff, o+this.F.n8);
if (this.F.isZero(x) && this.F.isZero(y)) {
return this.zero;
}
return [x, y, this.F.one];
}
fromRprLEM(buff, o) {
o = o || 0;
const x = this.F.fromRprLEM(buff, o);
const y = this.F.fromRprLEM(buff, o+this.F.n8);
if (this.F.isZero(x) && this.F.isZero(y)) {
return this.zero;
}
return [x, y, this.F.one];
}
fromRprLEJM(buff, o) {
o = o || 0;
const x = this.F.fromRprLEM(buff, o);
const y = this.F.fromRprLEM(buff, o+this.F.n8);
const z = this.F.fromRprLEM(buff, o+this.F.n8*2);
if (this.F.isZero(x) && this.F.isZero(y)) {
return this.zero;
}
return [x, y, z];
}
fromRprBEM(buff, o) {
o = o || 0;
const x = this.F.fromRprBEM(buff, o);
const y = this.F.fromRprBEM(buff, o+this.F.n8);
if (this.F.isZero(x) && this.F.isZero(y)) {
return this.zero;
}
return [x, y, this.F.one];
}
fromRprCompressed(buff, o) {
const F = this.F;
const v = new Uint8Array(buff.buffer, o, F.n8);
if (v[0] & 0x40) return this.zero;
const P = new Array(3);
const greatest = ((v[0] & 0x80) != 0);
v[0] = v[0] & 0x7F;
P[0] = F.fromRprBE(buff, o);
if (greatest) v[0] = v[0] | 0x80; // set back again the old value
const x3b = F.add(F.mul(F.square(P[0]), P[0]), this.b);
P[1] = F.sqrt(x3b);
if (P[1] === null) {
throw new Error("Invalid Point!");
}
const s = isGreatest(F, P[1]);
if (greatest ^ s) P[1] = F.neg(P[1]);
P[2] = F.one;
return P;
}
toRprCompressed(buff, o, p) {
p = this.affine(p);
const v = new Uint8Array(buff.buffer, o, this.F.n8);
if (this.isZero(p)) {
v.fill(0);
v[0] = 0x40;
return;
}
this.F.toRprBE(buff, o, p[0]);
if (isGreatest(this.F, p[1])) {
v[0] = v[0] | 0x80;
}
}
fromRprUncompressed(buff, o) {
if (buff[0] & 0x40) return this.zero;
return this.fromRprBE(buff, o);
}
toRprUncompressed(buff, o, p) {
this.toRprBE(buff, o, p);
if (this.isZero(p)) {
buff[o] = buff[o] | 0x40;
}
}
}
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 <https://www.gnu.org/licenses/>.
*/
utils$6.bigInt2BytesLE = function bigInt2BytesLE(_a, len) {
const b = Array(len);
let v = BigInt(_a);
for (let i=0; i<len; i++) {
b[i] = Number(v & 0xFFn);
v = v >> 8n;
}
return b;
};
utils$6.bigInt2U32LE = function bigInt2BytesLE(_a, len) {
const b = Array(len);
let v = BigInt(_a);
for (let i=0; i<len; i++) {
b[i] = Number(v & 0xFFFFFFFFn);
v = v >> 32n;
}
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 <https://www.gnu.org/licenses/>.
*/
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<n64; i++) {
f.addCode(
c.i64_store(
c.getLocal("pr"),
i*8,
c.i64_load(
c.getLocal("px"),
i*8
)
)
);
}
}
function buildZero() {
const f = module.addFunction(prefix+"_zero");
f.addParam("pr", "i32");
const c = f.getCodeBuilder();
for (let i=0; i<n64; i++) {
f.addCode(
c.i64_store(
c.getLocal("pr"),
i*8,
c.i64_const(0)
)
);
}
}
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<n64; i++) {
f.addCode(
c.i64_store(
c.getLocal("pr"),
i*8,
c.i64_const(0)
)
);
}
}
function buildIsZero() {
const f = module.addFunction(prefix+"_isZero");
f.addParam("px", "i32");
f.setReturnType("i32");
const c = f.getCodeBuilder();
function getCompCode(n) {
if (n==0) {
return c.ret(c.i64_eqz(
c.i64_load(c.getLocal("px"))
));
}
return c.if(
c.i64_eqz(
c.i64_load(c.getLocal("px"), n*8 )
),
getCompCode(n-1),
c.ret(c.i32_const(0))
);
}
f.addCode(getCompCode(n64-1));
f.addCode(c.ret(c.i32_const(0)));
}
function buildEq() {
const f = module.addFunction(prefix+"_eq");
f.addParam("px", "i32");
f.addParam("py", "i32");
f.setReturnType("i32");
const c = f.getCodeBuilder();
function getCompCode(n) {
if (n==0) {
return c.ret(c.i64_eq(
c.i64_load(c.getLocal("px")),
c.i64_load(c.getLocal("py"))
));
}
return c.if(
c.i64_eq(
c.i64_load(c.getLocal("px"), n*8 ),
c.i64_load(c.getLocal("py"), n*8 )
),
getCompCode(n-1),
c.ret(c.i32_const(0))
);
}
f.addCode(getCompCode(n64-1));
f.addCode(c.ret(c.i32_const(0)));
}
function buildGte() {
const f = module.addFunction(prefix+"_gte");
f.addParam("px", "i32");
f.addParam("py", "i32");
f.setReturnType("i32");
const c = f.getCodeBuilder();
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)
)
);
}
f.addCode(getCompCode(n64-1));
f.addCode(c.ret(c.i32_const(0)));
}
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");
const c = f.getCodeBuilder();
f.addCode(c.setLocal(
"c",
c.i64_add(
c.i64_load32_u(c.getLocal("x")),
c.i64_load32_u(c.getLocal("y"))
)
));
f.addCode(c.i64_store32(
c.getLocal("r"),
c.getLocal("c"),
));
for (let i=1; i<n32; i++) {
f.addCode(c.setLocal( "c",
c.i64_add(
c.i64_add(
c.i64_load32_u(c.getLocal("x"), 4*i),
c.i64_load32_u(c.getLocal("y"), 4*i)
),
c.i64_shr_u (c.getLocal("c"), c.i64_const(32))
)
));
f.addCode(c.i64_store32(
c.getLocal("r"),
i*4,
c.getLocal("c")
));
}
f.addCode(c.i32_wrap_i64(c.i64_shr_u (c.getLocal("c"), c.i64_const(32))));
}
function buildSub() {
const f = module.addFunction(prefix+"_sub");
f.addParam("x", "i32");
f.addParam("y", "i32");
f.addParam("r", "i32");
f.setReturnType("i32");
f.addLocal("c", "i64");
const c = f.getCodeBuilder();
f.addCode(c.setLocal(
"c",
c.i64_sub(
c.i64_load32_u(c.getLocal("x")),
c.i64_load32_u(c.getLocal("y"))
)
));
f.addCode(c.i64_store32(
c.getLocal("r"),
c.i64_and(
c.getLocal("c"),
c.i64_const("0xFFFFFFFF")
)
));
for (let i=1; i<n32; i++) {
f.addCode(c.setLocal( "c",
c.i64_add(
c.i64_sub(
c.i64_load32_u(c.getLocal("x"), 4*i),
c.i64_load32_u(c.getLocal("y"), 4*i)
),
c.i64_shr_s (c.getLocal("c"), c.i64_const(32))
)
));
f.addCode(c.i64_store32(
c.getLocal("r"),
i*4,
c.i64_and( c.getLocal("c"), c.i64_const("0xFFFFFFFF"))
));
}
f.addCode(c.i32_wrap_i64 ( c.i64_shr_s (c.getLocal("c"), c.i64_const(32))));
}
function buildMul() {
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");
for (let i=0;i<n32; i++) {
f.addLocal("x"+i, "i64");
f.addLocal("y"+i, "i64");
}
const c = f.getCodeBuilder();
const loadX = [];
const loadY = [];
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 (!loadY[j]) {
Y = c.teeLocal("y"+j, c.i64_load32_u( c.getLocal("y"), j*4));
loadY[j] = true;
} else {
Y = c.getLocal("y"+j);
}
return c.i64_mul( X, Y );
}
let c0 = "c0";
let c1 = "c1";
for (let k=0; k<n32*2-1; k++) {
for (let i=Math.max(0, k-n32+1); (i<=k)&&(i<n32); i++) {
const j= k-i;
f.addCode(
c.setLocal(c0,
c.i64_add(
c.i64_and(
c.getLocal(c0),
c.i64_const(0xFFFFFFFF)
),
mulij(i,j)
)
)
);
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.i64_store32(
c.getLocal("r"),
k*4,
c.getLocal(c0)
)
);
[c0, c1] = [c1, c0];
f.addCode(
c.setLocal(c1,
c.i64_shr_u(
c.getLocal(c0),
c.i64_const(32)
)
)
);
}
f.addCode(
c.i64_store32(
c.getLocal("r"),
n32*4*2-4,
c.getLocal(c0)
)
);
}
function buildSquare() {
const f = module.addFunction(prefix+"_square");
f.addParam("x", "i32");
f.addParam("r", "i32");
f.addLocal("c0", "i64");
f.addLocal("c1", "i64");
f.addLocal("c0_old", "i64");
f.addLocal("c1_old", "i64");
for (let i=0;i<n32; i++) {
f.addLocal("x"+i, "i64");
}
const c = f.getCodeBuilder();
const loadX = [];
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);
}
return c.i64_mul( X, Y );
}
let c0 = "c0";
let c1 = "c1";
let c0_old = "c0_old";
let c1_old = "c1_old";
for (let k=0; k<n32*2-1; k++) {
f.addCode(
c.setLocal(c0, c.i64_const(0)),
c.setLocal(c1, c.i64_const(0)),
);
for (let i=Math.max(0, k-n32+1); (i<((k+1)>>1) )&&(i<n32); i++) {
const j= k-i;
f.addCode(
c.setLocal(c0,
c.i64_add(
c.i64_and(
c.getLocal(c0),
c.i64_const(0xFFFFFFFF)
),
mulij(i,j)
)
)
);
f.addCode(
c.setLocal(c1,
c.i64_add(
c.getLocal(c1),
c.i64_shr_u(
c.getLocal(c0),
c.i64_const(32)
)
)
)
);
}
// Multiply by 2
f.addCode(
c.setLocal(c0,
c.i64_shl(
c.i64_and(
c.getLocal(c0),
c.i64_const(0xFFFFFFFF)
),
c.i64_const(1)
)
)
);
f.addCode(
c.setLocal(c1,
c.i64_add(
c.i64_shl(
c.getLocal(c1),
c.i64_const(1)
),
c.i64_shr_u(
c.getLocal(c0),
c.i64_const(32)
)
)
)
);
if (k%2 == 0) {
f.addCode(
c.setLocal(c0,
c.i64_add(
c.i64_and(
c.getLocal(c0),
c.i64_const(0xFFFFFFFF)
),
mulij(k>>1, k>>1)
)
)
);
f.addCode(
c.setLocal(c1,
c.i64_add(
c.getLocal(c1),
c.i64_shr_u(
c.getLocal(c0),
c.i64_const(32)
)
)
)
);
}
// Add the old carry
if (k>0) {
f.addCode(
c.setLocal(c0,
c.i64_add(
c.i64_and(
c.getLocal(c0),
c.i64_const(0xFFFFFFFF)
),
c.i64_and(
c.getLocal(c0_old),
c.i64_const(0xFFFFFFFF)
),
)
)
);
f.addCode(
c.setLocal(c1,
c.i64_add(
c.i64_add(
c.getLocal(c1),
c.i64_shr_u(
c.getLocal(c0),
c.i64_const(32)
)
),
c.getLocal(c1_old)
)
)
);
}
f.addCode(
c.i64_store32(
c.getLocal("r"),
k*4,
c.getLocal(c0)
)
);
f.addCode(
c.setLocal(
c0_old,
c.getLocal(c1)
),
c.setLocal(
c1_old,
c.i64_shr_u(
c.getLocal(c0_old),
c.i64_const(32)
)
)
);
}
f.addCode(
c.i64_store32(
c.getLocal("r"),
n32*4*2-4,
c.getLocal(c0_old)
)
);
}
function buildSquareOld() {
const f = module.addFunction(prefix+"_squareOld");
f.addParam("x", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
f.addCode(c.call(prefix + "_mul", c.getLocal("x"), c.getLocal("x"), c.getLocal("r")));
}
function _buildMul1() {
const f = module.addFunction(prefix+"__mul1");
f.addParam("px", "i32");
f.addParam("y", "i64");
f.addParam("pr", "i32");
f.addLocal("c", "i64");
const c = f.getCodeBuilder();
f.addCode(c.setLocal(
"c",
c.i64_mul(
c.i64_load32_u(c.getLocal("px"), 0, 0),
c.getLocal("y")
)
));
f.addCode(c.i64_store32(
c.getLocal("pr"),
0,
0,
c.getLocal("c"),
));
for (let i=1; i<n32; i++) {
f.addCode(c.setLocal( "c",
c.i64_add(
c.i64_mul(
c.i64_load32_u(c.getLocal("px"), 4*i, 0),
c.getLocal("y")
),
c.i64_shr_u (c.getLocal("c"), c.i64_const(32))
)
));
f.addCode(c.i64_store32(
c.getLocal("pr"),
i*4,
0,
c.getLocal("c")
));
}
}
function _buildAdd1() {
const f = module.addFunction(prefix+"__add1");
f.addParam("x", "i32");
f.addParam("y", "i64");
f.addLocal("c", "i64");
f.addLocal("px", "i32");
const c = f.getCodeBuilder();
f.addCode(c.setLocal("px", c.getLocal("x")));
f.addCode(c.setLocal(
"c",
c.i64_add(
c.i64_load32_u(c.getLocal("px"), 0, 0),
c.getLocal("y")
)
));
f.addCode(c.i64_store32(
c.getLocal("px"),
0,
0,
c.getLocal("c"),
));
f.addCode(c.setLocal(
"c",
c.i64_shr_u(
c.getLocal("c"),
c.i64_const(32)
)
));
f.addCode(c.block(c.loop(
c.br_if(
1,
c.i64_eqz(c.getLocal("c"))
),
c.setLocal(
"px",
c.i32_add(
c.getLocal("px"),
c.i32_const(4)
)
),
c.setLocal(
"c",
c.i64_add(
c.i64_load32_u(c.getLocal("px"), 0, 0),
c.getLocal("c")
)
),
c.i64_store32(
c.getLocal("px"),
0,
0,
c.getLocal("c"),
),
c.setLocal(
"c",
c.i64_shr_u(
c.getLocal("c"),
c.i64_const(32)
)
),
c.br(0)
)));
}
function buildDiv() {
_buildMul1();
_buildAdd1();
const f = module.addFunction(prefix+"_div");
f.addParam("x", "i32");
f.addParam("y", "i32");
f.addParam("c", "i32");
f.addParam("r", "i32");
f.addLocal("rr", "i32");
f.addLocal("cc", "i32");
f.addLocal("eX", "i32");
f.addLocal("eY", "i32");
f.addLocal("sy", "i64");
f.addLocal("sx", "i64");
f.addLocal("ec", "i32");
const c = f.getCodeBuilder();
const Y = c.i32_const(module.alloc(n8));
const Caux = c.i32_const(module.alloc(n8));
const Raux = c.i32_const(module.alloc(n8));
const C = c.getLocal("cc");
const R = c.getLocal("rr");
const pr1 = module.alloc(n8*2);
const R1 = c.i32_const(pr1);
const R2 = c.i32_const(pr1+n8);
// Ic c is 0 then store it in an auxiliary buffer
f.addCode(c.if(
c.getLocal("c"),
c.setLocal("cc", c.getLocal("c")),
c.setLocal("cc", Caux)
));
// Ic r is 0 then store it in an auxiliary buffer
f.addCode(c.if(
c.getLocal("r"),
c.setLocal("rr", c.getLocal("r")),
c.setLocal("rr", Raux)
));
// Copy
f.addCode(c.call(prefix + "_copy", c.getLocal("x"), R));
f.addCode(c.call(prefix + "_copy", c.getLocal("y"), Y));
f.addCode(c.call(prefix + "_zero", C));
f.addCode(c.call(prefix + "_zero", R1));
f.addCode(c.setLocal("eX", c.i32_const(n8-1)));
f.addCode(c.setLocal("eY", c.i32_const(n8-1)));
// while (eY>3)&&(Y[eY]==0) ey--;
f.addCode(c.block(c.loop(
c.br_if(
1,
c.i32_or(
c.i32_load8_u(
c.i32_add(Y , c.getLocal("eY")),
0,
0
),
c.i32_eq(
c.getLocal("eY"),
c.i32_const(3)
)
)
),
c.setLocal("eY", c.i32_sub(c.getLocal("eY"), c.i32_const(1))),
c.br(0)
)));
f.addCode(
c.setLocal(
"sy",
c.i64_add(
c.i64_load32_u(
c.i32_sub(
c.i32_add( Y, c.getLocal("eY")),
c.i32_const(3)
),
0,
0
),
c.i64_const(1)
)
)
);
// Force a divide by 0 if quotien is 0
f.addCode(
c.if(
c.i64_eq(
c.getLocal("sy"),
c.i64_const(1)
),
c.drop(c.i64_div_u(c.i64_const(0), c.i64_const(0)))
)
);
f.addCode(c.block(c.loop(
// while (eX>7)&&(Y[eX]==0) ex--;
c.block(c.loop(
c.br_if(
1,
c.i32_or(
c.i32_load8_u(
c.i32_add(R , c.getLocal("eX")),
0,
0
),
c.i32_eq(
c.getLocal("eX"),
c.i32_const(7)
)
)
),
c.setLocal("eX", c.i32_sub(c.getLocal("eX"), c.i32_const(1))),
c.br(0)
)),
c.setLocal(
"sx",
c.i64_load(
c.i32_sub(
c.i32_add( R, c.getLocal("eX")),
c.i32_const(7)
),
0,
0
)
),
c.setLocal(
"sx",
c.i64_div_u(
c.getLocal("sx"),
c.getLocal("sy")
)
),
c.setLocal(
"ec",
c.i32_sub(
c.i32_sub(
c.getLocal("eX"),
c.getLocal("eY")
),
c.i32_const(4)
)
),
// While greater than 32 bits or ec is neg, shr and inc exp
c.block(c.loop(
c.br_if(
1,
c.i32_and(
c.i64_eqz(
c.i64_and(
c.getLocal("sx"),
c.i64_const("0xFFFFFFFF00000000")
)
),
c.i32_ge_s(
c.getLocal("ec"),
c.i32_const(0)
)
)
),
c.setLocal(
"sx",
c.i64_shr_u(
c.getLocal("sx"),
c.i64_const(8)
)
),
c.setLocal(
"ec",
c.i32_add(
c.getLocal("ec"),
c.i32_const(1)
)
),
c.br(0)
)),
c.if(
c.i64_eqz(c.getLocal("sx")),
[
...c.br_if(
2,
c.i32_eqz(c.call(prefix + "_gte", R, Y))
),
...c.setLocal("sx", c.i64_const(1)),
...c.setLocal("ec", c.i32_const(0))
]
),
c.call(prefix + "__mul1", Y, c.getLocal("sx"), R2),
c.drop(c.call(
prefix + "_sub",
R,
c.i32_sub(R2, c.getLocal("ec")),
R
)),
c.call(
prefix + "__add1",
c.i32_add(C, c.getLocal("ec")),
c.getLocal("sx")
),
c.br(0)
)));
}
function buildInverseMod() {
const f = module.addFunction(prefix+"_inverseMod");
f.addParam("px", "i32");
f.addParam("pm", "i32");
f.addParam("pr", "i32");
f.addLocal("t", "i32");
f.addLocal("newt", "i32");
f.addLocal("r", "i32");
f.addLocal("qq", "i32");
f.addLocal("qr", "i32");
f.addLocal("newr", "i32");
f.addLocal("swp", "i32");
f.addLocal("x", "i32");
f.addLocal("signt", "i32");
f.addLocal("signnewt", "i32");
f.addLocal("signx", "i32");
const c = f.getCodeBuilder();
const aux1 = c.i32_const(module.alloc(n8));
const aux2 = c.i32_const(module.alloc(n8));
const aux3 = c.i32_const(module.alloc(n8));
const aux4 = c.i32_const(module.alloc(n8));
const aux5 = c.i32_const(module.alloc(n8));
const aux6 = c.i32_const(module.alloc(n8));
const mulBuff = c.i32_const(module.alloc(n8*2));
const aux7 = c.i32_const(module.alloc(n8));
f.addCode(
c.setLocal("t", aux1),
c.call(prefix + "_zero", aux1),
c.setLocal("signt", c.i32_const(0)),
);
f.addCode(
c.setLocal("r", aux2),
c.call(prefix + "_copy", c.getLocal("pm"), aux2)
);
f.addCode(
c.setLocal("newt", aux3),
c.call(prefix + "_one", aux3),
c.setLocal("signnewt", c.i32_const(0)),
);
f.addCode(
c.setLocal("newr", aux4),
c.call(prefix + "_copy", c.getLocal("px"), aux4)
);
f.addCode(c.setLocal("qq", aux5));
f.addCode(c.setLocal("qr", aux6));
f.addCode(c.setLocal("x", aux7));
f.addCode(c.block(c.loop(
c.br_if(
1,
c.call(prefix + "_isZero", c.getLocal("newr") )
),
c.call(prefix + "_div", c.getLocal("r"), c.getLocal("newr"), c.getLocal("qq"), c.getLocal("qr")),
c.call(prefix + "_mul", c.getLocal("qq"), c.getLocal("newt"), mulBuff),
c.if(
c.getLocal("signt"),
c.if(
c.getLocal("signnewt"),
c.if (
c.call(prefix + "_gte", mulBuff, c.getLocal("t")),
[
...c.drop(c.call(prefix + "_sub", mulBuff, c.getLocal("t"), c.getLocal("x"))),
...c.setLocal("signx", c.i32_const(0))
],
[
...c.drop(c.call(prefix + "_sub", c.getLocal("t"), mulBuff, c.getLocal("x"))),
...c.setLocal("signx", c.i32_const(1))
],
),
[
...c.drop(c.call(prefix + "_add", mulBuff, c.getLocal("t"), c.getLocal("x"))),
...c.setLocal("signx", c.i32_const(1))
]
),
c.if(
c.getLocal("signnewt"),
[
...c.drop(c.call(prefix + "_add", mulBuff, c.getLocal("t"), c.getLocal("x"))),
...c.setLocal("signx", c.i32_const(0))
],
c.if (
c.call(prefix + "_gte", c.getLocal("t"), mulBuff),
[
...c.drop(c.call(prefix + "_sub", c.getLocal("t"), mulBuff, c.getLocal("x"))),
...c.setLocal("signx", c.i32_const(0))
],
[
...c.drop(c.call(prefix + "_sub", mulBuff, c.getLocal("t"), c.getLocal("x"))),
...c.setLocal("signx", c.i32_const(1))
]
)
)
),
c.setLocal("swp", c.getLocal("t")),
c.setLocal("t", c.getLocal("newt")),
c.setLocal("newt", c.getLocal("x")),
c.setLocal("x", c.getLocal("swp")),
c.setLocal("signt", c.getLocal("signnewt")),
c.setLocal("signnewt", c.getLocal("signx")),
c.setLocal("swp", c.getLocal("r")),
c.setLocal("r", c.getLocal("newr")),
c.setLocal("newr", c.getLocal("qr")),
c.setLocal("qr", c.getLocal("swp")),
c.br(0)
)));
f.addCode(c.if(
c.getLocal("signt"),
c.drop(c.call(prefix + "_sub", c.getLocal("pm"), c.getLocal("t"), c.getLocal("pr"))),
c.call(prefix + "_copy", c.getLocal("t"), c.getLocal("pr"))
));
}
buildCopy();
buildZero();
buildIsZero();
buildOne();
buildEq();
buildGte();
buildAdd();
buildSub();
buildMul();
buildSquare();
buildSquareOld();
buildDiv();
buildInverseMod();
module.exportFunction(prefix+"_copy");
module.exportFunction(prefix+"_zero");
module.exportFunction(prefix+"_one");
module.exportFunction(prefix+"_isZero");
module.exportFunction(prefix+"_eq");
module.exportFunction(prefix+"_gte");
module.exportFunction(prefix+"_add");
module.exportFunction(prefix+"_sub");
module.exportFunction(prefix+"_mul");
module.exportFunction(prefix+"_square");
module.exportFunction(prefix+"_squareOld");
module.exportFunction(prefix+"_div");
module.exportFunction(prefix+"_inverseMod");
return prefix;
};
/*
Copyright 2019 0KIMS association.
This file is part of wasmsnark (Web Assembly zkSnark Prover).
wasmsnark is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
wasmsnark is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with wasmsnark. If not, see <https://www.gnu.org/licenses/>.
*/
var build_timesscalar = function buildTimesScalar(module, fnName, elementLen, opAB, opAA, opCopy, opInit) {
const f = module.addFunction(fnName);
f.addParam("base", "i32");
f.addParam("scalar", "i32");
f.addParam("scalarLength", "i32");
f.addParam("r", "i32");
f.addLocal("i", "i32");
f.addLocal("b", "i32");
const c = f.getCodeBuilder();
const aux = c.i32_const(module.alloc(elementLen));
f.addCode(
c.if(
c.i32_eqz(c.getLocal("scalarLength")),
[
...c.call(opInit, c.getLocal("r")),
...c.ret([])
]
)
);
f.addCode(c.call(opCopy, c.getLocal("base"), aux));
f.addCode(c.call(opInit, c.getLocal("r")));
f.addCode(c.setLocal("i", c.getLocal("scalarLength")));
f.addCode(c.block(c.loop(
c.setLocal("i", c.i32_sub(c.getLocal("i"), c.i32_const(1))),
c.setLocal(
"b",
c.i32_load8_u(
c.i32_add(
c.getLocal("scalar"),
c.getLocal("i")
)
)
),
...innerLoop(),
c.br_if(1, c.i32_eqz ( c.getLocal("i") )),
c.br(0)
)));
function innerLoop() {
const code = [];
for (let i=0; i<8; i++) {
code.push(
...c.call(opAA, c.getLocal("r"), c.getLocal("r")),
...c.if(
c.i32_ge_u( c.getLocal("b"), c.i32_const(0x80 >> i)),
[
...c.setLocal(
"b",
c.i32_sub(
c.getLocal("b"),
c.i32_const(0x80 >> i)
)
),
...c.call(opAB, c.getLocal("r"),aux, c.getLocal("r"))
]
)
);
}
return code;
}
};
var build_batchinverse = buildBatchInverse$3;
function buildBatchInverse$3(module, prefix) {
const n8 = module.modules[prefix].n64*8;
const f = module.addFunction(prefix+"_batchInverse");
f.addParam("pIn", "i32");
f.addParam("inStep", "i32");
f.addParam("n", "i32");
f.addParam("pOut", "i32");
f.addParam("outStep", "i32");
f.addLocal("itAux", "i32");
f.addLocal("itIn", "i32");
f.addLocal("itOut","i32");
f.addLocal("i","i32");
const c = f.getCodeBuilder();
const AUX = c.i32_const(module.alloc(n8));
// Alloc Working space for accumulated umltiplications
f.addCode(
c.setLocal("itAux", c.i32_load( c.i32_const(0) )),
c.i32_store(
c.i32_const(0),
c.i32_add(
c.getLocal("itAux"),
c.i32_mul(
c.i32_add(
c.getLocal("n"),
c.i32_const(1)
),
c.i32_const(n8)
)
)
)
);
f.addCode(
// aux[0] = a;
c.call(prefix+"_one", c.getLocal("itAux")),
// for (i=0;i<n;i++) aux[i] = aux[i-1]*in[i]
c.setLocal("itIn", c.getLocal("pIn")),
c.setLocal("itAux", c.i32_add(c.getLocal("itAux"), c.i32_const(n8))),
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.if(
c.call(prefix+"_isZero", c.getLocal("itIn")),
c.call(
prefix + "_copy",
c.i32_sub(c.getLocal("itAux"), c.i32_const(n8)),
c.getLocal("itAux")
),
c.call(
prefix+"_mul",
c.getLocal("itIn"),
c.i32_sub(c.getLocal("itAux"), c.i32_const(n8)),
c.getLocal("itAux")
)
),
c.setLocal("itIn", c.i32_add(c.getLocal("itIn"), c.getLocal("inStep"))),
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)
)),
// point to the last
c.setLocal("itIn", c.i32_sub(c.getLocal("itIn"), c.getLocal("inStep"))),
c.setLocal("itAux", c.i32_sub(c.getLocal("itAux"), c.i32_const(n8))),
// itOut = pOut + (n-1)*stepOut // Point to the last
c.setLocal(
"itOut",
c.i32_add(
c.getLocal("pOut"),
c.i32_mul(
c.i32_sub(c.getLocal("n"), c.i32_const(1)),
c.getLocal("outStep"),
)
)
),
// aux[n-1] = 1/aux[n-1]
c.call(prefix+"_inverse", c.getLocal("itAux"), c.getLocal("itAux") ),
c.block(c.loop(
c.br_if(1, c.i32_eqz( c.getLocal("i"))),
c.if(
c.call(prefix+"_isZero", c.getLocal("itIn")),
[
...c.call(
prefix + "_copy",
c.getLocal("itAux"),
c.i32_sub(c.getLocal("itAux"), c.i32_const(n8)),
),
...c.call(
prefix + "_zero",
c.getLocal("itOut")
)
],[
...c.call(prefix + "_copy", c.i32_sub(c.getLocal("itAux"), c.i32_const(n8)), AUX),
...c.call(
prefix+"_mul",
c.getLocal("itAux"),
c.getLocal("itIn"),
c.i32_sub(c.getLocal("itAux"), c.i32_const(n8)),
),
...c.call(
prefix+"_mul",
c.getLocal("itAux"),
AUX,
c.getLocal("itOut")
)
]
),
c.setLocal("itIn", c.i32_sub(c.getLocal("itIn"), c.getLocal("inStep"))),
c.setLocal("itOut", c.i32_sub(c.getLocal("itOut"), c.getLocal("outStep"))),
c.setLocal("itAux", c.i32_sub(c.getLocal("itAux"), c.i32_const(n8))),
c.setLocal("i", c.i32_sub(c.getLocal("i"), c.i32_const(1))),
c.br(0)
))
);
// Recover Old memory
f.addCode(
c.i32_store(
c.i32_const(0),
c.getLocal("itAux")
)
);
}
var build_batchconvertion = buildBatchConvertion$3;
function buildBatchConvertion$3(module, fnName, internalFnName, sizeIn, sizeOut, reverse) {
if (typeof reverse === "undefined") {
// Set the reverse in a way that allows to use the same buffer as in/out.
if (sizeIn < sizeOut) {
reverse = true;
} else {
reverse = false;
}
}
const f = module.addFunction(fnName);
f.addParam("pIn", "i32");
f.addParam("n", "i32");
f.addParam("pOut", "i32");
f.addLocal("i", "i32");
f.addLocal("itIn", "i32");
f.addLocal("itOut", "i32");
const c = f.getCodeBuilder();
if (reverse) {
f.addCode(
c.setLocal("itIn",
c.i32_add(
c.getLocal("pIn"),
c.i32_mul(
c.i32_sub(
c.getLocal("n"),
c.i32_const(1)
),
c.i32_const(sizeIn)
)
)
),
c.setLocal("itOut",
c.i32_add(
c.getLocal("pOut"),
c.i32_mul(
c.i32_sub(
c.getLocal("n"),
c.i32_const(1)
),
c.i32_const(sizeOut)
)
)
),
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(internalFnName, c.getLocal("itIn"), c.getLocal("itOut")),
c.setLocal("itIn", c.i32_sub(c.getLocal("itIn"), c.i32_const(sizeIn))),
c.setLocal("itOut", c.i32_sub(c.getLocal("itOut"), c.i32_const(sizeOut))),
c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
c.br(0)
)),
);
} else {
f.addCode(
c.setLocal("itIn", c.getLocal("pIn")),
c.setLocal("itOut", c.getLocal("pOut")),
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(internalFnName, c.getLocal("itIn"), c.getLocal("itOut")),
c.setLocal("itIn", c.i32_add(c.getLocal("itIn"), c.i32_const(sizeIn))),
c.setLocal("itOut", c.i32_add(c.getLocal("itOut"), c.i32_const(sizeOut))),
c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
c.br(0)
)),
);
}
}
var build_batchop = buildBatchConvertion$2;
function buildBatchConvertion$2(module, fnName, internalFnName, sizeIn, sizeOut, reverse) {
if (typeof reverse === "undefined") {
// Set the reverse in a way that allows to use the same buffer as in/out.
if (sizeIn < sizeOut) {
reverse = true;
} else {
reverse = false;
}
}
const f = module.addFunction(fnName);
f.addParam("pIn1", "i32");
f.addParam("pIn2", "i32");
f.addParam("n", "i32");
f.addParam("pOut", "i32");
f.addLocal("i", "i32");
f.addLocal("itIn1", "i32");
f.addLocal("itIn2", "i32");
f.addLocal("itOut", "i32");
const c = f.getCodeBuilder();
if (reverse) {
f.addCode(
c.setLocal("itIn1",
c.i32_add(
c.getLocal("pIn1"),
c.i32_mul(
c.i32_sub(
c.getLocal("n"),
c.i32_const(1)
),
c.i32_const(sizeIn)
)
)
),
c.setLocal("itIn2",
c.i32_add(
c.getLocal("pIn2"),
c.i32_mul(
c.i32_sub(
c.getLocal("n"),
c.i32_const(1)
),
c.i32_const(sizeIn)
)
)
),
c.setLocal("itOut",
c.i32_add(
c.getLocal("pOut"),
c.i32_mul(
c.i32_sub(
c.getLocal("n"),
c.i32_const(1)
),
c.i32_const(sizeOut)
)
)
),
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(internalFnName, c.getLocal("itIn1"), c.getLocal("itIn2"), c.getLocal("itOut")),
c.setLocal("itIn1", c.i32_sub(c.getLocal("itIn1"), c.i32_const(sizeIn))),
c.setLocal("itIn2", c.i32_sub(c.getLocal("itIn2"), c.i32_const(sizeIn))),
c.setLocal("itOut", c.i32_sub(c.getLocal("itOut"), c.i32_const(sizeOut))),
c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
c.br(0)
)),
);
} else {
f.addCode(
c.setLocal("itIn1", c.getLocal("pIn1")),
c.setLocal("itIn2", c.getLocal("pIn2")),
c.setLocal("itOut", c.getLocal("pOut")),
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(internalFnName, c.getLocal("itIn1"), c.getLocal("itIn2"), c.getLocal("itOut")),
c.setLocal("itIn1", c.i32_add(c.getLocal("itIn1"), c.i32_const(sizeIn))),
c.setLocal("itIn2", c.i32_add(c.getLocal("itIn2"), c.i32_const(sizeIn))),
c.setLocal("itOut", c.i32_add(c.getLocal("itOut"), c.i32_const(sizeOut))),
c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
c.br(0)
)),
);
}
}
var bigint = {};
// Many of these utilities are from the `big-integer` library,
// but adjusted to only work with native BigInt type
// Ref https://github.com/peterolson/BigInteger.js/blob/e5d2154d3c417069c51e7116bafc3b91d0b9fe41/BigInteger.js
// Originally licensed The Unlicense
function compare(a, b) {
return a === b ? 0 : a > b ? 1 : -1;
}
function square$1(n) {
return n * n;
}
function isOdd$4(n) {
return n % 2n !== 0n;
}
function isEven(n) {
return n % 2n === 0n;
}
function isNegative$3(n) {
return n < 0n;
}
function isPositive(n) {
return n > 0n;
}
function bitLength$5(n) {
if (isNegative$3(n)) {
return n.toString(2).length - 1; // discard the - sign
} else {
return n.toString(2).length;
}
}
function abs(n) {
return n < 0n ? -n : n;
}
function isUnit(n) {
return abs(n) === 1n;
}
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;
}
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 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;
}
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
}
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 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 <https://www.gnu.org/licenses/>.
*/
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;
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$5.bigInt2BytesLE(q, n8));
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));
const _ePlusOne = _e + 1n; // e = (p-1)/2
const pePlusOne = module.alloc(n8, utils$5.bigInt2BytesLE(_ePlusOne, n8));
module.modules[prefix] = {
pq: pq,
pR2: pR2,
n64: n64,
q: q,
pOne: pOne,
pZero: pZero,
pePlusOne: pePlusOne
};
function buildOne() {
const f = module.addFunction(prefix+"_one");
f.addParam("pr", "i32");
const c = f.getCodeBuilder();
f.addCode(c.call(intPrefix + "_copy", c.i32_const(pOne), c.getLocal("pr")));
}
function buildAdd() {
const f = module.addFunction(prefix+"_add");
f.addParam("x", "i32");
f.addParam("y", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
f.addCode(
c.if(
c.call(intPrefix+"_add", c.getLocal("x"), c.getLocal("y"), c.getLocal("r")),
c.drop(c.call(intPrefix+"_sub", c.getLocal("r"), c.i32_const(pq), c.getLocal("r"))),
c.if(
c.call(intPrefix+"_gte", c.getLocal("r"), c.i32_const(pq) ),
c.drop(c.call(intPrefix+"_sub", c.getLocal("r"), c.i32_const(pq), c.getLocal("r"))),
)
)
);
}
function buildSub() {
const f = module.addFunction(prefix+"_sub");
f.addParam("x", "i32");
f.addParam("y", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
f.addCode(
c.if(
c.call(intPrefix+"_sub", c.getLocal("x"), c.getLocal("y"), c.getLocal("r")),
c.drop(c.call(intPrefix+"_add", c.getLocal("r"), c.i32_const(pq), c.getLocal("r")))
)
);
}
function buildNeg() {
const f = module.addFunction(prefix+"_neg");
f.addParam("x", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
f.addCode(
c.call(prefix + "_sub", c.i32_const(pZero), c.getLocal("x"), c.getLocal("r"))
);
}
function buildIsNegative() {
const f = module.addFunction(prefix+"_isNegative");
f.addParam("x", "i32");
f.setReturnType("i32");
const c = f.getCodeBuilder();
const AUX = c.i32_const(module.alloc(n8));
f.addCode(
c.call(prefix + "_fromMontgomery", c.getLocal("x"), AUX),
c.call(intPrefix + "_gte", AUX, c.i32_const(pePlusOne) )
);
}
function buildSign() {
const f = module.addFunction(prefix+"_sign");
f.addParam("x", "i32");
f.setReturnType("i32");
const c = f.getCodeBuilder();
const AUX = c.i32_const(module.alloc(n8));
f.addCode(
c.if (
c.call(intPrefix + "_isZero", c.getLocal("x")),
c.ret(c.i32_const(0))
),
c.call(prefix + "_fromMontgomery", c.getLocal("x"), AUX),
c.if(
c.call(intPrefix + "_gte", AUX, c.i32_const(pePlusOne)),
c.ret(c.i32_const(-1))
),
c.ret(c.i32_const(1))
);
}
function buildMReduct() {
const carries = module.alloc(n32*n32*8);
const f = module.addFunction(prefix+"_mReduct");
f.addParam("t", "i32");
f.addParam("r", "i32");
f.addLocal("np32", "i64");
f.addLocal("c", "i64");
f.addLocal("m", "i64");
const c = f.getCodeBuilder();
const np32 = Number(0x100000000n - modInv$2(q, 0x100000000n));
f.addCode(c.setLocal("np32", c.i64_const(np32)));
for (let i=0; i<n32; i++) {
f.addCode(c.setLocal("c", c.i64_const(0)));
f.addCode(
c.setLocal(
"m",
c.i64_and(
c.i64_mul(
c.i64_load32_u(c.getLocal("t"), i*4),
c.getLocal("np32")
),
c.i64_const("0xFFFFFFFF")
)
)
);
for (let j=0; j<n32; j++) {
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")
)
)
)
);
f.addCode(
c.i64_store32(
c.getLocal("t"),
(i+j)*4,
c.getLocal("c")
)
);
}
f.addCode(
c.i64_store32(
c.i32_const(carries),
i*4,
c.i64_shr_u(c.getLocal("c"), c.i64_const(32))
)
);
}
f.addCode(
c.call(
prefix+"_add",
c.i32_const(carries),
c.i32_add(
c.getLocal("t"),
c.i32_const(n32*4)
),
c.getLocal("r")
)
);
}
function buildMul() {
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");
for (let i=0;i<n32; i++) {
f.addLocal("x"+i, "i64");
f.addLocal("y"+i, "i64");
f.addLocal("m"+i, "i64");
f.addLocal("q"+i, "i64");
}
const c = f.getCodeBuilder();
const np32 = Number(0x100000000n - modInv$2(q, 0x100000000n));
f.addCode(c.setLocal("np32", c.i64_const(np32)));
const loadX = [];
const loadY = [];
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 (!loadY[j]) {
Y = c.teeLocal("y"+j, c.i64_load32_u( c.getLocal("y"), j*4));
loadY[j] = true;
} else {
Y = c.getLocal("y"+j);
}
return c.i64_mul( X, Y );
}
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);
}
M = c.getLocal("m"+j);
return c.i64_mul( Q, M );
}
let c0 = "c0";
let c1 = "c1";
for (let k=0; k<n32*2-1; k++) {
for (let i=Math.max(0, k-n32+1); (i<=k)&&(i<n32); i++) {
const j= k-i;
f.addCode(
c.setLocal(c0,
c.i64_add(
c.i64_and(
c.getLocal(c0),
c.i64_const(0xFFFFFFFF)
),
mulij(i,j)
)
)
);
f.addCode(
c.setLocal(c1,
c.i64_add(
c.getLocal(c1),
c.i64_shr_u(
c.getLocal(c0),
c.i64_const(32)
)
)
)
);
}
for (let i=Math.max(1, k-n32+1); (i<=k)&&(i<n32); i++) {
const j= k-i;
f.addCode(
c.setLocal(c0,
c.i64_add(
c.i64_and(
c.getLocal(c0),
c.i64_const(0xFFFFFFFF)
),
mulqm(i,j)
)
)
);
f.addCode(
c.setLocal(c1,
c.i64_add(
c.getLocal(c1),
c.i64_shr_u(
c.getLocal(c0),
c.i64_const(32)
)
)
)
);
}
if (k<n32) {
f.addCode(
c.setLocal(
"m"+k,
c.i64_and(
c.i64_mul(
c.i64_and(
c.getLocal(c0),
c.i64_const(0xFFFFFFFF)
),
c.getLocal("np32")
),
c.i64_const("0xFFFFFFFF")
)
)
);
f.addCode(
c.setLocal(c0,
c.i64_add(
c.i64_and(
c.getLocal(c0),
c.i64_const(0xFFFFFFFF)
),
mulqm(0,k)
)
)
);
f.addCode(
c.setLocal(c1,
c.i64_add(
c.getLocal(c1),
c.i64_shr_u(
c.getLocal(c0),
c.i64_const(32)
)
)
)
);
}
if (k>=n32) {
f.addCode(
c.i64_store32(
c.getLocal("r"),
(k-n32)*4,
c.getLocal(c0)
)
);
}
[c0, c1] = [c1, c0];
f.addCode(
c.setLocal(c1,
c.i64_shr_u(
c.getLocal(c0),
c.i64_const(32)
)
)
);
}
f.addCode(
c.i64_store32(
c.getLocal("r"),
n32*4-4,
c.getLocal(c0)
)
);
f.addCode(
c.if(
c.i32_wrap_i64(c.getLocal(c1)),
c.drop(c.call(intPrefix+"_sub", c.getLocal("r"), c.i32_const(pq), c.getLocal("r"))),
c.if(
c.call(intPrefix+"_gte", c.getLocal("r"), c.i32_const(pq) ),
c.drop(c.call(intPrefix+"_sub", c.getLocal("r"), c.i32_const(pq), c.getLocal("r"))),
)
)
);
}
function buildSquare() {
const f = module.addFunction(prefix+"_square");
f.addParam("x", "i32");
f.addParam("r", "i32");
f.addLocal("c0", "i64");
f.addLocal("c1", "i64");
f.addLocal("c0_old", "i64");
f.addLocal("c1_old", "i64");
f.addLocal("np32", "i64");
for (let i=0;i<n32; i++) {
f.addLocal("x"+i, "i64");
f.addLocal("m"+i, "i64");
f.addLocal("q"+i, "i64");
}
const c = f.getCodeBuilder();
const np32 = Number(0x100000000n - modInv$2(q, 0x100000000n));
f.addCode(c.setLocal("np32", c.i64_const(np32)));
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);
}
return c.i64_mul( X, Y );
}
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);
}
M = c.getLocal("m"+j);
return c.i64_mul( Q, M );
}
let c0 = "c0";
let c1 = "c1";
let c0_old = "c0_old";
let c1_old = "c1_old";
for (let k=0; k<n32*2-1; k++) {
f.addCode(
c.setLocal(c0, c.i64_const(0)),
c.setLocal(c1, c.i64_const(0)),
);
for (let i=Math.max(0, k-n32+1); (i<((k+1)>>1) )&&(i<n32); i++) {
const j= k-i;
f.addCode(
c.setLocal(c0,
c.i64_add(
c.i64_and(
c.getLocal(c0),
c.i64_const(0xFFFFFFFF)
),
mulij(i,j)
)
)
);
f.addCode(
c.setLocal(c1,
c.i64_add(
c.getLocal(c1),
c.i64_shr_u(
c.getLocal(c0),
c.i64_const(32)
)
)
)
);
}
// Multiply by 2
f.addCode(
c.setLocal(c0,
c.i64_shl(
c.i64_and(
c.getLocal(c0),
c.i64_const(0xFFFFFFFF)
),
c.i64_const(1)
)
)
);
f.addCode(
c.setLocal(c1,
c.i64_add(
c.i64_shl(
c.getLocal(c1),
c.i64_const(1)
),
c.i64_shr_u(
c.getLocal(c0),
c.i64_const(32)
)
)
)
);
if (k%2 == 0) {
f.addCode(
c.setLocal(c0,
c.i64_add(
c.i64_and(
c.getLocal(c0),
c.i64_const(0xFFFFFFFF)
),
mulij(k>>1, k>>1)
)
)
);
f.addCode(
c.setLocal(c1,
c.i64_add(
c.getLocal(c1),
c.i64_shr_u(
c.getLocal(c0),
c.i64_const(32)
)
)
)
);
}
// Add the old carry
if (k>0) {
f.addCode(
c.setLocal(c0,
c.i64_add(
c.i64_and(
c.getLocal(c0),
c.i64_const(0xFFFFFFFF)
),
c.i64_and(
c.getLocal(c0_old),
c.i64_const(0xFFFFFFFF)
),
)
)
);
f.addCode(
c.setLocal(c1,
c.i64_add(
c.i64_add(
c.getLocal(c1),
c.i64_shr_u(
c.getLocal(c0),
c.i64_const(32)
)
),
c.getLocal(c1_old)
)
)
);
}
for (let i=Math.max(1, k-n32+1); (i<=k)&&(i<n32); i++) {
const j= k-i;
f.addCode(
c.setLocal(c0,
c.i64_add(
c.i64_and(
c.getLocal(c0),
c.i64_const(0xFFFFFFFF)
),
mulqm(i,j)
)
)
);
f.addCode(
c.setLocal(c1,
c.i64_add(
c.getLocal(c1),
c.i64_shr_u(
c.getLocal(c0),
c.i64_const(32)
)
)
)
);
}
if (k<n32) {
f.addCode(
c.setLocal(
"m"+k,
c.i64_and(
c.i64_mul(
c.i64_and(
c.getLocal(c0),
c.i64_const(0xFFFFFFFF)
),
c.getLocal("np32")
),
c.i64_const("0xFFFFFFFF")
)
)
);
f.addCode(
c.setLocal(c0,
c.i64_add(
c.i64_and(
c.getLocal(c0),
c.i64_const(0xFFFFFFFF)
),
mulqm(0,k)
)
)
);
f.addCode(
c.setLocal(c1,
c.i64_add(
c.getLocal(c1),
c.i64_shr_u(
c.getLocal(c0),
c.i64_const(32)
)
)
)
);
}
if (k>=n32) {
f.addCode(
c.i64_store32(
c.getLocal("r"),
(k-n32)*4,
c.getLocal(c0)
)
);
}
f.addCode(
c.setLocal(
c0_old,
c.getLocal(c1)
),
c.setLocal(
c1_old,
c.i64_shr_u(
c.getLocal(c0_old),
c.i64_const(32)
)
)
);
}
f.addCode(
c.i64_store32(
c.getLocal("r"),
n32*4-4,
c.getLocal(c0_old)
)
);
f.addCode(
c.if(
c.i32_wrap_i64(c.getLocal(c1_old)),
c.drop(c.call(intPrefix+"_sub", c.getLocal("r"), c.i32_const(pq), c.getLocal("r"))),
c.if(
c.call(intPrefix+"_gte", c.getLocal("r"), c.i32_const(pq) ),
c.drop(c.call(intPrefix+"_sub", c.getLocal("r"), c.i32_const(pq), c.getLocal("r"))),
)
)
);
}
function buildSquareOld() {
const f = module.addFunction(prefix+"_squareOld");
f.addParam("x", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
f.addCode(c.call(prefix + "_mul", c.getLocal("x"), c.getLocal("x"), c.getLocal("r")));
}
function buildToMontgomery() {
const f = module.addFunction(prefix+"_toMontgomery");
f.addParam("x", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
f.addCode(c.call(prefix+"_mul", c.getLocal("x"), c.i32_const(pR2), c.getLocal("r")));
}
function buildFromMontgomery() {
const pAux2 = module.alloc(n8*2);
const f = module.addFunction(prefix+"_fromMontgomery");
f.addParam("x", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
f.addCode(c.call(intPrefix + "_copy", c.getLocal("x"), c.i32_const(pAux2) ));
f.addCode(c.call(intPrefix + "_zero", c.i32_const(pAux2 + n8) ));
f.addCode(c.call(prefix+"_mReduct", c.i32_const(pAux2), c.getLocal("r")));
}
function buildInverse() {
const f = module.addFunction(prefix+ "_inverse");
f.addParam("x", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
f.addCode(c.call(prefix + "_fromMontgomery", c.getLocal("x"), c.getLocal("r")));
f.addCode(c.call(intPrefix + "_inverseMod", c.getLocal("r"), c.i32_const(pq), c.getLocal("r")));
f.addCode(c.call(prefix + "_toMontgomery", c.getLocal("r"), c.getLocal("r")));
}
// Calculate various valuse needed for sqrt
let _nqr = 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$5.bigInt2BytesLE(_t, n8));
const _nqrToT = modPow$1(_nqr, _t, q);
const pNqrToT = module.alloc(utils$5.bigInt2BytesLE((_nqrToT << BigInt(n64*64)) % q, n8));
const _tPlusOneOver2 = (_t + 1n) >> 1n;
const ptPlusOneOver2 = module.alloc(n8, utils$5.bigInt2BytesLE(_tPlusOneOver2, n8));
function buildSqrt() {
const f = module.addFunction(prefix+ "_sqrt");
f.addParam("n", "i32");
f.addParam("r", "i32");
f.addLocal("m", "i32");
f.addLocal("i", "i32");
f.addLocal("j", "i32");
const c = f.getCodeBuilder();
const ONE = c.i32_const(pOne);
const C = c.i32_const(module.alloc(n8));
const T = c.i32_const(module.alloc(n8));
const R = c.i32_const(module.alloc(n8));
const SQ = c.i32_const(module.alloc(n8));
const B = c.i32_const(module.alloc(n8));
f.addCode(
// If (n==0) return 0
c.if(
c.call(prefix + "_isZero", c.getLocal("n")),
c.ret(
c.call(prefix + "_zero", c.getLocal("r"))
)
),
c.setLocal("m", c.i32_const(s2)),
c.call(prefix + "_copy", c.i32_const(pNqrToT), C),
c.call(prefix + "_exp", c.getLocal("n"), c.i32_const(pt), c.i32_const(n8), T),
c.call(prefix + "_exp", c.getLocal("n"), c.i32_const(ptPlusOneOver2), c.i32_const(n8), R),
c.block(c.loop(
c.br_if(1, c.call(prefix + "_eq", T, ONE)),
c.call(prefix + "_square", T, SQ),
c.setLocal("i", c.i32_const(1)),
c.block(c.loop(
c.br_if(1, c.call(prefix + "_eq", SQ, ONE)),
c.call(prefix + "_square", SQ, SQ),
c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
c.br(0)
)),
c.call(prefix + "_copy", C, B),
c.setLocal("j", c.i32_sub(c.i32_sub( c.getLocal("m"), c.getLocal("i")), c.i32_const(1)) ),
c.block(c.loop(
c.br_if(1, c.i32_eqz(c.getLocal("j"))),
c.call(prefix + "_square", B, B),
c.setLocal("j", c.i32_sub(c.getLocal("j"), c.i32_const(1))),
c.br(0)
)),
c.setLocal("m", c.getLocal("i")),
c.call(prefix + "_square", B, C),
c.call(prefix + "_mul", T, C, T),
c.call(prefix + "_mul", R, B, R),
c.br(0)
)),
c.if(
c.call(prefix + "_isNegative", R),
c.call(prefix + "_neg", R, c.getLocal("r")),
c.call(prefix + "_copy", R, c.getLocal("r")),
)
);
}
function buildIsSquare() {
const f = module.addFunction(prefix+"_isSquare");
f.addParam("n", "i32");
f.setReturnType("i32");
const c = f.getCodeBuilder();
const ONE = c.i32_const(pOne);
const AUX = c.i32_const(module.alloc(n8));
f.addCode(
c.if(
c.call(prefix + "_isZero", c.getLocal("n")),
c.ret(c.i32_const(1))
),
c.call(prefix + "_exp", c.getLocal("n"), c.i32_const(pe), c.i32_const(n8), AUX),
c.call(prefix + "_eq", AUX, ONE)
);
}
function buildLoad() {
const f = module.addFunction(prefix+"_load");
f.addParam("scalar", "i32");
f.addParam("scalarLen", "i32");
f.addParam("r", "i32");
f.addLocal("p", "i32");
f.addLocal("l", "i32");
f.addLocal("i", "i32");
f.addLocal("j", "i32");
const c = f.getCodeBuilder();
const R = c.i32_const(module.alloc(n8));
const pAux = module.alloc(n8);
const AUX = c.i32_const(pAux);
f.addCode(
c.call(intPrefix + "_zero", c.getLocal("r")),
c.setLocal("i", c.i32_const(n8)),
c.setLocal("p", c.getLocal("scalar")),
c.block(c.loop(
c.br_if(1, c.i32_gt_u(c.getLocal("i"), c.getLocal("scalarLen"))),
c.if(
c.i32_eq(c.getLocal("i"), c.i32_const(n8)),
c.call(prefix + "_one", R),
c.call(prefix + "_mul", R, c.i32_const(pR2), R)
),
c.call(prefix + "_mul", c.getLocal("p"), R, AUX),
c.call(prefix + "_add", c.getLocal("r"), AUX, c.getLocal("r")),
c.setLocal("p", c.i32_add(c.getLocal("p"), c.i32_const(n8))),
c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(n8))),
c.br(0)
)),
c.setLocal("l", c.i32_rem_u( c.getLocal("scalarLen"), c.i32_const(n8))),
c.if(c.i32_eqz(c.getLocal("l")), c.ret([])),
c.call(intPrefix + "_zero", AUX),
c.setLocal("j", c.i32_const(0)),
c.block(c.loop(
c.br_if(1, c.i32_eq(c.getLocal("j"), c.getLocal("l"))),
c.i32_store8(
c.getLocal("j"),
pAux,
c.i32_load8_u(c.getLocal("p")),
),
c.setLocal("p", c.i32_add(c.getLocal("p"), c.i32_const(1))),
c.setLocal("j", c.i32_add(c.getLocal("j"), c.i32_const(1))),
c.br(0)
)),
c.if(
c.i32_eq(c.getLocal("i"), c.i32_const(n8)),
c.call(prefix + "_one", R),
c.call(prefix + "_mul", R, c.i32_const(pR2), R)
),
c.call(prefix + "_mul", AUX, R, AUX),
c.call(prefix + "_add", c.getLocal("r"), AUX, c.getLocal("r")),
);
}
function buildTimesScalar() {
const f = module.addFunction(prefix+"_timesScalar");
f.addParam("x", "i32");
f.addParam("scalar", "i32");
f.addParam("scalarLen", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
const AUX = c.i32_const(module.alloc(n8));
f.addCode(
c.call(prefix + "_load", c.getLocal("scalar"), c.getLocal("scalarLen"), AUX),
c.call(prefix + "_toMontgomery", AUX, AUX),
c.call(prefix + "_mul", c.getLocal("x"), AUX, c.getLocal("r")),
);
}
function buildIsOne() {
const f = module.addFunction(prefix+"_isOne");
f.addParam("x", "i32");
f.setReturnType("i32");
const c = f.getCodeBuilder();
f.addCode(
c.ret(c.call(intPrefix + "_eq", c.getLocal("x"), c.i32_const(pOne)))
);
}
module.exportFunction(intPrefix + "_copy", prefix+"_copy");
module.exportFunction(intPrefix + "_zero", prefix+"_zero");
module.exportFunction(intPrefix + "_isZero", prefix+"_isZero");
module.exportFunction(intPrefix + "_eq", prefix+"_eq");
buildIsOne();
buildAdd();
buildSub();
buildNeg();
buildMReduct();
buildMul();
buildSquare();
buildSquareOld();
buildToMontgomery();
buildFromMontgomery();
buildIsNegative();
buildSign();
buildInverse();
buildOne();
buildLoad();
buildTimesScalar();
buildBatchInverse$2(module, prefix);
buildBatchConvertion$1(module, prefix + "_batchToMontgomery", prefix + "_toMontgomery", n8, n8);
buildBatchConvertion$1(module, prefix + "_batchFromMontgomery", prefix + "_fromMontgomery", n8, n8);
buildBatchConvertion$1(module, prefix + "_batchNeg", prefix + "_neg", n8, n8);
buildBatchOp(module, prefix + "_batchAdd", prefix + "_add", n8, n8);
buildBatchOp(module, prefix + "_batchSub", prefix + "_sub", n8, n8);
buildBatchOp(module, prefix + "_batchMul", prefix + "_mul", n8, n8);
module.exportFunction(prefix + "_add");
module.exportFunction(prefix + "_sub");
module.exportFunction(prefix + "_neg");
module.exportFunction(prefix + "_isNegative");
module.exportFunction(prefix + "_isOne");
module.exportFunction(prefix + "_sign");
module.exportFunction(prefix + "_mReduct");
module.exportFunction(prefix + "_mul");
module.exportFunction(prefix + "_square");
module.exportFunction(prefix + "_squareOld");
module.exportFunction(prefix + "_fromMontgomery");
module.exportFunction(prefix + "_toMontgomery");
module.exportFunction(prefix + "_inverse");
module.exportFunction(prefix + "_one");
module.exportFunction(prefix + "_load");
module.exportFunction(prefix + "_timesScalar");
buildExp$2(
module,
prefix + "_exp",
n8,
prefix + "_mul",
prefix + "_square",
intPrefix + "_copy",
prefix + "_one",
);
module.exportFunction(prefix + "_exp");
module.exportFunction(prefix + "_batchInverse");
if (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.
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 <https://www.gnu.org/licenses/>.
*/
const buildF1m$2 =build_f1m;
const { bitLength: bitLength$3 } = bigint;
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 buildSquare() {
const f = module.addFunction(prefix+"_square");
f.addParam("x", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
f.addCode(c.call(prefix + "_mul", c.getLocal("x"), c.getLocal("x"), c.getLocal("r")));
}
function buildInverse() {
const f = module.addFunction(prefix+ "_inverse");
f.addParam("x", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
f.addCode(c.call(intPrefix + "_inverseMod", c.getLocal("x"), c.i32_const(pq), c.getLocal("r")));
}
function buildIsNegative() {
const f = module.addFunction(prefix+"_isNegative");
f.addParam("x", "i32");
f.setReturnType("i32");
const c = f.getCodeBuilder();
f.addCode(
c.call(intPrefix + "_gte", c.getLocal("x"), c.i32_const(pePlusOne) )
);
}
buildMul();
buildSquare();
buildInverse();
buildIsNegative();
module.exportFunction(f1mPrefix + "_add", prefix + "_add");
module.exportFunction(f1mPrefix + "_sub", prefix + "_sub");
module.exportFunction(f1mPrefix + "_neg", prefix + "_neg");
module.exportFunction(prefix + "_mul");
module.exportFunction(prefix + "_square");
module.exportFunction(prefix + "_inverse");
module.exportFunction(prefix + "_isNegative");
module.exportFunction(f1mPrefix + "_copy", prefix+"_copy");
module.exportFunction(f1mPrefix + "_zero", prefix+"_zero");
module.exportFunction(f1mPrefix + "_one", prefix+"_one");
module.exportFunction(f1mPrefix + "_isZero", prefix+"_isZero");
module.exportFunction(f1mPrefix + "_eq", prefix+"_eq");
return prefix;
};
/*
Copyright 2019 0KIMS association.
This file is part of wasmsnark (Web Assembly zkSnark Prover).
wasmsnark is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
wasmsnark is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with wasmsnark. If not, see <https://www.gnu.org/licenses/>.
*/
const buildExp$1 = build_timesscalar;
const buildBatchInverse$1 = build_batchinverse;
const utils$4 = utils$6;
var build_f2m = function buildF2m(module, mulNonResidueFn, prefix, f1mPrefix) {
if (module.modules[prefix]) return prefix; // already builded
const f1n8 = module.modules[f1mPrefix].n64*8;
const q = module.modules[f1mPrefix].q;
module.modules[prefix] = {
n64: module.modules[f1mPrefix].n64*2
};
function buildAdd() {
const f = module.addFunction(prefix+"_add");
f.addParam("x", "i32");
f.addParam("y", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
const y0 = c.getLocal("y");
const y1 = c.i32_add(c.getLocal("y"), c.i32_const(f1n8));
const r0 = c.getLocal("r");
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8));
f.addCode(
c.call(f1mPrefix+"_add", x0, y0, r0),
c.call(f1mPrefix+"_add", x1, y1, r1),
);
}
function buildTimesScalar() {
const f = module.addFunction(prefix+"_timesScalar");
f.addParam("x", "i32");
f.addParam("scalar", "i32");
f.addParam("scalarLen", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
const r0 = c.getLocal("r");
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8));
f.addCode(
c.call(f1mPrefix+"_timesScalar", x0, c.getLocal("scalar"), c.getLocal("scalarLen"), r0),
c.call(f1mPrefix+"_timesScalar", x1, c.getLocal("scalar"), c.getLocal("scalarLen"), r1),
);
}
function buildSub() {
const f = module.addFunction(prefix+"_sub");
f.addParam("x", "i32");
f.addParam("y", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
const y0 = c.getLocal("y");
const y1 = c.i32_add(c.getLocal("y"), c.i32_const(f1n8));
const r0 = c.getLocal("r");
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8));
f.addCode(
c.call(f1mPrefix+"_sub", x0, y0, r0),
c.call(f1mPrefix+"_sub", x1, y1, r1),
);
}
function buildNeg() {
const f = module.addFunction(prefix+"_neg");
f.addParam("x", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
const r0 = c.getLocal("r");
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8));
f.addCode(
c.call(f1mPrefix+"_neg", x0, r0),
c.call(f1mPrefix+"_neg", x1, r1),
);
}
function buildConjugate() {
const f = module.addFunction(prefix+"_conjugate");
f.addParam("x", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
const r0 = c.getLocal("r");
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8));
f.addCode(
c.call(f1mPrefix+"_copy", x0, r0),
c.call(f1mPrefix+"_neg", x1, r1),
);
}
function buildIsNegative() {
const f = module.addFunction(prefix+"_isNegative");
f.addParam("x", "i32");
f.setReturnType("i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
f.addCode(
c.if(
c.call(f1mPrefix+"_isZero", x1),
c.ret(c.call(f1mPrefix+"_isNegative", x0))
),
c.ret(c.call(f1mPrefix+"_isNegative", x1))
);
}
function buildMul() {
const f = module.addFunction(prefix+"_mul");
f.addParam("x", "i32");
f.addParam("y", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
const y0 = c.getLocal("y");
const y1 = c.i32_add(c.getLocal("y"), c.i32_const(f1n8));
const r0 = c.getLocal("r");
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8));
const A = c.i32_const(module.alloc(f1n8));
const B = c.i32_const(module.alloc(f1n8));
const C = c.i32_const(module.alloc(f1n8));
const D = c.i32_const(module.alloc(f1n8));
f.addCode(
c.call(f1mPrefix + "_mul", x0, y0, A), // A = x0*y0
c.call(f1mPrefix + "_mul", x1, y1, B), // B = x1*y1
c.call(f1mPrefix + "_add", x0, x1, C), // C = x0 + x1
c.call(f1mPrefix + "_add", y0, y1, D), // D = y0 + y1
c.call(f1mPrefix + "_mul", C, D, C), // C = (x0 + x1)*(y0 + y1) = x0*y0+x0*y1+x1*y0+x1*y1
// c.call(f1mPrefix + "_mul", B, c.i32_const(pNonResidue), r0), // r0 = nr*(x1*y1)
c.call(mulNonResidueFn, B, r0), // r0 = nr*(x1*y1)
c.call(f1mPrefix + "_add", A, r0, r0), // r0 = x0*y0 + nr*(x1*y1)
c.call(f1mPrefix + "_add", A, B, r1), // r1 = x0*y0+x1*y1
c.call(f1mPrefix + "_sub", C, r1, r1) // r1 = x0*y0+x0*y1+x1*y0+x1*y1 - x0*y0+x1*y1 = x0*y1+x1*y0
);
}
function buildMul1() {
const f = module.addFunction(prefix+"_mul1");
f.addParam("x", "i32");
f.addParam("y", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
const y = c.getLocal("y");
const r0 = c.getLocal("r");
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8));
f.addCode(
c.call(f1mPrefix + "_mul", x0, y, r0), // A = x0*y
c.call(f1mPrefix + "_mul", x1, y, r1), // B = x1*y
);
}
function buildSquare() {
const f = module.addFunction(prefix+"_square");
f.addParam("x", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
const r0 = c.getLocal("r");
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8));
const AB = c.i32_const(module.alloc(f1n8));
const APB = c.i32_const(module.alloc(f1n8));
const APNB = c.i32_const(module.alloc(f1n8));
const ABPNAB = c.i32_const(module.alloc(f1n8));
f.addCode(
// AB = x0*y1
c.call(f1mPrefix + "_mul", x0, x1, AB),
// APB = x0+y1
c.call(f1mPrefix + "_add", x0, x1, APB),
// APBN0 = x0 + nr*x1
c.call(mulNonResidueFn, x1, APNB),
c.call(f1mPrefix + "_add", x0, APNB, APNB),
// ABPNAB = ab + nr*ab
c.call(mulNonResidueFn, AB, ABPNAB),
c.call(f1mPrefix + "_add", ABPNAB, AB, ABPNAB),
// r0 = APB * APNB - ABPNAB
c.call(f1mPrefix + "_mul", APB, APNB, r0),
c.call(f1mPrefix + "_sub", r0, ABPNAB, r0),
// r1 = AB + AB
c.call(f1mPrefix + "_add", AB, AB, r1),
);
}
function buildToMontgomery() {
const f = module.addFunction(prefix+"_toMontgomery");
f.addParam("x", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
const r0 = c.getLocal("r");
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8));
f.addCode(
c.call(f1mPrefix+"_toMontgomery", x0, r0),
c.call(f1mPrefix+"_toMontgomery", x1, r1)
);
}
function buildFromMontgomery() {
const f = module.addFunction(prefix+"_fromMontgomery");
f.addParam("x", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
const r0 = c.getLocal("r");
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8));
f.addCode(
c.call(f1mPrefix+"_fromMontgomery", x0, r0),
c.call(f1mPrefix+"_fromMontgomery", x1, r1)
);
}
function buildCopy() {
const f = module.addFunction(prefix+"_copy");
f.addParam("x", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
const r0 = c.getLocal("r");
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8));
f.addCode(
c.call(f1mPrefix+"_copy", x0, r0),
c.call(f1mPrefix+"_copy", x1, r1)
);
}
function buildZero() {
const f = module.addFunction(prefix+"_zero");
f.addParam("x", "i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
f.addCode(
c.call(f1mPrefix+"_zero", x0),
c.call(f1mPrefix+"_zero", x1)
);
}
function buildOne() {
const f = module.addFunction(prefix+"_one");
f.addParam("x", "i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
f.addCode(
c.call(f1mPrefix+"_one", x0),
c.call(f1mPrefix+"_zero", x1)
);
}
function buildEq() {
const f = module.addFunction(prefix+"_eq");
f.addParam("x", "i32");
f.addParam("y", "i32");
f.setReturnType("i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
const y0 = c.getLocal("y");
const y1 = c.i32_add(c.getLocal("y"), c.i32_const(f1n8));
f.addCode(
c.i32_and(
c.call(f1mPrefix+"_eq", x0, y0),
c.call(f1mPrefix+"_eq", x1, y1)
)
);
}
function buildIsZero() {
const f = module.addFunction(prefix+"_isZero");
f.addParam("x", "i32");
f.setReturnType("i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
f.addCode(
c.i32_and(
c.call(f1mPrefix+"_isZero", x0),
c.call(f1mPrefix+"_isZero", x1)
)
);
}
function buildInverse() {
const f = module.addFunction(prefix+"_inverse");
f.addParam("x", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
const r0 = c.getLocal("r");
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8));
const t0 = c.i32_const(module.alloc(f1n8));
const t1 = c.i32_const(module.alloc(f1n8));
const t2 = c.i32_const(module.alloc(f1n8));
const t3 = c.i32_const(module.alloc(f1n8));
f.addCode(
c.call(f1mPrefix+"_square", x0, t0),
c.call(f1mPrefix+"_square", x1, t1),
// c.call(f1mPrefix+"_mul", t1, c.i32_const(pNonResidue), t2),
c.call(mulNonResidueFn, t1, t2),
c.call(f1mPrefix+"_sub", t0, t2, t2),
c.call(f1mPrefix+"_inverse", t2, t3),
c.call(f1mPrefix+"_mul", x0, t3, r0),
c.call(f1mPrefix+"_mul", x1, t3, r1),
c.call(f1mPrefix+"_neg", r1, r1),
);
}
function buildSign() {
const f = module.addFunction(prefix+"_sign");
f.addParam("x", "i32");
f.addLocal("s", "i32");
f.setReturnType("i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
f.addCode(
c.setLocal("s" , c.call( f1mPrefix + "_sign", x1)),
c.if(
c.getLocal("s"),
c.ret(c.getLocal("s"))
),
c.ret(c.call( f1mPrefix + "_sign", x0))
);
}
function buildIsOne() {
const f = module.addFunction(prefix+"_isOne");
f.addParam("x", "i32");
f.setReturnType("i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
f.addCode(
c.ret(c.i32_and(
c.call(f1mPrefix + "_isOne", x0),
c.call(f1mPrefix + "_isZero", x1),
))
);
}
// Check here: https://eprint.iacr.org/2012/685.pdf
// Alg 9adj
function buildSqrt() {
const f = module.addFunction(prefix+"_sqrt");
f.addParam("a", "i32");
f.addParam("pr", "i32");
const c = f.getCodeBuilder();
// 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 )));
const a = c.getLocal("a");
const a1 = c.i32_const(module.alloc(f1n8*2));
const alpha = c.i32_const(module.alloc(f1n8*2));
const a0 = c.i32_const(module.alloc(f1n8*2));
const pn1 = module.alloc(f1n8*2);
const n1 = c.i32_const(pn1);
const n1a = c.i32_const(pn1);
const n1b = c.i32_const(pn1+f1n8);
const x0 = c.i32_const(module.alloc(f1n8*2));
const b = c.i32_const(module.alloc(f1n8*2));
f.addCode(
c.call(prefix + "_one", n1),
c.call(prefix + "_neg", n1, n1),
// const a1 = F.pow(a, F.sqrt_e34);
c.call(prefix + "_exp", a, e34, c.i32_const(f1n8), a1),
// const a1 = F.pow(a, F.sqrt_e34);
c.call(prefix + "_square", a1, alpha),
c.call(prefix + "_mul", a, alpha, alpha),
// const a0 = F.mul(F.frobenius(1, alfa), alfa);
c.call(prefix + "_conjugate", alpha, a0),
c.call(prefix + "_mul", a0, alpha, a0),
// if (F.eq(a0, F.negone)) return null;
c.if(c.call(prefix + "_eq",a0,n1), c.unreachable() ),
// const x0 = F.mul(a1, a);
c.call(prefix + "_mul", a1, a, x0),
// if (F.eq(alfa, F.negone)) {
c.if(
c.call(prefix + "_eq", alpha, n1),
[
// x = F.mul(x0, [F.F.zero, F.F.one]);
...c.call(f1mPrefix + "_zero", n1a),
...c.call(f1mPrefix + "_one", n1b),
...c.call(prefix + "_mul", n1, x0, c.getLocal("pr")),
],
[
// const b = F.pow(F.add(F.one, alfa), F.sqrt_e12);
...c.call(prefix + "_one", b),
...c.call(prefix + "_add", b, alpha, b),
...c.call(prefix + "_exp", b, e12, c.i32_const(f1n8), b),
// x = F.mul(b, x0);
...c.call(prefix + "_mul", b, x0, c.getLocal("pr")),
]
)
);
}
function buildIsSquare() {
const f = module.addFunction(prefix+"_isSquare");
f.addParam("a", "i32");
f.setReturnType("i32");
const c = f.getCodeBuilder();
// 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 )));
const a = c.getLocal("a");
const a1 = c.i32_const(module.alloc(f1n8*2));
const alpha = c.i32_const(module.alloc(f1n8*2));
const a0 = c.i32_const(module.alloc(f1n8*2));
const pn1 = module.alloc(f1n8*2);
const n1 = c.i32_const(pn1);
f.addCode(
c.call(prefix + "_one", n1),
c.call(prefix + "_neg", n1, n1),
// const a1 = F.pow(a, F.sqrt_e34);
c.call(prefix + "_exp", a, e34, c.i32_const(f1n8), a1),
// const a1 = F.pow(a, F.sqrt_e34);
c.call(prefix + "_square", a1, alpha),
c.call(prefix + "_mul", a, alpha, alpha),
// const a0 = F.mul(F.frobenius(1, alfa), alfa);
c.call(prefix + "_conjugate", alpha, a0),
c.call(prefix + "_mul", a0, alpha, a0),
// if (F.eq(a0, F.negone)) return null;
c.if(
c.call(
prefix + "_eq",
a0,
n1
),
c.ret(c.i32_const(0))
),
c.ret(c.i32_const(1))
);
}
buildIsZero();
buildIsOne();
buildZero();
buildOne();
buildCopy();
buildMul();
buildMul1();
buildSquare();
buildAdd();
buildSub();
buildNeg();
buildConjugate();
buildToMontgomery();
buildFromMontgomery();
buildEq();
buildInverse();
buildTimesScalar();
buildSign();
buildIsNegative();
module.exportFunction(prefix + "_isZero");
module.exportFunction(prefix + "_isOne");
module.exportFunction(prefix + "_zero");
module.exportFunction(prefix + "_one");
module.exportFunction(prefix + "_copy");
module.exportFunction(prefix + "_mul");
module.exportFunction(prefix + "_mul1");
module.exportFunction(prefix + "_square");
module.exportFunction(prefix + "_add");
module.exportFunction(prefix + "_sub");
module.exportFunction(prefix + "_neg");
module.exportFunction(prefix + "_sign");
module.exportFunction(prefix + "_conjugate");
module.exportFunction(prefix + "_fromMontgomery");
module.exportFunction(prefix + "_toMontgomery");
module.exportFunction(prefix + "_eq");
module.exportFunction(prefix + "_inverse");
buildBatchInverse$1(module, prefix);
buildExp$1(
module,
prefix + "_exp",
f1n8*2,
prefix + "_mul",
prefix + "_square",
prefix + "_copy",
prefix + "_one",
);
buildSqrt();
buildIsSquare();
module.exportFunction(prefix + "_exp");
module.exportFunction(prefix + "_timesScalar");
module.exportFunction(prefix + "_batchInverse");
module.exportFunction(prefix + "_sqrt");
module.exportFunction(prefix + "_isSquare");
module.exportFunction(prefix + "_isNegative");
return prefix;
};
/*
Copyright 2019 0KIMS association.
This file is part of wasmsnark (Web Assembly zkSnark Prover).
wasmsnark is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
wasmsnark is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with wasmsnark. If not, see <https://www.gnu.org/licenses/>.
*/
const buildExp = build_timesscalar;
const buildBatchInverse = build_batchinverse;
var build_f3m = function buildF3m(module, mulNonResidueFn, prefix, f1mPrefix) {
if (module.modules[prefix]) return prefix; // already builded
const f1n8 = module.modules[f1mPrefix].n64*8;
module.modules[prefix] = {
n64: module.modules[f1mPrefix].n64*3
};
function buildAdd() {
const f = module.addFunction(prefix+"_add");
f.addParam("x", "i32");
f.addParam("y", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8));
const y0 = c.getLocal("y");
const y1 = c.i32_add(c.getLocal("y"), c.i32_const(f1n8));
const y2 = c.i32_add(c.getLocal("y"), c.i32_const(2*f1n8));
const r0 = c.getLocal("r");
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8));
const r2 = c.i32_add(c.getLocal("r"), c.i32_const(2*f1n8));
f.addCode(
c.call(f1mPrefix+"_add", x0, y0, r0),
c.call(f1mPrefix+"_add", x1, y1, r1),
c.call(f1mPrefix+"_add", x2, y2, r2),
);
}
function buildTimesScalar() {
const f = module.addFunction(prefix+"_timesScalar");
f.addParam("x", "i32");
f.addParam("scalar", "i32");
f.addParam("scalarLen", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8));
const r0 = c.getLocal("r");
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8));
const r2 = c.i32_add(c.getLocal("r"), c.i32_const(2*f1n8));
f.addCode(
c.call(f1mPrefix+"_timesScalar", x0, c.getLocal("scalar"), c.getLocal("scalarLen"), r0),
c.call(f1mPrefix+"_timesScalar", x1, c.getLocal("scalar"), c.getLocal("scalarLen"), r1),
c.call(f1mPrefix+"_timesScalar", x2, c.getLocal("scalar"), c.getLocal("scalarLen"), r2),
);
}
function buildSub() {
const f = module.addFunction(prefix+"_sub");
f.addParam("x", "i32");
f.addParam("y", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8));
const y0 = c.getLocal("y");
const y1 = c.i32_add(c.getLocal("y"), c.i32_const(f1n8));
const y2 = c.i32_add(c.getLocal("y"), c.i32_const(2*f1n8));
const r0 = c.getLocal("r");
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8));
const r2 = c.i32_add(c.getLocal("r"), c.i32_const(2*f1n8));
f.addCode(
c.call(f1mPrefix+"_sub", x0, y0, r0),
c.call(f1mPrefix+"_sub", x1, y1, r1),
c.call(f1mPrefix+"_sub", x2, y2, r2),
);
}
function buildNeg() {
const f = module.addFunction(prefix+"_neg");
f.addParam("x", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8));
const r0 = c.getLocal("r");
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8));
const r2 = c.i32_add(c.getLocal("r"), c.i32_const(2*f1n8));
f.addCode(
c.call(f1mPrefix+"_neg", x0, r0),
c.call(f1mPrefix+"_neg", x1, r1),
c.call(f1mPrefix+"_neg", x2, r2),
);
}
function buildIsNegative() {
const f = module.addFunction(prefix+"_isNegative");
f.addParam("x", "i32");
f.setReturnType("i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8));
f.addCode(
c.if(
c.call(f1mPrefix+"_isZero", x2),
c.if(
c.call(f1mPrefix+"_isZero", x1),
c.ret(c.call(f1mPrefix+"_isNegative", x0)),
c.ret(c.call(f1mPrefix+"_isNegative", x1))
)
),
c.ret(c.call(f1mPrefix+"_isNegative", x2))
);
}
function buildMul() {
const f = module.addFunction(prefix+"_mul");
f.addParam("x", "i32");
f.addParam("y", "i32");
f.addParam("r", "i32");
const cd = f.getCodeBuilder();
const a = cd.getLocal("x");
const b = cd.i32_add(cd.getLocal("x"), cd.i32_const(f1n8));
const c = cd.i32_add(cd.getLocal("x"), cd.i32_const(2*f1n8));
const A = cd.getLocal("y");
const B = cd.i32_add(cd.getLocal("y"), cd.i32_const(f1n8));
const C = cd.i32_add(cd.getLocal("y"), cd.i32_const(2*f1n8));
const r0 = cd.getLocal("r");
const r1 = cd.i32_add(cd.getLocal("r"), cd.i32_const(f1n8));
const r2 = cd.i32_add(cd.getLocal("r"), cd.i32_const(2*f1n8));
const aA = cd.i32_const(module.alloc(f1n8));
const bB = cd.i32_const(module.alloc(f1n8));
const cC = cd.i32_const(module.alloc(f1n8));
const a_b = cd.i32_const(module.alloc(f1n8));
const A_B = cd.i32_const(module.alloc(f1n8));
const a_c = cd.i32_const(module.alloc(f1n8));
const A_C = cd.i32_const(module.alloc(f1n8));
const b_c = cd.i32_const(module.alloc(f1n8));
const B_C = cd.i32_const(module.alloc(f1n8));
const aA_bB = cd.i32_const(module.alloc(f1n8));
const aA_cC = cd.i32_const(module.alloc(f1n8));
const bB_cC = cd.i32_const(module.alloc(f1n8));
const AUX = cd.i32_const(module.alloc(f1n8));
f.addCode(
cd.call(f1mPrefix + "_mul", a, A, aA),
cd.call(f1mPrefix + "_mul", b, B, bB),
cd.call(f1mPrefix + "_mul", c, C, cC),
cd.call(f1mPrefix + "_add", a, b, a_b),
cd.call(f1mPrefix + "_add", A, B, A_B),
cd.call(f1mPrefix + "_add", a, c, a_c),
cd.call(f1mPrefix + "_add", A, C, A_C),
cd.call(f1mPrefix + "_add", b, c, b_c),
cd.call(f1mPrefix + "_add", B, C, B_C),
cd.call(f1mPrefix + "_add", aA, bB, aA_bB),
cd.call(f1mPrefix + "_add", aA, cC, aA_cC),
cd.call(f1mPrefix + "_add", bB, cC, bB_cC),
cd.call(f1mPrefix + "_mul", b_c, B_C, r0),
cd.call(f1mPrefix + "_sub", r0, bB_cC, r0),
cd.call(mulNonResidueFn, r0, r0),
cd.call(f1mPrefix + "_add", aA, r0, r0),
cd.call(f1mPrefix + "_mul", a_b, A_B, r1),
cd.call(f1mPrefix + "_sub", r1, aA_bB, r1),
cd.call(mulNonResidueFn, cC, AUX),
cd.call(f1mPrefix + "_add", r1, AUX, r1),
cd.call(f1mPrefix + "_mul", a_c, A_C, r2),
cd.call(f1mPrefix + "_sub", r2, aA_cC, r2),
cd.call(f1mPrefix + "_add", r2, bB, r2),
);
}
function buildSquare() {
const f = module.addFunction(prefix+"_square");
f.addParam("x", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
const A = c.getLocal("x");
const B = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
const C = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8));
const r0 = c.getLocal("r");
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8));
const r2 = c.i32_add(c.getLocal("r"), c.i32_const(2*f1n8));
const s0 = c.i32_const(module.alloc(f1n8));
const ab = c.i32_const(module.alloc(f1n8));
const s1 = c.i32_const(module.alloc(f1n8));
const s2 = c.i32_const(module.alloc(f1n8));
const bc = c.i32_const(module.alloc(f1n8));
const s3 = c.i32_const(module.alloc(f1n8));
const s4 = c.i32_const(module.alloc(f1n8));
f.addCode(
c.call(f1mPrefix + "_square", A, s0),
c.call(f1mPrefix + "_mul", A, B, ab),
c.call(f1mPrefix + "_add", ab, ab, s1),
c.call(f1mPrefix + "_sub", A, B, s2),
c.call(f1mPrefix + "_add", s2, C, s2),
c.call(f1mPrefix + "_square", s2, s2),
c.call(f1mPrefix + "_mul", B, C, bc),
c.call(f1mPrefix + "_add", bc, bc, s3),
c.call(f1mPrefix + "_square", C, s4),
c.call(mulNonResidueFn, s3, r0),
c.call(f1mPrefix + "_add", s0, r0, r0),
c.call(mulNonResidueFn, s4, r1),
c.call(f1mPrefix + "_add", s1, r1, r1),
c.call(f1mPrefix + "_add", s0, s4, r2),
c.call(f1mPrefix + "_sub", s3, r2, r2),
c.call(f1mPrefix + "_add", s2, r2, r2),
c.call(f1mPrefix + "_add", s1, r2, r2),
);
}
function buildToMontgomery() {
const f = module.addFunction(prefix+"_toMontgomery");
f.addParam("x", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8));
const r0 = c.getLocal("r");
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8));
const r2 = c.i32_add(c.getLocal("r"), c.i32_const(2*f1n8));
f.addCode(
c.call(f1mPrefix+"_toMontgomery", x0, r0),
c.call(f1mPrefix+"_toMontgomery", x1, r1),
c.call(f1mPrefix+"_toMontgomery", x2, r2)
);
}
function buildFromMontgomery() {
const f = module.addFunction(prefix+"_fromMontgomery");
f.addParam("x", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8));
const r0 = c.getLocal("r");
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8));
const r2 = c.i32_add(c.getLocal("r"), c.i32_const(2*f1n8));
f.addCode(
c.call(f1mPrefix+"_fromMontgomery", x0, r0),
c.call(f1mPrefix+"_fromMontgomery", x1, r1),
c.call(f1mPrefix+"_fromMontgomery", x2, r2)
);
}
function buildCopy() {
const f = module.addFunction(prefix+"_copy");
f.addParam("x", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8));
const r0 = c.getLocal("r");
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8));
const r2 = c.i32_add(c.getLocal("r"), c.i32_const(2*f1n8));
f.addCode(
c.call(f1mPrefix+"_copy", x0, r0),
c.call(f1mPrefix+"_copy", x1, r1),
c.call(f1mPrefix+"_copy", x2, r2),
);
}
function buildZero() {
const f = module.addFunction(prefix+"_zero");
f.addParam("x", "i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8));
f.addCode(
c.call(f1mPrefix+"_zero", x0),
c.call(f1mPrefix+"_zero", x1),
c.call(f1mPrefix+"_zero", x2),
);
}
function buildOne() {
const f = module.addFunction(prefix+"_one");
f.addParam("x", "i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8));
f.addCode(
c.call(f1mPrefix+"_one", x0),
c.call(f1mPrefix+"_zero", x1),
c.call(f1mPrefix+"_zero", x2),
);
}
function buildEq() {
const f = module.addFunction(prefix+"_eq");
f.addParam("x", "i32");
f.addParam("y", "i32");
f.setReturnType("i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8));
const y0 = c.getLocal("y");
const y1 = c.i32_add(c.getLocal("y"), c.i32_const(f1n8));
const y2 = c.i32_add(c.getLocal("y"), c.i32_const(2*f1n8));
f.addCode(
c.i32_and(
c.i32_and(
c.call(f1mPrefix+"_eq", x0, y0),
c.call(f1mPrefix+"_eq", x1, y1),
),
c.call(f1mPrefix+"_eq", x2, y2)
)
);
}
function buildIsZero() {
const f = module.addFunction(prefix+"_isZero");
f.addParam("x", "i32");
f.setReturnType("i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8));
f.addCode(
c.i32_and(
c.i32_and(
c.call(f1mPrefix+"_isZero", x0),
c.call(f1mPrefix+"_isZero", x1)
),
c.call(f1mPrefix+"_isZero", x2)
)
);
}
function buildInverse() {
const f = module.addFunction(prefix+"_inverse");
f.addParam("x", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8));
const r0 = c.getLocal("r");
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(f1n8));
const r2 = c.i32_add(c.getLocal("r"), c.i32_const(2*f1n8));
const t0 = c.i32_const(module.alloc(f1n8));
const t1 = c.i32_const(module.alloc(f1n8));
const t2 = c.i32_const(module.alloc(f1n8));
const t3 = c.i32_const(module.alloc(f1n8));
const t4 = c.i32_const(module.alloc(f1n8));
const t5 = c.i32_const(module.alloc(f1n8));
const c0 = c.i32_const(module.alloc(f1n8));
const c1 = c.i32_const(module.alloc(f1n8));
const c2 = c.i32_const(module.alloc(f1n8));
const t6 = c.i32_const(module.alloc(f1n8));
const AUX = c.i32_const(module.alloc(f1n8));
f.addCode(
c.call(f1mPrefix+"_square", x0, t0),
c.call(f1mPrefix+"_square", x1, t1),
c.call(f1mPrefix+"_square", x2, t2),
c.call(f1mPrefix+"_mul", x0, x1, t3),
c.call(f1mPrefix+"_mul", x0, x2, t4),
c.call(f1mPrefix+"_mul", x1, x2, t5),
c.call(mulNonResidueFn, t5, c0),
c.call(f1mPrefix+"_sub", t0, c0, c0),
c.call(mulNonResidueFn, t2, c1),
c.call(f1mPrefix+"_sub", c1, t3, c1),
c.call(f1mPrefix+"_sub", t1, t4, c2),
c.call(f1mPrefix+"_mul", x2, c1, t6),
c.call(f1mPrefix+"_mul", x1, c2, AUX),
c.call(f1mPrefix+"_add", t6, AUX, t6),
c.call(mulNonResidueFn, t6, t6),
c.call(f1mPrefix+"_mul", x0, c0, AUX),
c.call(f1mPrefix+"_add", AUX, t6, t6),
c.call(f1mPrefix+"_inverse", t6, t6),
c.call(f1mPrefix+"_mul", t6, c0, r0),
c.call(f1mPrefix+"_mul", t6, c1, r1),
c.call(f1mPrefix+"_mul", t6, c2, r2)
);
}
function buildSign() {
const f = module.addFunction(prefix+"_sign");
f.addParam("x", "i32");
f.addLocal("s", "i32");
f.setReturnType("i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
const x2 = c.i32_add(c.getLocal("x"), c.i32_const(2*f1n8));
f.addCode(
c.setLocal("s" , c.call( f1mPrefix + "_sign", x2)),
c.if(
c.getLocal("s"),
c.ret(c.getLocal("s"))
),
c.setLocal("s" , c.call( f1mPrefix + "_sign", x1)),
c.if(
c.getLocal("s"),
c.ret(c.getLocal("s"))
),
c.ret(c.call( f1mPrefix + "_sign", x0))
);
}
function buildIsOne() {
const f = module.addFunction(prefix+"_isOne");
f.addParam("x", "i32");
f.setReturnType("i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8));
const x2 = c.i32_add(c.getLocal("x"), c.i32_const(f1n8*2));
f.addCode(
c.ret(
c.i32_and(
c.i32_and(
c.call(f1mPrefix + "_isOne", x0),
c.call(f1mPrefix + "_isZero", x1)
),
c.call(f1mPrefix + "_isZero", x2)
)
)
);
}
buildIsZero();
buildIsOne();
buildZero();
buildOne();
buildCopy();
buildMul();
buildSquare();
buildAdd();
buildSub();
buildNeg();
buildSign();
buildToMontgomery();
buildFromMontgomery();
buildEq();
buildInverse();
buildTimesScalar();
buildIsNegative();
module.exportFunction(prefix + "_isZero");
module.exportFunction(prefix + "_isOne");
module.exportFunction(prefix + "_zero");
module.exportFunction(prefix + "_one");
module.exportFunction(prefix + "_copy");
module.exportFunction(prefix + "_mul");
module.exportFunction(prefix + "_square");
module.exportFunction(prefix + "_add");
module.exportFunction(prefix + "_sub");
module.exportFunction(prefix + "_neg");
module.exportFunction(prefix + "_sign");
module.exportFunction(prefix + "_fromMontgomery");
module.exportFunction(prefix + "_toMontgomery");
module.exportFunction(prefix + "_eq");
module.exportFunction(prefix + "_inverse");
buildBatchInverse(module, prefix);
buildExp(
module,
prefix + "_exp",
f1n8*3,
prefix + "_mul",
prefix + "_square",
prefix + "_copy",
prefix + "_one"
);
module.exportFunction(prefix + "_exp");
module.exportFunction(prefix + "_timesScalar");
module.exportFunction(prefix + "_batchInverse");
module.exportFunction(prefix + "_isNegative");
return prefix;
};
/*
Copyright 2019 0KIMS association.
This file is part of wasmsnark (Web Assembly zkSnark Prover).
wasmsnark is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
wasmsnark is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with wasmsnark. If not, see <https://www.gnu.org/licenses/>.
*/
var build_timesscalarnaf = function buildTimesScalarNAF(module, fnName, elementLen, opAB, opAA, opAmB, opCopy, opInit) {
const f = module.addFunction(fnName);
f.addParam("base", "i32");
f.addParam("scalar", "i32");
f.addParam("scalarLength", "i32");
f.addParam("r", "i32");
f.addLocal("old0", "i32");
f.addLocal("nbits", "i32");
f.addLocal("i", "i32");
f.addLocal("last", "i32");
f.addLocal("cur", "i32");
f.addLocal("carry", "i32");
f.addLocal("p", "i32");
const c = f.getCodeBuilder();
const aux = c.i32_const(module.alloc(elementLen));
function getBit(IDX) {
return c.i32_and(
c.i32_shr_u(
c.i32_load(
c.i32_add(
c.getLocal("scalar"),
c.i32_and(
c.i32_shr_u(
IDX,
c.i32_const(3)
),
c.i32_const(0xFFFFFFFC)
)
)
),
c.i32_and(
IDX,
c.i32_const(0x1F)
)
),
c.i32_const(1)
);
}
function pushBit(b) {
return [
...c.i32_store8(
c.getLocal("p"),
c.i32_const(b)
),
...c.setLocal(
"p",
c.i32_add(
c.getLocal("p"),
c.i32_const(1)
)
)
];
}
f.addCode(
c.if(
c.i32_eqz(c.getLocal("scalarLength")),
[
...c.call(opInit, c.getLocal("r")),
...c.ret([])
]
),
c.setLocal("nbits", c.i32_shl(c.getLocal("scalarLength"), c.i32_const(3))),
c.setLocal("old0", c.i32_load(c.i32_const(0))),
c.setLocal("p", c.getLocal("old0")),
c.i32_store(
c.i32_const(0),
c.i32_and(
c.i32_add(
c.i32_add(
c.getLocal("old0"),
c.i32_const(32)
),
c.getLocal("nbits")
),
c.i32_const(0xFFFFFFF8)
)
),
c.setLocal("i", c.i32_const(1)),
c.setLocal("last",getBit(c.i32_const(0))),
c.setLocal("carry",c.i32_const(0)),
c.block(c.loop(
c.br_if(1, c.i32_eq( c.getLocal("i"), c.getLocal("nbits"))),
c.setLocal("cur", getBit(c.getLocal("i"))),
c.if( c.getLocal("last"),
c.if( c.getLocal("cur"),
c.if(c.getLocal("carry"),
[
...c.setLocal("last", c.i32_const(0)),
...c.setLocal("carry", c.i32_const(1)),
...pushBit(1)
]
,
[
...c.setLocal("last", c.i32_const(0)),
...c.setLocal("carry", c.i32_const(1)),
...pushBit(255)
],
),
c.if(c.getLocal("carry"),
[
...c.setLocal("last", c.i32_const(0)),
...c.setLocal("carry", c.i32_const(1)),
...pushBit(255)
]
,
[
...c.setLocal("last", c.i32_const(0)),
...c.setLocal("carry", c.i32_const(0)),
...pushBit(1)
],
),
),
c.if( c.getLocal("cur"),
c.if(c.getLocal("carry"),
[
...c.setLocal("last", c.i32_const(0)),
...c.setLocal("carry", c.i32_const(1)),
...pushBit(0)
]
,
[
...c.setLocal("last", c.i32_const(1)),
...c.setLocal("carry", c.i32_const(0)),
...pushBit(0)
],
),
c.if(c.getLocal("carry"),
[
...c.setLocal("last", c.i32_const(1)),
...c.setLocal("carry", c.i32_const(0)),
...pushBit(0)
]
,
[
...c.setLocal("last", c.i32_const(0)),
...c.setLocal("carry", c.i32_const(0)),
...pushBit(0)
],
),
)
),
c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
c.br(0)
)),
c.if( c.getLocal("last"),
c.if(c.getLocal("carry"),
[
...pushBit(255),
...pushBit(0),
...pushBit(1)
]
,
[
...pushBit(1)
],
),
c.if(c.getLocal("carry"),
[
...pushBit(0),
...pushBit(1)
]
),
),
c.setLocal("p", c.i32_sub(c.getLocal("p"), c.i32_const(1))),
// p already points to the last bit
c.call(opCopy, c.getLocal("base"), aux),
c.call(opInit, c.getLocal("r")),
c.block(c.loop(
c.call(opAA, c.getLocal("r"), c.getLocal("r")),
c.setLocal("cur",
c.i32_load8_u(
c.getLocal("p")
)
),
c.if(
c.getLocal("cur"),
c.if(
c.i32_eq(c.getLocal("cur"), c.i32_const(1)),
c.call(opAB, c.getLocal("r"), aux, c.getLocal("r")),
c.call(opAmB, c.getLocal("r"), aux, c.getLocal("r")),
)
),
c.br_if(1, c.i32_eq( c.getLocal("old0"), c.getLocal("p"))),
c.setLocal("p", c.i32_sub(c.getLocal("p"), c.i32_const(1))),
c.br(0)
)),
c.i32_store( c.i32_const(0), c.getLocal("old0"))
);
};
/*
Copyright 2019 0KIMS association.
This file is part of wasmsnark (Web Assembly zkSnark Prover).
wasmsnark is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
wasmsnark is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with wasmsnark. If not, see <https://www.gnu.org/licenses/>.
*/
var build_multiexp = function buildMultiexp(module, prefix, fnName, opAdd, n8b) {
const n64g = module.modules[prefix].n64;
const n8g = n64g*8;
function buildGetChunk() {
const f = module.addFunction(fnName + "_getChunk");
f.addParam("pScalar", "i32");
f.addParam("scalarSize", "i32"); // Number of bytes of the scalar
f.addParam("startBit", "i32"); // Bit to start extract
f.addParam("chunkSize", "i32"); // Chunk size in bits
f.addLocal("bitsToEnd", "i32");
f.addLocal("mask", "i32");
f.setReturnType("i32");
const c = f.getCodeBuilder();
f.addCode(
c.setLocal("bitsToEnd",
c.i32_sub(
c.i32_mul(
c.getLocal("scalarSize"),
c.i32_const(8)
),
c.getLocal("startBit")
)
),
c.if(
c.i32_gt_s(
c.getLocal("chunkSize"),
c.getLocal("bitsToEnd")
),
c.setLocal(
"mask",
c.i32_sub(
c.i32_shl(
c.i32_const(1),
c.getLocal("bitsToEnd")
),
c.i32_const(1)
)
),
c.setLocal(
"mask",
c.i32_sub(
c.i32_shl(
c.i32_const(1),
c.getLocal("chunkSize")
),
c.i32_const(1)
)
)
),
c.i32_and(
c.i32_shr_u(
c.i32_load(
c.i32_add(
c.getLocal("pScalar"),
c.i32_shr_u(
c.getLocal("startBit"),
c.i32_const(3)
)
),
0, // offset
0 // align to byte.
),
c.i32_and(
c.getLocal("startBit"),
c.i32_const(0x7)
)
),
c.getLocal("mask")
)
);
}
function buildMutiexpChunk() {
const f = module.addFunction(fnName + "_chunk");
f.addParam("pBases", "i32");
f.addParam("pScalars", "i32");
f.addParam("scalarSize", "i32"); // Number of points
f.addParam("n", "i32"); // Number of points
f.addParam("startBit", "i32"); // bit where it starts the chunk
f.addParam("chunkSize", "i32"); // bit where it starts the chunk
f.addParam("pr", "i32");
f.addLocal("nChunks", "i32");
f.addLocal("itScalar", "i32");
f.addLocal("endScalar", "i32");
f.addLocal("itBase", "i32");
f.addLocal("i", "i32");
f.addLocal("j", "i32");
f.addLocal("nTable", "i32");
f.addLocal("pTable", "i32");
f.addLocal("idx", "i32");
f.addLocal("pIdxTable", "i32");
const c = f.getCodeBuilder();
f.addCode(
c.if(
c.i32_eqz(c.getLocal("n")),
[
...c.call(prefix + "_zero", c.getLocal("pr")),
...c.ret([])
]
),
// Allocate memory
c.setLocal(
"nTable",
c.i32_shl(
c.i32_const(1),
c.getLocal("chunkSize")
)
),
c.setLocal("pTable", c.i32_load( c.i32_const(0) )),
c.i32_store(
c.i32_const(0),
c.i32_add(
c.getLocal("pTable"),
c.i32_mul(
c.getLocal("nTable"),
c.i32_const(n8g)
)
)
),
// Reset Table
c.setLocal("j", c.i32_const(0)),
c.block(c.loop(
c.br_if(
1,
c.i32_eq(
c.getLocal("j"),
c.getLocal("nTable")
)
),
c.call(
prefix + "_zero",
c.i32_add(
c.getLocal("pTable"),
c.i32_mul(
c.getLocal("j"),
c.i32_const(n8g)
)
)
),
c.setLocal("j", c.i32_add(c.getLocal("j"), c.i32_const(1))),
c.br(0)
)),
// Distribute elements
c.setLocal("itBase", c.getLocal("pBases")),
c.setLocal("itScalar", c.getLocal("pScalars")),
c.setLocal("endScalar",
c.i32_add(
c.getLocal("pScalars"),
c.i32_mul(
c.getLocal("n"),
c.getLocal("scalarSize")
)
)
),
c.block(c.loop(
c.br_if(
1,
c.i32_eq(
c.getLocal("itScalar"),
c.getLocal("endScalar")
)
),
c.setLocal(
"idx",
c.call(fnName + "_getChunk",
c.getLocal("itScalar"),
c.getLocal("scalarSize"),
c.getLocal("startBit"),
c.getLocal("chunkSize")
)
),
c.if(
c.getLocal("idx"),
[
...c.setLocal(
"pIdxTable",
c.i32_add(
c.getLocal("pTable"),
c.i32_mul(
c.i32_sub(
c.getLocal("idx"),
c.i32_const(1)
),
c.i32_const(n8g)
)
)
),
...c.call(
opAdd,
c.getLocal("pIdxTable"),
c.getLocal("itBase"),
c.getLocal("pIdxTable"),
)
]
),
c.setLocal("itScalar", c.i32_add(c.getLocal("itScalar"), c.getLocal("scalarSize"))),
c.setLocal("itBase", c.i32_add(c.getLocal("itBase"), c.i32_const(n8b))),
c.br(0)
)),
c.call(fnName + "_reduceTable", c.getLocal("pTable"), c.getLocal("chunkSize")),
c.call(
prefix + "_copy",
c.getLocal("pTable"),
c.getLocal("pr")
),
c.i32_store(
c.i32_const(0),
c.getLocal("pTable")
)
);
}
function buildMultiexp() {
const f = module.addFunction(fnName);
f.addParam("pBases", "i32");
f.addParam("pScalars", "i32");
f.addParam("scalarSize", "i32"); // Number of points
f.addParam("n", "i32"); // Number of points
f.addParam("pr", "i32");
f.addLocal("chunkSize", "i32");
f.addLocal("nChunks", "i32");
f.addLocal("itScalar", "i32");
f.addLocal("endScalar", "i32");
f.addLocal("itBase", "i32");
f.addLocal("itBit", "i32");
f.addLocal("i", "i32");
f.addLocal("j", "i32");
f.addLocal("nTable", "i32");
f.addLocal("pTable", "i32");
f.addLocal("idx", "i32");
f.addLocal("pIdxTable", "i32");
const c = f.getCodeBuilder();
const aux = c.i32_const(module.alloc(n8g));
const pTSizes = module.alloc([
17, 17, 17, 17, 17, 17, 17, 17,
17, 17, 16, 16, 15, 14, 13, 13,
12, 11, 10, 9, 8, 7, 7, 6,
5 , 4, 3, 2, 1, 1, 1, 1
]);
f.addCode(
c.call(prefix + "_zero", c.getLocal("pr")),
c.if(
c.i32_eqz(c.getLocal("n")),
c.ret([])
),
c.setLocal("chunkSize", c.i32_load8_u( c.i32_clz(c.getLocal("n")), pTSizes )),
c.setLocal(
"nChunks",
c.i32_add(
c.i32_div_u(
c.i32_sub(
c.i32_shl(
c.getLocal("scalarSize"),
c.i32_const(3)
),
c.i32_const(1)
),
c.getLocal("chunkSize")
),
c.i32_const(1)
)
),
// Allocate memory
c.setLocal(
"itBit",
c.i32_mul(
c.i32_sub(
c.getLocal("nChunks"),
c.i32_const(1)
),
c.getLocal("chunkSize")
)
),
c.block(c.loop(
c.br_if(
1,
c.i32_lt_s(
c.getLocal("itBit"),
c.i32_const(0)
)
),
// Double nChunk times
c.if(
c.i32_eqz(c.call(prefix + "_isZero", c.getLocal("pr"))),
[
...c.setLocal("j", c.i32_const(0)),
...c.block(c.loop(
c.br_if(
1,
c.i32_eq(
c.getLocal("j"),
c.getLocal("chunkSize")
)
),
c.call(prefix + "_double", c.getLocal("pr"), c.getLocal("pr")),
c.setLocal("j", c.i32_add(c.getLocal("j"), c.i32_const(1))),
c.br(0)
))
]
),
c.call(
fnName + "_chunk",
c.getLocal("pBases"),
c.getLocal("pScalars"),
c.getLocal("scalarSize"),
c.getLocal("n"),
c.getLocal("itBit"),
c.getLocal("chunkSize"),
aux
),
c.call(
prefix + "_add",
c.getLocal("pr"),
aux,
c.getLocal("pr")
),
c.setLocal("itBit", c.i32_sub(c.getLocal("itBit"), c.getLocal("chunkSize"))),
c.br(0)
))
);
}
function buildReduceTable() {
const f = module.addFunction(fnName + "_reduceTable");
f.addParam("pTable", "i32");
f.addParam("p", "i32"); // Number of bits of the table
f.addLocal("half", "i32");
f.addLocal("it1", "i32");
f.addLocal("it2", "i32");
f.addLocal("pAcc", "i32");
const c = f.getCodeBuilder();
f.addCode(
c.if(
c.i32_eq(c.getLocal("p"), c.i32_const(1)),
c.ret([])
),
c.setLocal(
"half",
c.i32_shl(
c.i32_const(1),
c.i32_sub(
c.getLocal("p"),
c.i32_const(1)
)
)
),
c.setLocal("it1", c.getLocal("pTable")),
c.setLocal(
"it2",
c.i32_add(
c.getLocal("pTable"),
c.i32_mul(
c.getLocal("half"),
c.i32_const(n8g)
)
)
),
c.setLocal("pAcc",
c.i32_sub(
c.getLocal("it2"),
c.i32_const(n8g)
)
),
c.block(c.loop(
c.br_if(
1,
c.i32_eq(
c.getLocal("it1"),
c.getLocal("pAcc")
)
),
c.call(
prefix + "_add",
c.getLocal("it1"),
c.getLocal("it2"),
c.getLocal("it1")
),
c.call(
prefix + "_add",
c.getLocal("pAcc"),
c.getLocal("it2"),
c.getLocal("pAcc")
),
c.setLocal("it1", c.i32_add(c.getLocal("it1"), c.i32_const(n8g))),
c.setLocal("it2", c.i32_add(c.getLocal("it2"), c.i32_const(n8g))),
c.br(0)
)),
c.call(
fnName + "_reduceTable",
c.getLocal("pTable"),
c.i32_sub(
c.getLocal("p"),
c.i32_const(1)
)
),
c.setLocal("p", c.i32_sub(c.getLocal("p"), c.i32_const(1))),
c.block(c.loop(
c.br_if(1, c.i32_eqz(c.getLocal("p"))),
c.call(prefix + "_double", c.getLocal("pAcc"), c.getLocal("pAcc")),
c.setLocal("p", c.i32_sub(c.getLocal("p"), c.i32_const(1))),
c.br(0)
)),
c.call(prefix + "_add", c.getLocal("pTable"), c.getLocal("pAcc"), c.getLocal("pTable"))
);
}
buildGetChunk();
buildReduceTable();
buildMutiexpChunk();
buildMultiexp();
module.exportFunction(fnName);
module.exportFunction(fnName +"_chunk");
};
/*
Copyright 2019 0KIMS association.
This file is part of wasmsnark (Web Assembly zkSnark Prover).
wasmsnark is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
wasmsnark is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with wasmsnark. If not, see <https://www.gnu.org/licenses/>.
*/
const buildTimesScalarNAF = build_timesscalarnaf;
//const buildTimesScalar = require("./build_timesscalar");
const buildBatchConvertion = build_batchconvertion;
const buildMultiexp$1 = build_multiexp;
var build_curve_jacobian_a0 = function buildCurve(module, prefix, prefixField, pB) {
const n64 = module.modules[prefixField].n64;
const n8 = n64*8;
if (module.modules[prefix]) return prefix; // already builded
module.modules[prefix] = {
n64: n64*3
};
function buildIsZero() {
const f = module.addFunction(prefix + "_isZero");
f.addParam("p1", "i32");
f.setReturnType("i32");
const c = f.getCodeBuilder();
f.addCode(c.call(
prefixField + "_isZero",
c.i32_add(
c.getLocal("p1"),
c.i32_const(n8*2)
)
));
}
function buildIsZeroAffine() {
const f = module.addFunction(prefix + "_isZeroAffine");
f.addParam("p1", "i32");
f.setReturnType("i32");
const c = f.getCodeBuilder();
f.addCode(
c.i32_and(
c.call(
prefixField + "_isZero",
c.getLocal("p1")
),
c.call(
prefixField + "_isZero",
c.i32_add(
c.getLocal("p1"),
c.i32_const(n8)
)
)
)
);
}
function buildCopy() {
const f = module.addFunction(prefix + "_copy");
f.addParam("ps", "i32");
f.addParam("pd", "i32");
const c = f.getCodeBuilder();
for (let i=0; i<n64*3; i++) {
f.addCode(
c.i64_store(
c.getLocal("pd"),
i*8,
c.i64_load(
c.getLocal("ps"),
i*8
)
)
);
}
}
function buildCopyAffine() {
const f = module.addFunction(prefix + "_copyAffine");
f.addParam("ps", "i32");
f.addParam("pd", "i32");
const c = f.getCodeBuilder();
for (let i=0; i<n64*2; i++) {
f.addCode(
c.i64_store(
c.getLocal("pd"),
i*8,
c.i64_load(
c.getLocal("ps"),
i*8
)
)
);
}
}
function buildZero() {
const f = module.addFunction(prefix + "_zero");
f.addParam("pr", "i32");
const c = f.getCodeBuilder();
f.addCode(c.call(
prefixField + "_zero",
c.getLocal("pr")
));
f.addCode(c.call(
prefixField + "_one",
c.i32_add(
c.getLocal("pr"),
c.i32_const(n8)
)
));
f.addCode(c.call(
prefixField + "_zero",
c.i32_add(
c.getLocal("pr"),
c.i32_const(n8*2)
)
));
}
function buildZeroAffine() {
const f = module.addFunction(prefix + "_zeroAffine");
f.addParam("pr", "i32");
const c = f.getCodeBuilder();
f.addCode(c.call(
prefixField + "_zero",
c.getLocal("pr")
));
f.addCode(c.call(
prefixField + "_zero",
c.i32_add(
c.getLocal("pr"),
c.i32_const(n8)
)
));
}
function buildEq() {
const f = module.addFunction(prefix + "_eq");
f.addParam("p1", "i32");
f.addParam("p2", "i32");
f.setReturnType("i32");
f.addLocal("z1", "i32");
f.addLocal("z2", "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 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));
f.addCode(
c.if(
c.call(prefix + "_isZero", c.getLocal("p1")),
c.ret( c.call(prefix + "_isZero", c.getLocal("p2"))),
),
c.if(
c.call(prefix + "_isZero", c.getLocal("p2")),
c.ret(c.i32_const(0))
),
c.if(
c.call(prefixField + "_isOne", z1),
c.ret(c.call(prefix + "_eqMixed", c.getLocal("p2"), c.getLocal("p1")))
),
c.if(
c.call(prefixField + "_isOne", z2),
c.ret(c.call(prefix + "_eqMixed", c.getLocal("p1"), c.getLocal("p2")))
),
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.ret(c.i32_const(1))
)
),
c.ret(c.i32_const(0))
);
}
function buildEqMixed() {
const f = module.addFunction(prefix + "_eqMixed");
f.addParam("p1", "i32");
f.addParam("p2", "i32");
f.setReturnType("i32");
f.addLocal("z1", "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));
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));
f.addCode(
c.if(
c.call(prefix + "_isZero", c.getLocal("p1")),
c.ret( c.call(prefix + "_isZeroAffine", c.getLocal("p2"))),
),
c.if(
c.call(prefix + "_isZeroAffine", c.getLocal("p2")),
c.ret(c.i32_const(0))
),
c.if(
c.call(prefixField + "_isOne", z1),
c.ret(c.call(prefix + "_eqAffine", c.getLocal("p1"), c.getLocal("p2")))
),
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),
c.if(
c.call(prefixField + "_eq", x1, U2),
c.if(
c.call(prefixField + "_eq", y1, S2),
c.ret(c.i32_const(1))
)
),
c.ret(c.i32_const(0))
);
}
function buildDouble() {
const f = module.addFunction(prefix + "_double");
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));
const A = c.i32_const(module.alloc(n8));
const B = c.i32_const(module.alloc(n8));
const C = c.i32_const(module.alloc(n8));
const D = c.i32_const(module.alloc(n8));
const E = c.i32_const(module.alloc(n8));
const F = c.i32_const(module.alloc(n8));
const G = c.i32_const(module.alloc(n8));
const eightC = c.i32_const(module.alloc(n8));
f.addCode(
c.if(
c.call(prefix + "_isZero", c.getLocal("p1")),
[
...c.call(prefix + "_copy", c.getLocal("p1"), c.getLocal("pr")),
...c.ret([])
]
),
c.if(
c.call(prefixField + "_isOne", z),
[
...c.ret(c.call(prefix + "_doubleAffine", c.getLocal("p1"), c.getLocal("pr"))),
...c.ret([])
]
),
c.call(prefixField + "_square", x, A),
c.call(prefixField + "_square", y, B),
c.call(prefixField + "_square", B, C),
c.call(prefixField + "_add", x, B, D),
c.call(prefixField + "_square", D, D),
c.call(prefixField + "_sub", D, A, D),
c.call(prefixField + "_sub", D, C, D),
c.call(prefixField + "_add", D, D, D),
c.call(prefixField + "_add", A, A, E),
c.call(prefixField + "_add", E, A, E),
c.call(prefixField + "_square", E, F),
c.call(prefixField + "_mul", y, z, G),
c.call(prefixField + "_add", D, D, x3),
c.call(prefixField + "_sub", F, x3, x3),
c.call(prefixField + "_add", C, C, eightC),
c.call(prefixField + "_add", eightC, eightC, eightC),
c.call(prefixField + "_add", eightC, eightC, eightC),
c.call(prefixField + "_sub", D, x3, y3),
c.call(prefixField + "_mul", y3, E, y3),
c.call(prefixField + "_sub", y3, eightC, y3),
c.call(prefixField + "_add", G, G, z3),
);
}
function buildDoubleAffine() {
const f = module.addFunction(prefix + "_doubleAffine");
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 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 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));
f.addCode(
c.if(
c.call(prefix + "_isZeroAffine", c.getLocal("p1")),
[
...c.call(prefix + "_toJacobian", c.getLocal("p1"), c.getLocal("pr")),
...c.ret([])
]
),
// XX = X1^2
c.call(prefixField + "_square", x, XX),
// YY = Y1^2
c.call(prefixField + "_square", y, YY),
// YYYY = YY^2
c.call(prefixField + "_square", YY, YYYY),
// 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),
// M = 3*XX+a (Hera a=0)
c.call(prefixField + "_add", XX, XX, M),
c.call(prefixField + "_add", M, XX, M),
// Z3 = 2*Y1
c.call(prefixField + "_add", y, y, z3),
// 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),
// 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 buildEqAffine() {
const f = module.addFunction(prefix + "_eqAffine");
f.addParam("p1", "i32");
f.addParam("p2", "i32");
f.setReturnType("i32");
f.addLocal("z1", "i32");
const c = f.getCodeBuilder();
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 buildToMontgomery() {
const f = module.addFunction(prefix + "_toMontgomery");
f.addParam("p1", "i32");
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))
));
}
}
function buildToMontgomeryAffine() {
const f = module.addFunction(prefix + "_toMontgomeryAffine");
f.addParam("p1", "i32");
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<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))
));
}
}
function buildFromMontgomery() {
const f = module.addFunction(prefix + "_fromMontgomery");
f.addParam("p1", "i32");
f.addParam("pr", "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))
));
}
}
function buildFromMontgomeryAffine() {
const f = module.addFunction(prefix + "_fromMontgomeryAffine");
f.addParam("p1", "i32");
f.addParam("pr", "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))
));
}
}
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");
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));
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(prefixField + "_sub", r2, J, x3),
c.call(prefixField + "_sub", x3, V2, x3),
c.call(prefixField + "_mul", S1, J, S1_J2),
c.call(prefixField + "_add", S1_J2, S1_J2, S1_J2),
c.call(prefixField + "_sub", V, x3, y3),
c.call(prefixField + "_mul", y3, r, y3),
c.call(prefixField + "_sub", y3, S1_J2, y3),
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),
);
}
function buildAddMixed() {
const f = module.addFunction(prefix + "_addMixed");
f.addParam("p1", "i32");
f.addParam("p2", "i32");
f.addParam("pr", "i32");
f.addLocal("z1", "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));
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 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.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),
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([])
]
)
),
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),
c.call(prefixField + "_mul", y1, J, y1_J2),
c.call(prefixField + "_add", y1_J2, y1_J2, y1_J2),
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() {
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("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 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([])
]
),
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([])
]
)
),
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),
c.call(prefixField + "_sub", r2, J, x3),
c.call(prefixField + "_sub", x3, V2, x3),
c.call(prefixField + "_mul", y1, J, y1_J2),
c.call(prefixField + "_add", y1_J2, y1_J2, y1_J2),
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 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(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));
f.addCode(
c.call(prefixField + "_copy", x, x3),
c.call(prefixField + "_neg", y, y3),
c.call(prefixField + "_copy", z, z3)
);
}
function buildNegAffine() {
const f = module.addFunction(prefix + "_negAffine");
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 x3 = c.getLocal("pr");
const y3 = c.i32_add(c.getLocal("pr"), c.i32_const(n8));
f.addCode(
c.call(prefixField + "_copy", x, x3),
c.call(prefixField + "_neg", y, y3),
);
}
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 + "_neg", c.getLocal("p2"), AUX),
c.call(prefix + "_add", c.getLocal("p1"), AUX, c.getLocal("pr")),
);
}
function buildSubMixed() {
const f = module.addFunction(prefix + "_subMixed");
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 + "_addMixed", c.getLocal("p1"), AUX, c.getLocal("pr")),
);
}
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")),
);
}
// 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));
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),
]
)
);
}
// Does not set Z.
function buildToAffine() {
const f = module.addFunction(prefix + "_toAffine");
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 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(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),
]
)
);
}
function buildToJacobian() {
const f = module.addFunction(prefix + "_toJacobian");
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 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 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 tmp = c.i32_const(module.alloc(n8));
f.addCode(
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.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("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.br_if(1, c.i32_eq ( c.getLocal("i"), c.getLocal("n") )),
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)),
),
]
),
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")
)
);
}
// 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();
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();
const tmp = 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)
)
)
),
);
}
function buildLEMtoU() {
const f = module.addFunction(prefix + "_LEMtoU");
f.addParam("pIn", "i32");
f.addParam("pOut", "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))),
);
}
function buildUtoLEM() {
const f = module.addFunction(prefix + "_UtoLEM");
f.addParam("pIn", "i32");
f.addParam("pOut", "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.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"))
);
}
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();
const pTmp = module.alloc(n8*2);
const tmpX = c.i32_const(pTmp);
const tmpY = c.i32_const(pTmp + n8);
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)
)
),
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")),
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),
c.call(prefixField + "_sqrt", tmpY, tmpY),
c.call(prefixField + "_neg", tmpY, tmpX),
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");
const c = f.getCodeBuilder();
const x = c.getLocal("pIn");
const y = c.i32_add(c.getLocal("pIn"), c.i32_const(n8));
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),
c.ret(
c.call(prefixField + "_eq", y2, x3b)
)
);
}
function buildInCurve() {
const f = module.addFunction(prefix + "_inCurve");
f.addParam("pIn", "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),
)
);
}
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();
buildNormalize();
buildReverseBytes();
buildLEMtoU();
buildLEMtoC();
buildUtoLEM();
buildCtoLEM();
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);
buildBatchConvertion(module, prefix + "_batchToJacobian", prefix + "_toJacobian", n8*2, n8*3, true);
buildMultiexp$1(module, prefix, prefix + "_multiexp", prefix + "_add", n8*3);
buildMultiexp$1(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"
);
buildTimesScalarNAF(
module,
prefix + "_timesScalarAffine",
n8*2,
prefix + "_addMixed",
prefix + "_double",
prefix + "_subMixed",
prefix + "_copyAffine",
prefix + "_zero"
);
module.exportFunction(prefix + "_isZero");
module.exportFunction(prefix + "_isZeroAffine");
module.exportFunction(prefix + "_eq");
module.exportFunction(prefix + "_eqMixed");
module.exportFunction(prefix + "_eqAffine");
module.exportFunction(prefix + "_copy");
module.exportFunction(prefix + "_copyAffine");
module.exportFunction(prefix + "_zero");
module.exportFunction(prefix + "_zeroAffine");
module.exportFunction(prefix + "_double");
module.exportFunction(prefix + "_doubleAffine");
module.exportFunction(prefix + "_add");
module.exportFunction(prefix + "_addMixed");
module.exportFunction(prefix + "_addAffine");
module.exportFunction(prefix + "_neg");
module.exportFunction(prefix + "_negAffine");
module.exportFunction(prefix + "_sub");
module.exportFunction(prefix + "_subMixed");
module.exportFunction(prefix + "_subAffine");
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");
// Convertion functions
module.exportFunction(prefix + "_LEMtoU");
module.exportFunction(prefix + "_LEMtoC");
module.exportFunction(prefix + "_UtoLEM");
module.exportFunction(prefix + "_CtoLEM");
module.exportFunction(prefix + "_batchLEMtoU");
module.exportFunction(prefix + "_batchLEMtoC");
module.exportFunction(prefix + "_batchUtoLEM");
module.exportFunction(prefix + "_batchCtoLEM");
module.exportFunction(prefix + "_toAffine");
module.exportFunction(prefix + "_toJacobian");
module.exportFunction(prefix + "_batchToAffine");
module.exportFunction(prefix + "_batchToJacobian");
module.exportFunction(prefix + "_inCurve");
module.exportFunction(prefix + "_inCurveAffine");
/*
buildG1MulScalar(module, zq);
module.exportFunction("g1MulScalar");
*/
return prefix;
};
/*
Copyright 2019 0KIMS association.
This file is part of wasmsnark (Web Assembly zkSnark Prover).
wasmsnark is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
wasmsnark is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with wasmsnark. If not, see <https://www.gnu.org/licenses/>.
*/
const { isOdd: isOdd$2, modInv: modInv$1, modPow } = bigint;
const utils$3 = utils$6;
var build_fft = function buildFFT(module, prefix, gPrefix, fPrefix, opGtimesF) {
const n64f = module.modules[fPrefix].n64;
const n8f = n64f*8;
const n64g = module.modules[gPrefix].n64;
const n8g = n64g*8;
const q = module.modules[fPrefix].q;
let rem = q - 1n;
let maxBits = 0;
while (!isOdd$2(rem)) {
maxBits ++;
rem = rem >> 1n;
}
let nr = 2n;
while ( modPow(nr, q >> 1n, q) === 1n ) nr = nr + 1n;
// console.log(nr);
const w = new Array(maxBits+1);
w[maxBits] = modPow(nr, rem, q);
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;
for (let i=0; i<w.length; i++) {
const m = w[i] * R % q;
bytes.push(...utils$3.bigInt2BytesLE(m, n8f));
}
const ROOTs = module.alloc(bytes);
const i2 = new Array(maxBits+1);
i2[0] = 1n;
for (let i=1; i<=maxBits; i++) {
i2[i] = i2[i-1] * 2n;
}
const bytesi2 =[];
for (let i=0; i<=maxBits; i++) {
const m = modInv$1(i2[i], q) * R % q;
bytesi2.push(...utils$3.bigInt2BytesLE(m, n8f));
}
const INV2 = module.alloc(bytesi2);
const shift = modPow(nr, 2n, q);
const bytesShiftToSmallM =[];
const bytesSConst =[];
for (let i=0; i<=maxBits; i++) {
const shiftToSmallM = modPow(shift, 2n ** BigInt(i), q);
const sConst = modInv$1(q + 1n - shiftToSmallM, q);
bytesShiftToSmallM.push(...utils$3.bigInt2BytesLE(shiftToSmallM * R % q, n8f));
bytesSConst.push(...utils$3.bigInt2BytesLE(sConst * R % q, n8f));
}
const SHIFT_TO_M = module.alloc( bytesShiftToSmallM );
const SCONST = module.alloc( bytesSConst );
function rev(x) {
let r=0;
for (let i=0; i<8; i++) {
if (x & (1 << i)) {
r = r | (0x80 >> i);
}
}
return r;
}
const rtable = Array(256);
for (let i=0; i<256; i++) {
rtable[i] = rev(i);
}
const REVTABLE = module.alloc(rtable);
function buildLog2() {
const f = module.addFunction(prefix+"__log2");
f.addParam("n", "i32");
f.setReturnType("i32");
f.addLocal("bits", "i32");
f.addLocal("aux", "i32");
const c = f.getCodeBuilder();
f.addCode(
c.setLocal(
"aux",
c.i32_shr_u(
c.getLocal("n"),
c.i32_const(1)
)
)
);
f.addCode(c.setLocal("bits", c.i32_const(0)));
f.addCode(c.block(c.loop(
c.br_if(
1,
c.i32_eqz(c.getLocal("aux"))
),
c.setLocal(
"aux",
c.i32_shr_u(
c.getLocal("aux"),
c.i32_const(1)
)
),
c.setLocal(
"bits",
c.i32_add(
c.getLocal("bits"),
c.i32_const(1)
)
),
c.br(0)
)));
f.addCode(c.if(
c.i32_ne(
c.getLocal("n"),
c.i32_shl(
c.i32_const(1),
c.getLocal("bits")
)
),
c.unreachable()
));
f.addCode(c.if(
c.i32_gt_u(
c.getLocal("bits"),
c.i32_const(maxBits)
),
c.unreachable()
));
f.addCode(c.getLocal("bits"));
}
function buildFFT() {
const f = module.addFunction(prefix+"_fft");
f.addParam("px", "i32");
f.addParam("n", "i32");
f.addLocal("bits", "i32");
const c = f.getCodeBuilder();
const One = c.i32_const(module.alloc(n8f));
f.addCode(
c.setLocal(
"bits",
c.call(
prefix + "__log2",
c.getLocal("n")
)
),
c.call(fPrefix + "_one", One),
c.call(
prefix+"_rawfft",
c.getLocal("px"),
c.getLocal("bits"),
c.i32_const(0),
One
)
);
}
function buildIFFT() {
const f = module.addFunction(prefix+"_ifft");
f.addParam("px", "i32");
f.addParam("n", "i32");
f.addLocal("bits", "i32");
f.addLocal("pInv2", "i32");
const c = f.getCodeBuilder();
f.addCode(
c.setLocal(
"bits",
c.call(
prefix + "__log2",
c.getLocal("n")
)
),
c.setLocal(
"pInv2",
c.i32_add(
c.i32_const(INV2),
c.i32_mul(
c.getLocal("bits"),
c.i32_const(n8f)
)
)
),
c.call(
prefix+"_rawfft",
c.getLocal("px"),
c.getLocal("bits"),
c.i32_const(1),
c.getLocal("pInv2")
),
);
}
function buildRawFFT() {
const f = module.addFunction(prefix+"_rawfft");
f.addParam("px", "i32");
f.addParam("bits", "i32"); // 2 power
f.addParam("reverse", "i32");
f.addParam("mulFactor", "i32");
f.addLocal("s", "i32");
f.addLocal("k", "i32");
f.addLocal("j", "i32");
f.addLocal("m", "i32");
f.addLocal("mdiv2", "i32");
f.addLocal("n", "i32");
f.addLocal("pwm", "i32");
f.addLocal("idx1", "i32");
f.addLocal("idx2", "i32");
const c = f.getCodeBuilder();
const W = c.i32_const(module.alloc(n8f));
const T = c.i32_const(module.alloc(n8g));
const U = c.i32_const(module.alloc(n8g));
f.addCode(
c.call(prefix + "__reversePermutation", c.getLocal("px"), c.getLocal("bits")),
c.setLocal("n", c.i32_shl(c.i32_const(1), c.getLocal("bits"))),
c.setLocal("s", c.i32_const(1)),
c.block(c.loop(
c.br_if(
1,
c.i32_gt_u(
c.getLocal("s"),
c.getLocal("bits")
)
),
c.setLocal("m", c.i32_shl(c.i32_const(1), c.getLocal("s"))),
c.setLocal("pwm",
c.i32_add(
c.i32_const(ROOTs),
c.i32_mul(
c.getLocal("s"),
c.i32_const(n8f)
)
)
),
c.setLocal("k", c.i32_const(0)),
c.block(c.loop(
c.br_if(
1,
c.i32_ge_u(
c.getLocal("k"),
c.getLocal("n")
)
),
c.call(fPrefix + "_one", W),
c.setLocal("mdiv2", c.i32_shr_u(c.getLocal("m"), c.i32_const(1)) ),
c.setLocal("j", c.i32_const(0)),
c.block(c.loop(
c.br_if(
1,
c.i32_ge_u(
c.getLocal("j"),
c.getLocal("mdiv2")
)
),
c.setLocal(
"idx1",
c.i32_add(
c.getLocal("px"),
c.i32_mul(
c.i32_add(
c.getLocal("k"),
c.getLocal("j")
),
c.i32_const(n8g)
)
)
),
c.setLocal(
"idx2",
c.i32_add(
c.getLocal("idx1"),
c.i32_mul(
c.getLocal("mdiv2"),
c.i32_const(n8g)
)
)
),
c.call(
opGtimesF,
c.getLocal("idx2"),
W,
T
),
c.call(
gPrefix + "_copy",
c.getLocal("idx1"),
U
),
c.call(
gPrefix + "_add",
U,
T,
c.getLocal("idx1"),
),
c.call(
gPrefix + "_sub",
U,
T,
c.getLocal("idx2"),
),
c.call(
fPrefix + "_mul",
W,
c.getLocal("pwm"),
W,
),
c.setLocal("j", c.i32_add(c.getLocal("j"), c.i32_const(1))),
c.br(0)
)),
c.setLocal("k", c.i32_add(c.getLocal("k"), c.getLocal("m"))),
c.br(0)
)),
c.setLocal("s", c.i32_add(c.getLocal("s"), c.i32_const(1))),
c.br(0)
)),
c.call(
prefix + "__fftFinal",
c.getLocal("px"),
c.getLocal("bits"),
c.getLocal("reverse"),
c.getLocal("mulFactor")
)
);
}
function buildFinalInverse() {
const f = module.addFunction(prefix+"__fftFinal");
f.addParam("px", "i32");
f.addParam("bits", "i32");
f.addParam("reverse", "i32");
f.addParam("mulFactor", "i32");
f.addLocal("n", "i32");
f.addLocal("ndiv2", "i32");
f.addLocal("pInv2", "i32");
f.addLocal("i", "i32");
f.addLocal("mask", "i32");
f.addLocal("idx1", "i32");
f.addLocal("idx2", "i32");
const c = f.getCodeBuilder();
const T = c.i32_const(module.alloc(n8g));
f.addCode(
c.if(
c.i32_and(
c.i32_eqz(c.getLocal("reverse")),
c.call(fPrefix + "_isOne", c.getLocal("mulFactor"))
),
c.ret([])
),
c.setLocal("n", c.i32_shl( c.i32_const(1), c.getLocal("bits"))),
c.setLocal("mask", c.i32_sub( c.getLocal("n") , c.i32_const(1))),
c.setLocal("i", c.i32_const(1)),
c.setLocal(
"ndiv2",
c.i32_shr_u(
c.getLocal("n"),
c.i32_const(1)
)
),
c.block(c.loop(
c.br_if(
1,
c.i32_ge_u(
c.getLocal("i"),
c.getLocal("ndiv2")
)
),
c.setLocal("idx1",
c.i32_add(
c.getLocal("px"),
c.i32_mul(
c.getLocal("i"),
c.i32_const(n8g)
)
)
),
c.setLocal("idx2",
c.i32_add(
c.getLocal("px"),
c.i32_mul(
c.i32_sub(
c.getLocal("n"),
c.getLocal("i")
),
c.i32_const(n8g)
)
)
),
c.if(
c.getLocal("reverse"),
c.if(
c.call(fPrefix + "_isOne", c.getLocal("mulFactor")),
[
...c.call(gPrefix + "_copy", c.getLocal("idx1"), T),
...c.call(gPrefix + "_copy", c.getLocal("idx2") , c.getLocal("idx1") ),
...c.call(gPrefix + "_copy", T , c.getLocal("idx2")),
],
[
...c.call(gPrefix + "_copy", c.getLocal("idx1"), T),
...c.call(opGtimesF , c.getLocal("idx2") , c.getLocal("mulFactor"), c.getLocal("idx1") ),
...c.call(opGtimesF , T , c.getLocal("mulFactor"), c.getLocal("idx2")),
]
),
c.if(
c.call(fPrefix + "_isOne", c.getLocal("mulFactor")),
[
// Do nothing (It should not be here)
],
[
...c.call(opGtimesF , c.getLocal("idx1") , c.getLocal("mulFactor"), c.getLocal("idx1") ),
...c.call(opGtimesF , c.getLocal("idx2") , c.getLocal("mulFactor"), c.getLocal("idx2")),
]
)
),
c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
c.br(0)
)),
c.if(
c.call(fPrefix + "_isOne", c.getLocal("mulFactor")),
[
// Do nothing (It should not be here)
],
[
...c.call(opGtimesF, c.getLocal("px") , c.getLocal("mulFactor"), c.getLocal("px")),
...c.setLocal("idx2",
c.i32_add(
c.getLocal("px"),
c.i32_mul(
c.getLocal("ndiv2"),
c.i32_const(n8g)
)
)
),
...c.call(opGtimesF, c.getLocal("idx2"),c.getLocal("mulFactor"), c.getLocal("idx2"))
]
)
);
}
function buildReversePermutation() {
const f = module.addFunction(prefix+"__reversePermutation");
f.addParam("px", "i32");
f.addParam("bits", "i32");
f.addLocal("n", "i32");
f.addLocal("i", "i32");
f.addLocal("ri", "i32");
f.addLocal("idx1", "i32");
f.addLocal("idx2", "i32");
const c = f.getCodeBuilder();
const T = c.i32_const(module.alloc(n8g));
f.addCode(
c.setLocal("n", c.i32_shl( c.i32_const(1), c.getLocal("bits"))),
c.setLocal("i", c.i32_const(0)),
c.block(c.loop(
c.br_if(
1,
c.i32_eq(
c.getLocal("i"),
c.getLocal("n")
)
),
c.setLocal("idx1",
c.i32_add(
c.getLocal("px"),
c.i32_mul(
c.getLocal("i"),
c.i32_const(n8g)
)
)
),
c.setLocal("ri", c.call(prefix + "__rev", c.getLocal("i"), c.getLocal("bits"))),
c.setLocal("idx2",
c.i32_add(
c.getLocal("px"),
c.i32_mul(
c.getLocal("ri"),
c.i32_const(n8g)
)
)
),
c.if(
c.i32_lt_u(
c.getLocal("i"),
c.getLocal("ri")
),
[
...c.call(gPrefix + "_copy", c.getLocal("idx1"), T),
...c.call(gPrefix + "_copy", c.getLocal("idx2") , c.getLocal("idx1")),
...c.call(gPrefix + "_copy", T , c.getLocal("idx2"))
]
),
c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
c.br(0)
))
);
}
function buildRev() {
const f = module.addFunction(prefix+"__rev");
f.addParam("x", "i32");
f.addParam("bits", "i32");
f.setReturnType("i32");
const c = f.getCodeBuilder();
f.addCode(
c.i32_rotl(
c.i32_add(
c.i32_add(
c.i32_shl(
c.i32_load8_u(
c.i32_and(
c.getLocal("x"),
c.i32_const(0xFF)
),
REVTABLE,
0
),
c.i32_const(24)
),
c.i32_shl(
c.i32_load8_u(
c.i32_and(
c.i32_shr_u(
c.getLocal("x"),
c.i32_const(8)
),
c.i32_const(0xFF)
),
REVTABLE,
0
),
c.i32_const(16)
),
),
c.i32_add(
c.i32_shl(
c.i32_load8_u(
c.i32_and(
c.i32_shr_u(
c.getLocal("x"),
c.i32_const(16)
),
c.i32_const(0xFF)
),
REVTABLE,
0
),
c.i32_const(8)
),
c.i32_load8_u(
c.i32_and(
c.i32_shr_u(
c.getLocal("x"),
c.i32_const(24)
),
c.i32_const(0xFF)
),
REVTABLE,
0
),
)
),
c.getLocal("bits")
)
);
}
function buildFFTJoin() {
const f = module.addFunction(prefix+"_fftJoin");
f.addParam("pBuff1", "i32");
f.addParam("pBuff2", "i32");
f.addParam("n", "i32");
f.addParam("first", "i32");
f.addParam("inc", "i32");
f.addLocal("idx1", "i32");
f.addLocal("idx2", "i32");
f.addLocal("i", "i32");
const c = f.getCodeBuilder();
const W = c.i32_const(module.alloc(n8f));
const T = c.i32_const(module.alloc(n8g));
const U = c.i32_const(module.alloc(n8g));
f.addCode(
c.call( fPrefix + "_copy", c.getLocal("first"), W),
c.setLocal("i", c.i32_const(0)),
c.block(c.loop(
c.br_if(
1,
c.i32_eq(
c.getLocal("i"),
c.getLocal("n")
)
),
c.setLocal(
"idx1",
c.i32_add(
c.getLocal("pBuff1"),
c.i32_mul(
c.getLocal("i"),
c.i32_const(n8g)
)
)
),
c.setLocal(
"idx2",
c.i32_add(
c.getLocal("pBuff2"),
c.i32_mul(
c.getLocal("i"),
c.i32_const(n8g)
)
)
),
c.call(
opGtimesF,
c.getLocal("idx2"),
W,
T
),
c.call(
gPrefix + "_copy",
c.getLocal("idx1"),
U
),
c.call(
gPrefix + "_add",
U,
T,
c.getLocal("idx1"),
),
c.call(
gPrefix + "_sub",
U,
T,
c.getLocal("idx2"),
),
c.call(
fPrefix + "_mul",
W,
c.getLocal("inc"),
W,
),
c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
c.br(0)
))
);
}
function buildFFTJoinExt() {
const f = module.addFunction(prefix+"_fftJoinExt");
f.addParam("pBuff1", "i32");
f.addParam("pBuff2", "i32");
f.addParam("n", "i32");
f.addParam("first", "i32");
f.addParam("inc", "i32");
f.addParam("totalBits", "i32");
f.addLocal("idx1", "i32");
f.addLocal("idx2", "i32");
f.addLocal("i", "i32");
f.addLocal("pShiftToM", "i32");
const c = f.getCodeBuilder();
const W = c.i32_const(module.alloc(n8f));
const U = c.i32_const(module.alloc(n8g));
f.addCode(
c.setLocal("pShiftToM",
c.i32_add(
c.i32_const(SHIFT_TO_M),
c.i32_mul(
c.getLocal("totalBits"),
c.i32_const(n8f)
)
)
),
c.call( fPrefix + "_copy", c.getLocal("first"), W),
c.setLocal("i", c.i32_const(0)),
c.block(c.loop(
c.br_if(
1,
c.i32_eq(
c.getLocal("i"),
c.getLocal("n")
)
),
c.setLocal(
"idx1",
c.i32_add(
c.getLocal("pBuff1"),
c.i32_mul(
c.getLocal("i"),
c.i32_const(n8g)
)
)
),
c.setLocal(
"idx2",
c.i32_add(
c.getLocal("pBuff2"),
c.i32_mul(
c.getLocal("i"),
c.i32_const(n8g)
)
)
),
c.call(
gPrefix + "_add",
c.getLocal("idx1"),
c.getLocal("idx2"),
U
),
c.call(
opGtimesF,
c.getLocal("idx2"),
c.getLocal("pShiftToM"),
c.getLocal("idx2")
),
c.call(
gPrefix + "_add",
c.getLocal("idx1"),
c.getLocal("idx2"),
c.getLocal("idx2")
),
c.call(
opGtimesF,
c.getLocal("idx2"),
W,
c.getLocal("idx2"),
),
c.call(
gPrefix + "_copy",
U,
c.getLocal("idx1")
),
c.call(
fPrefix + "_mul",
W,
c.getLocal("inc"),
W
),
c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
c.br(0)
))
);
}
function buildFFTJoinExtInv() {
const f = module.addFunction(prefix+"_fftJoinExtInv");
f.addParam("pBuff1", "i32");
f.addParam("pBuff2", "i32");
f.addParam("n", "i32");
f.addParam("first", "i32");
f.addParam("inc", "i32");
f.addParam("totalBits", "i32");
f.addLocal("idx1", "i32");
f.addLocal("idx2", "i32");
f.addLocal("i", "i32");
f.addLocal("pShiftToM", "i32");
f.addLocal("pSConst", "i32");
const c = f.getCodeBuilder();
const W = c.i32_const(module.alloc(n8f));
const U = c.i32_const(module.alloc(n8g));
f.addCode(
c.setLocal("pShiftToM",
c.i32_add(
c.i32_const(SHIFT_TO_M),
c.i32_mul(
c.getLocal("totalBits"),
c.i32_const(n8f)
)
)
),
c.setLocal("pSConst",
c.i32_add(
c.i32_const(SCONST),
c.i32_mul(
c.getLocal("totalBits"),
c.i32_const(n8f)
)
)
),
c.call( fPrefix + "_copy", c.getLocal("first"), W),
c.setLocal("i", c.i32_const(0)),
c.block(c.loop(
c.br_if(
1,
c.i32_eq(
c.getLocal("i"),
c.getLocal("n")
)
),
c.setLocal(
"idx1",
c.i32_add(
c.getLocal("pBuff1"),
c.i32_mul(
c.getLocal("i"),
c.i32_const(n8g)
)
)
),
c.setLocal(
"idx2",
c.i32_add(
c.getLocal("pBuff2"),
c.i32_mul(
c.getLocal("i"),
c.i32_const(n8g)
)
)
),
c.call(
opGtimesF,
c.getLocal("idx2"),
W,
U
),
c.call(
gPrefix + "_sub",
c.getLocal("idx1"),
U,
c.getLocal("idx2"),
),
c.call(
opGtimesF,
c.getLocal("idx2"),
c.getLocal("pSConst"),
c.getLocal("idx2")
),
c.call(
opGtimesF,
c.getLocal("idx1"),
c.getLocal("pShiftToM"),
c.getLocal("idx1")
),
c.call(
gPrefix + "_sub",
U,
c.getLocal("idx1"),
c.getLocal("idx1")
),
c.call(
opGtimesF,
c.getLocal("idx1"),
c.getLocal("pSConst"),
c.getLocal("idx1")
),
c.call(
fPrefix + "_mul",
W,
c.getLocal("inc"),
W
),
c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
c.br(0)
))
);
}
function buildPrepareLagrangeEvaluation() {
const f = module.addFunction(prefix+"_prepareLagrangeEvaluation");
f.addParam("pBuff1", "i32");
f.addParam("pBuff2", "i32");
f.addParam("n", "i32");
f.addParam("first", "i32");
f.addParam("inc", "i32");
f.addParam("totalBits", "i32");
f.addLocal("idx1", "i32");
f.addLocal("idx2", "i32");
f.addLocal("i", "i32");
f.addLocal("pShiftToM", "i32");
f.addLocal("pSConst", "i32");
const c = f.getCodeBuilder();
const W = c.i32_const(module.alloc(n8f));
const U = c.i32_const(module.alloc(n8g));
f.addCode(
c.setLocal("pShiftToM",
c.i32_add(
c.i32_const(SHIFT_TO_M),
c.i32_mul(
c.getLocal("totalBits"),
c.i32_const(n8f)
)
)
),
c.setLocal("pSConst",
c.i32_add(
c.i32_const(SCONST),
c.i32_mul(
c.getLocal("totalBits"),
c.i32_const(n8f)
)
)
),
c.call( fPrefix + "_copy", c.getLocal("first"), W),
c.setLocal("i", c.i32_const(0)),
c.block(c.loop(
c.br_if(
1,
c.i32_eq(
c.getLocal("i"),
c.getLocal("n")
)
),
c.setLocal(
"idx1",
c.i32_add(
c.getLocal("pBuff1"),
c.i32_mul(
c.getLocal("i"),
c.i32_const(n8g)
)
)
),
c.setLocal(
"idx2",
c.i32_add(
c.getLocal("pBuff2"),
c.i32_mul(
c.getLocal("i"),
c.i32_const(n8g)
)
)
),
c.call(
opGtimesF,
c.getLocal("idx1"),
c.getLocal("pShiftToM"),
U
),
c.call(
gPrefix + "_sub",
c.getLocal("idx2"),
U,
U
),
c.call(
gPrefix + "_sub",
c.getLocal("idx1"),
c.getLocal("idx2"),
c.getLocal("idx2"),
),
c.call(
opGtimesF,
U,
c.getLocal("pSConst"),
c.getLocal("idx1"),
),
c.call(
opGtimesF,
c.getLocal("idx2"),
W,
c.getLocal("idx2"),
),
c.call(
fPrefix + "_mul",
W,
c.getLocal("inc"),
W
),
c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
c.br(0)
))
);
}
function buildFFTMix() {
const f = module.addFunction(prefix+"_fftMix");
f.addParam("pBuff", "i32");
f.addParam("n", "i32");
f.addParam("exp", "i32");
f.addLocal("nGroups", "i32");
f.addLocal("nPerGroup", "i32");
f.addLocal("nPerGroupDiv2", "i32");
f.addLocal("pairOffset", "i32");
f.addLocal("idx1", "i32");
f.addLocal("idx2", "i32");
f.addLocal("i", "i32");
f.addLocal("j", "i32");
f.addLocal("pwm", "i32");
const c = f.getCodeBuilder();
const W = c.i32_const(module.alloc(n8f));
const T = c.i32_const(module.alloc(n8g));
const U = c.i32_const(module.alloc(n8g));
f.addCode(
c.setLocal("nPerGroup", c.i32_shl(c.i32_const(1), c.getLocal("exp"))),
c.setLocal("nPerGroupDiv2", c.i32_shr_u(c.getLocal("nPerGroup"), c.i32_const(1))),
c.setLocal("nGroups", c.i32_shr_u(c.getLocal("n"), c.getLocal("exp"))),
c.setLocal("pairOffset", c.i32_mul(c.getLocal("nPerGroupDiv2"), c.i32_const(n8g))),
c.setLocal("pwm",
c.i32_add(
c.i32_const(ROOTs),
c.i32_mul(
c.getLocal("exp"),
c.i32_const(n8f)
)
)
),
c.setLocal("i", c.i32_const(0)),
c.block(c.loop(
c.br_if(
1,
c.i32_eq(
c.getLocal("i"),
c.getLocal("nGroups")
)
),
c.call( fPrefix + "_one", W),
c.setLocal("j", c.i32_const(0)),
c.block(c.loop(
c.br_if(
1,
c.i32_eq(
c.getLocal("j"),
c.getLocal("nPerGroupDiv2")
)
),
c.setLocal(
"idx1",
c.i32_add(
c.getLocal("pBuff"),
c.i32_mul(
c.i32_add(
c.i32_mul(
c.getLocal("i"),
c.getLocal("nPerGroup")
),
c.getLocal("j")
),
c.i32_const(n8g)
)
)
),
c.setLocal(
"idx2",
c.i32_add(
c.getLocal("idx1"),
c.getLocal("pairOffset")
)
),
c.call(
opGtimesF,
c.getLocal("idx2"),
W,
T
),
c.call(
gPrefix + "_copy",
c.getLocal("idx1"),
U
),
c.call(
gPrefix + "_add",
U,
T,
c.getLocal("idx1"),
),
c.call(
gPrefix + "_sub",
U,
T,
c.getLocal("idx2"),
),
c.call(
fPrefix + "_mul",
W,
c.getLocal("pwm"),
W,
),
c.setLocal("j", c.i32_add(c.getLocal("j"), c.i32_const(1))),
c.br(0)
)),
c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
c.br(0)
))
);
}
// Reverse all and multiply by factor
function buildFFTFinal() {
const f = module.addFunction(prefix+"_fftFinal");
f.addParam("pBuff", "i32");
f.addParam("n", "i32");
f.addParam("factor", "i32");
f.addLocal("idx1", "i32");
f.addLocal("idx2", "i32");
f.addLocal("i", "i32");
f.addLocal("ndiv2", "i32");
const c = f.getCodeBuilder();
const T = c.i32_const(module.alloc(n8g));
f.addCode(
c.setLocal("ndiv2", c.i32_shr_u(c.getLocal("n"), c.i32_const(1))),
c.if(
c.i32_and(
c.getLocal("n"),
c.i32_const(1)
),
c.call(
opGtimesF,
c.i32_add(
c.getLocal("pBuff"),
c.i32_mul(
c.getLocal("ndiv2"),
c.i32_const(n8g)
)
),
c.getLocal("factor"),
c.i32_add(
c.getLocal("pBuff"),
c.i32_mul(
c.getLocal("ndiv2"),
c.i32_const(n8g)
)
),
),
),
c.setLocal("i", c.i32_const(0)),
c.block(c.loop(
c.br_if(
1,
c.i32_ge_u(
c.getLocal("i"),
c.getLocal("ndiv2")
)
),
c.setLocal(
"idx1",
c.i32_add(
c.getLocal("pBuff"),
c.i32_mul(
c.getLocal("i"),
c.i32_const(n8g)
)
)
),
c.setLocal(
"idx2",
c.i32_add(
c.getLocal("pBuff"),
c.i32_mul(
c.i32_sub(
c.i32_sub(
c.getLocal("n"),
c.i32_const(1)
),
c.getLocal("i")
),
c.i32_const(n8g)
)
)
),
c.call(
opGtimesF,
c.getLocal("idx2"),
c.getLocal("factor"),
T
),
c.call(
opGtimesF,
c.getLocal("idx1"),
c.getLocal("factor"),
c.getLocal("idx2"),
),
c.call(
gPrefix + "_copy",
T,
c.getLocal("idx1"),
),
c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
c.br(0)
))
);
}
buildRev();
buildReversePermutation();
buildFinalInverse();
buildRawFFT();
buildLog2();
buildFFT();
buildIFFT();
buildFFTJoin();
buildFFTJoinExt();
buildFFTJoinExtInv();
buildFFTMix();
buildFFTFinal();
buildPrepareLagrangeEvaluation();
module.exportFunction(prefix+"_fft");
module.exportFunction(prefix+"_ifft");
module.exportFunction(prefix+"_rawfft");
module.exportFunction(prefix+"_fftJoin");
module.exportFunction(prefix+"_fftJoinExt");
module.exportFunction(prefix+"_fftJoinExtInv");
module.exportFunction(prefix+"_fftMix");
module.exportFunction(prefix+"_fftFinal");
module.exportFunction(prefix+"_prepareLagrangeEvaluation");
};
/*
Copyright 2019 0KIMS association.
This file is part of wasmsnark (Web Assembly zkSnark Prover).
wasmsnark is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
wasmsnark is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with wasmsnark. If not, see <https://www.gnu.org/licenses/>.
*/
var build_pol = function buildPol(module, prefix, prefixField) {
const n64 = module.modules[prefixField].n64;
const n8 = n64*8;
function buildZero() {
const f = module.addFunction(prefix+"_zero");
f.addParam("px", "i32");
f.addParam("n", "i32");
f.addLocal("lastp", "i32");
f.addLocal("p", "i32");
const c = f.getCodeBuilder();
f.addCode(
c.setLocal("p", c.getLocal("px")),
c.setLocal(
"lastp",
c.i32_add(
c.getLocal("px"),
c.i32_mul(
c.getLocal("n"),
c.i32_const(n8)
)
)
),
c.block(c.loop(
c.br_if(
1,
c.i32_eq(
c.getLocal("p"),
c.getLocal("lastp")
)
),
c.call(prefixField + "_zero", c.getLocal("p")),
c.setLocal("p", c.i32_add(c.getLocal("p"), c.i32_const(n8))),
c.br(0)
))
);
}
function buildConstructLC() {
const f = module.addFunction(prefix+"_constructLC");
f.addParam("ppolynomials", "i32");
f.addParam("psignals", "i32");
f.addParam("nSignals", "i32");
f.addParam("pres", "i32");
f.addLocal("i", "i32");
f.addLocal("j", "i32");
f.addLocal("pp", "i32");
f.addLocal("ps", "i32");
f.addLocal("pd", "i32");
f.addLocal("ncoefs", "i32");
const c = f.getCodeBuilder();
const aux = c.i32_const(module.alloc(n8));
f.addCode(
c.setLocal("i", c.i32_const(0)),
c.setLocal("pp", c.getLocal("ppolynomials")),
c.setLocal("ps", c.getLocal("psignals")),
c.block(c.loop(
c.br_if(
1,
c.i32_eq(
c.getLocal("i"),
c.getLocal("nSignals")
)
),
c.setLocal("ncoefs", c.i32_load(c.getLocal("pp"))),
c.setLocal("pp", c.i32_add(c.getLocal("pp"), c.i32_const(4))),
c.setLocal("j", c.i32_const(0)),
c.block(c.loop(
c.br_if(
1,
c.i32_eq(
c.getLocal("j"),
c.getLocal("ncoefs")
)
),
c.setLocal(
"pd",
c.i32_add(
c.getLocal("pres"),
c.i32_mul(
c.i32_load(c.getLocal("pp")),
c.i32_const(n8)
)
)
),
c.setLocal("pp", c.i32_add(c.getLocal("pp"), c.i32_const(4))),
c.call(
prefixField + "_mul",
c.getLocal("ps"),
c.getLocal("pp"),
aux
),
c.call(
prefixField + "_add",
aux,
c.getLocal("pd"),
c.getLocal("pd")
),
c.setLocal("pp", c.i32_add(c.getLocal("pp"), c.i32_const(n8))),
c.setLocal("j", c.i32_add(c.getLocal("j"), c.i32_const(1))),
c.br(0)
)),
c.setLocal("ps", c.i32_add(c.getLocal("ps"), c.i32_const(n8))),
c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
c.br(0)
))
);
}
buildZero();
buildConstructLC();
module.exportFunction(prefix + "_zero");
module.exportFunction(prefix + "_constructLC");
return prefix;
};
var build_qap = function buildQAP(module, prefix, prefixField) {
const n64 = module.modules[prefixField].n64;
const n8 = n64*8;
function buildBuildABC() {
const f = module.addFunction(prefix+"_buildABC");
f.addParam("pCoefs", "i32");
f.addParam("nCoefs", "i32");
f.addParam("pWitness", "i32");
f.addParam("pA", "i32");
f.addParam("pB", "i32");
f.addParam("pC", "i32");
f.addParam("offsetOut", "i32");
f.addParam("nOut", "i32");
f.addParam("offsetWitness", "i32");
f.addParam("nWitness", "i32");
f.addLocal("it", "i32");
f.addLocal("ita", "i32");
f.addLocal("itb", "i32");
f.addLocal("last", "i32");
f.addLocal("m", "i32");
f.addLocal("c", "i32");
f.addLocal("s", "i32");
f.addLocal("pOut", "i32");
const c = f.getCodeBuilder();
const aux = c.i32_const(module.alloc(n8));
f.addCode(
// Set output a and b to 0
c.setLocal("ita", c.getLocal("pA")),
c.setLocal("itb", c.getLocal("pB")),
c.setLocal(
"last",
c.i32_add(
c.getLocal("pA"),
c.i32_mul(
c.getLocal("nOut"),
c.i32_const(n8)
)
)
),
c.block(c.loop(
c.br_if(
1,
c.i32_eq(
c.getLocal("ita"),
c.getLocal("last")
)
),
c.call(prefixField + "_zero", c.getLocal("ita")),
c.call(prefixField + "_zero", c.getLocal("itb")),
c.setLocal("ita", c.i32_add(c.getLocal("ita"), c.i32_const(n8))),
c.setLocal("itb", c.i32_add(c.getLocal("itb"), c.i32_const(n8))),
c.br(0)
)),
c.setLocal("it", c.getLocal("pCoefs")),
c.setLocal(
"last",
c.i32_add(
c.getLocal("pCoefs"),
c.i32_mul(
c.getLocal("nCoefs"),
c.i32_const(n8+12)
)
)
),
c.block(c.loop(
c.br_if(
1,
c.i32_eq(
c.getLocal("it"),
c.getLocal("last")
)
),
c.setLocal(
"s",
c.i32_load(c.getLocal("it"), 8)
),
c.if(
c.i32_or(
c.i32_lt_u(
c.getLocal("s"),
c.getLocal("offsetWitness"),
),
c.i32_ge_u(
c.getLocal("s"),
c.i32_add(
c.getLocal("offsetWitness"),
c.getLocal("nWitness"),
)
)
),
[
...c.setLocal("it", c.i32_add(c.getLocal("it"), c.i32_const(n8+12))),
...c.br(1)
]
),
c.setLocal(
"m",
c.i32_load(c.getLocal("it"))
),
c.if(
c.i32_eq(c.getLocal("m"), c.i32_const(0)),
c.setLocal("pOut", c.getLocal("pA")),
c.if(
c.i32_eq(c.getLocal("m"), c.i32_const(1)),
c.setLocal("pOut", c.getLocal("pB")),
[
...c.setLocal("it", c.i32_add(c.getLocal("it"), c.i32_const(n8+12))),
...c.br(1)
]
)
),
c.setLocal(
"c",
c.i32_load(c.getLocal("it"), 4)
),
c.if(
c.i32_or(
c.i32_lt_u(
c.getLocal("c"),
c.getLocal("offsetOut"),
),
c.i32_ge_u(
c.getLocal("c"),
c.i32_add(
c.getLocal("offsetOut"),
c.getLocal("nOut"),
)
)
),
[
...c.setLocal("it", c.i32_add(c.getLocal("it"), c.i32_const(n8+12))),
...c.br(1)
]
),
c.setLocal(
"pOut",
c.i32_add(
c.getLocal("pOut"),
c.i32_mul(
c.i32_sub(
c.getLocal("c"),
c.getLocal("offsetOut")
),
c.i32_const(n8)
)
)
),
c.call(
prefixField + "_mul",
c.i32_add(
c.getLocal("pWitness"),
c.i32_mul(
c.i32_sub(c.getLocal("s"), c.getLocal("offsetWitness")),
c.i32_const(n8)
)
),
c.i32_add( c.getLocal("it"), c.i32_const(12)),
aux
),
c.call(
prefixField + "_add",
c.getLocal("pOut"),
aux,
c.getLocal("pOut"),
),
c.setLocal("it", c.i32_add(c.getLocal("it"), c.i32_const(n8+12))),
c.br(0)
)),
c.setLocal("ita", c.getLocal("pA")),
c.setLocal("itb", c.getLocal("pB")),
c.setLocal("it", c.getLocal("pC")),
c.setLocal(
"last",
c.i32_add(
c.getLocal("pA"),
c.i32_mul(
c.getLocal("nOut"),
c.i32_const(n8)
)
)
),
c.block(c.loop(
c.br_if(
1,
c.i32_eq(
c.getLocal("ita"),
c.getLocal("last")
)
),
c.call(
prefixField + "_mul",
c.getLocal("ita"),
c.getLocal("itb"),
c.getLocal("it")
),
c.setLocal("ita", c.i32_add(c.getLocal("ita"), c.i32_const(n8))),
c.setLocal("itb", c.i32_add(c.getLocal("itb"), c.i32_const(n8))),
c.setLocal("it", c.i32_add(c.getLocal("it"), c.i32_const(n8))),
c.br(0)
)),
);
}
function buildJoinABC() {
const f = module.addFunction(prefix+"_joinABC");
f.addParam("pA", "i32");
f.addParam("pB", "i32");
f.addParam("pC", "i32");
f.addParam("n", "i32");
f.addParam("pP", "i32");
f.addLocal("ita", "i32");
f.addLocal("itb", "i32");
f.addLocal("itc", "i32");
f.addLocal("itp", "i32");
f.addLocal("last", "i32");
const c = f.getCodeBuilder();
const aux = c.i32_const(module.alloc(n8));
f.addCode(
c.setLocal("ita", c.getLocal("pA")),
c.setLocal("itb", c.getLocal("pB")),
c.setLocal("itc", c.getLocal("pC")),
c.setLocal("itp", c.getLocal("pP")),
c.setLocal(
"last",
c.i32_add(
c.getLocal("pA"),
c.i32_mul(
c.getLocal("n"),
c.i32_const(n8)
)
)
),
c.block(c.loop(
c.br_if(
1,
c.i32_eq(
c.getLocal("ita"),
c.getLocal("last")
)
),
c.call(
prefixField + "_mul",
c.getLocal("ita"),
c.getLocal("itb"),
aux
),
c.call(
prefixField + "_sub",
aux,
c.getLocal("itc"),
c.getLocal("itp"),
),
c.setLocal("ita", c.i32_add(c.getLocal("ita"), c.i32_const(n8))),
c.setLocal("itb", c.i32_add(c.getLocal("itb"), c.i32_const(n8))),
c.setLocal("itc", c.i32_add(c.getLocal("itc"), c.i32_const(n8))),
c.setLocal("itp", c.i32_add(c.getLocal("itp"), c.i32_const(n8))),
c.br(0)
))
);
}
function buildBatchAdd() {
const f = module.addFunction(prefix+"_batchAdd");
f.addParam("pa", "i32");
f.addParam("pb", "i32");
f.addParam("n", "i32");
f.addParam("pr", "i32");
f.addLocal("ita", "i32");
f.addLocal("itb", "i32");
f.addLocal("itr", "i32");
f.addLocal("last", "i32");
const c = f.getCodeBuilder();
f.addCode(
c.setLocal("ita", c.getLocal("pa")),
c.setLocal("itb", c.getLocal("pb")),
c.setLocal("itr", c.getLocal("pr")),
c.setLocal(
"last",
c.i32_add(
c.getLocal("pa"),
c.i32_mul(
c.getLocal("n"),
c.i32_const(n8)
)
)
),
c.block(c.loop(
c.br_if(
1,
c.i32_eq(
c.getLocal("ita"),
c.getLocal("last")
)
),
c.call(
prefixField + "_add",
c.getLocal("ita"),
c.getLocal("itb"),
c.getLocal("itr"),
),
c.setLocal("ita", c.i32_add(c.getLocal("ita"), c.i32_const(n8))),
c.setLocal("itb", c.i32_add(c.getLocal("itb"), c.i32_const(n8))),
c.setLocal("itr", c.i32_add(c.getLocal("itr"), c.i32_const(n8))),
c.br(0)
))
);
}
buildBuildABC();
buildJoinABC();
buildBatchAdd();
module.exportFunction(prefix + "_buildABC");
module.exportFunction(prefix + "_joinABC");
module.exportFunction(prefix + "_batchAdd");
return prefix;
};
/*
Copyright 2019 0KIMS association.
This file is part of wasmsnark (Web Assembly zkSnark Prover).
wasmsnark is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
wasmsnark is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with wasmsnark. If not, see <https://www.gnu.org/licenses/>.
*/
var build_applykey = function buildApplyKey(module, fnName, gPrefix, frPrefix, sizeGIn, sizeGOut, sizeF, opGtimesF) {
const f = module.addFunction(fnName);
f.addParam("pIn", "i32");
f.addParam("n", "i32");
f.addParam("pFirst", "i32");
f.addParam("pInc", "i32");
f.addParam("pOut", "i32");
f.addLocal("pOldFree", "i32");
f.addLocal("i", "i32");
f.addLocal("pFrom", "i32");
f.addLocal("pTo", "i32");
const c = f.getCodeBuilder();
const t = c.i32_const(module.alloc(sizeF));
f.addCode(
c.setLocal("pFrom", c.getLocal("pIn")),
c.setLocal("pTo", c.getLocal("pOut")),
);
// t = first
f.addCode(
c.call(
frPrefix + "_copy",
c.getLocal("pFirst"),
t
)
);
f.addCode(
c.setLocal("i", c.i32_const(0)),
c.block(c.loop(
c.br_if(1, c.i32_eq ( c.getLocal("i"), c.getLocal("n") )),
c.call(
opGtimesF,
c.getLocal("pFrom"),
t,
c.getLocal("pTo")
),
c.setLocal("pFrom", c.i32_add(c.getLocal("pFrom"), c.i32_const(sizeGIn))),
c.setLocal("pTo", c.i32_add(c.getLocal("pTo"), c.i32_const(sizeGOut))),
// t = t* inc
c.call(
frPrefix + "_mul",
t,
c.getLocal("pInc"),
t
),
c.setLocal("i", c.i32_add(c.getLocal("i"), c.i32_const(1))),
c.br(0)
))
);
module.exportFunction(fnName);
};
const utils$2 = utils$6;
const buildF1m$1 =build_f1m;
const buildF1$1 =build_f1;
const buildF2m$1 =build_f2m;
const buildF3m$1 =build_f3m;
const buildCurve$1 =build_curve_jacobian_a0;
const buildFFT$2 = build_fft;
const buildPol$1 = build_pol;
const buildQAP$1 = build_qap;
const buildApplyKey$1 = build_applykey;
const { bitLength: bitLength$2, modInv, isOdd: isOdd$1, isNegative: isNegative$2 } = bigint;
var build_bn128 = function buildBN128(module, _prefix) {
const prefix = _prefix || "bn128";
if (module.modules[prefix]) return prefix; // already builded
const q = 21888242871839275222246405745257275088696311157297823662689037894645226208583n;
const r = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
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 pr = module.alloc(utils$2.bigInt2BytesLE( r, frsize ));
const f1mPrefix = buildF1m$1(module, q, "f1m");
buildF1$1(module, r, "fr", "frm");
const pG1b = module.alloc(utils$2.bigInt2BytesLE( toMontgomery(3n), f1size ));
const g1mPrefix = buildCurve$1(module, "g1m", "f1m", pG1b);
buildFFT$2(module, "frm", "frm", "frm", "frm_mul");
buildPol$1(module, "pol", "frm");
buildQAP$1(module, "qap", "frm");
const f2mPrefix = buildF2m$1(module, "f1m_neg", "f2m", "f1m");
const pG2b = module.alloc([
...utils$2.bigInt2BytesLE( toMontgomery(19485874751759354771024239261021720505790618469301721065564631296452457478373n), f1size ),
...utils$2.bigInt2BytesLE( toMontgomery(266929791119991161246907387137283842545076965332900288569378510910307636690n), f1size )
]);
const g2mPrefix = buildCurve$1(module, "g2m", "f2m", pG2b);
function buildGTimesFr(fnName, opMul) {
const f = module.addFunction(fnName);
f.addParam("pG", "i32");
f.addParam("pFr", "i32");
f.addParam("pr", "i32");
const c = f.getCodeBuilder();
const AUX = c.i32_const(module.alloc(n8));
f.addCode(
c.call("frm_fromMontgomery", c.getLocal("pFr"), AUX),
c.call(
opMul,
c.getLocal("pG"),
AUX,
c.i32_const(n8),
c.getLocal("pr")
)
);
module.exportFunction(fnName);
}
buildGTimesFr("g1m_timesFr", "g1m_timesScalar");
buildFFT$2(module, "g1m", "g1m", "frm", "g1m_timesFr");
buildGTimesFr("g2m_timesFr", "g2m_timesScalar");
buildFFT$2(module, "g2m", "g2m", "frm", "g2m_timesFr");
buildGTimesFr("g1m_timesFrAffine", "g1m_timesScalarAffine");
buildGTimesFr("g2m_timesFrAffine", "g2m_timesScalarAffine");
buildApplyKey$1(module, "frm_batchApplyKey", "fmr", "frm", n8, n8, n8, "frm_mul");
buildApplyKey$1(module, "g1m_batchApplyKey", "g1m", "frm", n8*3, n8*3, n8, "g1m_timesFr");
buildApplyKey$1(module, "g1m_batchApplyKeyMixed", "g1m", "frm", n8*2, n8*3, n8, "g1m_timesFrAffine");
buildApplyKey$1(module, "g2m_batchApplyKey", "g2m", "frm", n8*2*3, n8*3*2, n8, "g2m_timesFr");
buildApplyKey$1(module, "g2m_batchApplyKeyMixed", "g2m", "frm", n8*2*2, n8*3*2, n8, "g2m_timesFrAffine");
function toMontgomery(a) {
return BigInt(a) * ( 1n << BigInt(f1size*8)) % q;
}
const G1gen = [
1n,
2n,
1n
];
const pG1gen = module.alloc(
[
...utils$2.bigInt2BytesLE( toMontgomery(G1gen[0]), f1size ),
...utils$2.bigInt2BytesLE( toMontgomery(G1gen[1]), f1size ),
...utils$2.bigInt2BytesLE( toMontgomery(G1gen[2]), f1size ),
]
);
const G1zero = [
0n,
1n,
0n
];
const pG1zero = module.alloc(
[
...utils$2.bigInt2BytesLE( toMontgomery(G1zero[0]), f1size ),
...utils$2.bigInt2BytesLE( toMontgomery(G1zero[1]), f1size ),
...utils$2.bigInt2BytesLE( toMontgomery(G1zero[2]), f1size )
]
);
const G2gen = [
[
10857046999023057135944570762232829481370756359578518086990519993285655852781n,
11559732032986387107991004021392285783925812861821192530917403151452391805634n,
],[
8495653923123431417604973247489272438418190587263600148770280649306958101930n,
4082367875863433681332203403145435568316851327593401208105741076214120093531n,
],[
1n,
0n,
]
];
const pG2gen = module.alloc(
[
...utils$2.bigInt2BytesLE( toMontgomery(G2gen[0][0]), f1size ),
...utils$2.bigInt2BytesLE( toMontgomery(G2gen[0][1]), f1size ),
...utils$2.bigInt2BytesLE( toMontgomery(G2gen[1][0]), f1size ),
...utils$2.bigInt2BytesLE( toMontgomery(G2gen[1][1]), f1size ),
...utils$2.bigInt2BytesLE( toMontgomery(G2gen[2][0]), f1size ),
...utils$2.bigInt2BytesLE( toMontgomery(G2gen[2][1]), f1size ),
]
);
const G2zero = [
[
0n,
0n,
],[
1n,
0n,
],[
0n,
0n,
]
];
const pG2zero = module.alloc(
[
...utils$2.bigInt2BytesLE( toMontgomery(G2zero[0][0]), f1size ),
...utils$2.bigInt2BytesLE( toMontgomery(G2zero[0][1]), f1size ),
...utils$2.bigInt2BytesLE( toMontgomery(G2zero[1][0]), f1size ),
...utils$2.bigInt2BytesLE( toMontgomery(G2zero[1][1]), f1size ),
...utils$2.bigInt2BytesLE( toMontgomery(G2zero[2][0]), f1size ),
...utils$2.bigInt2BytesLE( toMontgomery(G2zero[2][1]), f1size ),
]
);
const pOneT = module.alloc([
...utils$2.bigInt2BytesLE( toMontgomery(1), f1size ),
...utils$2.bigInt2BytesLE( toMontgomery(0), f1size ),
...utils$2.bigInt2BytesLE( toMontgomery(0), f1size ),
...utils$2.bigInt2BytesLE( toMontgomery(0), f1size ),
...utils$2.bigInt2BytesLE( toMontgomery(0), f1size ),
...utils$2.bigInt2BytesLE( toMontgomery(0), f1size ),
...utils$2.bigInt2BytesLE( toMontgomery(0), f1size ),
...utils$2.bigInt2BytesLE( toMontgomery(0), f1size ),
...utils$2.bigInt2BytesLE( toMontgomery(0), f1size ),
...utils$2.bigInt2BytesLE( toMontgomery(0), f1size ),
...utils$2.bigInt2BytesLE( toMontgomery(0), f1size ),
...utils$2.bigInt2BytesLE( toMontgomery(0), f1size ),
]);
const pNonResidueF6 = module.alloc([
...utils$2.bigInt2BytesLE( toMontgomery(9), f1size ),
...utils$2.bigInt2BytesLE( toMontgomery(1), f1size ),
]);
const pTwoInv = module.alloc([
...utils$2.bigInt2BytesLE( toMontgomery( modInv(2n, q)), f1size ),
...utils$2.bigInt2BytesLE( 0n, f1size )
]);
const pAltBn128Twist = pNonResidueF6;
const pTwistCoefB = module.alloc([
...utils$2.bigInt2BytesLE( toMontgomery(19485874751759354771024239261021720505790618469301721065564631296452457478373n), f1size ),
...utils$2.bigInt2BytesLE( toMontgomery(266929791119991161246907387137283842545076965332900288569378510910307636690n), f1size ),
]);
function build_mulNR6() {
const f = module.addFunction(prefix + "_mulNR6");
f.addParam("x", "i32");
f.addParam("pr", "i32");
const c = f.getCodeBuilder();
f.addCode(
c.call(
f2mPrefix + "_mul",
c.i32_const(pNonResidueF6),
c.getLocal("x"),
c.getLocal("pr")
)
);
}
build_mulNR6();
const f6mPrefix = buildF3m$1(module, prefix+"_mulNR6", "f6m", "f2m");
function build_mulNR12() {
const f = module.addFunction(prefix + "_mulNR12");
f.addParam("x", "i32");
f.addParam("pr", "i32");
const c = f.getCodeBuilder();
f.addCode(
c.call(
f2mPrefix + "_mul",
c.i32_const(pNonResidueF6),
c.i32_add(c.getLocal("x"), c.i32_const(n8*4)),
c.getLocal("pr")
),
c.call(
f2mPrefix + "_copy",
c.getLocal("x"),
c.i32_add(c.getLocal("pr"), c.i32_const(n8*2)),
),
c.call(
f2mPrefix + "_copy",
c.i32_add(c.getLocal("x"), c.i32_const(n8*2)),
c.i32_add(c.getLocal("pr"), c.i32_const(n8*4)),
)
);
}
build_mulNR12();
const ftmPrefix = buildF2m$1(module, prefix+"_mulNR12", "ftm", f6mPrefix);
const ateLoopCount = 29793968203157093288n;
const ateLoopBitBytes = bits(ateLoopCount);
const pAteLoopBitBytes = module.alloc(ateLoopBitBytes);
const ateCoefSize = 3 * f2size;
const ateNDblCoefs = ateLoopBitBytes.length-1;
const ateNAddCoefs = ateLoopBitBytes.reduce((acc, b) => acc + ( b!=0 ? 1 : 0) ,0);
const ateNCoefs = ateNAddCoefs + ateNDblCoefs + 1;
const prePSize = 3*2*n8;
const preQSize = 3*n8*2 + ateNCoefs*ateCoefSize;
module.modules[prefix] = {
n64: n64,
pG1gen: pG1gen,
pG1zero: pG1zero,
pG1b: pG1b,
pG2gen: pG2gen,
pG2zero: pG2zero,
pG2b: pG2b,
pq: module.modules["f1m"].pq,
pr: pr,
pOneT: pOneT,
prePSize: prePSize,
preQSize: preQSize,
r: r.toString(),
q: q.toString()
};
// console.log("PrePSize: " +prePSize);
// console.log("PreQSize: " +preQSize);
const finalExpZ = 4965661367192848881n;
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;
}
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 buildPrepareG1() {
const f = module.addFunction(prefix+ "_prepareG1");
f.addParam("pP", "i32");
f.addParam("ppreP", "i32");
const c = f.getCodeBuilder();
f.addCode(
c.call(g1mPrefix + "_normalize", c.getLocal("pP"), c.getLocal("ppreP")), // TODO Remove if already in affine
);
}
function buildPrepAddStep() {
const f = module.addFunction(prefix+ "_prepAddStep");
f.addParam("pQ", "i32");
f.addParam("pR", "i32");
f.addParam("pCoef", "i32");
const c = f.getCodeBuilder();
const X2 = c.getLocal("pQ");
const Y2 = c.i32_add(c.getLocal("pQ"), c.i32_const(f2size));
const X1 = c.getLocal("pR");
const Y1 = c.i32_add(c.getLocal("pR"), c.i32_const(f2size));
const Z1 = c.i32_add(c.getLocal("pR"), c.i32_const(2*f2size));
const ELL_0 = c.getLocal("pCoef");
const ELL_VW = c.i32_add(c.getLocal("pCoef"), c.i32_const(f2size));
const ELL_VV = c.i32_add(c.getLocal("pCoef"), c.i32_const(2*f2size));
const D = ELL_VW;
const E = c.i32_const(module.alloc(f2size));
const F = c.i32_const(module.alloc(f2size));
const G = c.i32_const(module.alloc(f2size));
const H = c.i32_const(module.alloc(f2size));
const I = c.i32_const(module.alloc(f2size));
const J = c.i32_const(module.alloc(f2size));
const AUX = c.i32_const(module.alloc(f2size));
f.addCode(
// D = X1 - X2*Z1
c.call(f2mPrefix + "_mul", X2, Z1, D),
c.call(f2mPrefix + "_sub", X1, D, D),
// E = Y1 - Y2*Z1
c.call(f2mPrefix + "_mul", Y2, Z1, E),
c.call(f2mPrefix + "_sub", Y1, E, E),
// F = D^2
c.call(f2mPrefix + "_square", D, F),
// G = E^2
c.call(f2mPrefix + "_square", E, G),
// H = D*F
c.call(f2mPrefix + "_mul", D, F, H),
// I = X1 * F
c.call(f2mPrefix + "_mul", X1, F, I),
// J = H + Z1*G - (I+I)
c.call(f2mPrefix + "_add", I, I, AUX),
c.call(f2mPrefix + "_mul", Z1, G, J),
c.call(f2mPrefix + "_add", H, J, J),
c.call(f2mPrefix + "_sub", J, AUX, J),
// X3 (X1) = D*J
c.call(f2mPrefix + "_mul", D, J, X1),
// Y3 (Y1) = E*(I-J)-(H*Y1)
c.call(f2mPrefix + "_mul", H, Y1, Y1),
c.call(f2mPrefix + "_sub", I, J, AUX),
c.call(f2mPrefix + "_mul", E, AUX, AUX),
c.call(f2mPrefix + "_sub", AUX, Y1, Y1),
// Z3 (Z1) = Z1*H
c.call(f2mPrefix + "_mul", Z1, H, Z1),
// ell_0 = xi * (E * X2 - D * Y2)
c.call(f2mPrefix + "_mul", D, Y2, AUX),
c.call(f2mPrefix + "_mul", E, X2, ELL_0),
c.call(f2mPrefix + "_sub", ELL_0, AUX, ELL_0),
c.call(f2mPrefix + "_mul", ELL_0, c.i32_const(pAltBn128Twist), ELL_0),
// ell_VV = - E (later: * xP)
c.call(f2mPrefix + "_neg", E, ELL_VV),
// ell_VW = D (later: * yP )
// Already assigned
);
}
function buildPrepDoubleStep() {
const f = module.addFunction(prefix+ "_prepDblStep");
f.addParam("pR", "i32");
f.addParam("pCoef", "i32");
const c = f.getCodeBuilder();
const X1 = c.getLocal("pR");
const Y1 = c.i32_add(c.getLocal("pR"), c.i32_const(f2size));
const Z1 = c.i32_add(c.getLocal("pR"), c.i32_const(2*f2size));
const ELL_0 = c.getLocal("pCoef");
const ELL_VW = c.i32_add(c.getLocal("pCoef"), c.i32_const(f2size));
const ELL_VV = c.i32_add(c.getLocal("pCoef"), c.i32_const(2*f2size));
const A = c.i32_const(module.alloc(f2size));
const B = c.i32_const(module.alloc(f2size));
const C = c.i32_const(module.alloc(f2size));
const D = c.i32_const(module.alloc(f2size));
const E = c.i32_const(module.alloc(f2size));
const F = c.i32_const(module.alloc(f2size));
const G = c.i32_const(module.alloc(f2size));
const H = c.i32_const(module.alloc(f2size));
const I = c.i32_const(module.alloc(f2size));
const J = c.i32_const(module.alloc(f2size));
const E2 = c.i32_const(module.alloc(f2size));
const AUX = c.i32_const(module.alloc(f2size));
f.addCode(
// A = X1 * Y1 / 2
c.call(f2mPrefix + "_mul", Y1, c.i32_const(pTwoInv), A),
c.call(f2mPrefix + "_mul", X1, A, A),
// B = Y1^2
c.call(f2mPrefix + "_square", Y1, B),
// C = Z1^2
c.call(f2mPrefix + "_square", Z1, C),
// D = 3 * C
c.call(f2mPrefix + "_add", C, C, D),
c.call(f2mPrefix + "_add", D, C, D),
// E = twist_b * D
c.call(f2mPrefix + "_mul", c.i32_const(pTwistCoefB), D, E),
// F = 3 * E
c.call(f2mPrefix + "_add", E, E, F),
c.call(f2mPrefix + "_add", E, F, F),
// G = (B+F)/2
c.call(f2mPrefix + "_add", B, F, G),
c.call(f2mPrefix + "_mul", G, c.i32_const(pTwoInv), G),
// H = (Y1+Z1)^2-(B+C)
c.call(f2mPrefix + "_add", B, C, AUX),
c.call(f2mPrefix + "_add", Y1, Z1, H),
c.call(f2mPrefix + "_square", H, H),
c.call(f2mPrefix + "_sub", H, AUX, H),
// I = E-B
c.call(f2mPrefix + "_sub", E, B, I),
// J = X1^2
c.call(f2mPrefix + "_square", X1, J),
// E_squared = E^2
c.call(f2mPrefix + "_square", E, E2),
// X3 (X1) = A * (B-F)
c.call(f2mPrefix + "_sub", B, F, AUX),
c.call(f2mPrefix + "_mul", A, AUX, X1),
// Y3 (Y1) = G^2 - 3*E^2
c.call(f2mPrefix + "_add", E2, E2, AUX),
c.call(f2mPrefix + "_add", E2, AUX, AUX),
c.call(f2mPrefix + "_square", G, Y1),
c.call(f2mPrefix + "_sub", Y1, AUX, Y1),
// Z3 (Z1) = B * H
c.call(f2mPrefix + "_mul", B, H, Z1),
// ell_0 = xi * I
c.call(f2mPrefix + "_mul", c.i32_const(pAltBn128Twist), I, ELL_0),
// ell_VW = - H (later: * yP)
c.call(f2mPrefix + "_neg", H, ELL_VW),
// ell_VV = 3*J (later: * xP)
c.call(f2mPrefix + "_add", J, J, ELL_VV),
c.call(f2mPrefix + "_add", J, ELL_VV, ELL_VV),
);
}
function buildMulByQ() {
const f = module.addFunction(prefix + "_mulByQ");
f.addParam("p1", "i32");
f.addParam("pr", "i32");
const c = f.getCodeBuilder();
const x = c.getLocal("p1");
const y = c.i32_add(c.getLocal("p1"), c.i32_const(f2size));
const z = c.i32_add(c.getLocal("p1"), c.i32_const(f2size*2));
const x3 = c.getLocal("pr");
const y3 = c.i32_add(c.getLocal("pr"), c.i32_const(f2size));
const z3 = c.i32_add(c.getLocal("pr"), c.i32_const(f2size*2));
const MulByQX = c.i32_const(module.alloc([
...utils$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 ),
]));
f.addCode(
// The frobeniusMap(1) in this field, is the conjugate
c.call(f2mPrefix + "_conjugate", x, x3),
c.call(f2mPrefix + "_mul", MulByQX, x3, x3),
c.call(f2mPrefix + "_conjugate", y, y3),
c.call(f2mPrefix + "_mul", MulByQY, y3, y3),
c.call(f2mPrefix + "_conjugate", z, z3),
);
}
function buildPrepareG2() {
buildMulByQ();
const f = module.addFunction(prefix+ "_prepareG2");
f.addParam("pQ", "i32");
f.addParam("ppreQ", "i32");
f.addLocal("pCoef", "i32");
f.addLocal("i", "i32");
const c = f.getCodeBuilder();
const QX = c.getLocal("pQ");
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);
f.addCode(
c.call(g2mPrefix + "_normalize", QX, cQX), // TODO Remove if already in affine
c.call(f2mPrefix + "_copy", cQX, RX),
c.call(f2mPrefix + "_copy", cQY, RY),
c.call(f2mPrefix + "_one", RZ),
);
f.addCode(
c.setLocal("pCoef", c.i32_add( c.getLocal("ppreQ"), c.i32_const(f2size*3))),
c.setLocal("i", c.i32_const(ateLoopBitBytes.length-2)),
c.block(c.loop(
c.call(prefix + "_prepDblStep", R, c.getLocal("pCoef")),
c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))),
c.if(
c.i32_load8_s(c.getLocal("i"), pAteLoopBitBytes),
[
...c.call(prefix + "_prepAddStep", cQX, R, c.getLocal("pCoef")),
...c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))),
]
),
c.br_if(1, c.i32_eqz ( c.getLocal("i") )),
c.setLocal("i", c.i32_sub(c.getLocal("i"), c.i32_const(1))),
c.br(0)
))
);
f.addCode(
c.call(prefix + "_mulByQ", cQX, Q1),
c.call(prefix + "_mulByQ", Q1, Q2)
);
f.addCode(
c.call(f2mPrefix + "_neg", Q2Y, Q2Y),
c.call(prefix + "_prepAddStep", Q1, R, c.getLocal("pCoef")),
c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))),
c.call(prefix + "_prepAddStep", Q2, R, c.getLocal("pCoef")),
c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))),
);
}
function buildMulBy024Old() {
const f = module.addFunction(prefix+ "__mulBy024Old");
f.addParam("pEll0", "i32");
f.addParam("pEllVW", "i32");
f.addParam("pEllVV", "i32");
f.addParam("pR", "i32"); // Result in F12
const c = f.getCodeBuilder();
const x0 = c.getLocal("pEll0");
const x2 = c.getLocal("pEllVV");
const x4 = c.getLocal("pEllVW");
const z0 = c.getLocal("pR");
const pAUX12 = module.alloc(ftsize);
const AUX12 = c.i32_const(pAUX12);
const AUX12_0 = c.i32_const(pAUX12);
const AUX12_2 = c.i32_const(pAUX12+f2size);
const AUX12_4 = c.i32_const(pAUX12+f2size*2);
const AUX12_6 = c.i32_const(pAUX12+f2size*3);
const AUX12_8 = c.i32_const(pAUX12+f2size*4);
const AUX12_10 = c.i32_const(pAUX12+f2size*5);
f.addCode(
c.call(f2mPrefix + "_copy", x0, AUX12_0),
c.call(f2mPrefix + "_zero", AUX12_2),
c.call(f2mPrefix + "_copy", x2, AUX12_4),
c.call(f2mPrefix + "_zero", AUX12_6),
c.call(f2mPrefix + "_copy", x4, AUX12_8),
c.call(f2mPrefix + "_zero", AUX12_10),
c.call(ftmPrefix + "_mul", AUX12, z0, z0),
);
}
function buildMulBy024() {
const f = module.addFunction(prefix+ "__mulBy024");
f.addParam("pEll0", "i32");
f.addParam("pEllVW", "i32");
f.addParam("pEllVV", "i32");
f.addParam("pR", "i32"); // Result in F12
const c = f.getCodeBuilder();
const x0 = c.getLocal("pEll0");
const x2 = c.getLocal("pEllVV");
const x4 = c.getLocal("pEllVW");
const z0 = c.getLocal("pR");
const z1 = c.i32_add(c.getLocal("pR"), c.i32_const(2*n8));
const z2 = c.i32_add(c.getLocal("pR"), c.i32_const(4*n8));
const z3 = c.i32_add(c.getLocal("pR"), c.i32_const(6*n8));
const z4 = c.i32_add(c.getLocal("pR"), c.i32_const(8*n8));
const z5 = c.i32_add(c.getLocal("pR"), c.i32_const(10*n8));
const t0 = c.i32_const(module.alloc(f2size));
const t1 = c.i32_const(module.alloc(f2size));
const t2 = c.i32_const(module.alloc(f2size));
const s0 = c.i32_const(module.alloc(f2size));
const T3 = c.i32_const(module.alloc(f2size));
const T4 = c.i32_const(module.alloc(f2size));
const D0 = c.i32_const(module.alloc(f2size));
const D2 = c.i32_const(module.alloc(f2size));
const D4 = c.i32_const(module.alloc(f2size));
const S1 = c.i32_const(module.alloc(f2size));
const AUX = c.i32_const(module.alloc(f2size));
f.addCode(
// D0 = z0 * x0;
c.call(f2mPrefix + "_mul", z0, x0, D0),
// D2 = z2 * x2;
c.call(f2mPrefix + "_mul", z2, x2, D2),
// D4 = z4 * x4;
c.call(f2mPrefix + "_mul", z4, x4, D4),
// t2 = z0 + z4;
c.call(f2mPrefix + "_add", z0, z4, t2),
// t1 = z0 + z2;
c.call(f2mPrefix + "_add", z0, z2, t1),
// s0 = z1 + z3 + z5;
c.call(f2mPrefix + "_add", z1, z3, s0),
c.call(f2mPrefix + "_add", s0, z5, s0),
// For z.a_.a_ = z0.
// S1 = z1 * x2;
c.call(f2mPrefix + "_mul", z1, x2, S1),
// T3 = S1 + D4;
c.call(f2mPrefix + "_add", S1, D4, T3),
// T4 = my_Fp6::non_residue * T3 + D0;
c.call(f2mPrefix + "_mul", c.i32_const(pNonResidueF6), T3, T4),
c.call(f2mPrefix + "_add", T4, D0, z0),
// z0 = T4;
// For z.a_.b_ = z1
// T3 = z5 * x4;
c.call(f2mPrefix + "_mul", z5, x4, T3),
// S1 = S1 + T3;
c.call(f2mPrefix + "_add", S1, T3, S1),
// T3 = T3 + D2;
c.call(f2mPrefix + "_add", T3, D2, T3),
// T4 = my_Fp6::non_residue * T3;
c.call(f2mPrefix + "_mul", c.i32_const(pNonResidueF6), T3, T4),
// T3 = z1 * x0;
c.call(f2mPrefix + "_mul", z1, x0, T3),
// S1 = S1 + T3;
c.call(f2mPrefix + "_add", S1, T3, S1),
// T4 = T4 + T3;
c.call(f2mPrefix + "_add", T4, T3, z1),
// z1 = T4;
// For z.a_.c_ = z2
// t0 = x0 + x2;
c.call(f2mPrefix + "_add", x0, x2, t0),
// T3 = t1 * t0 - D0 - D2;
c.call(f2mPrefix + "_mul", t1, t0, T3),
c.call(f2mPrefix + "_add", D0, D2, AUX),
c.call(f2mPrefix + "_sub", T3, AUX, T3),
// T4 = z3 * x4;
c.call(f2mPrefix + "_mul", z3, x4, T4),
// S1 = S1 + T4;
c.call(f2mPrefix + "_add", S1, T4, S1),
// For z.b_.a_ = z3 (z3 needs z2)
// t0 = z2 + z4;
c.call(f2mPrefix + "_add", z2, z4, t0),
// T3 = T3 + T4;
// z2 = T3;
c.call(f2mPrefix + "_add", T3, T4, z2),
// t1 = x2 + x4;
c.call(f2mPrefix + "_add", x2, x4, t1),
// T3 = t0 * t1 - D2 - D4;
c.call(f2mPrefix + "_mul", t1, t0, T3),
c.call(f2mPrefix + "_add", D2, D4, AUX),
c.call(f2mPrefix + "_sub", T3, AUX, T3),
// T4 = my_Fp6::non_residue * T3;
c.call(f2mPrefix + "_mul", c.i32_const(pNonResidueF6), T3, T4),
// T3 = z3 * x0;
c.call(f2mPrefix + "_mul", z3, x0, T3),
// S1 = S1 + T3;
c.call(f2mPrefix + "_add", S1, T3, S1),
// T4 = T4 + T3;
c.call(f2mPrefix + "_add", T4, T3, z3),
// z3 = T4;
// For z.b_.b_ = z4
// T3 = z5 * x2;
c.call(f2mPrefix + "_mul", z5, x2, T3),
// S1 = S1 + T3;
c.call(f2mPrefix + "_add", S1, T3, S1),
// T4 = my_Fp6::non_residue * T3;
c.call(f2mPrefix + "_mul", c.i32_const(pNonResidueF6), T3, T4),
// t0 = x0 + x4;
c.call(f2mPrefix + "_add", x0, x4, t0),
// T3 = t2 * t0 - D0 - D4;
c.call(f2mPrefix + "_mul", t2, t0, T3),
c.call(f2mPrefix + "_add", D0, D4, AUX),
c.call(f2mPrefix + "_sub", T3, AUX, T3),
// T4 = T4 + T3;
c.call(f2mPrefix + "_add", T4, T3, z4),
// z4 = T4;
// For z.b_.c_ = z5.
// t0 = x0 + x2 + x4;
c.call(f2mPrefix + "_add", x0, x2, t0),
c.call(f2mPrefix + "_add", t0, x4, t0),
// T3 = s0 * t0 - S1;
c.call(f2mPrefix + "_mul", s0, t0, T3),
c.call(f2mPrefix + "_sub", T3, S1, z5),
// z5 = T3;
);
}
function buildMillerLoop() {
const f = module.addFunction(prefix+ "_millerLoop");
f.addParam("ppreP", "i32");
f.addParam("ppreQ", "i32");
f.addParam("r", "i32");
f.addLocal("pCoef", "i32");
f.addLocal("i", "i32");
const c = f.getCodeBuilder();
const preP_PX = c.getLocal("ppreP");
const preP_PY = c.i32_add(c.getLocal("ppreP"), c.i32_const(f1size));
const ELL_0 = c.getLocal("pCoef");
const ELL_VW = c.i32_add(c.getLocal("pCoef"), c.i32_const(f2size));
const ELL_VV = c.i32_add(c.getLocal("pCoef"), c.i32_const(2*f2size));
const pVW = module.alloc(f2size);
const VW = c.i32_const(pVW);
const pVV = module.alloc(f2size);
const VV = c.i32_const(pVV);
const F = c.getLocal("r");
f.addCode(
c.call(ftmPrefix + "_one", F),
c.setLocal("pCoef", c.i32_add( c.getLocal("ppreQ"), c.i32_const(f2size*3))),
c.setLocal("i", c.i32_const(ateLoopBitBytes.length-2)),
c.block(c.loop(
c.call(ftmPrefix + "_square", F, F),
c.call(f2mPrefix + "_mul1", ELL_VW,preP_PY, VW),
c.call(f2mPrefix + "_mul1", ELL_VV, preP_PX, VV),
c.call(prefix + "__mulBy024", ELL_0, VW, VV, F),
c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))),
c.if(
c.i32_load8_s(c.getLocal("i"), pAteLoopBitBytes),
[
...c.call(f2mPrefix + "_mul1", ELL_VW, preP_PY, VW),
...c.call(f2mPrefix + "_mul1", ELL_VV, preP_PX, VV),
...c.call(prefix + "__mulBy024", ELL_0, VW, VV, F),
...c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))),
]
),
c.br_if(1, c.i32_eqz ( c.getLocal("i") )),
c.setLocal("i", c.i32_sub(c.getLocal("i"), c.i32_const(1))),
c.br(0)
))
);
f.addCode(
c.call(f2mPrefix + "_mul1", ELL_VW, preP_PY, VW),
c.call(f2mPrefix + "_mul1", ELL_VV, preP_PX, VV),
c.call(prefix + "__mulBy024", ELL_0, VW, VV, F),
c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))),
c.call(f2mPrefix + "_mul1", ELL_VW, preP_PY, VW),
c.call(f2mPrefix + "_mul1", ELL_VV, preP_PX, VV),
c.call(prefix + "__mulBy024", ELL_0, VW, VV, F),
c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))),
);
}
function buildFrobeniusMap(n) {
const F12 = [
[
[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");
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;
}
}
function buildFinalExponentiationFirstChunk() {
const f = module.addFunction(prefix+ "__finalExponentiationFirstChunk");
f.addParam("x", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
const elt = c.getLocal("x");
const eltC0 = elt;
const eltC1 = c.i32_add(elt, c.i32_const(n8*6));
const r = c.getLocal("r");
const pA = module.alloc(ftsize);
const A = c.i32_const(pA);
const Ac0 = A;
const Ac1 = c.i32_const(pA + n8*6);
const B = c.i32_const(module.alloc(ftsize));
const C = c.i32_const(module.alloc(ftsize));
const D = c.i32_const(module.alloc(ftsize));
f.addCode(
// const alt_bn128_Fq12 A = alt_bn128_Fq12(elt.c0,-elt.c1);
c.call(f6mPrefix + "_copy", eltC0, Ac0),
c.call(f6mPrefix + "_neg", eltC1, Ac1),
// const alt_bn128_Fq12 B = elt.inverse();
c.call(ftmPrefix + "_inverse", elt, B),
// const alt_bn128_Fq12 C = A * B;
c.call(ftmPrefix + "_mul", A, B, C),
// const alt_bn128_Fq12 D = C.Frobenius_map(2);
c.call(prefix + "__frobeniusMap2", C, D),
// const alt_bn128_Fq12 result = D * C;
c.call(ftmPrefix + "_mul", C, D, r),
);
}
function buildCyclotomicSquare() {
const f = module.addFunction(prefix+ "__cyclotomicSquare");
f.addParam("x", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x4 = c.i32_add(c.getLocal("x"), c.i32_const(f2size));
const x3 = c.i32_add(c.getLocal("x"), c.i32_const(2*f2size));
const x2 = c.i32_add(c.getLocal("x"), c.i32_const(3*f2size));
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(4*f2size));
const x5 = c.i32_add(c.getLocal("x"), c.i32_const(5*f2size));
const r0 = c.getLocal("r");
const r4 = c.i32_add(c.getLocal("r"), c.i32_const(f2size));
const r3 = c.i32_add(c.getLocal("r"), c.i32_const(2*f2size));
const r2 = c.i32_add(c.getLocal("r"), c.i32_const(3*f2size));
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(4*f2size));
const r5 = c.i32_add(c.getLocal("r"), c.i32_const(5*f2size));
const t0 = c.i32_const(module.alloc(f2size));
const t1 = c.i32_const(module.alloc(f2size));
const t2 = c.i32_const(module.alloc(f2size));
const t3 = c.i32_const(module.alloc(f2size));
const t4 = c.i32_const(module.alloc(f2size));
const t5 = c.i32_const(module.alloc(f2size));
const tmp = c.i32_const(module.alloc(f2size));
const AUX = c.i32_const(module.alloc(f2size));
f.addCode(
// // t0 + t1*y = (z0 + z1*y)^2 = a^2
// tmp = z0 * z1;
// t0 = (z0 + z1) * (z0 + my_Fp6::non_residue * z1) - tmp - my_Fp6::non_residue * tmp;
// t1 = tmp + tmp;
c.call(f2mPrefix + "_mul", x0, x1, tmp),
c.call(f2mPrefix + "_mul", x1, c.i32_const(pNonResidueF6), t0),
c.call(f2mPrefix + "_add", x0, t0, t0),
c.call(f2mPrefix + "_add", x0, x1, AUX),
c.call(f2mPrefix + "_mul", AUX, t0, t0),
c.call(f2mPrefix + "_mul", c.i32_const(pNonResidueF6), tmp, AUX),
c.call(f2mPrefix + "_add", tmp, AUX, AUX),
c.call(f2mPrefix + "_sub", t0, AUX, t0),
c.call(f2mPrefix + "_add", tmp, tmp, t1),
// // t2 + t3*y = (z2 + z3*y)^2 = b^2
// tmp = z2 * z3;
// t2 = (z2 + z3) * (z2 + my_Fp6::non_residue * z3) - tmp - my_Fp6::non_residue * tmp;
// t3 = tmp + tmp;
c.call(f2mPrefix + "_mul", x2, x3, tmp),
c.call(f2mPrefix + "_mul", x3, c.i32_const(pNonResidueF6), t2),
c.call(f2mPrefix + "_add", x2, t2, t2),
c.call(f2mPrefix + "_add", x2, x3, AUX),
c.call(f2mPrefix + "_mul", AUX, t2, t2),
c.call(f2mPrefix + "_mul", c.i32_const(pNonResidueF6), tmp, AUX),
c.call(f2mPrefix + "_add", tmp, AUX, AUX),
c.call(f2mPrefix + "_sub", t2, AUX, t2),
c.call(f2mPrefix + "_add", tmp, tmp, t3),
// // t4 + t5*y = (z4 + z5*y)^2 = c^2
// tmp = z4 * z5;
// t4 = (z4 + z5) * (z4 + my_Fp6::non_residue * z5) - tmp - my_Fp6::non_residue * tmp;
// t5 = tmp + tmp;
c.call(f2mPrefix + "_mul", x4, x5, tmp),
c.call(f2mPrefix + "_mul", x5, c.i32_const(pNonResidueF6), t4),
c.call(f2mPrefix + "_add", x4, t4, t4),
c.call(f2mPrefix + "_add", x4, x5, AUX),
c.call(f2mPrefix + "_mul", AUX, t4, t4),
c.call(f2mPrefix + "_mul", c.i32_const(pNonResidueF6), tmp, AUX),
c.call(f2mPrefix + "_add", tmp, AUX, AUX),
c.call(f2mPrefix + "_sub", t4, AUX, t4),
c.call(f2mPrefix + "_add", tmp, tmp, t5),
// For A
// z0 = 3 * t0 - 2 * z0
c.call(f2mPrefix + "_sub", t0, x0, r0),
c.call(f2mPrefix + "_add", r0, r0, r0),
c.call(f2mPrefix + "_add", t0, r0, r0),
// z1 = 3 * t1 + 2 * z1
c.call(f2mPrefix + "_add", t1, x1, r1),
c.call(f2mPrefix + "_add", r1, r1, r1),
c.call(f2mPrefix + "_add", t1, r1, r1),
// For B
// z2 = 3 * (xi * t5) + 2 * z2
c.call(f2mPrefix + "_mul", t5, c.i32_const(pAltBn128Twist), AUX),
c.call(f2mPrefix + "_add", AUX, x2, r2),
c.call(f2mPrefix + "_add", r2, r2, r2),
c.call(f2mPrefix + "_add", AUX, r2, r2),
// z3 = 3 * t4 - 2 * z3
c.call(f2mPrefix + "_sub", t4, x3, r3),
c.call(f2mPrefix + "_add", r3, r3, r3),
c.call(f2mPrefix + "_add", t4, r3, r3),
// For C
// z4 = 3 * t2 - 2 * z4
c.call(f2mPrefix + "_sub", t2, x4, r4),
c.call(f2mPrefix + "_add", r4, r4, r4),
c.call(f2mPrefix + "_add", t2, r4, r4),
// z5 = 3 * t3 + 2 * z5
c.call(f2mPrefix + "_add", t3, x5, r5),
c.call(f2mPrefix + "_add", r5, r5, r5),
c.call(f2mPrefix + "_add", t3, r5, r5),
);
}
function buildCyclotomicExp(exponent, fnName) {
const exponentNafBytes = naf(exponent).map( (b) => (b==-1 ? 0xFF: b) );
const pExponentNafBytes = module.alloc(exponentNafBytes);
const f = module.addFunction(prefix+ "__cyclotomicExp_"+fnName);
f.addParam("x", "i32");
f.addParam("r", "i32");
f.addLocal("bit", "i32");
f.addLocal("i", "i32");
const c = f.getCodeBuilder();
const x = c.getLocal("x");
const res = c.getLocal("r");
const inverse = c.i32_const(module.alloc(ftsize));
f.addCode(
c.call(ftmPrefix + "_conjugate", x, inverse),
c.call(ftmPrefix + "_one", res),
c.if(
c.teeLocal("bit", c.i32_load8_s(c.i32_const(exponentNafBytes.length-1), pExponentNafBytes)),
c.if(
c.i32_eq(
c.getLocal("bit"),
c.i32_const(1)
),
c.call(ftmPrefix + "_mul", res, x, res),
c.call(ftmPrefix + "_mul", res, inverse, res),
)
),
c.setLocal("i", c.i32_const(exponentNafBytes.length-2)),
c.block(c.loop(
c.call(prefix + "__cyclotomicSquare", res, res),
c.if(
c.teeLocal("bit", c.i32_load8_s(c.getLocal("i"), pExponentNafBytes)),
c.if(
c.i32_eq(
c.getLocal("bit"),
c.i32_const(1)
),
c.call(ftmPrefix + "_mul", res, x, res),
c.call(ftmPrefix + "_mul", res, inverse, res),
)
),
c.br_if(1, c.i32_eqz ( c.getLocal("i") )),
c.setLocal("i", c.i32_sub(c.getLocal("i"), c.i32_const(1))),
c.br(0)
))
);
}
function buildFinalExponentiationLastChunk() {
buildCyclotomicSquare();
buildCyclotomicExp(finalExpZ, "w0");
const f = module.addFunction(prefix+ "__finalExponentiationLastChunk");
f.addParam("x", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
const elt = c.getLocal("x");
const result = c.getLocal("r");
const A = c.i32_const(module.alloc(ftsize));
const B = c.i32_const(module.alloc(ftsize));
const C = c.i32_const(module.alloc(ftsize));
const D = c.i32_const(module.alloc(ftsize));
const E = c.i32_const(module.alloc(ftsize));
const F = c.i32_const(module.alloc(ftsize));
const G = c.i32_const(module.alloc(ftsize));
const H = c.i32_const(module.alloc(ftsize));
const I = c.i32_const(module.alloc(ftsize));
const J = c.i32_const(module.alloc(ftsize));
const K = c.i32_const(module.alloc(ftsize));
const L = c.i32_const(module.alloc(ftsize));
const M = c.i32_const(module.alloc(ftsize));
const N = c.i32_const(module.alloc(ftsize));
const O = c.i32_const(module.alloc(ftsize));
const P = c.i32_const(module.alloc(ftsize));
const Q = c.i32_const(module.alloc(ftsize));
const R = c.i32_const(module.alloc(ftsize));
const S = c.i32_const(module.alloc(ftsize));
const T = c.i32_const(module.alloc(ftsize));
const U = c.i32_const(module.alloc(ftsize));
f.addCode(
// A = exp_by_neg_z(elt) // = elt^(-z)
c.call(prefix + "__cyclotomicExp_w0", elt, A),
c.call(ftmPrefix + "_conjugate", A, A),
// B = A^2 // = elt^(-2*z)
c.call(prefix + "__cyclotomicSquare", A, B),
// C = B^2 // = elt^(-4*z)
c.call(prefix + "__cyclotomicSquare", B, C),
// D = C * B // = elt^(-6*z)
c.call(ftmPrefix + "_mul", C, B, D),
// E = exp_by_neg_z(D) // = elt^(6*z^2)
c.call(prefix + "__cyclotomicExp_w0", D, E),
c.call(ftmPrefix + "_conjugate", E, E),
// F = E^2 // = elt^(12*z^2)
c.call(prefix + "__cyclotomicSquare", E, F),
// G = epx_by_neg_z(F) // = elt^(-12*z^3)
c.call(prefix + "__cyclotomicExp_w0", F, G),
c.call(ftmPrefix + "_conjugate", G, G),
// H = conj(D) // = elt^(6*z)
c.call(ftmPrefix + "_conjugate", D, H),
// I = conj(G) // = elt^(12*z^3)
c.call(ftmPrefix + "_conjugate", G, I),
// J = I * E // = elt^(12*z^3 + 6*z^2)
c.call(ftmPrefix + "_mul", I, E, J),
// K = J * H // = elt^(12*z^3 + 6*z^2 + 6*z)
c.call(ftmPrefix + "_mul", J, H, K),
// L = K * B // = elt^(12*z^3 + 6*z^2 + 4*z)
c.call(ftmPrefix + "_mul", K, B, L),
// M = K * E // = elt^(12*z^3 + 12*z^2 + 6*z)
c.call(ftmPrefix + "_mul", K, E, M),
// N = M * elt // = elt^(12*z^3 + 12*z^2 + 6*z + 1)
c.call(ftmPrefix + "_mul", M, elt, N),
// O = L.Frobenius_map(1) // = elt^(q*(12*z^3 + 6*z^2 + 4*z))
c.call(prefix + "__frobeniusMap1", L, O),
// P = O * N // = elt^(q*(12*z^3 + 6*z^2 + 4*z) * (12*z^3 + 12*z^2 + 6*z + 1))
c.call(ftmPrefix + "_mul", O, N, P),
// Q = K.Frobenius_map(2) // = elt^(q^2 * (12*z^3 + 6*z^2 + 6*z))
c.call(prefix + "__frobeniusMap2", K, Q),
// R = Q * P // = elt^(q^2 * (12*z^3 + 6*z^2 + 6*z) + q*(12*z^3 + 6*z^2 + 4*z) * (12*z^3 + 12*z^2 + 6*z + 1))
c.call(ftmPrefix + "_mul", Q, P, R),
// S = conj(elt) // = elt^(-1)
c.call(ftmPrefix + "_conjugate", elt, S),
// T = S * L // = elt^(12*z^3 + 6*z^2 + 4*z - 1)
c.call(ftmPrefix + "_mul", S, L, T),
// U = T.Frobenius_map(3) // = elt^(q^3(12*z^3 + 6*z^2 + 4*z - 1))
c.call(prefix + "__frobeniusMap3", T, U),
// V = U * R // = elt^(q^3(12*z^3 + 6*z^2 + 4*z - 1) + q^2 * (12*z^3 + 6*z^2 + 6*z) + q*(12*z^3 + 6*z^2 + 4*z) * (12*z^3 + 12*z^2 + 6*z + 1))
c.call(ftmPrefix + "_mul", U, R, result),
// result = V
);
}
function buildFinalExponentiation() {
buildFinalExponentiationFirstChunk();
buildFinalExponentiationLastChunk();
const f = module.addFunction(prefix+ "_finalExponentiation");
f.addParam("x", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
const elt = c.getLocal("x");
const result = c.getLocal("r");
const eltToFirstChunk = c.i32_const(module.alloc(ftsize));
f.addCode(
c.call(prefix + "__finalExponentiationFirstChunk", elt, eltToFirstChunk ),
c.call(prefix + "__finalExponentiationLastChunk", eltToFirstChunk, result )
);
}
function buildFinalExponentiationOld() {
const f = module.addFunction(prefix+ "_finalExponentiationOld");
f.addParam("x", "i32");
f.addParam("r", "i32");
const exponent = 552484233613224096312617126783173147097382103762957654188882734314196910839907541213974502761540629817009608548654680343627701153829446747810907373256841551006201639677726139946029199968412598804882391702273019083653272047566316584365559776493027495458238373902875937659943504873220554161550525926302303331747463515644711876653177129578303191095900909191624817826566688241804408081892785725967931714097716709526092261278071952560171111444072049229123565057483750161460024353346284167282452756217662335528813519139808291170539072125381230815729071544861602750936964829313608137325426383735122175229541155376346436093930287402089517426973178917569713384748081827255472576937471496195752727188261435633271238710131736096299798168852925540549342330775279877006784354801422249722573783561685179618816480037695005515426162362431072245638324744480n;
const pExponent = module.alloc(utils$2.bigInt2BytesLE( exponent, 352 ));
const c = f.getCodeBuilder();
f.addCode(
c.call(ftmPrefix + "_exp", c.getLocal("x"), c.i32_const(pExponent), c.i32_const(352), c.getLocal("r")),
);
}
const pPreP = module.alloc(prePSize);
const pPreQ = module.alloc(preQSize);
function buildPairingEquation(nPairings) {
const f = module.addFunction(prefix+ "_pairingEq"+nPairings);
for (let i=0; i<nPairings; i++) {
f.addParam("p_"+i, "i32");
f.addParam("q_"+i, "i32");
}
f.addParam("c", "i32");
f.setReturnType("i32");
const c = f.getCodeBuilder();
const resT = c.i32_const(module.alloc(ftsize));
const auxT = c.i32_const(module.alloc(ftsize));
f.addCode(c.call(ftmPrefix + "_one", resT ));
for (let i=0; i<nPairings; i++) {
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) ));
f.addCode(c.call(prefix + "_millerLoop", c.i32_const(pPreP), c.i32_const(pPreQ), auxT ));
f.addCode(c.call(ftmPrefix + "_mul", resT, auxT, resT ));
}
f.addCode(c.call(prefix + "_finalExponentiation", resT, resT ));
f.addCode(c.call(ftmPrefix + "_eq", resT, c.getLocal("c")));
}
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") ));
}
buildPrepAddStep();
buildPrepDoubleStep();
buildPrepareG1();
buildPrepareG2();
buildMulBy024();
buildMulBy024Old();
buildMillerLoop();
for (let i=0; i<10; i++) {
buildFrobeniusMap(i);
module.exportFunction(prefix + "__frobeniusMap"+i);
}
buildFinalExponentiationOld();
buildFinalExponentiation();
for (let i=1; i<=5; i++) {
buildPairingEquation(i);
module.exportFunction(prefix + "_pairingEq"+i);
}
buildPairing();
module.exportFunction(prefix + "_pairing");
module.exportFunction(prefix + "_prepareG1");
module.exportFunction(prefix + "_prepareG2");
module.exportFunction(prefix + "_millerLoop");
module.exportFunction(prefix + "_finalExponentiation");
module.exportFunction(prefix + "_finalExponentiationOld");
module.exportFunction(prefix + "__mulBy024");
module.exportFunction(prefix + "__mulBy024Old");
module.exportFunction(prefix + "__cyclotomicSquare");
module.exportFunction(prefix + "__cyclotomicExp_w0");
// console.log(module.functionIdxByName);
};
const utils$1 = utils$6;
const buildF1m =build_f1m;
const buildF1 =build_f1;
const buildF2m =build_f2m;
const buildF3m =build_f3m;
const buildCurve =build_curve_jacobian_a0;
const buildFFT$1 = build_fft;
const buildPol = build_pol;
const buildQAP = build_qap;
const buildApplyKey = build_applykey;
const { bitLength: bitLength$1, isOdd, isNegative: isNegative$1 } = bigint;
// Definition here: https://electriccoin.co/blog/new-snark-curve/
var build_bls12381 = function buildBLS12381(module, _prefix) {
const prefix = _prefix || "bls12381";
if (module.modules[prefix]) return prefix; // already builded
const q = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaabn;
const r = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001n;
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 n64r = Math.floor((bitLength$1(r - 1n) - 1)/64) +1;
const n8r = n64r*8;
const frsize = n8r;
const pr = module.alloc(utils$1.bigInt2BytesLE( r, frsize ));
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);
buildFFT$1(module, "frm", "frm", "frm", "frm_mul");
buildPol(module, "pol", "frm");
buildQAP(module, "qap", "frm");
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);
function buildGTimesFr(fnName, opMul) {
const f = module.addFunction(fnName);
f.addParam("pG", "i32");
f.addParam("pFr", "i32");
f.addParam("pr", "i32");
const c = f.getCodeBuilder();
const AUX = c.i32_const(module.alloc(n8r));
f.addCode(
c.call("frm_fromMontgomery", c.getLocal("pFr"), AUX),
c.call(
opMul,
c.getLocal("pG"),
AUX,
c.i32_const(n8r),
c.getLocal("pr")
)
);
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");
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");
function toMontgomery(a) {
return BigInt(a) * (1n << BigInt(f1size*8)) % q;
}
const G1gen = [
3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507n,
1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569n,
1n
];
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 ),
]
);
const G1zero = [
0n,
1n,
0n
];
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 G2gen = [
[
352701069587466618187139116011060144890029952792775240219908644239793785735715026873347600343865175952761926303160n,
3059144344244213709971259814753781636986470325476647558659373206291635324768958432433509563104347017837885763365758n,
],[
1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905n,
927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582n,
],[
1n,
0n,
]
];
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 ),
]
);
const G2zero = [
[
0n,
0n,
],[
1n,
0n,
],[
0n,
0n,
]
];
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 ),
]
);
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 ),
]);
const pBls12381Twist = module.alloc([
...utils$1.bigInt2BytesLE( toMontgomery(1n), f1size ),
...utils$1.bigInt2BytesLE( toMontgomery(1n), f1size ),
]);
function build_mulNR2() {
const f = module.addFunction(f2mPrefix + "_mulNR");
f.addParam("x", "i32");
f.addParam("pr", "i32");
const c = f.getCodeBuilder();
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));
f.addCode(
c.call(f1mPrefix+"_copy", x0, x0c),
c.call(f1mPrefix+"_sub", x0, x1, r0),
c.call(f1mPrefix+"_add", x0c, x1, r1),
);
}
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");
const c = f.getCodeBuilder();
const c0copy = c.i32_const(module.alloc(f1size*2));
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.call(
f2mPrefix + "_copy",
c0copy,
c.i32_add(c.getLocal("pr"), c.i32_const(n8q*2)),
),
);
}
build_mulNR6();
const ftmPrefix = buildF2m(module, f6mPrefix+"_mulNR", "ftm", f6mPrefix);
const ateLoopCount = 0xd201000000010000n;
const ateLoopBitBytes = bits(ateLoopCount);
const pAteLoopBitBytes = module.alloc(ateLoopBitBytes);
const ateCoefSize = 3 * f2size;
const ateNDblCoefs = ateLoopBitBytes.length-1;
const ateNAddCoefs = ateLoopBitBytes.reduce((acc, b) => acc + ( b!=0 ? 1 : 0) ,0);
const ateNCoefs = ateNAddCoefs + ateNDblCoefs + 1;
const prePSize = 3*2*n8q;
const preQSize = 3*n8q*2 + ateNCoefs*ateCoefSize;
const finalExpIsNegative = true;
const finalExpZ = 15132376222941642752n;
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 {
res.push( 0 );
}
E = E >> 1n;
}
return res;
}
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;
}
function buildPrepareG1() {
const f = module.addFunction(prefix+ "_prepareG1");
f.addParam("pP", "i32");
f.addParam("ppreP", "i32");
const c = f.getCodeBuilder();
f.addCode(
c.call(g1mPrefix + "_normalize", c.getLocal("pP"), c.getLocal("ppreP")), // TODO Remove if already in affine
);
}
function buildPrepDoubleStep() {
const f = module.addFunction(prefix+ "_prepDblStep");
f.addParam("R", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
const Rx = c.getLocal("R");
const Ry = c.i32_add(c.getLocal("R"), c.i32_const(2*n8q));
const Rz = c.i32_add(c.getLocal("R"), c.i32_const(4*n8q));
const t0 = c.getLocal("r");
const t3 = c.i32_add(c.getLocal("r"), c.i32_const(2*n8q));
const t6 = c.i32_add(c.getLocal("r"), c.i32_const(4*n8q));
const zsquared = c.i32_const(module.alloc(f2size));
const t1 = c.i32_const(module.alloc(f2size));
const t2 = c.i32_const(module.alloc(f2size));
const t4 = c.i32_const(module.alloc(f2size));
const t5 = c.i32_const(module.alloc(f2size));
f.addCode(
// tmp0 = r.x.square();
c.call(f2mPrefix + "_square", Rx, t0),
// tmp1 = r.y.square();
c.call(f2mPrefix + "_square", Ry, t1),
// tmp2 = tmp1.square();
c.call(f2mPrefix + "_square", t1, t2),
// tmp3 = (tmp1 + r.x).square() - tmp0 - tmp2;
c.call(f2mPrefix + "_add", t1, Rx, t3),
c.call(f2mPrefix + "_square", t3, t3),
c.call(f2mPrefix + "_sub", t3, t0, t3),
c.call(f2mPrefix + "_sub", t3, t2, t3),
// tmp3 = tmp3 + tmp3;
c.call(f2mPrefix + "_add", t3, t3, t3),
// tmp4 = tmp0 + tmp0 + tmp0;
c.call(f2mPrefix + "_add", t0, t0, t4),
c.call(f2mPrefix + "_add", t4, t0, t4),
// tmp6 = r.x + tmp4;
c.call(f2mPrefix + "_add", Rx, t4, t6),
// tmp5 = tmp4.square();
c.call(f2mPrefix + "_square", t4, t5),
// zsquared = r.z.square();
c.call(f2mPrefix + "_square", Rz, zsquared),
// r.x = tmp5 - tmp3 - tmp3;
c.call(f2mPrefix + "_sub", t5, t3, Rx),
c.call(f2mPrefix + "_sub", Rx, t3, Rx),
// r.z = (r.z + r.y).square() - tmp1 - zsquared;
c.call(f2mPrefix + "_add", Rz, Ry, Rz),
c.call(f2mPrefix + "_square", Rz, Rz),
c.call(f2mPrefix + "_sub", Rz, t1, Rz),
c.call(f2mPrefix + "_sub", Rz, zsquared, Rz),
// r.y = (tmp3 - r.x) * tmp4;
c.call(f2mPrefix + "_sub", t3, Rx, Ry),
c.call(f2mPrefix + "_mul", Ry, t4, Ry),
// tmp2 = tmp2 + tmp2;
c.call(f2mPrefix + "_add", t2, t2, t2),
// tmp2 = tmp2 + tmp2;
c.call(f2mPrefix + "_add", t2, t2, t2),
// tmp2 = tmp2 + tmp2;
c.call(f2mPrefix + "_add", t2, t2, t2),
// r.y -= tmp2;
c.call(f2mPrefix + "_sub", Ry, t2, Ry),
// tmp3 = tmp4 * zsquared;
c.call(f2mPrefix + "_mul", t4, zsquared, t3),
// tmp3 = tmp3 + tmp3;
c.call(f2mPrefix + "_add", t3, t3, t3),
// tmp3 = -tmp3;
c.call(f2mPrefix + "_neg", t3, t3),
// tmp6 = tmp6.square() - tmp0 - tmp5;
c.call(f2mPrefix + "_square", t6, t6),
c.call(f2mPrefix + "_sub", t6, t0, t6),
c.call(f2mPrefix + "_sub", t6, t5, t6),
// tmp1 = tmp1 + tmp1;
c.call(f2mPrefix + "_add", t1, t1, t1),
// tmp1 = tmp1 + tmp1;
c.call(f2mPrefix + "_add", t1, t1, t1),
// tmp6 = tmp6 - tmp1;
c.call(f2mPrefix + "_sub", t6, t1, t6),
// tmp0 = r.z * zsquared;
c.call(f2mPrefix + "_mul", Rz, zsquared, t0),
// tmp0 = tmp0 + tmp0;
c.call(f2mPrefix + "_add", t0, t0, t0),
);
}
function buildPrepAddStep() {
const f = module.addFunction(prefix+ "_prepAddStep");
f.addParam("R", "i32");
f.addParam("Q", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
const Rx = c.getLocal("R");
const Ry = c.i32_add(c.getLocal("R"), c.i32_const(2*n8q));
const Rz = c.i32_add(c.getLocal("R"), c.i32_const(4*n8q));
const Qx = c.getLocal("Q");
const Qy = c.i32_add(c.getLocal("Q"), c.i32_const(2*n8q));
const t10 = c.getLocal("r");
const t1 = c.i32_add(c.getLocal("r"), c.i32_const(2*n8q));
const t9 = c.i32_add(c.getLocal("r"), c.i32_const(4*n8q));
const zsquared = c.i32_const(module.alloc(f2size));
const ysquared = c.i32_const(module.alloc(f2size));
const ztsquared = c.i32_const(module.alloc(f2size));
const t0 = c.i32_const(module.alloc(f2size));
const t2 = c.i32_const(module.alloc(f2size));
const t3 = c.i32_const(module.alloc(f2size));
const t4 = c.i32_const(module.alloc(f2size));
const t5 = c.i32_const(module.alloc(f2size));
const t6 = c.i32_const(module.alloc(f2size));
const t7 = c.i32_const(module.alloc(f2size));
const t8 = c.i32_const(module.alloc(f2size));
f.addCode(
// zsquared = r.z.square();
c.call(f2mPrefix + "_square", Rz, zsquared),
// ysquared = q.y.square();
c.call(f2mPrefix + "_square", Qy, ysquared),
// t0 = zsquared * q.x;
c.call(f2mPrefix + "_mul", zsquared, Qx, t0),
// t1 = ((q.y + r.z).square() - ysquared - zsquared) * zsquared;
c.call(f2mPrefix + "_add", Qy, Rz, t1),
c.call(f2mPrefix + "_square", t1, t1),
c.call(f2mPrefix + "_sub", t1, ysquared, t1),
c.call(f2mPrefix + "_sub", t1, zsquared, t1),
c.call(f2mPrefix + "_mul", t1, zsquared, t1),
// t2 = t0 - r.x;
c.call(f2mPrefix + "_sub", t0, Rx, t2),
// t3 = t2.square();
c.call(f2mPrefix + "_square", t2, t3),
// t4 = t3 + t3;
c.call(f2mPrefix + "_add", t3, t3, t4),
// t4 = t4 + t4;
c.call(f2mPrefix + "_add", t4, t4, t4),
// t5 = t4 * t2;
c.call(f2mPrefix + "_mul", t4, t2, t5),
// t6 = t1 - r.y - r.y;
c.call(f2mPrefix + "_sub", t1, Ry, t6),
c.call(f2mPrefix + "_sub", t6, Ry, t6),
// t9 = t6 * q.x;
c.call(f2mPrefix + "_mul", t6, Qx, t9),
// t7 = t4 * r.x;
c.call(f2mPrefix + "_mul", t4, Rx, t7),
// r.x = t6.square() - t5 - t7 - t7;
c.call(f2mPrefix + "_square", t6, Rx),
c.call(f2mPrefix + "_sub", Rx, t5, Rx),
c.call(f2mPrefix + "_sub", Rx, t7, Rx),
c.call(f2mPrefix + "_sub", Rx, t7, Rx),
// r.z = (r.z + t2).square() - zsquared - t3;
c.call(f2mPrefix + "_add", Rz, t2, Rz),
c.call(f2mPrefix + "_square", Rz, Rz),
c.call(f2mPrefix + "_sub", Rz, zsquared, Rz),
c.call(f2mPrefix + "_sub", Rz, t3, Rz),
// t10 = q.y + r.z;
c.call(f2mPrefix + "_add", Qy, Rz, t10),
// t8 = (t7 - r.x) * t6;
c.call(f2mPrefix + "_sub", t7, Rx, t8),
c.call(f2mPrefix + "_mul", t8, t6, t8),
// t0 = r.y * t5;
c.call(f2mPrefix + "_mul", Ry, t5, t0),
// t0 = t0 + t0;
c.call(f2mPrefix + "_add", t0, t0, t0),
// r.y = t8 - t0;
c.call(f2mPrefix + "_sub", t8, t0, Ry),
// t10 = t10.square() - ysquared;
c.call(f2mPrefix + "_square", t10, t10),
c.call(f2mPrefix + "_sub", t10, ysquared, t10),
// ztsquared = r.z.square();
c.call(f2mPrefix + "_square", Rz, ztsquared),
// t10 = t10 - ztsquared;
c.call(f2mPrefix + "_sub", t10, ztsquared, t10),
// t9 = t9 + t9 - t10;
c.call(f2mPrefix + "_add", t9, t9, t9),
c.call(f2mPrefix + "_sub", t9, t10, t9),
// t10 = r.z + r.z;
c.call(f2mPrefix + "_add", Rz, Rz, t10),
// t6 = -t6;
c.call(f2mPrefix + "_neg", t6, t6),
// t1 = t6 + t6;
c.call(f2mPrefix + "_add", t6, t6, t1),
);
}
function buildPrepareG2() {
const f = module.addFunction(prefix+ "_prepareG2");
f.addParam("pQ", "i32");
f.addParam("ppreQ", "i32");
f.addLocal("pCoef", "i32");
f.addLocal("i", "i32");
const c = f.getCodeBuilder();
const Q = c.getLocal("pQ");
const pR = module.alloc(f2size*3);
const R = c.i32_const(pR);
const base = c.getLocal("ppreQ");
f.addCode(
c.call(g2mPrefix + "_normalize", Q, base),
c.if(
c.call(g2mPrefix + "_isZero", base),
c.ret([])
),
c.call(g2mPrefix + "_copy", base, R),
c.setLocal("pCoef", c.i32_add(c.getLocal("ppreQ"), c.i32_const(f2size*3))),
);
f.addCode(
c.setLocal("i", c.i32_const(ateLoopBitBytes.length-2)),
c.block(c.loop(
c.call(prefix + "_prepDblStep", R, c.getLocal("pCoef")),
c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))),
c.if(
c.i32_load8_s(c.getLocal("i"), pAteLoopBitBytes),
[
...c.call(prefix + "_prepAddStep", R, base, c.getLocal("pCoef")),
...c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))),
]
),
c.br_if(1, c.i32_eqz ( c.getLocal("i") )),
c.setLocal("i", c.i32_sub(c.getLocal("i"), c.i32_const(1))),
c.br(0)
))
);
}
function buildF6Mul1() {
const f = module.addFunction(f6mPrefix+ "_mul1");
f.addParam("pA", "i32"); // F6
f.addParam("pC1", "i32"); // F2
f.addParam("pR", "i32"); // F6
const c = f.getCodeBuilder();
const A_c0 = c.getLocal("pA");
const A_c1 = c.i32_add(c.getLocal("pA"), c.i32_const(f1size*2));
const A_c2 = c.i32_add(c.getLocal("pA"), c.i32_const(f1size*4));
const c1 = c.getLocal("pC1");
const t1 = c.getLocal("pR");
const t2 = c.i32_add(c.getLocal("pR"), c.i32_const(f1size*2));
const b_b = c.i32_add(c.getLocal("pR"), c.i32_const(f1size*4));
const Ac0_Ac1 = c.i32_const(module.alloc(f1size*2));
const Ac1_Ac2 = c.i32_const(module.alloc(f1size*2));
f.addCode(
c.call(f2mPrefix + "_add", A_c0, A_c1, Ac0_Ac1),
c.call(f2mPrefix + "_add", A_c1, A_c2, Ac1_Ac2),
// let b_b = self.c1 * c1;
c.call(f2mPrefix + "_mul", A_c1, c1, b_b),
// let t1 = (self.c1 + self.c2) * c1 - b_b;
c.call(f2mPrefix + "_mul", Ac1_Ac2, c1, t1),
c.call(f2mPrefix + "_sub", t1, b_b, t1),
// let t1 = t1.mul_by_nonresidue();
c.call(f2mPrefix + "_mulNR", t1, t1),
// let t2 = (self.c0 + self.c1) * c1 - b_b;
c.call(f2mPrefix + "_mul", Ac0_Ac1, c1, t2),
c.call(f2mPrefix + "_sub", t2, b_b, t2),
);
}
buildF6Mul1();
function buildF6Mul01() {
const f = module.addFunction(f6mPrefix+ "_mul01");
f.addParam("pA", "i32"); // F6
f.addParam("pC0", "i32"); // F2
f.addParam("pC1", "i32"); // F2
f.addParam("pR", "i32"); // F6
const c = f.getCodeBuilder();
const A_c0 = c.getLocal("pA");
const A_c1 = c.i32_add(c.getLocal("pA"), c.i32_const(f1size*2));
const A_c2 = c.i32_add(c.getLocal("pA"), c.i32_const(f1size*4));
const c0 = c.getLocal("pC0");
const c1 = c.getLocal("pC1");
const t1 = c.getLocal("pR");
const t2 = c.i32_add(c.getLocal("pR"), c.i32_const(f1size*2));
const t3 = c.i32_add(c.getLocal("pR"), c.i32_const(f1size*4));
const a_a = c.i32_const(module.alloc(f1size*2));
const b_b = c.i32_const(module.alloc(f1size*2));
const Ac0_Ac1 = c.i32_const(module.alloc(f1size*2));
const Ac0_Ac2 = c.i32_const(module.alloc(f1size*2));
f.addCode(
// let a_a = self.c0 * c0;
c.call(f2mPrefix + "_mul", A_c0, c0, a_a),
// let b_b = self.c1 * c1;
c.call(f2mPrefix + "_mul", A_c1, c1, b_b),
c.call(f2mPrefix + "_add", A_c0, A_c1, Ac0_Ac1),
c.call(f2mPrefix + "_add", A_c0, A_c2, Ac0_Ac2),
// let t1 = (self.c1 + self.c2) * c1 - b_b;
c.call(f2mPrefix + "_add", A_c1, A_c2, t1),
c.call(f2mPrefix + "_mul", t1, c1, t1),
c.call(f2mPrefix + "_sub", t1, b_b, t1),
// let t1 = t1.mul_by_nonresidue() + a_a;
c.call(f2mPrefix + "_mulNR", t1, t1),
c.call(f2mPrefix + "_add", t1, a_a, t1),
// let t2 = (c0 + c1) * (self.c0 + self.c1) - a_a - b_b;
c.call(f2mPrefix + "_add", c0, c1, t2),
c.call(f2mPrefix + "_mul", t2, Ac0_Ac1, t2),
c.call(f2mPrefix + "_sub", t2, a_a, t2),
c.call(f2mPrefix + "_sub", t2, b_b, t2),
// let t3 = (self.c0 + self.c2) * c0 - a_a + b_b;
c.call(f2mPrefix + "_mul", Ac0_Ac2, c0, t3),
c.call(f2mPrefix + "_sub", t3, a_a, t3),
c.call(f2mPrefix + "_add", t3, b_b, t3),
);
}
buildF6Mul01();
function buildF12Mul014() {
const f = module.addFunction(ftmPrefix+ "_mul014");
f.addParam("pA", "i32"); // F12
f.addParam("pC0", "i32"); // F2
f.addParam("pC1", "i32"); // F2
f.addParam("pC4", "i32"); // F2
f.addParam("pR", "i32"); // F12
const c = f.getCodeBuilder();
const A_c0 = c.getLocal("pA");
const A_c1 = c.i32_add(c.getLocal("pA"), c.i32_const(f1size*6));
const c0 = c.getLocal("pC0");
const c1 = c.getLocal("pC1");
const c4 = c.getLocal("pC4");
const aa = c.i32_const(module.alloc(f1size*6));
const bb = c.i32_const(module.alloc(f1size*6));
const o = c.i32_const(module.alloc(f1size*2));
const R_c0 = c.getLocal("pR");
const R_c1 = c.i32_add(c.getLocal("pR"), c.i32_const(f1size*6));
f.addCode(
// let aa = self.c0.mul_by_01(c0, c1);
c.call(f6mPrefix + "_mul01", A_c0, c0, c1, aa),
// let bb = self.c1.mul_by_1(c4);
c.call(f6mPrefix + "_mul1", A_c1, c4, bb),
// let o = c1 + c4;
c.call(f2mPrefix + "_add", c1, c4, o),
// let c1 = self.c1 + self.c0;
c.call(f6mPrefix + "_add", A_c1, A_c0, R_c1),
// let c1 = c1.mul_by_01(c0, &o);
c.call(f6mPrefix + "_mul01", R_c1, c0, o, R_c1),
// let c1 = c1 - aa - bb;
c.call(f6mPrefix + "_sub", R_c1, aa, R_c1),
c.call(f6mPrefix + "_sub", R_c1, bb, R_c1),
// let c0 = bb;
c.call(f6mPrefix + "_copy", bb, R_c0),
// let c0 = c0.mul_by_nonresidue();
c.call(f6mPrefix + "_mulNR", R_c0, R_c0),
// let c0 = c0 + aa;
c.call(f6mPrefix + "_add", R_c0, aa, R_c0),
);
}
buildF12Mul014();
function buildELL() {
const f = module.addFunction(prefix+ "_ell");
f.addParam("pP", "i32");
f.addParam("pCoefs", "i32");
f.addParam("pF", "i32");
const c = f.getCodeBuilder();
const Px = c.getLocal("pP");
const Py = c.i32_add(c.getLocal("pP"), c.i32_const(n8q));
const F = c.getLocal("pF");
const coef0_0 = c.getLocal("pCoefs");
const coef0_1 = c.i32_add(c.getLocal("pCoefs"), c.i32_const(f1size));
const coef1_0 = c.i32_add(c.getLocal("pCoefs"), c.i32_const(f1size*2));
const coef1_1 = c.i32_add(c.getLocal("pCoefs"), c.i32_const(f1size*3));
const coef2 = c.i32_add(c.getLocal("pCoefs"), c.i32_const(f1size*4));
const pc0 = module.alloc(f1size*2);
const c0 = c.i32_const(pc0);
const c0_c0 = c.i32_const(pc0);
const c0_c1 = c.i32_const(pc0+f1size);
const pc1 = module.alloc(f1size*2);
const c1 = c.i32_const(pc1);
const c1_c0 = c.i32_const(pc1);
const c1_c1 = c.i32_const(pc1+f1size);
f.addCode(
// let mut c0 = coeffs.0;
// let mut c1 = coeffs.1;
//
// c0.c0 *= p.y;
// c0.c1 *= p.y;
//
// c1.c0 *= p.x;
// c1.c1 *= p.x;
//
// f.mul_by_014(&coeffs.2, &c1, &c0)
c.call(f1mPrefix + "_mul", coef0_0, Py, c0_c0),
c.call(f1mPrefix + "_mul", coef0_1, Py, c0_c1),
c.call(f1mPrefix + "_mul", coef1_0, Px, c1_c0),
c.call(f1mPrefix + "_mul", coef1_1, Px, c1_c1),
c.call(ftmPrefix + "_mul014", F, coef2, c1, c0, F),
);
}
buildELL();
function buildMillerLoop() {
const f = module.addFunction(prefix+ "_millerLoop");
f.addParam("ppreP", "i32");
f.addParam("ppreQ", "i32");
f.addParam("r", "i32");
f.addLocal("pCoef", "i32");
f.addLocal("i", "i32");
const c = f.getCodeBuilder();
const preP = c.getLocal("ppreP");
const coefs = c.getLocal("pCoef");
const F = c.getLocal("r");
f.addCode(
c.call(ftmPrefix + "_one", F),
c.if(
c.call(g1mPrefix + "_isZero", preP),
c.ret([])
),
c.if(
c.call(g1mPrefix + "_isZero", c.getLocal("ppreQ")),
c.ret([])
),
c.setLocal("pCoef", c.i32_add( c.getLocal("ppreQ"), c.i32_const(f2size*3))),
c.setLocal("i", c.i32_const(ateLoopBitBytes.length-2)),
c.block(c.loop(
c.call(prefix + "_ell", preP, coefs, F),
c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))),
c.if(
c.i32_load8_s(c.getLocal("i"), pAteLoopBitBytes),
[
...c.call(prefix + "_ell", preP, coefs, F),
...c.setLocal("pCoef", c.i32_add(c.getLocal("pCoef"), c.i32_const(ateCoefSize))),
]
),
c.call(ftmPrefix + "_square", F, F),
c.br_if(1, c.i32_eq ( c.getLocal("i"), c.i32_const(1) )),
c.setLocal("i", c.i32_sub(c.getLocal("i"), c.i32_const(1))),
c.br(0)
)),
c.call(prefix + "_ell", preP, coefs, F),
);
{
f.addCode(
c.call(ftmPrefix + "_conjugate", F, F),
);
}
}
function buildFrobeniusMap(n) {
const F12 = [
[
[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");
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;
}
}
function buildCyclotomicSquare() {
const f = module.addFunction(prefix+ "__cyclotomicSquare");
f.addParam("x", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
const x0 = c.getLocal("x");
const x4 = c.i32_add(c.getLocal("x"), c.i32_const(f2size));
const x3 = c.i32_add(c.getLocal("x"), c.i32_const(2*f2size));
const x2 = c.i32_add(c.getLocal("x"), c.i32_const(3*f2size));
const x1 = c.i32_add(c.getLocal("x"), c.i32_const(4*f2size));
const x5 = c.i32_add(c.getLocal("x"), c.i32_const(5*f2size));
const r0 = c.getLocal("r");
const r4 = c.i32_add(c.getLocal("r"), c.i32_const(f2size));
const r3 = c.i32_add(c.getLocal("r"), c.i32_const(2*f2size));
const r2 = c.i32_add(c.getLocal("r"), c.i32_const(3*f2size));
const r1 = c.i32_add(c.getLocal("r"), c.i32_const(4*f2size));
const r5 = c.i32_add(c.getLocal("r"), c.i32_const(5*f2size));
const t0 = c.i32_const(module.alloc(f2size));
const t1 = c.i32_const(module.alloc(f2size));
const t2 = c.i32_const(module.alloc(f2size));
const t3 = c.i32_const(module.alloc(f2size));
const t4 = c.i32_const(module.alloc(f2size));
const t5 = c.i32_const(module.alloc(f2size));
const tmp = c.i32_const(module.alloc(f2size));
const AUX = c.i32_const(module.alloc(f2size));
f.addCode(
// // t0 + t1*y = (z0 + z1*y)^2 = a^2
// tmp = z0 * z1;
// t0 = (z0 + z1) * (z0 + my_Fp6::non_residue * z1) - tmp - my_Fp6::non_residue * tmp;
// t1 = tmp + tmp;
c.call(f2mPrefix + "_mul", x0, x1, tmp),
c.call(f2mPrefix + "_mulNR", x1, t0),
c.call(f2mPrefix + "_add", x0, t0, t0),
c.call(f2mPrefix + "_add", x0, x1, AUX),
c.call(f2mPrefix + "_mul", AUX, t0, t0),
c.call(f2mPrefix + "_mulNR", tmp, AUX),
c.call(f2mPrefix + "_add", tmp, AUX, AUX),
c.call(f2mPrefix + "_sub", t0, AUX, t0),
c.call(f2mPrefix + "_add", tmp, tmp, t1),
// // t2 + t3*y = (z2 + z3*y)^2 = b^2
// tmp = z2 * z3;
// t2 = (z2 + z3) * (z2 + my_Fp6::non_residue * z3) - tmp - my_Fp6::non_residue * tmp;
// t3 = tmp + tmp;
c.call(f2mPrefix + "_mul", x2, x3, tmp),
c.call(f2mPrefix + "_mulNR", x3, t2),
c.call(f2mPrefix + "_add", x2, t2, t2),
c.call(f2mPrefix + "_add", x2, x3, AUX),
c.call(f2mPrefix + "_mul", AUX, t2, t2),
c.call(f2mPrefix + "_mulNR", tmp, AUX),
c.call(f2mPrefix + "_add", tmp, AUX, AUX),
c.call(f2mPrefix + "_sub", t2, AUX, t2),
c.call(f2mPrefix + "_add", tmp, tmp, t3),
// // t4 + t5*y = (z4 + z5*y)^2 = c^2
// tmp = z4 * z5;
// t4 = (z4 + z5) * (z4 + my_Fp6::non_residue * z5) - tmp - my_Fp6::non_residue * tmp;
// t5 = tmp + tmp;
c.call(f2mPrefix + "_mul", x4, x5, tmp),
c.call(f2mPrefix + "_mulNR", x5, t4),
c.call(f2mPrefix + "_add", x4, t4, t4),
c.call(f2mPrefix + "_add", x4, x5, AUX),
c.call(f2mPrefix + "_mul", AUX, t4, t4),
c.call(f2mPrefix + "_mulNR", tmp, AUX),
c.call(f2mPrefix + "_add", tmp, AUX, AUX),
c.call(f2mPrefix + "_sub", t4, AUX, t4),
c.call(f2mPrefix + "_add", tmp, tmp, t5),
// For A
// z0 = 3 * t0 - 2 * z0
c.call(f2mPrefix + "_sub", t0, x0, r0),
c.call(f2mPrefix + "_add", r0, r0, r0),
c.call(f2mPrefix + "_add", t0, r0, r0),
// z1 = 3 * t1 + 2 * z1
c.call(f2mPrefix + "_add", t1, x1, r1),
c.call(f2mPrefix + "_add", r1, r1, r1),
c.call(f2mPrefix + "_add", t1, r1, r1),
// For B
// z2 = 3 * (xi * t5) + 2 * z2
c.call(f2mPrefix + "_mul", t5, c.i32_const(pBls12381Twist), AUX),
c.call(f2mPrefix + "_add", AUX, x2, r2),
c.call(f2mPrefix + "_add", r2, r2, r2),
c.call(f2mPrefix + "_add", AUX, r2, r2),
// z3 = 3 * t4 - 2 * z3
c.call(f2mPrefix + "_sub", t4, x3, r3),
c.call(f2mPrefix + "_add", r3, r3, r3),
c.call(f2mPrefix + "_add", t4, r3, r3),
// For C
// z4 = 3 * t2 - 2 * z4
c.call(f2mPrefix + "_sub", t2, x4, r4),
c.call(f2mPrefix + "_add", r4, r4, r4),
c.call(f2mPrefix + "_add", t2, r4, r4),
// z5 = 3 * t3 + 2 * z5
c.call(f2mPrefix + "_add", t3, x5, r5),
c.call(f2mPrefix + "_add", r5, r5, r5),
c.call(f2mPrefix + "_add", t3, r5, r5),
);
}
function buildCyclotomicExp(exponent, isExpNegative, fnName) {
const exponentNafBytes = naf(exponent).map( (b) => (b==-1 ? 0xFF: b) );
const pExponentNafBytes = module.alloc(exponentNafBytes);
// const pExponent = module.alloc(utils.bigInt2BytesLE(exponent, n8));
const f = module.addFunction(prefix+ "__cyclotomicExp_"+fnName);
f.addParam("x", "i32");
f.addParam("r", "i32");
f.addLocal("bit", "i32");
f.addLocal("i", "i32");
const c = f.getCodeBuilder();
const x = c.getLocal("x");
const res = c.getLocal("r");
const inverse = c.i32_const(module.alloc(ftsize));
f.addCode(
c.call(ftmPrefix + "_conjugate", x, inverse),
c.call(ftmPrefix + "_one", res),
c.if(
c.teeLocal("bit", c.i32_load8_s(c.i32_const(exponentNafBytes.length-1), pExponentNafBytes)),
c.if(
c.i32_eq(
c.getLocal("bit"),
c.i32_const(1)
),
c.call(ftmPrefix + "_mul", res, x, res),
c.call(ftmPrefix + "_mul", res, inverse, res),
)
),
c.setLocal("i", c.i32_const(exponentNafBytes.length-2)),
c.block(c.loop(
c.call(prefix + "__cyclotomicSquare", res, res),
c.if(
c.teeLocal("bit", c.i32_load8_s(c.getLocal("i"), pExponentNafBytes)),
c.if(
c.i32_eq(
c.getLocal("bit"),
c.i32_const(1)
),
c.call(ftmPrefix + "_mul", res, x, res),
c.call(ftmPrefix + "_mul", res, inverse, res),
)
),
c.br_if(1, c.i32_eqz ( c.getLocal("i") )),
c.setLocal("i", c.i32_sub(c.getLocal("i"), c.i32_const(1))),
c.br(0)
))
);
if (isExpNegative) {
f.addCode(
c.call(ftmPrefix + "_conjugate", res, res),
);
}
}
function buildFinalExponentiation() {
buildCyclotomicSquare();
buildCyclotomicExp(finalExpZ, finalExpIsNegative, "w0");
const f = module.addFunction(prefix+ "_finalExponentiation");
f.addParam("x", "i32");
f.addParam("r", "i32");
const c = f.getCodeBuilder();
const elt = c.getLocal("x");
const res = c.getLocal("r");
const t0 = c.i32_const(module.alloc(ftsize));
const t1 = c.i32_const(module.alloc(ftsize));
const t2 = c.i32_const(module.alloc(ftsize));
const t3 = c.i32_const(module.alloc(ftsize));
const t4 = c.i32_const(module.alloc(ftsize));
const t5 = c.i32_const(module.alloc(ftsize));
const t6 = c.i32_const(module.alloc(ftsize));
f.addCode(
// let mut t0 = f.frobenius_map(6)
c.call(ftmPrefix + "_frobeniusMap6", elt, t0),
// let t1 = f.invert()
c.call(ftmPrefix + "_inverse", elt, t1),
// let mut t2 = t0 * t1;
c.call(ftmPrefix + "_mul", t0, t1, t2),
// t1 = t2.clone();
c.call(ftmPrefix + "_copy", t2, t1),
// t2 = t2.frobenius_map().frobenius_map();
c.call(ftmPrefix + "_frobeniusMap2", t2, t2),
// t2 *= t1;
c.call(ftmPrefix + "_mul", t2, t1, t2),
// t1 = cyclotomic_square(t2).conjugate();
c.call(prefix + "__cyclotomicSquare", t2, t1),
c.call(ftmPrefix + "_conjugate", t1, t1),
// let mut t3 = cycolotomic_exp(t2);
c.call(prefix + "__cyclotomicExp_w0", t2, t3),
// let mut t4 = cyclotomic_square(t3);
c.call(prefix + "__cyclotomicSquare", t3, t4),
// let mut t5 = t1 * t3;
c.call(ftmPrefix + "_mul", t1, t3, t5),
// t1 = cycolotomic_exp(t5);
c.call(prefix + "__cyclotomicExp_w0", t5, t1),
// t0 = cycolotomic_exp(t1);
c.call(prefix + "__cyclotomicExp_w0", t1, t0),
// let mut t6 = cycolotomic_exp(t0);
c.call(prefix + "__cyclotomicExp_w0", t0, t6),
// t6 *= t4;
c.call(ftmPrefix + "_mul", t6, t4, t6),
// t4 = cycolotomic_exp(t6);
c.call(prefix + "__cyclotomicExp_w0", t6, t4),
// t5 = t5.conjugate();
c.call(ftmPrefix + "_conjugate", t5, t5),
// t4 *= t5 * t2;
c.call(ftmPrefix + "_mul", t4, t5, t4),
c.call(ftmPrefix + "_mul", t4, t2, t4),
// t5 = t2.conjugate();
c.call(ftmPrefix + "_conjugate", t2, t5),
// t1 *= t2;
c.call(ftmPrefix + "_mul", t1, t2, t1),
// t1 = t1.frobenius_map().frobenius_map().frobenius_map();
c.call(ftmPrefix + "_frobeniusMap3", t1, t1),
// t6 *= t5;
c.call(ftmPrefix + "_mul", t6, t5, t6),
// t6 = t6.frobenius_map();
c.call(ftmPrefix + "_frobeniusMap1", t6, t6),
// t3 *= t0;
c.call(ftmPrefix + "_mul", t3, t0, t3),
// t3 = t3.frobenius_map().frobenius_map();
c.call(ftmPrefix + "_frobeniusMap2", t3, t3),
// t3 *= t1;
c.call(ftmPrefix + "_mul", t3, t1, t3),
// t3 *= t6;
c.call(ftmPrefix + "_mul", t3, t6, t3),
// f = t3 * t4;
c.call(ftmPrefix + "_mul", t3, t4, res),
);
}
function buildFinalExponentiationOld() {
const f = module.addFunction(prefix+ "_finalExponentiationOld");
f.addParam("x", "i32");
f.addParam("r", "i32");
const exponent = 322277361516934140462891564586510139908379969514828494218366688025288661041104682794998680497580008899973249814104447692778988208376779573819485263026159588510513834876303014016798809919343532899164848730280942609956670917565618115867287399623286813270357901731510188149934363360381614501334086825442271920079363289954510565375378443704372994881406797882676971082200626541916413184642520269678897559532260949334760604962086348898118982248842634379637598665468817769075878555493752214492790122785850202957575200176084204422751485957336465472324810982833638490904279282696134323072515220044451592646885410572234451732790590013479358343841220074174848221722017083597872017638514103174122784843925578370430843522959600095676285723737049438346544753168912974976791528535276317256904336520179281145394686565050419250614107803233314658825463117900250701199181529205942363159325765991819433914303908860460720581408201373164047773794825411011922305820065611121544561808414055302212057471395719432072209245600258134364584636810093520285711072578721435517884103526483832733289802426157301542744476740008494780363354305116978805620671467071400711358839553375340724899735460480144599782014906586543813292157922220645089192130209334926661588737007768565838519456601560804957985667880395221049249803753582637708560n;
const pExponent = module.alloc(utils$1.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<nPairings; i++) {
f.addParam("p_"+i, "i32");
f.addParam("q_"+i, "i32");
}
f.addParam("c", "i32");
f.setReturnType("i32");
const c = f.getCodeBuilder();
const resT = c.i32_const(module.alloc(ftsize));
const auxT = c.i32_const(module.alloc(ftsize));
f.addCode(c.call(ftmPrefix + "_one", resT ));
for (let i=0; i<nPairings; i++) {
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))
)
);
f.addCode(c.call(prefix + "_millerLoop", c.i32_const(pPreP), c.i32_const(pPreQ), auxT ));
f.addCode(c.call(ftmPrefix + "_mul", resT, auxT, resT ));
}
f.addCode(c.call(prefix + "_finalExponentiation", resT, resT ));
f.addCode(c.call(ftmPrefix + "_eq", resT, c.getLocal("c")));
}
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 buildInGroupG2() {
const f = module.addFunction(g2mPrefix+ "_inGroupAffine");
f.addParam("p", "i32");
f.setReturnType("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));
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);
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),
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),
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),
c.call(f2mPrefix + "_one", f3z),
c.call(g2mPrefix + "_timesScalar", f3, z, c.i32_const(8), f3),
c.call(g2mPrefix + "_addMixed", f3, f2, f3),
c.ret(
c.call(g2mPrefix + "_eqMixed", f3, c.getLocal("p"))
)
);
const fInGroup = module.addFunction(g2mPrefix + "_inGroup");
fInGroup.addParam("pIn", "i32");
fInGroup.setReturnType("i32");
const c2 = fInGroup.getCodeBuilder();
const aux2 = c2.i32_const(module.alloc(f2size*2));
fInGroup.addCode(
c2.call(g2mPrefix + "_toAffine", c2.getLocal("pIn"), aux2),
c2.ret(
c2.call(g2mPrefix + "_inGroupAffine", aux2),
)
);
}
function buildInGroupG1() {
const f = module.addFunction(g1mPrefix+ "_inGroupAffine");
f.addParam("p", "i32");
f.setReturnType("i32");
const c = f.getCodeBuilder();
const BETA = 4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939436n;
const BETA2 = 793479390729215512621379701633421447060886740281060493010456487427281649075476305620758731620350n;
const Z2M1D3 = (finalExpZ * finalExpZ - 1n) / 3n;
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)));
const z2m1d3 = c.i32_const(module.alloc(utils$1.bigInt2BytesLE(Z2M1D3, 16)));
const px = c.getLocal("p");
const py = c.i32_add(c.getLocal("p"), c.i32_const(f1size));
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);
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);
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)),
),
c.call(f1mPrefix + "_mul", px, beta, spx),
c.call(f1mPrefix + "_copy", py, spy),
c.call(f1mPrefix + "_mul", px, beta2, s2px),
c.call(f1mPrefix + "_copy", py, s2py),
c.call(g1mPrefix + "_doubleAffine", sp, sp),
c.call(g1mPrefix + "_subMixed", sp, c.getLocal("p"), sp),
c.call(g1mPrefix + "_subMixed", sp, s2p, sp),
c.call(g1mPrefix + "_timesScalar", sp, z2m1d3, c.i32_const(16), sp),
c.ret(
c.call(g1mPrefix + "_eqMixed", sp, s2p)
)
);
const fInGroup = module.addFunction(g1mPrefix + "_inGroup");
fInGroup.addParam("pIn", "i32");
fInGroup.setReturnType("i32");
const c2 = fInGroup.getCodeBuilder();
const aux2 = c2.i32_const(module.alloc(f1size*2));
fInGroup.addCode(
c2.call(g1mPrefix + "_toAffine", c2.getLocal("pIn"), aux2),
c2.ret(
c2.call(g1mPrefix + "_inGroupAffine", aux2),
)
);
}
for (let i=0; i<10; i++) {
buildFrobeniusMap(i);
module.exportFunction(ftmPrefix + "_frobeniusMap"+i);
}
buildInGroupG1();
buildInGroupG2();
buildPrepAddStep();
buildPrepDoubleStep();
buildPrepareG1();
buildPrepareG2();
buildMillerLoop();
buildFinalExponentiationOld();
buildFinalExponentiation();
for (let i=1; i<=5; i++) {
buildPairingEquation(i);
module.exportFunction(prefix + "_pairingEq"+i);
}
buildPairing();
module.exportFunction(prefix + "_pairing");
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");
module.exportFunction(f6mPrefix + "_mul1");
module.exportFunction(f6mPrefix + "_mul01");
module.exportFunction(ftmPrefix + "_mul014");
module.exportFunction(g1mPrefix + "_inGroupAffine");
module.exportFunction(g1mPrefix + "_inGroup");
module.exportFunction(g2mPrefix + "_inGroupAffine");
module.exportFunction(g2mPrefix + "_inGroup");
// console.log(module.functionIdxByName);
};
/*
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 <https://www.gnu.org/licenses/>.
*/
// module.exports.bn128_wasm = require("./build/bn128_wasm.js");
// module.exports.bls12381_wasm = require("./build/bls12381_wasm.js");
// module.exports.mnt6753_wasm = require("./build/mnt6753_wasm.js");
var buildBn128$1 = build_bn128;
var buildBls12381$1 = build_bls12381;
/* global BigInt */
function stringifyBigInts(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;
}
}
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 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;
}
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;
}
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;
}
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;
}
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 _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;
}
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 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)
);
}
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);
}
return buff;
}
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;
}
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;
class BigBuffer {
constructor(size) {
this.buffers = [];
this.byteLength = size;
for (let i=0; i<size; i+= PAGE_SIZE) {
const n = Math.min(size-i, PAGE_SIZE);
this.buffers.push(new Uint8Array(n));
}
}
slice(fr, to) {
if ( to === undefined ) to = this.byteLength;
if ( fr === undefined ) fr = 0;
const len = to-fr;
const firstPage = Math.floor(fr / PAGE_SIZE);
const lastPage = Math.floor((fr+len-1) / PAGE_SIZE);
if ((firstPage == lastPage)||(len==0))
return this.buffers[firstPage].slice(fr%PAGE_SIZE, fr%PAGE_SIZE + len);
let buff;
let p = firstPage;
let o = fr % PAGE_SIZE;
// Remaining bytes to read
let r = len;
while (r>0) {
// bytes to copy from this page
const l = (o+r > PAGE_SIZE) ? (PAGE_SIZE -o) : r;
const srcView = new Uint8Array(this.buffers[p].buffer, this.buffers[p].byteOffset+o, l);
if (l == len) return srcView.slice();
if (!buff) {
if (len <= PAGE_SIZE) {
buff = new Uint8Array(len);
} else {
buff = new BigBuffer(len);
}
}
buff.set(srcView, len-r);
r = r-l;
p ++;
o = 0;
}
return buff;
}
set(buff, offset) {
if (offset === undefined) offset = 0;
const len = buff.byteLength;
if (len==0) return;
const firstPage = Math.floor(offset / PAGE_SIZE);
const lastPage = Math.floor((offset+len-1) / PAGE_SIZE);
if (firstPage == lastPage) {
if ((buff instanceof BigBuffer)&&(buff.buffers.length==1)) {
return this.buffers[firstPage].set(buff.buffers[0], offset % PAGE_SIZE);
} else {
return this.buffers[firstPage].set(buff, offset % PAGE_SIZE);
}
}
let p = firstPage;
let o = offset % PAGE_SIZE;
let r = len;
while (r>0) {
const l = (o+r > PAGE_SIZE) ? (PAGE_SIZE -o) : r;
const srcView = buff.slice( len -r, len -r+l);
const dstView = new Uint8Array(this.buffers[p].buffer, this.buffers[p].byteOffset + o, l);
dstView.set(srcView);
r = r-l;
p ++;
o = 0;
}
}
}
function buildBatchConvert(tm, fnName, sIn, sOut) {
return async function batchConvert(buffIn) {
const nPoints = Math.floor(buffIn.byteLength / sIn);
if ( nPoints * sIn !== buffIn.byteLength) {
throw new Error("Invalid buffer size");
}
const pointsPerChunk = Math.floor(nPoints/tm.concurrency);
const opPromises = [];
for (let i=0; i<tm.concurrency; i++) {
let n;
if (i< tm.concurrency-1) {
n = pointsPerChunk;
} else {
n = nPoints - i*pointsPerChunk;
}
if (n==0) continue;
const buffChunk = buffIn.slice(i*pointsPerChunk*sIn, i*pointsPerChunk*sIn + n*sIn);
const task = [
{cmd: "ALLOCSET", var: 0, buff:buffChunk},
{cmd: "ALLOC", var: 1, len:sOut * n},
{cmd: "CALL", fnName: fnName, params: [
{var: 0},
{val: n},
{var: 1}
]},
{cmd: "GET", out: 0, var: 1, len:sOut * n},
];
opPromises.push(
tm.queueAction(task)
);
}
const result = await Promise.all(opPromises);
let fullBuffOut;
if (buffIn instanceof BigBuffer) {
fullBuffOut = new BigBuffer(nPoints*sOut);
} else {
fullBuffOut = new Uint8Array(nPoints*sOut);
}
let p =0;
for (let i=0; i<result.length; i++) {
fullBuffOut.set(result[i][0], p);
p+=result[i][0].byteLength;
}
return fullBuffOut;
};
}
class WasmField1 {
constructor(tm, prefix, n8, p) {
this.tm = tm;
this.prefix = prefix;
this.p = p;
this.n8 = n8;
this.type = "F1";
this.m = 1;
this.half = shiftRight(p, one);
this.bitLength = bitLength$6(p);
this.mask = sub(shiftLeft(one, this.bitLength), one);
this.pOp1 = tm.alloc(n8);
this.pOp2 = tm.alloc(n8);
this.pOp3 = tm.alloc(n8);
this.tm.instance.exports[prefix + "_zero"](this.pOp1);
this.zero = this.tm.getBuff(this.pOp1, this.n8);
this.tm.instance.exports[prefix + "_one"](this.pOp1);
this.one = this.tm.getBuff(this.pOp1, this.n8);
this.negone = this.neg(this.one);
this.two = this.add(this.one, this.one);
this.n64 = Math.floor(n8/8);
this.n32 = Math.floor(n8/4);
if(this.n64*8 != this.n8) {
throw new Error("n8 must be a multiple of 8");
}
this.half = shiftRight(this.p, one);
this.nqr = this.two;
let r = this.exp(this.nqr, this.half);
while (!this.eq(r, this.negone)) {
this.nqr = this.add(this.nqr, this.one);
r = this.exp(this.nqr, this.half);
}
this.shift = this.mul(this.nqr, this.nqr);
this.shiftInv = this.inv(this.shift);
this.s = 0;
let t = sub(this.p, one);
while ( !isOdd$5(t) ) {
this.s = this.s + 1;
t = shiftRight(t, one);
}
this.w = [];
this.w[this.s] = this.exp(this.nqr, t);
for (let i= this.s-1; i>=0; i--) {
this.w[i] = this.square(this.w[i+1]);
}
if (!this.eq(this.w[0], this.one)) {
throw new Error("Error calculating roots of unity");
}
this.batchToMontgomery = buildBatchConvert(tm, prefix + "_batchToMontgomery", this.n8, this.n8);
this.batchFromMontgomery = buildBatchConvert(tm, prefix + "_batchFromMontgomery", this.n8, this.n8);
}
op2(opName, a, b) {
this.tm.setBuff(this.pOp1, a);
this.tm.setBuff(this.pOp2, b);
this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp2, this.pOp3);
return this.tm.getBuff(this.pOp3, this.n8);
}
op2Bool(opName, a, b) {
this.tm.setBuff(this.pOp1, a);
this.tm.setBuff(this.pOp2, b);
return !!this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp2);
}
op1(opName, a) {
this.tm.setBuff(this.pOp1, a);
this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp3);
return this.tm.getBuff(this.pOp3, this.n8);
}
op1Bool(opName, a) {
this.tm.setBuff(this.pOp1, a);
return !!this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp3);
}
add(a,b) {
return this.op2("_add", a, b);
}
eq(a,b) {
return this.op2Bool("_eq", a, b);
}
isZero(a) {
return this.op1Bool("_isZero", a);
}
sub(a,b) {
return this.op2("_sub", a, b);
}
neg(a) {
return this.op1("_neg", a);
}
inv(a) {
return this.op1("_inverse", a);
}
toMontgomery(a) {
return this.op1("_toMontgomery", a);
}
fromMontgomery(a) {
return this.op1("_fromMontgomery", a);
}
mul(a,b) {
return this.op2("_mul", a, b);
}
div(a, b) {
this.tm.setBuff(this.pOp1, a);
this.tm.setBuff(this.pOp2, b);
this.tm.instance.exports[this.prefix + "_inverse"](this.pOp2, this.pOp2);
this.tm.instance.exports[this.prefix + "_mul"](this.pOp1, this.pOp2, this.pOp3);
return this.tm.getBuff(this.pOp3, this.n8);
}
square(a) {
return this.op1("_square", a);
}
isSquare(a) {
return this.op1Bool("_isSquare", a);
}
sqrt(a) {
return this.op1("_sqrt", a);
}
exp(a, b) {
if (!(b instanceof Uint8Array)) {
b = toLEBuff(e(b));
}
this.tm.setBuff(this.pOp1, a);
this.tm.setBuff(this.pOp2, b);
this.tm.instance.exports[this.prefix + "_exp"](this.pOp1, this.pOp2, b.byteLength, this.pOp3);
return this.tm.getBuff(this.pOp3, this.n8);
}
isNegative(a) {
return this.op1Bool("_isNegative", a);
}
e(a, b) {
if (a instanceof Uint8Array) return a;
let ra = e(a, b);
if (isNegative$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);
}
fromRng(rng) {
let v;
const buff = new Uint8Array(this.n8);
do {
v = zero;
for (let i=0; i<this.n64; i++) {
v = add(v, shiftLeft(rng.nextU64(), 64*i));
}
v = band(v, this.mask);
} while (geq(v, this.p));
toRprLE(buff, 0, v, this.n8);
return buff;
}
random() {
return this.fromRng(getThreadRng());
}
toObject(a) {
const an = this.fromMontgomery(a);
return fromRprLE(an, 0);
}
fromObject(a) {
const buff = new Uint8Array(this.n8);
toRprLE(buff, 0, a, this.n8);
return this.toMontgomery(buff);
}
toRprLE(buff, offset, a) {
buff.set(this.fromMontgomery(a), offset);
}
toRprBE(buff, offset, a) {
const buff2 = this.fromMontgomery(a);
for (let i=0; i<this.n8/2; i++) {
const aux = buff2[i];
buff2[i] = buff2[this.n8-1-i];
buff2[this.n8-1-i] = aux;
}
buff.set(buff2, offset);
}
fromRprLE(buff, offset) {
offset = offset || 0;
const res = buff.slice(offset, offset + this.n8);
return this.toMontgomery(res);
}
async batchInverse(buffIn) {
let returnArray = false;
const sIn = this.n8;
const sOut = this.n8;
if (Array.isArray(buffIn)) {
buffIn = array2buffer(buffIn, sIn );
returnArray = true;
} else {
buffIn = buffIn.slice(0, buffIn.byteLength);
}
const nPoints = Math.floor(buffIn.byteLength / sIn);
if ( nPoints * sIn !== buffIn.byteLength) {
throw new Error("Invalid buffer size");
}
const pointsPerChunk = Math.floor(nPoints/this.tm.concurrency);
const opPromises = [];
for (let i=0; i<this.tm.concurrency; i++) {
let n;
if (i< this.tm.concurrency-1) {
n = pointsPerChunk;
} else {
n = nPoints - i*pointsPerChunk;
}
if (n==0) continue;
const buffChunk = buffIn.slice(i*pointsPerChunk*sIn, i*pointsPerChunk*sIn + n*sIn);
const task = [
{cmd: "ALLOCSET", var: 0, buff:buffChunk},
{cmd: "ALLOC", var: 1, len:sOut * n},
{cmd: "CALL", fnName: this.prefix + "_batchInverse", params: [
{var: 0},
{val: sIn},
{val: n},
{var: 1},
{val: sOut},
]},
{cmd: "GET", out: 0, var: 1, len:sOut * n},
];
opPromises.push(
this.tm.queueAction(task)
);
}
const result = await Promise.all(opPromises);
let fullBuffOut;
if (buffIn instanceof BigBuffer) {
fullBuffOut = new BigBuffer(nPoints*sOut);
} else {
fullBuffOut = new Uint8Array(nPoints*sOut);
}
let p =0;
for (let i=0; i<result.length; i++) {
fullBuffOut.set(result[i][0], p);
p+=result[i][0].byteLength;
}
if (returnArray) {
return buffer2array(fullBuffOut, sOut);
} else {
return fullBuffOut;
}
}
}
class WasmField2 {
constructor(tm, prefix, F) {
this.tm = tm;
this.prefix = prefix;
this.F = F;
this.type = "F2";
this.m = F.m * 2;
this.n8 = this.F.n8*2;
this.n32 = this.F.n32*2;
this.n64 = this.F.n64*2;
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);
this.negone = this.neg(this.one);
this.two = this.add(this.one, this.one);
}
op2(opName, a, b) {
this.tm.setBuff(this.pOp1, a);
this.tm.setBuff(this.pOp2, b);
this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp2, this.pOp3);
return this.tm.getBuff(this.pOp3, this.n8);
}
op2Bool(opName, a, b) {
this.tm.setBuff(this.pOp1, a);
this.tm.setBuff(this.pOp2, b);
return !!this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp2);
}
op1(opName, a) {
this.tm.setBuff(this.pOp1, a);
this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp3);
return this.tm.getBuff(this.pOp3, this.n8);
}
op1Bool(opName, a) {
this.tm.setBuff(this.pOp1, a);
return !!this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp3);
}
add(a,b) {
return this.op2("_add", a, b);
}
eq(a,b) {
return this.op2Bool("_eq", a, b);
}
isZero(a) {
return this.op1Bool("_isZero", a);
}
sub(a,b) {
return this.op2("_sub", a, b);
}
neg(a) {
return this.op1("_neg", a);
}
inv(a) {
return this.op1("_inverse", a);
}
isNegative(a) {
return this.op1Bool("_isNegative", a);
}
toMontgomery(a) {
return this.op1("_toMontgomery", a);
}
fromMontgomery(a) {
return this.op1("_fromMontgomery", a);
}
mul(a,b) {
return this.op2("_mul", a, b);
}
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);
}
sqrt(a) {
return this.op1("_sqrt", a);
}
exp(a, b) {
if (!(b instanceof Uint8Array)) {
b = toLEBuff(e(b));
}
this.tm.setBuff(this.pOp1, a);
this.tm.setBuff(this.pOp2, b);
this.tm.instance.exports[this.prefix + "_exp"](this.pOp1, this.pOp2, b.byteLength, this.pOp3);
return this.tm.getBuff(this.pOp3, this.n8);
}
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");
}
}
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}]`;
}
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;
}
random() {
return this.fromRng(getThreadRng());
}
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];
}
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;
}
c1(a) {
return a.slice(0, this.F.n8);
}
c2(a) {
return a.slice(this.F.n8);
}
}
class WasmField3 {
constructor(tm, prefix, F) {
this.tm = tm;
this.prefix = prefix;
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;
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);
this.negone = this.neg(this.one);
this.two = this.add(this.one, this.one);
}
op2(opName, a, b) {
this.tm.setBuff(this.pOp1, a);
this.tm.setBuff(this.pOp2, b);
this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp2, this.pOp3);
return this.tm.getBuff(this.pOp3, this.n8);
}
op2Bool(opName, a, b) {
this.tm.setBuff(this.pOp1, a);
this.tm.setBuff(this.pOp2, b);
return !!this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp2);
}
op1(opName, a) {
this.tm.setBuff(this.pOp1, a);
this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp3);
return this.tm.getBuff(this.pOp3, this.n8);
}
op1Bool(opName, a) {
this.tm.setBuff(this.pOp1, a);
return !!this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp3);
}
eq(a,b) {
return this.op2Bool("_eq", a, b);
}
isZero(a) {
return this.op1Bool("_isZero", a);
}
add(a,b) {
return this.op2("_add", a, b);
}
sub(a,b) {
return this.op2("_sub", a, b);
}
neg(a) {
return this.op1("_neg", a);
}
inv(a) {
return this.op1("_inverse", a);
}
isNegative(a) {
return this.op1Bool("_isNegative", a);
}
toMontgomery(a) {
return this.op1("_toMontgomery", a);
}
fromMontgomery(a) {
return this.op1("_fromMontgomery", a);
}
mul(a,b) {
return this.op2("_mul", a, b);
}
div(a, b) {
this.tm.setBuff(this.pOp1, a);
this.tm.setBuff(this.pOp2, b);
this.tm.instance.exports[this.prefix + "_inverse"](this.pOp2, this.pOp2);
this.tm.instance.exports[this.prefix + "_mul"](this.pOp1, this.pOp2, this.pOp3);
return this.tm.getBuff(this.pOp3, this.n8);
}
square(a) {
return this.op1("_square", a);
}
isSquare(a) {
return this.op1Bool("_isSquare", a);
}
sqrt(a) {
return this.op1("_sqrt", a);
}
exp(a, b) {
if (!(b instanceof Uint8Array)) {
b = toLEBuff(e(b));
}
this.tm.setBuff(this.pOp1, a);
this.tm.setBuff(this.pOp2, b);
this.tm.instance.exports[this.prefix + "_exp"](this.pOp1, this.pOp2, b.byteLength, this.pOp3);
return this.getBuff(this.pOp3, this.n8);
}
e(a, b) {
if (a instanceof Uint8Array) return a;
if ((Array.isArray(a)) && (a.length == 3)) {
const c1 = this.F.e(a[0], b);
const c2 = this.F.e(a[1], b);
const c3 = this.F.e(a[2], b);
const res = new Uint8Array(this.F.n8*3);
res.set(c1);
res.set(c2, this.F.n8);
res.set(c3, this.F.n8*2);
return res;
} else {
throw new Error("invalid F3");
}
}
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, this.F.n8*2), radix);
const s3 = this.F.toString(a.slice(this.F.n8*2), radix);
return `[${s1}, ${s2}, ${s3}]`;
}
fromRng(rng) {
const c1 = this.F.fromRng(rng);
const c2 = this.F.fromRng(rng);
const c3 = this.F.fromRng(rng);
const res = new Uint8Array(this.F.n8*3);
res.set(c1);
res.set(c2, this.F.n8);
res.set(c3, this.F.n8*2);
return res;
}
random() {
return this.fromRng(getThreadRng());
}
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));
const c3 = this.F.toObject(a.slice(this.F.n8*2, this.F.n8*3));
return [c1, c2, c3];
}
fromObject(a) {
const buff = new Uint8Array(this.F.n8*3);
const b1 = this.F.fromObject(a[0]);
const b2 = this.F.fromObject(a[1]);
const b3 = this.F.fromObject(a[2]);
buff.set(b1);
buff.set(b2, this.F.n8);
buff.set(b3, this.F.n8*2);
return buff;
}
c1(a) {
return a.slice(0, this.F.n8);
}
c2(a) {
return a.slice(this.F.n8, this.F.n8*2);
}
c3(a) {
return a.slice(this.F.n8*2);
}
}
class WasmCurve {
constructor(tm, prefix, F, pGen, pGb, cofactor) {
this.tm = tm;
this.prefix = prefix;
this.F = F;
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 = this.tm.getBuff(this.pOp1, F.n8*3);
this.tm.instance.exports[prefix + "_zeroAffine"](this.pOp1);
this.zeroAffine = this.tm.getBuff(this.pOp1, F.n8*2);
this.one = this.tm.getBuff(pGen, F.n8*3);
this.g = this.one;
this.oneAffine = this.tm.getBuff(pGen, F.n8*2);
this.gAffine = this.oneAffine;
this.b = this.tm.getBuff(pGb, F.n8);
if (cofactor) {
this.cofactor = toLEBuff(cofactor);
}
this.negone = this.neg(this.one);
this.two = this.add(this.one, this.one);
this.batchLEMtoC = buildBatchConvert(tm, prefix + "_batchLEMtoC", F.n8*2, F.n8);
this.batchLEMtoU = buildBatchConvert(tm, prefix + "_batchLEMtoU", F.n8*2, F.n8*2);
this.batchCtoLEM = buildBatchConvert(tm, prefix + "_batchCtoLEM", F.n8, F.n8*2);
this.batchUtoLEM = buildBatchConvert(tm, prefix + "_batchUtoLEM", F.n8*2, F.n8*2);
this.batchToJacobian = buildBatchConvert(tm, prefix + "_batchToJacobian", F.n8*2, F.n8*3);
this.batchToAffine = buildBatchConvert(tm, prefix + "_batchToAffine", F.n8*3, F.n8*2);
}
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.F.n8*3);
}
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, this.pOp3);
}
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.F.n8*3);
}
op1Affine(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.F.n8*2);
}
op1Bool(opName, a) {
this.tm.setBuff(this.pOp1, a);
return !!this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp3);
}
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);
} else {
throw new Error("invalid point size");
}
} else {
throw new Error("invalid point size");
}
}
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);
} else {
throw new Error("invalid point size");
}
} else {
throw new Error("invalid point size");
}
}
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");
}
}
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");
}
}
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");
}
}
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");
}
}
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");
}
}
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");
}
}
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);
}
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);
}
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);
}
toUncompressed(a) {
const buff = new Uint8Array(this.F.n8*2);
this.toRprUncompressed(buff, 0, a);
return buff;
}
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");
}
}
fromRprLEM(arr, offset) {
offset = offset || 0;
return arr.slice(offset, offset+this.F.n8*2);
}
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");
}
}
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);
}
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));
P[1] = F.sqrt(x3b);
const s = F.isNegative(P[1]);
if (greatest ^ s) P[1] = F.neg(P[1]);
let Pbuff = new Uint8Array(this.F.n8*2);
Pbuff.set(P[0]);
Pbuff.set(P[1], this.F.n8);
if (this.cofactor) {
Pbuff = this.timesScalar(Pbuff, this.cofactor);
}
return Pbuff;
}
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];
}
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;
}
}
e(a) {
if (a instanceof Uint8Array) return a;
return this.fromObject(a);
}
x(a) {
const tmp = this.toAffine(a);
return tmp.slice(0, this.F.n8);
}
y(a) {
const tmp = this.toAffine(a);
return tmp.slice(this.F.n8);
}
}
/* global WebAssembly */
function thread(self) {
const MAXMEM = 32767;
let instance;
let memory;
if (self) {
self.onmessage = function(e) {
let data;
if (e.data) {
data = e.data;
} else {
data = e;
}
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);
}
};
}
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});
instance = await WebAssembly.instantiate(wasmModule, {
env: {
"memory": memory
}
});
}
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;
}
function allocBuffer(buffer) {
const p = alloc(buffer.byteLength);
setBuffer(p, buffer);
return p;
}
function getBuffer(pointer, length) {
const u8 = new Uint8Array(memory.buffer);
return new Uint8Array(u8.buffer, u8.byteOffset + pointer, length);
}
function setBuffer(pointer, buffer) {
const u8 = new Uint8Array(memory.buffer);
u8.set(new Uint8Array(buffer), pointer);
}
function runTask(task) {
if (task[0].cmd == "INIT") {
return init(task[0]);
}
const ctx = {
vars: [],
out: []
};
const u32a = new Uint32Array(memory.buffer, 0, 1);
const oldAlloc = u32a[0];
for (let i=0; i<task.length; i++) {
switch (task[i].cmd) {
case "ALLOCSET":
ctx.vars[task[i].var] = allocBuffer(task[i].buff);
break;
case "ALLOC":
ctx.vars[task[i].var] = alloc(task[i].len);
break;
case "SET":
setBuffer(ctx.vars[task[i].var], task[i].buff);
break;
case "CALL": {
const params = [];
for (let j=0; j<task[i].params.length; j++) {
const p = task[i].params[j];
if (typeof p.var !== "undefined") {
params.push(ctx.vars[p.var] + (p.offset || 0));
} else if (typeof p.val != "undefined") {
params.push(p.val);
}
}
instance.exports[task[i].fnName](...params);
break;
}
case "GET":
ctx.out[task[i].out] = getBuffer(ctx.vars[task[i].var], task[i].len).slice();
break;
default:
throw new Error("Invalid cmd");
}
}
const u32b = new Uint32Array(memory.buffer, 0, 1);
u32b[0] = oldAlloc;
return ctx.out;
}
return runTask;
}
/*
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 <https://www.gnu.org/licenses/>.
*/
// const MEM_SIZE = 1000; // Memory size in 64K Pakes (512Mb)
const MEM_SIZE = 25; // Memory size in 64K Pakes (1600Kb)
class Deferred {
constructor() {
this.promise = new Promise((resolve, reject)=> {
this.reject = reject;
this.resolve = resolve;
});
}
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
let workerSource;
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; i<task.length; i++) {\n switch (task[i].cmd) {\n case \"ALLOCSET\":\n ctx.vars[task[i].var] = allocBuffer(task[i].buff);\n break;\n case \"ALLOC\":\n ctx.vars[task[i].var] = alloc(task[i].len);\n break;\n case \"SET\":\n setBuffer(ctx.vars[task[i].var], task[i].buff);\n break;\n case \"CALL\": {\n const params = [];\n for (let j=0; j<task[i].params.length; j++) {\n const p = task[i].params[j];\n if (typeof p.var !== \"undefined\") {\n params.push(ctx.vars[p.var] + (p.offset || 0));\n } else if (typeof p.val != \"undefined\") {\n params.push(p.val);\n }\n }\n instance.exports[task[i].fnName](...params);\n break;\n }\n case \"GET\":\n ctx.out[task[i].out] = getBuffer(ctx.vars[task[i].var], task[i].len).slice();\n break;\n default:\n throw new Error(\"Invalid cmd\");\n }\n }\n const u32b = new Uint32Array(memory.buffer, 0, 1);\n u32b[0] = oldAlloc;\n return ctx.out;\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);
}
}
async function buildThreadManager(wasm, singleThread) {
const tm = new ThreadManager();
tm.memory = new WebAssembly.Memory({initial:MEM_SIZE});
tm.u8 = new Uint8Array(tm.memory.buffer);
tm.u32 = new Uint32Array(tm.memory.buffer);
const wasmModule = await WebAssembly.compile(wasm.code);
tm.instance = await WebAssembly.instantiate(wasmModule, {
env: {
"memory": tm.memory
}
});
if(!globalThis?.Worker) {
singleThread = true;
}
tm.singleThread = singleThread;
tm.initalPFree = tm.u32[0]; // Save the Pointer to free space.
tm.pq = wasm.pq;
tm.pr = wasm.pr;
tm.pG1gen = wasm.pG1gen;
tm.pG1zero = wasm.pG1zero;
tm.pG2gen = wasm.pG2gen;
tm.pG2zero = wasm.pG2zero;
tm.pOneT = wasm.pOneT;
// tm.pTmp0 = tm.alloc(curve.G2.F.n8*3);
// tm.pTmp1 = tm.alloc(curve.G2.F.n8*3);
if (singleThread) {
tm.code = wasm.code;
tm.taskManager = thread();
await tm.taskManager([{
cmd: "INIT",
init: MEM_SIZE,
code: tm.code.slice()
}]);
tm.concurrency = 1;
} else {
tm.workers = [];
tm.pendingDeferreds = [];
tm.working = [];
let concurrency = 2;
{
if (typeof navigator === "object" && navigator.hardwareConcurrency) {
concurrency = navigator.hardwareConcurrency;
}
}
if(concurrency == 0){
concurrency = 2;
}
// Limit to 64 threads for memory reasons.
if (concurrency>64) concurrency=64;
tm.concurrency = concurrency;
for (let i = 0; i<concurrency; i++) {
tm.workers[i] = new Worker(workerSource);
tm.workers[i].addEventListener("message", getOnMsg(i));
tm.working[i]=false;
}
const initPromises = [];
for (let i=0; i<tm.workers.length;i++) {
const copyCode = wasm.code.slice();
initPromises.push(tm.postAction(i, [{
cmd: "INIT",
init: MEM_SIZE,
code: copyCode
}], [copyCode.buffer]));
}
await Promise.all(initPromises);
}
return tm;
function getOnMsg(i) {
return function(e) {
let data;
if ((e)&&(e.data)) {
data = e.data;
} else {
data = e;
}
tm.working[i]=false;
tm.pendingDeferreds[i].resolve(data);
tm.processWorks();
};
}
}
class ThreadManager {
constructor() {
this.actionQueue = [];
this.oldPFree = 0;
}
startSyncOp() {
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");
this.u32[0] = this.oldPFree;
this.oldPFree = 0;
}
postAction(workerId, e, transfers, _deferred) {
if (this.working[workerId]) {
throw new Error("Posting a job t a working worker");
}
this.working[workerId] = true;
this.pendingDeferreds[workerId] = _deferred ? _deferred : new Deferred();
this.workers[workerId].postMessage(e, transfers);
return this.pendingDeferreds[workerId].promise;
}
processWorks() {
for (let i=0; (i<this.workers.length)&&(this.actionQueue.length > 0); i++) {
if (this.working[i] == false) {
const work = this.actionQueue.shift();
this.postAction(i, work.data, work.transfers, work.deferred);
}
}
}
queueAction(actionData, transfers) {
const d = new Deferred();
if (this.singleThread) {
const res = this.taskManager(actionData);
d.resolve(res);
} else {
this.actionQueue.push({
data: actionData,
transfers: transfers,
deferred: d
});
this.processWorks();
}
return d.promise;
}
resetMemory() {
this.u32[0] = this.initalPFree;
}
allocBuff(buff) {
const pointer = this.alloc(buff.byteLength);
this.setBuff(pointer, buff);
return pointer;
}
getBuff(pointer, length) {
return this.u8.slice(pointer, pointer+ length);
}
setBuff(pointer, buffer) {
this.u8.set(new Uint8Array(buffer), pointer);
}
alloc(length) {
while (this.u32[0] & 3) this.u32[0]++; // Return always aligned pointers
const res = this.u32[0];
this.u32[0] += length;
return res;
}
async terminate() {
for (let i=0; i<this.workers.length; i++) {
this.workers[i].postMessage([{cmd: "TERMINATE"}]);
}
await sleep(200);
}
}
function buildBatchApplyKey(curve, groupName) {
const G = curve[groupName];
const Fr = curve.Fr;
const tm = curve.tm;
curve[groupName].batchApplyKey = async function(buff, first, inc, inType, outType) {
inType = inType || "affine";
outType = outType || "affine";
let fnName, fnAffine;
let sGin, sGmid, sGout;
if (groupName == "G1") {
if (inType == "jacobian") {
sGin = G.F.n8*3;
fnName = "g1m_batchApplyKey";
} else {
sGin = G.F.n8*2;
fnName = "g1m_batchApplyKeyMixed";
}
sGmid = G.F.n8*3;
if (outType == "jacobian") {
sGout = G.F.n8*3;
} else {
fnAffine = "g1m_batchToAffine";
sGout = G.F.n8*2;
}
} else if (groupName == "G2") {
if (inType == "jacobian") {
sGin = G.F.n8*3;
fnName = "g2m_batchApplyKey";
} else {
sGin = G.F.n8*2;
fnName = "g2m_batchApplyKeyMixed";
}
sGmid = G.F.n8*3;
if (outType == "jacobian") {
sGout = G.F.n8*3;
} else {
fnAffine = "g2m_batchToAffine";
sGout = G.F.n8*2;
}
} else if (groupName == "Fr") {
fnName = "frm_batchApplyKey";
sGin = G.n8;
sGmid = G.n8;
sGout = G.n8;
} else {
throw new Error("Invalid group: " + groupName);
}
const nPoints = Math.floor(buff.byteLength / sGin);
const pointsPerChunk = Math.floor(nPoints/tm.concurrency);
const opPromises = [];
inc = Fr.e(inc);
let t = Fr.e(first);
for (let i=0; i<tm.concurrency; i++) {
let n;
if (i< tm.concurrency-1) {
n = pointsPerChunk;
} else {
n = nPoints - i*pointsPerChunk;
}
if (n==0) continue;
const task = [];
task.push({
cmd: "ALLOCSET",
var: 0,
buff: buff.slice(i*pointsPerChunk*sGin, i*pointsPerChunk*sGin + n*sGin)
});
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));
t = Fr.mul(t, Fr.exp(inc, n));
}
const result = await Promise.all(opPromises);
let outBuff;
if (buff instanceof BigBuffer) {
outBuff = new BigBuffer(nPoints*sGout);
} else {
outBuff = new Uint8Array(nPoints*sGout);
}
let p=0;
for (let i=0; i<result.length; i++) {
outBuff.set(result[i][0], p);
p += result[i][0].byteLength;
}
return outBuff;
};
}
function buildPairing(curve) {
const tm = curve.tm;
curve.pairing = function pairing(a, b) {
tm.startSyncOp();
const pA = tm.allocBuff(curve.G1.toJacobian(a));
const pB = tm.allocBuff(curve.G2.toJacobian(b));
const pRes = tm.alloc(curve.Gt.n8);
tm.instance.exports[curve.name + "_pairing"](pA, pB, pRes);
const res = tm.getBuff(pRes, curve.Gt.n8);
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;
}
const opPromises = [];
for (let i=0; i<nEqs; i++) {
const task = [];
const g1Buff = curve.G1.toJacobian(arguments[i*2]);
task.push({cmd: "ALLOCSET", var: 0, buff: g1Buff});
task.push({cmd: "ALLOC", var: 1, len: curve.prePSize});
const g2Buff = curve.G2.toJacobian(arguments[i*2 +1]);
task.push({cmd: "ALLOCSET", var: 2, buff: g2Buff});
task.push({cmd: "ALLOC", var: 3, len: curve.preQSize});
task.push({cmd: "ALLOC", var: 4, len: curve.Gt.n8});
task.push({cmd: "CALL", fnName: curve.name + "_prepareG1", params: [
{var: 0},
{var: 1}
]});
task.push({cmd: "CALL", fnName: curve.name + "_prepareG2", params: [
{var: 2},
{var: 3}
]});
task.push({cmd: "CALL", fnName: curve.name + "_millerLoop", params: [
{var: 1},
{var: 3},
{var: 4}
]});
task.push({cmd: "GET", out: 0, var: 4, len: curve.Gt.n8});
opPromises.push(
tm.queueAction(task)
);
}
const result = await Promise.all(opPromises);
tm.startSyncOp();
const pRes = tm.alloc(curve.Gt.n8);
tm.instance.exports.ftm_one(pRes);
for (let i=0; i<result.length; i++) {
const pMR = tm.allocBuff(result[i][0]);
tm.instance.exports.ftm_mul(pRes, pMR, pRes);
}
tm.instance.exports[curve.name + "_finalExponentiation"](pRes, pRes);
const pCt = tm.allocBuff(buffCt);
const r = !!tm.instance.exports.ftm_eq(pRes, pCt);
tm.endSyncOp();
return r;
};
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;
};
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;
};
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;
};
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 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
];
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`);
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";
let sGIn;
let fnName;
if (groupName == "G1") {
if (inType == "affine") {
fnName = "g1m_multiexpAffine_chunk";
sGIn = G.F.n8*2;
} else {
fnName = "g1m_multiexp_chunk";
sGIn = G.F.n8*3;
}
} else if (groupName == "G2") {
if (inType == "affine") {
fnName = "g2m_multiexpAffine_chunk";
sGIn = G.F.n8*2;
} else {
fnName = "g2m_multiexp_chunk";
sGIn = G.F.n8*3;
}
} else {
throw new Error("Invalid group");
}
const nPoints = Math.floor(buffBases.byteLength / sGIn);
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");
}
const bitChunkSize = pTSizes[log2(nPoints)];
const nChunks = Math.floor((sScalar*8 - 1) / bitChunkSize) +1;
const opPromises = [];
for (let i=0; i<nChunks; i++) {
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},
{var: 1},
{val: sScalar},
{val: nPoints},
{val: i*bitChunkSize},
{val: Math.min(sScalar*8 - i*bitChunkSize, bitChunkSize)},
{var: 2}
]},
{cmd: "GET", out: 0, var: 2, len: G.F.n8*3}
];
opPromises.push(
G.tm.queueAction(task)
);
}
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; j<bitChunkSize; j++) res = G.double(res);
}
res = G.add(res, result[i][0]);
}
return res;
}
async function _multiExp(buffBases, buffScalars, inType, logger, logText) {
const MAX_CHUNK_SIZE = 1 << 22;
const MIN_CHUNK_SIZE = 1 << 10;
let sGIn;
if (groupName == "G1") {
if (inType == "affine") {
sGIn = G.F.n8*2;
} else {
sGIn = G.F.n8*3;
}
} else if (groupName == "G2") {
if (inType == "affine") {
sGIn = G.F.n8*2;
} else {
sGIn = G.F.n8*3;
}
} else {
throw new Error("Invalid group");
}
const nPoints = Math.floor(buffBases.byteLength / sGIn);
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");
}
const bitChunkSize = pTSizes[log2(nPoints)];
const nChunks = Math.floor((sScalar*8 - 1) / bitChunkSize) +1;
let chunkSize;
chunkSize = Math.floor(nPoints / (tm.concurrency /nChunks));
if (chunkSize>MAX_CHUNK_SIZE) chunkSize = MAX_CHUNK_SIZE;
if (chunkSize<MIN_CHUNK_SIZE) chunkSize = MIN_CHUNK_SIZE;
const opPromises = [];
for (let i=0; i<nPoints; i += chunkSize) {
if (logger) logger.debug(`Multiexp start: ${logText}: ${i}/${nPoints}`);
const n= Math.min(nPoints - i, chunkSize);
const buffBasesChunk = buffBases.slice(i*sGIn, (i+n)*sGIn);
const buffScalarsChunk = buffScalars.slice(i*sScalar, (i+n)*sScalar);
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 res = G.zero;
for (let i=result.length-1; i>=0; i--) {
res = G.add(res, result[i]);
}
return res;
}
G.multiExp = async function multiExpAffine(buffBases, buffScalars, logger, logText) {
return await _multiExp(buffBases, buffScalars, "jacobian", logger, logText);
};
G.multiExpAffine = async function multiExpAffine(buffBases, buffScalars, logger, logText) {
return await _multiExp(buffBases, buffScalars, "affine", logger, logText);
};
}
function buildFFT(curve, groupName) {
const G = curve[groupName];
const Fr = curve.Fr;
const tm = G.tm;
async function _fft(buff, inverse, inType, outType, logger, loggerTxt) {
inType = inType || "affine";
outType = outType || "affine";
const MAX_BITS_THREAD = 14;
let sIn, sMid, sOut, fnIn2Mid, fnMid2Out, fnFFTMix, fnFFTJoin, fnFFTFinal;
if (groupName == "G1") {
if (inType == "affine") {
sIn = G.F.n8*2;
fnIn2Mid = "g1m_batchToJacobian";
} else {
sIn = G.F.n8*3;
}
sMid = G.F.n8*3;
if (inverse) {
fnFFTFinal = "g1m_fftFinal";
}
fnFFTJoin = "g1m_fftJoin";
fnFFTMix = "g1m_fftMix";
if (outType == "affine") {
sOut = G.F.n8*2;
fnMid2Out = "g1m_batchToAffine";
} else {
sOut = G.F.n8*3;
}
} else if (groupName == "G2") {
if (inType == "affine") {
sIn = G.F.n8*2;
fnIn2Mid = "g2m_batchToJacobian";
} else {
sIn = G.F.n8*3;
}
sMid = G.F.n8*3;
if (inverse) {
fnFFTFinal = "g2m_fftFinal";
}
fnFFTJoin = "g2m_fftJoin";
fnFFTMix = "g2m_fftMix";
if (outType == "affine") {
sOut = G.F.n8*2;
fnMid2Out = "g2m_batchToAffine";
} else {
sOut = G.F.n8*3;
}
} else if (groupName == "Fr") {
sIn = G.n8;
sMid = G.n8;
sOut = G.n8;
if (inverse) {
fnFFTFinal = "frm_fftFinal";
}
fnFFTMix = "frm_fftMix";
fnFFTJoin = "frm_fftJoin";
}
let returnArray = false;
if (Array.isArray(buff)) {
buff = array2buffer(buff, sIn);
returnArray = true;
} else {
buff = buff.slice(0, buff.byteLength);
}
const nPoints = buff.byteLength / sIn;
const bits = log2(nPoints);
if ((1 << bits) != nPoints) {
throw new Error("fft must be multiple of 2" );
}
if (bits == Fr.s +1) {
let buffOut;
if (inverse) {
buffOut = await _fftExtInv(buff, inType, outType, logger, loggerTxt);
} else {
buffOut = await _fftExt(buff, inType, outType, logger, loggerTxt);
}
if (returnArray) {
return buffer2array(buffOut, sOut);
} else {
return buffOut;
}
}
let inv;
if (inverse) {
inv = Fr.inv(Fr.e(nPoints));
}
let buffOut;
buffReverseBits(buff, sIn);
let chunks;
let pointsInChunk = Math.min(1 << MAX_BITS_THREAD, nPoints);
let nChunks = nPoints / pointsInChunk;
while ((nChunks < tm.concurrency)&&(pointsInChunk>=16)) {
nChunks *= 2;
pointsInChunk /= 2;
}
const l2Chunk = log2(pointsInChunk);
const promises = [];
for (let i = 0; i< nChunks; i++) {
if (logger) logger.debug(`${loggerTxt}: fft ${bits} mix start: ${i}/${nChunks}`);
const task = [];
task.push({cmd: "ALLOC", var: 0, len: sMid*pointsInChunk});
const buffChunk = buff.slice( (pointsInChunk * i)*sIn, (pointsInChunk * (i+1))*sIn);
task.push({cmd: "SET", var: 0, buff: buffChunk});
if (fnIn2Mid) {
task.push({cmd: "CALL", fnName:fnIn2Mid, params: [{var:0}, {val: pointsInChunk}, {var: 0}]});
}
for (let j=1; j<=l2Chunk;j++) {
task.push({cmd: "CALL", fnName:fnFFTMix, params: [{var:0}, {val: pointsInChunk}, {val: j}]});
}
if (l2Chunk==bits) {
if (fnFFTFinal) {
task.push({cmd: "ALLOCSET", var: 1, buff: inv});
task.push({cmd: "CALL", fnName: fnFFTFinal, params:[
{var: 0},
{val: pointsInChunk},
{var: 1},
]});
}
if (fnMid2Out) {
task.push({cmd: "CALL", fnName:fnMid2Out, params: [{var:0}, {val: pointsInChunk}, {var: 0}]});
}
task.push({cmd: "GET", out: 0, var: 0, len: pointsInChunk*sOut});
} else {
task.push({cmd: "GET", out:0, var: 0, len: sMid*pointsInChunk});
}
promises.push(tm.queueAction(task).then( (r) => {
if (logger) logger.debug(`${loggerTxt}: fft ${bits} mix end: ${i}/${nChunks}`);
return r;
}));
}
chunks = await Promise.all(promises);
for (let i = 0; i< nChunks; i++) chunks[i] = chunks[i][0];
for (let i = l2Chunk+1; i<=bits; i++) {
if (logger) logger.debug(`${loggerTxt}: fft ${bits} join: ${i}/${bits}`);
const nGroups = 1 << (bits - i);
const nChunksPerGroup = nChunks / nGroups;
const opPromises = [];
for (let j=0; j<nGroups; j++) {
for (let k=0; k <nChunksPerGroup/2; k++) {
const first = Fr.exp( Fr.w[i], k*pointsInChunk);
const inc = Fr.w[i];
const o1 = j*nChunksPerGroup + k;
const o2 = j*nChunksPerGroup + k + nChunksPerGroup/2;
const task = [];
task.push({cmd: "ALLOCSET", var: 0, buff: chunks[o1]});
task.push({cmd: "ALLOCSET", var: 1, buff: chunks[o2]});
task.push({cmd: "ALLOCSET", var: 2, buff: first});
task.push({cmd: "ALLOCSET", var: 3, buff: inc});
task.push({cmd: "CALL", fnName: fnFFTJoin, params:[
{var: 0},
{var: 1},
{val: pointsInChunk},
{var: 2},
{var: 3}
]});
if (i==bits) {
if (fnFFTFinal) {
task.push({cmd: "ALLOCSET", var: 4, buff: inv});
task.push({cmd: "CALL", fnName: fnFFTFinal, params:[
{var: 0},
{val: pointsInChunk},
{var: 4},
]});
task.push({cmd: "CALL", fnName: fnFFTFinal, params:[
{var: 1},
{val: pointsInChunk},
{var: 4},
]});
}
if (fnMid2Out) {
task.push({cmd: "CALL", fnName:fnMid2Out, params: [{var:0}, {val: pointsInChunk}, {var: 0}]});
task.push({cmd: "CALL", fnName:fnMid2Out, params: [{var:1}, {val: pointsInChunk}, {var: 1}]});
}
task.push({cmd: "GET", out: 0, var: 0, len: pointsInChunk*sOut});
task.push({cmd: "GET", out: 1, var: 1, len: pointsInChunk*sOut});
} else {
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;
}));
}
}
const res = await Promise.all(opPromises);
for (let j=0; j<nGroups; j++) {
for (let k=0; k <nChunksPerGroup/2; k++) {
const o1 = j*nChunksPerGroup + k;
const o2 = j*nChunksPerGroup + k + nChunksPerGroup/2;
const resChunk = res.shift();
chunks[o1] = resChunk[0];
chunks[o2] = resChunk[1];
}
}
}
if (buff instanceof BigBuffer) {
buffOut = new BigBuffer(nPoints*sOut);
} else {
buffOut = new Uint8Array(nPoints*sOut);
}
if (inverse) {
buffOut.set(chunks[0].slice((pointsInChunk-1)*sOut));
let p= sOut;
for (let i=nChunks-1; i>0; 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<nChunks; i++) {
buffOut.set(chunks[i], pointsInChunk*sOut*i);
delete chunks[i];
}
}
if (returnArray) {
return buffer2array(buffOut, sOut);
} else {
return buffOut;
}
}
async function _fftExt(buff, inType, outType, logger, loggerTxt) {
let b1, b2;
b1 = buff.slice( 0 , buff.byteLength/2);
b2 = buff.slice( buff.byteLength/2, buff.byteLength);
const promises = [];
[b1, b2] = await _fftJoinExt(b1, b2, "fftJoinExt", Fr.one, Fr.shift, inType, "jacobian", logger, loggerTxt);
promises.push( _fft(b1, false, "jacobian", outType, logger, loggerTxt));
promises.push( _fft(b2, false, "jacobian", outType, logger, loggerTxt));
const res1 = await Promise.all(promises);
let buffOut;
if (res1[0].byteLength > (1<<28)) {
buffOut = new BigBuffer(res1[0].byteLength*2);
} else {
buffOut = new Uint8Array(res1[0].byteLength*2);
}
buffOut.set(res1[0]);
buffOut.set(res1[1], res1[0].byteLength);
return buffOut;
}
async function _fftExtInv(buff, inType, outType, logger, loggerTxt) {
let b1, b2;
b1 = buff.slice( 0 , buff.byteLength/2);
b2 = buff.slice( buff.byteLength/2, buff.byteLength);
const promises = [];
promises.push( _fft(b1, true, inType, "jacobian", logger, loggerTxt));
promises.push( _fft(b2, true, inType, "jacobian", logger, loggerTxt));
[b1, b2] = await Promise.all(promises);
const res1 = await _fftJoinExt(b1, b2, "fftJoinExtInv", Fr.one, Fr.shiftInv, "jacobian", outType, logger, loggerTxt);
let buffOut;
if (res1[0].byteLength > (1<<28)) {
buffOut = new BigBuffer(res1[0].byteLength*2);
} else {
buffOut = new Uint8Array(res1[0].byteLength*2);
}
buffOut.set(res1[0]);
buffOut.set(res1[1], res1[0].byteLength);
return buffOut;
}
async function _fftJoinExt(buff1, buff2, fn, first, inc, inType, outType, logger, loggerTxt) {
const MAX_CHUNK_SIZE = 1<<16;
const MIN_CHUNK_SIZE = 1<<4;
let fnName;
let fnIn2Mid, fnMid2Out;
let sOut, sIn, sMid;
if (groupName == "G1") {
if (inType == "affine") {
sIn = G.F.n8*2;
fnIn2Mid = "g1m_batchToJacobian";
} else {
sIn = G.F.n8*3;
}
sMid = G.F.n8*3;
fnName = "g1m_"+fn;
if (outType == "affine") {
fnMid2Out = "g1m_batchToAffine";
sOut = G.F.n8*2;
} else {
sOut = G.F.n8*3;
}
} else if (groupName == "G2") {
if (inType == "affine") {
sIn = G.F.n8*2;
fnIn2Mid = "g2m_batchToJacobian";
} else {
sIn = G.F.n8*3;
}
fnName = "g2m_"+fn;
sMid = G.F.n8*3;
if (outType == "affine") {
fnMid2Out = "g2m_batchToAffine";
sOut = G.F.n8*2;
} else {
sOut = G.F.n8*3;
}
} else if (groupName == "Fr") {
sIn = Fr.n8;
sOut = Fr.n8;
sMid = Fr.n8;
fnName = "frm_" + fn;
} else {
throw new Error("Invalid group");
}
if (buff1.byteLength != buff2.byteLength) {
throw new Error("Invalid buffer size");
}
const nPoints = Math.floor(buff1.byteLength / sIn);
if (nPoints != 1 << log2(nPoints)) {
throw new Error("Invalid number of points");
}
let chunkSize = Math.floor(nPoints /tm.concurrency);
if (chunkSize < MIN_CHUNK_SIZE) chunkSize = MIN_CHUNK_SIZE;
if (chunkSize > MAX_CHUNK_SIZE) chunkSize = MAX_CHUNK_SIZE;
const opPromises = [];
for (let i=0; i<nPoints; i += chunkSize) {
if (logger) logger.debug(`${loggerTxt}: fftJoinExt Start: ${i}/${nPoints}`);
const n= Math.min(nPoints - i, chunkSize);
const firstChunk = Fr.mul(first, Fr.exp( inc, i));
const task = [];
const b1 = buff1.slice(i*sIn, (i+n)*sIn);
const b2 = buff2.slice(i*sIn, (i+n)*sIn);
task.push({cmd: "ALLOC", var: 0, len: sMid*n});
task.push({cmd: "SET", var: 0, buff: b1});
task.push({cmd: "ALLOC", var: 1, len: sMid*n});
task.push({cmd: "SET", var: 1, buff: b2});
task.push({cmd: "ALLOCSET", var: 2, buff: firstChunk});
task.push({cmd: "ALLOCSET", var: 3, buff: inc});
if (fnIn2Mid) {
task.push({cmd: "CALL", fnName:fnIn2Mid, params: [{var:0}, {val: n}, {var: 0}]});
task.push({cmd: "CALL", fnName:fnIn2Mid, params: [{var:1}, {val: n}, {var: 1}]});
}
task.push({cmd: "CALL", fnName: fnName, params: [
{var: 0},
{var: 1},
{val: n},
{var: 2},
{var: 3},
{val: Fr.s},
]});
if (fnMid2Out) {
task.push({cmd: "CALL", fnName:fnMid2Out, params: [{var:0}, {val: n}, {var: 0}]});
task.push({cmd: "CALL", fnName:fnMid2Out, params: [{var:1}, {val: n}, {var: 1}]});
}
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) => {
if (logger) logger.debug(`${loggerTxt}: fftJoinExt End: ${i}/${nPoints}`);
return r;
})
);
}
const result = await Promise.all(opPromises);
let fullBuffOut1;
let fullBuffOut2;
if (nPoints * sOut > 1<<28) {
fullBuffOut1 = new BigBuffer(nPoints*sOut);
fullBuffOut2 = new BigBuffer(nPoints*sOut);
} else {
fullBuffOut1 = new Uint8Array(nPoints*sOut);
fullBuffOut2 = new Uint8Array(nPoints*sOut);
}
let p =0;
for (let i=0; i<result.length; i++) {
fullBuffOut1.set(result[i][0], p);
fullBuffOut2.set(result[i][1], p);
p+=result[i][0].byteLength;
}
return [fullBuffOut1, fullBuffOut2];
}
G.fft = async function(buff, inType, outType, logger, loggerTxt) {
return await _fft(buff, false, inType, outType, logger, loggerTxt);
};
G.ifft = async function(buff, inType, outType, logger, loggerTxt) {
return await _fft(buff, true, inType, outType, logger, loggerTxt);
};
G.lagrangeEvaluations = async function (buff, inType, outType, logger, loggerTxt) {
inType = inType || "affine";
outType = outType || "affine";
let sIn;
if (groupName == "G1") {
if (inType == "affine") {
sIn = G.F.n8*2;
} else {
sIn = G.F.n8*3;
}
} else if (groupName == "G2") {
if (inType == "affine") {
sIn = G.F.n8*2;
} else {
sIn = G.F.n8*3;
}
} else if (groupName == "Fr") {
sIn = Fr.n8;
} else {
throw new Error("Invalid group");
}
const nPoints = buff.byteLength /sIn;
const bits = log2(nPoints);
if ((2 ** bits)*sIn != buff.byteLength) {
if (logger) logger.error("lagrangeEvaluations iinvalid input size");
throw new Error("lagrangeEvaluations invalid Input size");
}
if (bits <= Fr.s) {
return await G.ifft(buff, inType, outType, logger, loggerTxt);
}
if (bits > Fr.s+1) {
if (logger) logger.error("lagrangeEvaluations input too big");
throw new Error("lagrangeEvaluations input too big");
}
let t0 = buff.slice(0, buff.byteLength/2);
let t1 = buff.slice(buff.byteLength/2, buff.byteLength);
const shiftToSmallM = Fr.exp(Fr.shift, nPoints/2);
const sConst = Fr.inv( Fr.sub(Fr.one, shiftToSmallM));
[t0, t1] = await _fftJoinExt(t0, t1, "prepareLagrangeEvaluation", sConst, Fr.shiftInv, inType, "jacobian", logger, loggerTxt + " prep");
const promises = [];
promises.push( _fft(t0, true, "jacobian", outType, logger, loggerTxt + " t0"));
promises.push( _fft(t1, true, "jacobian", outType, logger, loggerTxt + " t1"));
[t0, t1] = await Promise.all(promises);
let buffOut;
if (t0.byteLength > (1<<28)) {
buffOut = new BigBuffer(t0.byteLength*2);
} else {
buffOut = new Uint8Array(t0.byteLength*2);
}
buffOut.set(t0);
buffOut.set(t1, t0.byteLength);
return buffOut;
};
G.fftMix = async function fftMix(buff) {
const sG = G.F.n8*3;
let fnName, fnFFTJoin;
if (groupName == "G1") {
fnName = "g1m_fftMix";
fnFFTJoin = "g1m_fftJoin";
} else if (groupName == "G2") {
fnName = "g2m_fftMix";
fnFFTJoin = "g2m_fftJoin";
} else if (groupName == "Fr") {
fnName = "frm_fftMix";
fnFFTJoin = "frm_fftJoin";
} else {
throw new Error("Invalid group");
}
const nPoints = Math.floor(buff.byteLength / sG);
const power = log2(nPoints);
let nChunks = 1 << log2(tm.concurrency);
if (nPoints <= nChunks*2) nChunks = 1;
const pointsPerChunk = nPoints / nChunks;
const powerChunk = log2(pointsPerChunk);
const opPromises = [];
for (let i=0; i<nChunks; i++) {
const task = [];
const b = buff.slice((i* pointsPerChunk)*sG, ((i+1)* pointsPerChunk)*sG);
task.push({cmd: "ALLOCSET", var: 0, buff: b});
for (let j=1; j<=powerChunk; j++) {
task.push({cmd: "CALL", fnName: fnName, params: [
{var: 0},
{val: pointsPerChunk},
{val: j}
]});
}
task.push({cmd: "GET", out: 0, var: 0, len: pointsPerChunk*sG});
opPromises.push(
tm.queueAction(task)
);
}
const result = await Promise.all(opPromises);
const chunks = [];
for (let i=0; i<result.length; i++) chunks[i] = result[i][0];
for (let i = powerChunk+1; i<=power; i++) {
const nGroups = 1 << (power - i);
const nChunksPerGroup = nChunks / nGroups;
const opPromises = [];
for (let j=0; j<nGroups; j++) {
for (let k=0; k <nChunksPerGroup/2; k++) {
const first = Fr.exp( Fr.w[i], k*pointsPerChunk);
const inc = Fr.w[i];
const o1 = j*nChunksPerGroup + k;
const o2 = j*nChunksPerGroup + k + nChunksPerGroup/2;
const task = [];
task.push({cmd: "ALLOCSET", var: 0, buff: chunks[o1]});
task.push({cmd: "ALLOCSET", var: 1, buff: chunks[o2]});
task.push({cmd: "ALLOCSET", var: 2, buff: first});
task.push({cmd: "ALLOCSET", var: 3, buff: inc});
task.push({cmd: "CALL", fnName: fnFFTJoin, params:[
{var: 0},
{var: 1},
{val: pointsPerChunk},
{var: 2},
{var: 3}
]});
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));
}
}
const res = await Promise.all(opPromises);
for (let j=0; j<nGroups; j++) {
for (let k=0; k <nChunksPerGroup/2; k++) {
const o1 = j*nChunksPerGroup + k;
const o2 = j*nChunksPerGroup + k + nChunksPerGroup/2;
const resChunk = res.shift();
chunks[o1] = resChunk[0];
chunks[o2] = resChunk[1];
}
}
}
let fullBuffOut;
if (buff instanceof BigBuffer) {
fullBuffOut = new BigBuffer(nPoints*sG);
} else {
fullBuffOut = new Uint8Array(nPoints*sG);
}
let p =0;
for (let i=0; i<nChunks; i++) {
fullBuffOut.set(chunks[i], p);
p+=chunks[i].byteLength;
}
return fullBuffOut;
};
G.fftJoin = async function fftJoin(buff1, buff2, first, inc) {
const sG = G.F.n8*3;
let fnName;
if (groupName == "G1") {
fnName = "g1m_fftJoin";
} else if (groupName == "G2") {
fnName = "g2m_fftJoin";
} else if (groupName == "Fr") {
fnName = "frm_fftJoin";
} else {
throw new Error("Invalid group");
}
if (buff1.byteLength != buff2.byteLength) {
throw new Error("Invalid buffer size");
}
const nPoints = Math.floor(buff1.byteLength / sG);
if (nPoints != 1 << log2(nPoints)) {
throw new Error("Invalid number of points");
}
let nChunks = 1 << log2(tm.concurrency);
if (nPoints <= nChunks*2) nChunks = 1;
const pointsPerChunk = nPoints / nChunks;
const opPromises = [];
for (let i=0; i<nChunks; i++) {
const task = [];
const firstChunk = Fr.mul(first, Fr.exp(inc, i*pointsPerChunk));
const b1 = buff1.slice((i* pointsPerChunk)*sG, ((i+1)* pointsPerChunk)*sG);
const b2 = buff2.slice((i* pointsPerChunk)*sG, ((i+1)* pointsPerChunk)*sG);
task.push({cmd: "ALLOCSET", var: 0, buff: b1});
task.push({cmd: "ALLOCSET", var: 1, buff: b2});
task.push({cmd: "ALLOCSET", var: 2, buff: firstChunk});
task.push({cmd: "ALLOCSET", var: 3, buff: inc});
task.push({cmd: "CALL", fnName: fnName, params: [
{var: 0},
{var: 1},
{val: pointsPerChunk},
{var: 2},
{var: 3}
]});
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)
);
}
const result = await Promise.all(opPromises);
let fullBuffOut1;
let fullBuffOut2;
if (buff1 instanceof BigBuffer) {
fullBuffOut1 = new BigBuffer(nPoints*sG);
fullBuffOut2 = new BigBuffer(nPoints*sG);
} else {
fullBuffOut1 = new Uint8Array(nPoints*sG);
fullBuffOut2 = new Uint8Array(nPoints*sG);
}
let p =0;
for (let i=0; i<result.length; i++) {
fullBuffOut1.set(result[i][0], p);
fullBuffOut2.set(result[i][1], p);
p+=result[i][0].byteLength;
}
return [fullBuffOut1, fullBuffOut2];
};
G.fftFinal = async function fftFinal(buff, factor) {
const sG = G.F.n8*3;
const sGout = G.F.n8*2;
let fnName, fnToAffine;
if (groupName == "G1") {
fnName = "g1m_fftFinal";
fnToAffine = "g1m_batchToAffine";
} else if (groupName == "G2") {
fnName = "g2m_fftFinal";
fnToAffine = "g2m_batchToAffine";
} else {
throw new Error("Invalid group");
}
const nPoints = Math.floor(buff.byteLength / sG);
if (nPoints != 1 << log2(nPoints)) {
throw new Error("Invalid number of points");
}
const pointsPerChunk = Math.floor(nPoints / tm.concurrency);
const opPromises = [];
for (let i=0; i<tm.concurrency; i++) {
let n;
if (i< tm.concurrency-1) {
n = pointsPerChunk;
} else {
n = nPoints - i*pointsPerChunk;
}
if (n==0) continue;
const task = [];
const b = buff.slice((i* pointsPerChunk)*sG, (i*pointsPerChunk+n)*sG);
task.push({cmd: "ALLOCSET", var: 0, buff: b});
task.push({cmd: "ALLOCSET", var: 1, buff: factor});
task.push({cmd: "CALL", fnName: fnName, params: [
{var: 0},
{val: n},
{var: 1},
]});
task.push({cmd: "CALL", fnName: fnToAffine, params: [
{var: 0},
{val: n},
{var: 0},
]});
task.push({cmd: "GET", out: 0, var: 0, len: n*sGout});
opPromises.push(
tm.queueAction(task)
);
}
const result = await Promise.all(opPromises);
let fullBuffOut;
if (buff instanceof BigBuffer) {
fullBuffOut = new BigBuffer(nPoints*sGout);
} else {
fullBuffOut = new Uint8Array(nPoints*sGout);
}
let p =0;
for (let i=result.length-1; i>=0; i--) {
fullBuffOut.set(result[i][0], p);
p+=result[i][0].byteLength;
}
return fullBuffOut;
};
}
async function buildEngine(params) {
const tm = await buildThreadManager(params.wasm, params.singleThread);
const curve = {};
curve.q = e(params.wasm.q.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;
buildBatchApplyKey(curve, "G1");
buildBatchApplyKey(curve, "G2");
buildBatchApplyKey(curve, "Fr");
buildMultiexp(curve, "G1");
buildMultiexp(curve, "G2");
buildFFT(curve, "G1");
buildFFT(curve, "G2");
buildFFT(curve, "Fr");
buildPairing(curve);
curve.array2buffer = function(arr, sG) {
const buff = new Uint8Array(sG*arr.length);
for (let i=0; i<arr.length; i++) {
buff.set(arr[i], i*sG);
}
return buff;
};
curve.buffer2array = function(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;
};
return curve;
}
/*
Copyright 2019 0KIMS association.
This file is part of wasmbuilder
wasmbuilder is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
wasmbuilder is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with wasmbuilder. If not, see <https://www.gnu.org/licenses/>.
*/
function toNumber(n) {
return BigInt(n);
}
function isNegative(n) {
return n < 0n;
}
function isZero(n) {
return n === 0n;
}
function bitLength(n) {
if (isNegative(n)) {
return n.toString(2).length - 1; // discard the - sign
} else {
return n.toString(2).length;
}
}
function u32(n) {
const b = [];
const v = toNumber(n);
b.push(Number(v & 0xFFn));
b.push(Number(v >> 8n & 0xFFn));
b.push(Number(v >> 16n & 0xFFn));
b.push(Number(v >> 24n & 0xFFn));
return b;
}
function toUTF8Array(str) {
var utf8 = [];
for (var i=0; i < str.length; i++) {
var charcode = str.charCodeAt(i);
if (charcode < 0x80) utf8.push(charcode);
else if (charcode < 0x800) {
utf8.push(0xc0 | (charcode >> 6),
0x80 | (charcode & 0x3f));
}
else if (charcode < 0xd800 || charcode >= 0xe000) {
utf8.push(0xe0 | (charcode >> 12),
0x80 | ((charcode>>6) & 0x3f),
0x80 | (charcode & 0x3f));
}
// surrogate pair
else {
i++;
// UTF-16 encodes 0x10000-0x10FFFF by
// subtracting 0x10000 and splitting the
// 20 bits of 0x0-0xFFFFF into two halves
charcode = 0x10000 + (((charcode & 0x3ff)<<10)
| (str.charCodeAt(i) & 0x3ff));
utf8.push(0xf0 | (charcode >>18),
0x80 | ((charcode>>12) & 0x3f),
0x80 | ((charcode>>6) & 0x3f),
0x80 | (charcode & 0x3f));
}
}
return utf8;
}
function string(str) {
const bytes = toUTF8Array(str);
return [ ...varuint32(bytes.length), ...bytes ];
}
function varuint(n) {
const code = [];
let v = toNumber(n);
if (isNegative(v)) throw new Error("Number cannot be negative");
while (!isZero(v)) {
code.push(Number(v & 0x7Fn));
v = v >> 7n;
}
if (code.length==0) code.push(0);
for (let i=0; i<code.length-1; i++) {
code[i] = code[i] | 0x80;
}
return code;
}
function varint(_n) {
let n, sign;
const bits = bitLength(_n);
if (_n<0) {
sign = true;
n = (1n << BigInt(bits)) + _n;
} else {
sign = false;
n = toNumber(_n);
}
const paddingBits = 7 - (bits % 7);
const padding = ((1n << BigInt(paddingBits)) - 1n) << BigInt(bits);
const paddingMask = ((1 << (7 - paddingBits))-1) | 0x80;
const code = varuint(n + padding);
if (!sign) {
code[code.length-1] = code[code.length-1] & paddingMask;
}
return code;
}
function varint32(n) {
let v = toNumber(n);
if (v > 0xFFFFFFFFn) throw new Error("Number too big");
if (v > 0x7FFFFFFFn) v = v - 0x100000000n;
// bigInt("-80000000", 16) as base10
if (v < -2147483648n) throw new Error("Number too small");
return varint(v);
}
function varint64(n) {
let v = toNumber(n);
if (v > 0xFFFFFFFFFFFFFFFFn) throw new Error("Number too big");
if (v > 0x7FFFFFFFFFFFFFFFn) v = v - 0x10000000000000000n;
// bigInt("-8000000000000000", 16) as base10
if (v < -9223372036854775808n) throw new Error("Number too small");
return varint(v);
}
function varuint32(n) {
let v = toNumber(n);
if (v > 0xFFFFFFFFn) throw new Error("Number too big");
return varuint(v);
}
function toHexString(byteArray) {
return Array.from(byteArray, function(byte) {
return ("0" + (byte & 0xFF).toString(16)).slice(-2);
}).join("");
}
/*
Copyright 2019 0KIMS association.
This file is part of wasmbuilder
wasmbuilder is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
wasmbuilder is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with wasmbuilder. If not, see <https://www.gnu.org/licenses/>.
*/
class CodeBuilder {
constructor(func) {
this.func = func;
this.functionName = func.functionName;
this.module = func.module;
}
setLocal(localName, valCode) {
const idx = this.func.localIdxByName[localName];
if (idx === undefined)
throw new Error(`Local Variable not defined: Function: ${this.functionName} local: ${localName} `);
return [...valCode, 0x21, ...varuint32( idx )];
}
teeLocal(localName, valCode) {
const idx = this.func.localIdxByName[localName];
if (idx === undefined)
throw new Error(`Local Variable not defined: Function: ${this.functionName} local: ${localName} `);
return [...valCode, 0x22, ...varuint32( idx )];
}
getLocal(localName) {
const idx = this.func.localIdxByName[localName];
if (idx === undefined)
throw new Error(`Local Variable not defined: Function: ${this.functionName} local: ${localName} `);
return [0x20, ...varuint32( idx )];
}
i64_load8_s(idxCode, _offset, _align) {
const offset = _offset || 0;
const align = (_align === undefined) ? 0 : _align; // 8 bits alignment by default
return [...idxCode, 0x30, align, ...varuint32(offset)];
}
i64_load8_u(idxCode, _offset, _align) {
const offset = _offset || 0;
const align = (_align === undefined) ? 0 : _align; // 8 bits alignment by default
return [...idxCode, 0x31, align, ...varuint32(offset)];
}
i64_load16_s(idxCode, _offset, _align) {
const offset = _offset || 0;
const align = (_align === undefined) ? 1 : _align; // 16 bits alignment by default
return [...idxCode, 0x32, align, ...varuint32(offset)];
}
i64_load16_u(idxCode, _offset, _align) {
const offset = _offset || 0;
const align = (_align === undefined) ? 1 : _align; // 16 bits alignment by default
return [...idxCode, 0x33, align, ...varuint32(offset)];
}
i64_load32_s(idxCode, _offset, _align) {
const offset = _offset || 0;
const align = (_align === undefined) ? 2 : _align; // 32 bits alignment by default
return [...idxCode, 0x34, align, ...varuint32(offset)];
}
i64_load32_u(idxCode, _offset, _align) {
const offset = _offset || 0;
const align = (_align === undefined) ? 2 : _align; // 32 bits alignment by default
return [...idxCode, 0x35, align, ...varuint32(offset)];
}
i64_load(idxCode, _offset, _align) {
const offset = _offset || 0;
const align = (_align === undefined) ? 3 : _align; // 64 bits alignment by default
return [...idxCode, 0x29, align, ...varuint32(offset)];
}
i64_store(idxCode, _offset, _align, _codeVal) {
let offset, align, codeVal;
if (Array.isArray(_offset)) {
offset = 0;
align = 3;
codeVal = _offset;
} else if (Array.isArray(_align)) {
offset = _offset;
align = 3;
codeVal = _align;
} else if (Array.isArray(_codeVal)) {
offset = _offset;
align = _align;
codeVal = _codeVal;
}
return [...idxCode, ...codeVal, 0x37, align, ...varuint32(offset)];
}
i64_store32(idxCode, _offset, _align, _codeVal) {
let offset, align, codeVal;
if (Array.isArray(_offset)) {
offset = 0;
align = 2;
codeVal = _offset;
} else if (Array.isArray(_align)) {
offset = _offset;
align = 2;
codeVal = _align;
} else if (Array.isArray(_codeVal)) {
offset = _offset;
align = _align;
codeVal = _codeVal;
}
return [...idxCode, ...codeVal, 0x3e, align, ...varuint32(offset)];
}
i64_store16(idxCode, _offset, _align, _codeVal) {
let offset, align, codeVal;
if (Array.isArray(_offset)) {
offset = 0;
align = 1;
codeVal = _offset;
} else if (Array.isArray(_align)) {
offset = _offset;
align = 1;
codeVal = _align;
} else if (Array.isArray(_codeVal)) {
offset = _offset;
align = _align;
codeVal = _codeVal;
}
return [...idxCode, ...codeVal, 0x3d, align, ...varuint32(offset)];
}
i64_store8(idxCode, _offset, _align, _codeVal) {
let offset, align, codeVal;
if (Array.isArray(_offset)) {
offset = 0;
align = 0;
codeVal = _offset;
} else if (Array.isArray(_align)) {
offset = _offset;
align = 0;
codeVal = _align;
} else if (Array.isArray(_codeVal)) {
offset = _offset;
align = _align;
codeVal = _codeVal;
}
return [...idxCode, ...codeVal, 0x3c, align, ...varuint32(offset)];
}
i32_load8_s(idxCode, _offset, _align) {
const offset = _offset || 0;
const align = (_align === undefined) ? 0 : _align; // 32 bits alignment by default
return [...idxCode, 0x2c, align, ...varuint32(offset)];
}
i32_load8_u(idxCode, _offset, _align) {
const offset = _offset || 0;
const align = (_align === undefined) ? 0 : _align; // 32 bits alignment by default
return [...idxCode, 0x2d, align, ...varuint32(offset)];
}
i32_load16_s(idxCode, _offset, _align) {
const offset = _offset || 0;
const align = (_align === undefined) ? 1 : _align; // 32 bits alignment by default
return [...idxCode, 0x2e, align, ...varuint32(offset)];
}
i32_load16_u(idxCode, _offset, _align) {
const offset = _offset || 0;
const align = (_align === undefined) ? 1 : _align; // 32 bits alignment by default
return [...idxCode, 0x2f, align, ...varuint32(offset)];
}
i32_load(idxCode, _offset, _align) {
const offset = _offset || 0;
const align = (_align === undefined) ? 2 : _align; // 32 bits alignment by default
return [...idxCode, 0x28, align, ...varuint32(offset)];
}
i32_store(idxCode, _offset, _align, _codeVal) {
let offset, align, codeVal;
if (Array.isArray(_offset)) {
offset = 0;
align = 2;
codeVal = _offset;
} else if (Array.isArray(_align)) {
offset = _offset;
align = 2;
codeVal = _align;
} else if (Array.isArray(_codeVal)) {
offset = _offset;
align = _align;
codeVal = _codeVal;
}
return [...idxCode, ...codeVal, 0x36, align, ...varuint32(offset)];
}
i32_store16(idxCode, _offset, _align, _codeVal) {
let offset, align, codeVal;
if (Array.isArray(_offset)) {
offset = 0;
align = 1;
codeVal = _offset;
} else if (Array.isArray(_align)) {
offset = _offset;
align = 1;
codeVal = _align;
} else if (Array.isArray(_codeVal)) {
offset = _offset;
align = _align;
codeVal = _codeVal;
}
return [...idxCode, ...codeVal, 0x3b, align, ...varuint32(offset)];
}
i32_store8(idxCode, _offset, _align, _codeVal) {
let offset, align, codeVal;
if (Array.isArray(_offset)) {
offset = 0;
align = 0;
codeVal = _offset;
} else if (Array.isArray(_align)) {
offset = _offset;
align = 0;
codeVal = _align;
} else if (Array.isArray(_codeVal)) {
offset = _offset;
align = _align;
codeVal = _codeVal;
}
return [...idxCode, ...codeVal, 0x3a, align, ...varuint32(offset)];
}
call(fnName, ...args) {
const idx = this.module.functionIdxByName[fnName];
if (idx === undefined)
throw new Error(`Function not defined: Function: ${fnName}`);
return [...[].concat(...args), 0x10, ...varuint32(idx)];
}
call_indirect(fnIdx, ...args) {
return [...[].concat(...args), ...fnIdx, 0x11, 0, 0];
}
if(condCode, thenCode, elseCode) {
if (elseCode) {
return [...condCode, 0x04, 0x40, ...thenCode, 0x05, ...elseCode, 0x0b];
} else {
return [...condCode, 0x04, 0x40, ...thenCode, 0x0b];
}
}
block(bCode) { return [0x02, 0x40, ...bCode, 0x0b]; }
loop(...args) {
return [0x03, 0x40, ...[].concat(...[...args]), 0x0b];
}
br_if(relPath, condCode) { return [...condCode, 0x0d, ...varuint32(relPath)]; }
br(relPath) { return [0x0c, ...varuint32(relPath)]; }
ret(rCode) { return [...rCode, 0x0f]; }
drop(dCode) { return [...dCode, 0x1a]; }
i64_const(num) { return [0x42, ...varint64(num)]; }
i32_const(num) { return [0x41, ...varint32(num)]; }
i64_eqz(opcode) { return [...opcode, 0x50]; }
i64_eq(op1code, op2code) { return [...op1code, ...op2code, 0x51]; }
i64_ne(op1code, op2code) { return [...op1code, ...op2code, 0x52]; }
i64_lt_s(op1code, op2code) { return [...op1code, ...op2code, 0x53]; }
i64_lt_u(op1code, op2code) { return [...op1code, ...op2code, 0x54]; }
i64_gt_s(op1code, op2code) { return [...op1code, ...op2code, 0x55]; }
i64_gt_u(op1code, op2code) { return [...op1code, ...op2code, 0x56]; }
i64_le_s(op1code, op2code) { return [...op1code, ...op2code, 0x57]; }
i64_le_u(op1code, op2code) { return [...op1code, ...op2code, 0x58]; }
i64_ge_s(op1code, op2code) { return [...op1code, ...op2code, 0x59]; }
i64_ge_u(op1code, op2code) { return [...op1code, ...op2code, 0x5a]; }
i64_add(op1code, op2code) { return [...op1code, ...op2code, 0x7c]; }
i64_sub(op1code, op2code) { return [...op1code, ...op2code, 0x7d]; }
i64_mul(op1code, op2code) { return [...op1code, ...op2code, 0x7e]; }
i64_div_s(op1code, op2code) { return [...op1code, ...op2code, 0x7f]; }
i64_div_u(op1code, op2code) { return [...op1code, ...op2code, 0x80]; }
i64_rem_s(op1code, op2code) { return [...op1code, ...op2code, 0x81]; }
i64_rem_u(op1code, op2code) { return [...op1code, ...op2code, 0x82]; }
i64_and(op1code, op2code) { return [...op1code, ...op2code, 0x83]; }
i64_or(op1code, op2code) { return [...op1code, ...op2code, 0x84]; }
i64_xor(op1code, op2code) { return [...op1code, ...op2code, 0x85]; }
i64_shl(op1code, op2code) { return [...op1code, ...op2code, 0x86]; }
i64_shr_s(op1code, op2code) { return [...op1code, ...op2code, 0x87]; }
i64_shr_u(op1code, op2code) { return [...op1code, ...op2code, 0x88]; }
i64_extend_i32_s(op1code) { return [...op1code, 0xac]; }
i64_extend_i32_u(op1code) { return [...op1code, 0xad]; }
i64_clz(op1code) { return [...op1code, 0x79]; }
i64_ctz(op1code) { return [...op1code, 0x7a]; }
i32_eqz(op1code) { return [...op1code, 0x45]; }
i32_eq(op1code, op2code) { return [...op1code, ...op2code, 0x46]; }
i32_ne(op1code, op2code) { return [...op1code, ...op2code, 0x47]; }
i32_lt_s(op1code, op2code) { return [...op1code, ...op2code, 0x48]; }
i32_lt_u(op1code, op2code) { return [...op1code, ...op2code, 0x49]; }
i32_gt_s(op1code, op2code) { return [...op1code, ...op2code, 0x4a]; }
i32_gt_u(op1code, op2code) { return [...op1code, ...op2code, 0x4b]; }
i32_le_s(op1code, op2code) { return [...op1code, ...op2code, 0x4c]; }
i32_le_u(op1code, op2code) { return [...op1code, ...op2code, 0x4d]; }
i32_ge_s(op1code, op2code) { return [...op1code, ...op2code, 0x4e]; }
i32_ge_u(op1code, op2code) { return [...op1code, ...op2code, 0x4f]; }
i32_add(op1code, op2code) { return [...op1code, ...op2code, 0x6a]; }
i32_sub(op1code, op2code) { return [...op1code, ...op2code, 0x6b]; }
i32_mul(op1code, op2code) { return [...op1code, ...op2code, 0x6c]; }
i32_div_s(op1code, op2code) { return [...op1code, ...op2code, 0x6d]; }
i32_div_u(op1code, op2code) { return [...op1code, ...op2code, 0x6e]; }
i32_rem_s(op1code, op2code) { return [...op1code, ...op2code, 0x6f]; }
i32_rem_u(op1code, op2code) { return [...op1code, ...op2code, 0x70]; }
i32_and(op1code, op2code) { return [...op1code, ...op2code, 0x71]; }
i32_or(op1code, op2code) { return [...op1code, ...op2code, 0x72]; }
i32_xor(op1code, op2code) { return [...op1code, ...op2code, 0x73]; }
i32_shl(op1code, op2code) { return [...op1code, ...op2code, 0x74]; }
i32_shr_s(op1code, op2code) { return [...op1code, ...op2code, 0x75]; }
i32_shr_u(op1code, op2code) { return [...op1code, ...op2code, 0x76]; }
i32_rotl(op1code, op2code) { return [...op1code, ...op2code, 0x77]; }
i32_rotr(op1code, op2code) { return [...op1code, ...op2code, 0x78]; }
i32_wrap_i64(op1code) { return [...op1code, 0xa7]; }
i32_clz(op1code) { return [...op1code, 0x67]; }
i32_ctz(op1code) { return [...op1code, 0x68]; }
unreachable() { return [ 0x0 ]; }
current_memory() { return [ 0x3f, 0]; }
comment() { return []; }
}
/*
Copyright 2019 0KIMS association.
This file is part of wasmbuilder
wasmbuilder is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
wasmbuilder is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with wasmbuilder. If not, see <https://www.gnu.org/licenses/>.
*/
const typeCodes = {
"i32": 0x7f,
"i64": 0x7e,
"f32": 0x7d,
"f64": 0x7c,
"anyfunc": 0x70,
"func": 0x60,
"emptyblock": 0x40
};
class FunctionBuilder {
constructor (module, fnName, fnType, moduleName, fieldName) {
if (fnType == "import") {
this.fnType = "import";
this.moduleName = moduleName;
this.fieldName = fieldName;
} else if (fnType == "internal") {
this.fnType = "internal";
} else {
throw new Error("Invalid function fnType: " + fnType);
}
this.module = module;
this.fnName = fnName;
this.params = [];
this.locals = [];
this.localIdxByName = {};
this.code = [];
this.returnType = null;
this.nextLocal =0;
}
addParam(paramName, paramType) {
if (this.localIdxByName[paramName])
throw new Error(`param already exists. Function: ${this.fnName}, Param: ${paramName} `);
const idx = this.nextLocal++;
this.localIdxByName[paramName] = idx;
this.params.push({
type: paramType
});
}
addLocal(localName, localType, _length) {
const length = _length || 1;
if (this.localIdxByName[localName])
throw new Error(`local already exists. Function: ${this.fnName}, Param: ${localName} `);
const idx = this.nextLocal++;
this.localIdxByName[localName] = idx;
this.locals.push({
type: localType,
length: length
});
}
setReturnType(returnType) {
if (this.returnType)
throw new Error(`returnType already defined. Function: ${this.fnName}`);
this.returnType = returnType;
}
getSignature() {
const params = [...varuint32(this.params.length), ...this.params.map((p) => typeCodes[p.type])];
const returns = this.returnType ? [0x01, typeCodes[this.returnType]] : [0];
return [0x60, ...params, ...returns];
}
getBody() {
const locals = this.locals.map((l) => [
...varuint32(l.length),
typeCodes[l.type]
]);
const body = [
...varuint32(this.locals.length),
...[].concat(...locals),
...this.code,
0x0b
];
return [
...varuint32(body.length),
...body
];
}
addCode(...code) {
this.code.push(...[].concat(...[...code]));
}
getCodeBuilder() {
return new CodeBuilder(this);
}
}
/*
Copyright 2019 0KIMS association.
This file is part of wasmbuilder
wasmbuilder is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
wasmbuilder is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with wasmbuilder. If not, see <https://www.gnu.org/licenses/>.
*/
class ModuleBuilder {
constructor() {
this.functions = [];
this.functionIdxByName = {};
this.nImportFunctions = 0;
this.nInternalFunctions =0;
this.memory = {
pagesSize: 1,
moduleName: "env",
fieldName: "memory"
};
this.free = 8;
this.datas = [];
this.modules = {};
this.exports = [];
this.functionsTable = [];
}
build() {
this._setSignatures();
return new Uint8Array([
...u32(0x6d736100),
...u32(1),
...this._buildType(),
...this._buildImport(),
...this._buildFunctionDeclarations(),
...this._buildFunctionsTable(),
...this._buildExports(),
...this._buildElements(),
...this._buildCode(),
...this._buildData()
]);
}
addFunction(fnName) {
if (typeof(this.functionIdxByName[fnName]) !== "undefined")
throw new Error(`Function already defined: ${fnName}`);
const idx = this.functions.length;
this.functionIdxByName[fnName] = idx;
this.functions.push(new FunctionBuilder(this, fnName, "internal"));
this.nInternalFunctions++;
return this.functions[idx];
}
addIimportFunction(fnName, moduleName, _fieldName) {
if (typeof(this.functionIdxByName[fnName]) !== "undefined")
throw new Error(`Function already defined: ${fnName}`);
if ( (this.functions.length>0)
&&(this.functions[this.functions.length-1].type == "internal"))
throw new Error(`Import functions must be declared before internal: ${fnName}`);
let fieldName = _fieldName || fnName;
const idx = this.functions.length;
this.functionIdxByName[fnName] = idx;
this.functions.push(new FunctionBuilder(this, fnName, "import", moduleName, fieldName));
this.nImportFunctions ++;
return this.functions[idx];
}
setMemory(pagesSize, moduleName, fieldName) {
this.memory = {
pagesSize: pagesSize,
moduleName: moduleName || "env",
fieldName: fieldName || "memory"
};
}
exportFunction(fnName, _exportName) {
const exportName = _exportName || fnName;
if (typeof(this.functionIdxByName[fnName]) === "undefined")
throw new Error(`Function not defined: ${fnName}`);
const idx = this.functionIdxByName[fnName];
if (exportName != fnName) {
this.functionIdxByName[exportName] = idx;
}
this.exports.push({
exportName: exportName,
idx: idx
});
}
addFunctionToTable(fnName) {
const idx = this.functionIdxByName[fnName];
this.functionsTable.push(idx);
}
addData(offset, bytes) {
this.datas.push({
offset: offset,
bytes: bytes
});
}
alloc(a, b) {
let size;
let bytes;
if ((Array.isArray(a) || ArrayBuffer.isView(a)) && (typeof(b) === "undefined")) {
size = a.length;
bytes = a;
} else {
size = a;
bytes = b;
}
size = (((size-1)>>3) +1)<<3; // Align to 64 bits.
const p = this.free;
this.free += size;
if (bytes) {
this.addData(p, bytes);
}
return p;
}
allocString(s) {
const encoder = new globalThis.TextEncoder();
const uint8array = encoder.encode(s);
return this.alloc([...uint8array, 0]);
}
_setSignatures() {
this.signatures = [];
const signatureIdxByName = {};
if (this.functionsTable.length>0) {
const signature = this.functions[this.functionsTable[0]].getSignature();
const signatureName = "s_"+toHexString(signature);
signatureIdxByName[signatureName] = 0;
this.signatures.push(signature);
}
for (let i=0; i<this.functions.length; i++) {
const signature = this.functions[i].getSignature();
const signatureName = "s_"+toHexString(signature);
if (typeof(signatureIdxByName[signatureName]) === "undefined") {
signatureIdxByName[signatureName] = this.signatures.length;
this.signatures.push(signature);
}
this.functions[i].signatureIdx = signatureIdxByName[signatureName];
}
}
_buildSection(sectionType, section) {
return [sectionType, ...varuint32(section.length), ...section];
}
_buildType() {
return this._buildSection(
0x01,
[
...varuint32(this.signatures.length),
...[].concat(...this.signatures)
]
);
}
_buildImport() {
const entries = [];
entries.push([
...string(this.memory.moduleName),
...string(this.memory.fieldName),
0x02,
0x00, //Flags no init valua
...varuint32(this.memory.pagesSize)
]);
for (let i=0; i< this.nImportFunctions; i++) {
entries.push([
...string(this.functions[i].moduleName),
...string(this.functions[i].fieldName),
0x00,
...varuint32(this.functions[i].signatureIdx)
]);
}
return this._buildSection(
0x02,
varuint32(entries.length).concat(...entries)
);
}
_buildFunctionDeclarations() {
const entries = [];
for (let i=this.nImportFunctions; i< this.nImportFunctions + this.nInternalFunctions; i++) {
entries.push(...varuint32(this.functions[i].signatureIdx));
}
return this._buildSection(
0x03,
[
...varuint32(entries.length),
...[...entries]
]
);
}
_buildFunctionsTable() {
if (this.functionsTable.length == 0) return [];
return this._buildSection(
0x04,
[
...varuint32(1),
0x70, 0, ...varuint32(this.functionsTable.length)
]
);
}
_buildElements() {
if (this.functionsTable.length == 0) return [];
const entries = [];
for (let i=0; i<this.functionsTable.length; i++) {
entries.push(...varuint32(this.functionsTable[i]));
}
return this._buildSection(
0x09,
[
...varuint32(1), // 1 entry
...varuint32(0), // Table (0 in MVP)
0x41, // offset 0
...varint32(0),
0x0b,
...varuint32(this.functionsTable.length), // Number of elements
...[...entries]
]
);
}
_buildExports() {
const entries = [];
for (let i=0; i< this.exports.length; i++) {
entries.push([
...string(this.exports[i].exportName),
0x00,
...varuint32(this.exports[i].idx)
]);
}
return this._buildSection(
0x07,
varuint32(entries.length).concat(...entries)
);
}
_buildCode() {
const entries = [];
for (let i=this.nImportFunctions; i< this.nImportFunctions + this.nInternalFunctions; i++) {
entries.push(this.functions[i].getBody());
}
return this._buildSection(
0x0a,
varuint32(entries.length).concat(...entries)
);
}
_buildData() {
const entries = [];
entries.push([
0x00,
0x41,
0x00,
0x0b,
0x04,
...u32(this.free)
]);
for (let i=0; i< this.datas.length; i++) {
entries.push([
0x00,
0x41,
...varint32(this.datas[i].offset),
0x0b,
...varuint32(this.datas[i].bytes.length),
...this.datas[i].bytes,
]);
}
return this._buildSection(
0x0b,
varuint32(entries.length).concat(...entries)
);
}
}
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;
}
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;
}
async function getCurveFromName(name, singleThread, plugins) {
let curve;
const normName = normalizeName(name);
if (["BN128", "BN254", "ALTBN128"].indexOf(normName) >= 0) {
curve = await buildBn128(singleThread, plugins);
} else if (["BLS12381"].indexOf(normName) >= 0) {
curve = await buildBls12381(singleThread, plugins);
} else {
throw new Error(`Curve not supported: ${name}`);
}
return curve;
function normalizeName(n) {
return n.toUpperCase().match(/[A-Za-z0-9]+/g).join("");
}
}
const Scalar=_Scalar;
const utils = _utils;
export { BigBuffer, ChaCha, EC, ZqField as F1Field, F2Field, F3Field, PolField, Scalar, ZqField, buildBls12381, buildBn128, getCurveFromName, getCurveFromQ, getCurveFromR, utils };