diff --git a/build/main.cjs b/build/main.cjs index 9283f0d..b252d9f 100644 --- a/build/main.cjs +++ b/build/main.cjs @@ -4,17 +4,11 @@ Object.defineProperty(exports, '__esModule', { value: true }); var bigInt = require('big-integer'); var crypto = require('crypto'); -var wasmcurves = require('wasmcurves'); -var os = require('os'); -var Worker = require('web-worker'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var bigInt__default = /*#__PURE__*/_interopDefaultLegacy(bigInt); var crypto__default = /*#__PURE__*/_interopDefaultLegacy(crypto); -var wasmcurves__default = /*#__PURE__*/_interopDefaultLegacy(wasmcurves); -var os__default = /*#__PURE__*/_interopDefaultLegacy(os); -var Worker__default = /*#__PURE__*/_interopDefaultLegacy(Worker); /* global BigInt */ const hexLen = [ 0, 1, 2, 2, 3, 3, 3, 3, 4 ,4 ,4 ,4 ,4 ,4 ,4 ,4]; @@ -645,5725 +639,1196 @@ var _Scalar = /*#__PURE__*/Object.freeze({ snarkjs. If not, see . */ -/* - 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; +/* +exports.mulScalar = (F, base, e) =>{ + let res = F.zero; + let rem = bigInt(e); + let exp = base; - const five = this.F.add(this.F.add(this.F.two, this.F.two), this.F.one); + 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); + } - 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]); + return res; +}; +*/ - 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--; - } +function exp(F, base, e) { - 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 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=0; i--) { - sub(a, b) { - const m = Math.max(a.length, b.length); - const res = new Array(m); - for (let i=0; i a.length) { - [b, a] = [a, b]; +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); } - - if ((b.length <= 2) || (b.length < log2$1(a.length))) { - return this.mulNormal(a,b); + } 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 { - return this.mulFFT(a,b); + alg8_complex(F); } - } - mulNormal(a, b) { - let res = []; - for (let i=0; i0) { - const z = new Array(n).fill(this.F.zero); - return z.concat(p); - } else { - if (-n >= p.length) return []; - return p.slice(-n); + w = z; + for (let i=0; i> 1), - F.mul( - x, - _eval(p, newX, offset+step , step << 1, n >> 1))); - return res; - } - } +function alg3_atkin(F) { + F.sqrt = function() { + throw new Error("Sqrt alg 3 not implemented"); + }; +} - lagrange(points) { - let roots = [this.F.one]; - for (let i=0; i>>0; + } } + } + else { // NodeJS + crypto__default['default'].randomFillSync(array); + } + return array; +} - return resn; +/* global BigInt */ - } +class ZqField$1 { + 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(this.p); + this.mask = (this.one << BigInt(this.bitLength)) - this.one; - _fft(pall, bits, offset, step) { + 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 n = 1 << bits; - if (n==1) { - return [ pall[offset] ]; + 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); } - 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); + this.s = 0; + this.t = this.negone; - let m= this.F.one; - for (let i=0; i> this.one; } - 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); - } + this.nqr_to_t = this.pow(this.nqr, this.t); - 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); + buildSqrt(this); } - 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= this.p) nres = nres % this.p; + return this.p - nres; + } else { + return (res>= this.p) ? res%this.p : res; } - 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; + add(a, b) { + const res = a + b; + return res >= this.p ? res-this.p : res; } - _next2Power(v) { - v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v++; - return v; + sub(a, b) { + return (a >= b) ? a-b : this.p-b+a; } - 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; + neg(a) { + return a ? this.p-a : a; } - normalize(p) { - const res = new Array(p.length); - for (let i=0; i this.half) ? a - this.p : a; + const bb = (b > this.half) ? b - this.p : b; + return aa < bb; + } - // 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) + gt(a, b) { + const aa = (a > this.half) ? a - this.p : a; + const bb = (b > this.half) ? b - this.p : b; + return aa > bb; + } - const rec = this._reciprocal(this.scaleX(v, scaleV), kbits); - const res = this.scaleX(rec, m - 2*k + 2 + scaleV); + leq(a, b) { + const aa = (a > this.half) ? a - this.p : a; + const bb = (b > this.half) ? b - this.p : b; + return aa <= bb; + } - return res; + 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(_u, _v) { - if (_u.length < _v.length) return []; - const kbits = log2$1(_v.length-1)+1; - const k = 1 << kbits; + div(a, b) { + return this.mul(a, this.inv(b)); + } - const u = this.scaleX(_u, k-_v.length); - const v = this.scaleX(_v, k-_v.length); + idiv(a, b) { + if (!b) throw new Error("Division by zero"); + return a / b; + } - const n = v.length-1; - let m = u.length-1; + inv(a) { + if (!a) throw new Error("Division by zero"); - 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 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 2*n ) { - ut = this.mul(rem, t); - rem = this.scaleX(ut, -2*n); - m = rem.length-1; - } else { - finish = true; - } - } + mod(a, b) { + return a % b; + } - return q; + pow(b, e) { + return exp(this, b, e); } + exp(b, e) { + return exp(this, b, e); + } - // returns the ith nth-root of one - oneRoot(n, i) { - let nbits = log2$1(n-1)+1; - let res = this.F.one; - let r = i; + band(a, b) { + const res = ((a & b) & this.mask); + return res >= this.p ? res-this.p : res; + } - if(i>=n) { - throw new Error("Given 'i' should be lower than 'n'"); - } - else if (1<= this.p ? res-this.p : res; + } - while (r>0) { - if (r & 1 == 1) { - res = this.F.mul(res, this.w[nbits]); - } - r = r >> 1; - nbits --; - } - return res; + bxor(a, b) { + const res = ((a ^ b) & this.mask); + return res >= this.p ? res-this.p : res; } - computeVanishingPolinomial(bits, t) { - const m = 1 << bits; - return this.F.sub(this.F.pow(t, m), this.F.one); + bnot(a) { + const res = a ^ this.mask; + return res >= this.p ? res-this.p : res; } - 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; - } + 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; } } + } - 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); + 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; + } } - - return u; } - log2(V) { - return log2$1(V); + land(a, b) { + return (a && b) ? this.one : this.zero; } -} - -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.F.add(pall[offset], pall[offset + step]), - PF.F.sub(pall[offset], pall[offset + step])]; + lor(a, b) { + return (a || b) ? this.one : this.zero; } - 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> this.one); + if ( res != this.one ) return null; - const ndiv2 = n >> 1; - const p1 = __fft2(PF, pall.slice(0, ndiv2), bits-1); - const p2 = __fft2(PF, pall.slice(ndiv2), bits-1); + 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 ); - const out = new Array(n); + while ( t != this.one ) { + let sq = this.square(t); + let i = 1; + while (sq != this.one ) { + i++; + sq = this.square(sq); + } - for (let i=0; i (this.p >> this.one)) { + r = this.neg(r); + } -function _revSlow$1(idx, bits) { - let res =0; - let a = idx; - for (let i=0; i>=1; + return r; } - 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; kk) { - const tmp= p[k]; - p[k] = p[r]; - p[r] = tmp; + 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; } } -} - -/* - 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 . -*/ - - -function mulScalar(F, base, e) { - let res; - - if (isZero(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"); + random() { + const nBytes = (this.bitLength*2 / 8); + let res =this.zero; + for (let i=0; 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); + toString(a, base) { + let vs; + if (a > this.half) { + const v = this.p-a; + vs = "-"+v.toString(base); + } else { + vs = a.toString(base); } + return vs; } - return res; -} + isZero(a) { + return a == this.zero; + } - -/* -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); + fromRng(rng) { + let v; + do { + v=this.zero; + for (let i=0; i= this.p); + v = (v * this.Ri) % this.p; // Convert from montgomery + return v; } - return res; -}; -*/ +} +class ZqField { + constructor(p) { + this.type="F1"; + this.one = bigInt__default['default'].one; + this.zero = bigInt__default['default'].zero; + this.p = bigInt__default['default'](p); + this.m = 1; + this.negone = this.p.minus(bigInt__default['default'].one); + this.two = bigInt__default['default'](2); + this.half = this.p.shiftRight(1); + this.bitLength = this.p.bitLength(); + this.mask = bigInt__default['default'].one.shiftLeft(this.bitLength).minus(bigInt__default['default'].one); -function exp(F, base, e) { + this.n64 = Math.floor((this.bitLength - 1) / 64)+1; + this.n32 = this.n64*2; + this.n8 = this.n64*8; + this.R = bigInt__default['default'].one.shiftLeft(this.n64*64); + this.Ri = this.inv(this.R); - if (isZero(e)) return F.one; + const e = this.negone.shiftRight(this.one); + this.nqr = this.two; + let r = this.pow(this.nqr, e); + while (!r.equals(this.negone)) { + this.nqr = this.nqr.add(this.one); + r = this.pow(this.nqr, e); + } - const n = bits(e); + this.s = this.zero; + this.t = this.negone; - if (n.legth==0) return F.one; + while (!this.t.isOdd()) { + this.s = this.s.add(this.one); + this.t = this.t.shiftRight(this.one); + } - let res = base; + this.nqr_to_t = this.pow(this.nqr, this.t); - for (let i=n.length-2; i>=0; i--) { + buildSqrt(this); + } - res = F.square(res); + e(a,b) { - if (n[i]) { - res = F.mul(res, base); - } - } + const res = bigInt__default['default'](a,b); - return res; -} + return this.normalize(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); + add(a, b) { + let res = a.add(b); + if (res.geq(this.p)) { + res = res.minus(this.p); } - } else { - const pm2mod4 = mod(pow(F.p, F.m/2), 4); - if (pm2mod4 == 1) { - alg10_adj(F); - } else if (pm2mod4 == 3) { - alg9_adj(F); + return res; + } + + sub(a, b) { + if (a.geq(b)) { + return a.minus(b); } else { - alg8_complex(F); + return this.p.minus(b.minus(a)); } - } -} + neg(a) { + if (a.isZero()) return a; + return this.p.minus(a); + } -function alg5_tonelliShanks(F) { - F.sqrt_q = pow(F.p, F.m); + mul(a, b) { + return a.times(b).mod(this.p); + } - F.sqrt_s = 0; - F.sqrt_t = sub(F.sqrt_q, 1); + mulScalar(base, s) { + return base.times(bigInt__default['default'](s)).mod(this.p); + } - while (!isOdd(F.sqrt_t)) { - F.sqrt_s = F.sqrt_s + 1; - F.sqrt_t = div(F.sqrt_t, 2); + square(a) { + return a.square().mod(this.p); } - let c0 = F.one; + eq(a, b) { + return a.eq(b); + } - 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) ); + neq(a, b) { + return a.neq(b); } - F.sqrt_tm1d2 = div(sub(F.sqrt_t, 1),2); + lt(a, b) { + const aa = a.gt(this.half) ? a.minus(this.p) : a; + const bb = b.gt(this.half) ? b.minus(this.p) : b; + return aa.lt(bb); + } - 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; + gt(a, b) { + const aa = a.gt(this.half) ? a.minus(this.p) : a; + const bb = b.gt(this.half) ? b.minus(this.p) : b; + return aa.gt(bb); + } - 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++; - } + leq(a, b) { + const aa = a.gt(this.half) ? a.minus(this.p) : a; + const bb = b.gt(this.half) ? b.minus(this.p) : b; + return aa.leq(bb); + } - w = z; - for (let i=0; i>> 0; - st[d] = (st[d] ^ st[a]) >>> 0; - st[d] = ((st[d] << 16) | ((st[d]>>>16) & 0xFFFF)) >>> 0; + sqrt_old(n) { - st[c] = (st[c] + st[d]) >>> 0; - st[b] = (st[b] ^ st[c]) >>> 0; - st[b] = ((st[b] << 12) | ((st[b]>>>20) & 0xFFF)) >>> 0; + if (n.equals(this.zero)) return this.zero; - st[a] = (st[a] + st[b]) >>> 0; - st[d] = (st[d] ^ st[a]) >>> 0; - st[d] = ((st[d] << 8) | ((st[d]>>>24) & 0xFF)) >>> 0; + // Test that have solution + const res = this.pow(n, this.negone.shiftRight(this.one)); + if (!res.equals(this.one)) return null; - st[c] = (st[c] + st[d]) >>> 0; - st[b] = (st[b] ^ st[c]) >>> 0; - st[b] = ((st[b] << 7) | ((st[b]>>>25) & 0x7F)) >>> 0; -} + let m = parseInt(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).shiftRight(this.one) ); -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); + while (!t.equals(this.one)) { + let sq = this.square(t); + let i = 1; + while (!sq.equals(this.one)) { + i++; + sq = this.square(sq); + } - quarterRound(st, 0, 5,10,15); - quarterRound(st, 1, 6,11,12); - quarterRound(st, 2, 7, 8,13); - quarterRound(st, 3, 4, 9,14); -} + // b = c ^ m-i-1 + let b = c; + for (let j=0; j< m-i-1; j ++) b = this.square(b); -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); - } + m = i; + c = this.square(b); + t = this.mul(t, c); + r = this.mul(r, b); + } - nextU32() { - if (this.idx == 16) this.update(); - return this.buff[this.idx++]; - } + if (r.greater(this.p.shiftRight(this.one))) { + r = this.neg(r); + } - nextU64() { - return add(mul(this.nextU32(), 0x100000000), this.nextU32()); + return r; } - nextBool() { - return (this.nextU32() & 1) == 1; + normalize(a) { + a = bigInt__default['default'](a); + if (a.isNegative()) { + return this.p.minus(a.abs().mod(this.p)); + } else { + return a.mod(this.p); + } } - 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; + random() { + let res = bigInt__default['default'](0); + let n = bigInt__default['default'](this.p.square()); + while (!n.isZero()) { + res = res.shiftLeft(8).add(bigInt__default['default'](getRandomBytes(1)[0])); + n = n.shiftRight(8); + } + return res.mod(this.p); } -} - -/* global window */ -function getRandomBytes(n) { - let array = new Uint8Array(n); - if (typeof window !== "undefined") { // Browser - if (typeof window.crypto !== "undefined") { // Supported - window.crypto.getRandomValues(array); - } else { // fallback - for (let i=0; i>>0; - } + toString(a, base) { + let vs; + if (!a.lesserOrEquals(this.p.shiftRight(bigInt__default['default'](1)))) { + const v = this.p.minus(a); + vs = "-"+v.toString(base); + } else { + vs = a.toString(base); } + + return vs; } - else { // NodeJS - crypto__default['default'].randomFillSync(array); + + isZero(a) { + return a.isZero(); } - 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]); + fromRng(rng) { + let v; + do { + v = bigInt__default['default'](0); + for (let i=0; i> this.one; - this.bitLength = bitLength(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; - } +const supportsNativeBigInt$1 = typeof BigInt === "function"; +let _F1Field; +if (supportsNativeBigInt$1) { + _F1Field = ZqField$1; +} else { + _F1Field = ZqField; +} - this.nqr_to_t = this.pow(this.nqr, this.t); +class F1Field extends _F1Field { - buildSqrt(this); + // Returns a buffer with Little Endian Representation + toRprLE(buff, o, e) { + toRprLE(buff, o, e, this.n64*8); } - 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; - } - + // Returns a buffer with Big Endian Representation + toRprBE(buff, o, e) { + toRprBE(buff, o, e, this.n64*8); } - add(a, b) { - const res = a + b; - return res >= this.p ? res-this.p : res; + // Returns a buffer with Big Endian Montgomery Representation + toRprBEM(buff, o, e) { + return this.toRprBE(buff, o, this.mul(this.R, e)); } - sub(a, b) { - return (a >= b) ? a-b : this.p-b+a; + toRprLEM(buff, o, e) { + return this.toRprLE(buff, o, this.mul(this.R, e)); } - neg(a) { - return a ? this.p-a : a; - } - mul(a, b) { - return (a*b)%this.p; + // Pases a buffer with Little Endian Representation + fromRprLE(buff, o) { + return fromRprLE(buff, o, this.n8); } - mulScalar(base, s) { - return (base * this.e(s)) % this.p; + // Pases a buffer with Big Endian Representation + fromRprBE(buff, o) { + return fromRprBE(buff, o, this.n8); } - square(a) { - return (a*a) % this.p; + fromRprLEM(buff, o) { + return this.mul(this.fromRprLE(buff, o), this.Ri); } - eq(a, b) { - return a==b; + fromRprBEM(buff, o) { + return this.mul(this.fromRprBE(buff, o), this.Ri); } - 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<0n) 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 this.half) { - 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.p); - v = (v * this.Ri) % this.p; // Convert from montgomery - return v; - } - -} - -class ZqField { - constructor(p) { - this.type="F1"; - this.one = bigInt__default['default'].one; - this.zero = bigInt__default['default'].zero; - this.p = bigInt__default['default'](p); - this.m = 1; - this.negone = this.p.minus(bigInt__default['default'].one); - this.two = bigInt__default['default'](2); - this.half = this.p.shiftRight(1); - this.bitLength = this.p.bitLength(); - this.mask = bigInt__default['default'].one.shiftLeft(this.bitLength).minus(bigInt__default['default'].one); - - this.n64 = Math.floor((this.bitLength - 1) / 64)+1; - this.n32 = this.n64*2; - this.n8 = this.n64*8; - this.R = bigInt__default['default'].one.shiftLeft(this.n64*64); - this.Ri = this.inv(this.R); - - const e = this.negone.shiftRight(this.one); - this.nqr = this.two; - let r = this.pow(this.nqr, e); - while (!r.equals(this.negone)) { - this.nqr = this.nqr.add(this.one); - r = this.pow(this.nqr, e); - } - - this.s = this.zero; - this.t = this.negone; - - while (!this.t.isOdd()) { - this.s = this.s.add(this.one); - this.t = this.t.shiftRight(this.one); - } - - this.nqr_to_t = this.pow(this.nqr, this.t); - - buildSqrt(this); - } - - e(a,b) { - - const res = bigInt__default['default'](a,b); - - return this.normalize(res); - - } - - add(a, b) { - let res = a.add(b); - if (res.geq(this.p)) { - res = res.minus(this.p); - } - return res; - } - - sub(a, b) { - if (a.geq(b)) { - return a.minus(b); - } else { - return this.p.minus(b.minus(a)); - } - } - - neg(a) { - if (a.isZero()) return a; - return this.p.minus(a); - } - - mul(a, b) { - return a.times(b).mod(this.p); - } - - mulScalar(base, s) { - return base.times(bigInt__default['default'](s)).mod(this.p); - } - - square(a) { - return a.square().mod(this.p); - } - - eq(a, b) { - return a.eq(b); - } - - neq(a, b) { - return a.neq(b); - } - - lt(a, b) { - const aa = a.gt(this.half) ? a.minus(this.p) : a; - const bb = b.gt(this.half) ? b.minus(this.p) : b; - return aa.lt(bb); - } - - gt(a, b) { - const aa = a.gt(this.half) ? a.minus(this.p) : a; - const bb = b.gt(this.half) ? b.minus(this.p) : b; - return aa.gt(bb); - } - - leq(a, b) { - const aa = a.gt(this.half) ? a.minus(this.p) : a; - const bb = b.gt(this.half) ? b.minus(this.p) : b; - return aa.leq(bb); - } - - geq(a, b) { - const aa = a.gt(this.half) ? a.minus(this.p) : a; - const bb = b.gt(this.half) ? b.minus(this.p) : b; - return aa.geq(bb); - } - - div(a, b) { - if (b.isZero()) throw new Error("Division by zero"); - return a.times(b.modInv(this.p)).mod(this.p); - } - - idiv(a, b) { - if (b.isZero()) throw new Error("Division by zero"); - return a.divide(b); - } - - inv(a) { - if (a.isZero()) throw new Error("Division by zero"); - return a.modInv(this.p); - } - - mod(a, b) { - return a.mod(b); - } - - pow(a, b) { - return a.modPow(b, this.p); - } - - exp(a, b) { - return a.modPow(b, this.p); - } - - band(a, b) { - return a.and(b).and(this.mask).mod(this.p); - } - - bor(a, b) { - return a.or(b).and(this.mask).mod(this.p); - } - - bxor(a, b) { - return a.xor(b).and(this.mask).mod(this.p); - } - - bnot(a) { - return a.xor(this.mask).mod(this.p); - } - - shl(a, b) { - if (b.lt(this.bitLength)) { - return a.shiftLeft(b).and(this.mask).mod(this.p); - } else { - const nb = this.p.minus(b); - if (nb.lt(this.bitLength)) { - return this.shr(a, nb); - } else { - return bigInt__default['default'].zero; - } - } - } - - shr(a, b) { - if (b.lt(this.bitLength)) { - return a.shiftRight(b); - } else { - const nb = this.p.minus(b); - if (nb.lt(this.bitLength)) { - return this.shl(a, nb); - } else { - return bigInt__default['default'].zero; - } - } - } - - land(a, b) { - return (a.isZero() || b.isZero()) ? bigInt__default['default'].zero : bigInt__default['default'].one; - } - - lor(a, b) { - return (a.isZero() && b.isZero()) ? bigInt__default['default'].zero : bigInt__default['default'].one; - } - - lnot(a) { - return a.isZero() ? bigInt__default['default'].one : bigInt__default['default'].zero; - } - - sqrt_old(n) { - - if (n.equals(this.zero)) return this.zero; - - // Test that have solution - const res = this.pow(n, this.negone.shiftRight(this.one)); - if (!res.equals(this.one)) return null; - - let m = parseInt(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).shiftRight(this.one) ); - - while (!t.equals(this.one)) { - let sq = this.square(t); - let i = 1; - while (!sq.equals(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.greater(this.p.shiftRight(this.one))) { - r = this.neg(r); - } - - return r; - } - - normalize(a) { - a = bigInt__default['default'](a); - if (a.isNegative()) { - return this.p.minus(a.abs().mod(this.p)); - } else { - return a.mod(this.p); - } - } - - random() { - let res = bigInt__default['default'](0); - let n = bigInt__default['default'](this.p.square()); - while (!n.isZero()) { - res = res.shiftLeft(8).add(bigInt__default['default'](getRandomBytes(1)[0])); - n = n.shiftRight(8); - } - return res.mod(this.p); - } - - toString(a, base) { - let vs; - if (!a.lesserOrEquals(this.p.shiftRight(bigInt__default['default'](1)))) { - const v = this.p.minus(a); - vs = "-"+v.toString(base); - } else { - vs = a.toString(base); - } - - return vs; - } - - isZero(a) { - return a.isZero(); - } - - fromRng(rng) { - let v; - do { - v = bigInt__default['default'](0); - for (let i=0; i. -*/ - -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]; - } - -} - -/* - 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 . -*/ - -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]; - } - -} - -/* - 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 . -*/ - - -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; - } - } - - -} - -/* global BigInt */ - -function stringifyBigInts$2(o) { - if ((typeof(o) == "bigint") || o.eq !== undefined) { - return o.toString(10); - } else if (o instanceof Uint8Array) { - return fromRprLE(o, 0); - } else if (Array.isArray(o)) { - return o.map(stringifyBigInts$2); - } else if (typeof o == "object") { - const res = {}; - const keys = Object.keys(o); - keys.forEach( (k) => { - res[k] = stringifyBigInts$2(o[k]); - }); - return res; - } else { - return o; - } -} - -function unstringifyBigInts$2(o) { - if ((typeof(o) == "string") && (/^[0-9]+$/.test(o) )) { - return BigInt(o); - } else if (Array.isArray(o)) { - return o.map(unstringifyBigInts$2); - } else if (typeof o == "object") { - if (o===null) return null; - const res = {}; - const keys = Object.keys(o); - keys.forEach( (k) => { - res[k] = unstringifyBigInts$2(o[k]); - }); - return res; - } else { - return o; - } -} - -function beBuff2int$2(buff) { - let res = 0n; - let i = buff.length; - let offset = 0; - const buffV = new DataView(buff.buffer, buff.byteOffset, buff.byteLength); - while (i>0) { - if (i >= 4) { - i -= 4; - res += BigInt(buffV.getUint32(i)) << BigInt(offset*8); - offset += 4; - } else if (i >= 2) { - i -= 2; - res += BigInt(buffV.getUint16(i)) << BigInt(offset*8); - offset += 2; - } else { - i -= 1; - res += BigInt(buffV.getUint8(i)) << BigInt(offset*8); - offset += 1; - } - } - return res; -} - -function beInt2Buff$2(n, len) { - let r = n; - const buff = new Uint8Array(len); - const buffV = new DataView(buff.buffer); - let o = len; - while (o > 0) { - if (o-4 >= 0) { - o -= 4; - buffV.setUint32(o, Number(r & 0xFFFFFFFFn)); - r = r >> 32n; - } else if (o-2 >= 0) { - o -= 2; - buffV.setUint16(o, Number(r & 0xFFFFn)); - r = r >> 16n; - } else { - o -= 1; - buffV.setUint8(o, Number(r & 0xFFn)); - r = r >> 8n; - } - } - if (r) { - throw new Error("Number does not fit in this length"); - } - return buff; -} - - -function leBuff2int$2(buff) { - let res = 0n; - let i = 0; - const buffV = new DataView(buff.buffer, buff.byteOffset, buff.byteLength); - while (i> 32n; - } else if (o+2 <= len) { - buffV.setUint16(Number(o, r & 0xFFFFn), true ); - o += 2; - r = r >> 16n; - } else { - buffV.setUint8(Number(o, r & 0xFFn), true ); - o += 1; - r = r >> 8n; - } - } - if (r) { - throw new Error("Number does not fit in this length"); - } - return buff; -} - -var utils_native = /*#__PURE__*/Object.freeze({ - __proto__: null, - stringifyBigInts: stringifyBigInts$2, - unstringifyBigInts: unstringifyBigInts$2, - beBuff2int: beBuff2int$2, - beInt2Buff: beInt2Buff$2, - leBuff2int: leBuff2int$2, - leInt2Buff: leInt2Buff$2 -}); - -function stringifyBigInts$1(o) { - if ((typeof(o) == "bigint") || o.eq !== undefined) { - return o.toString(10); - } else if (Array.isArray(o)) { - return o.map(stringifyBigInts$1); - } else if (typeof o == "object") { - const res = {}; - const keys = Object.keys(o); - keys.forEach( (k) => { - res[k] = stringifyBigInts$1(o[k]); - }); - return res; - } else { - return o; - } -} - -function unstringifyBigInts$1(o) { - if ((typeof(o) == "string") && (/^[0-9]+$/.test(o) )) { - return bigInt__default['default'](o); - } else if (Array.isArray(o)) { - return o.map(unstringifyBigInts$1); - } else if (typeof o == "object") { - const res = {}; - const keys = Object.keys(o); - keys.forEach( (k) => { - res[k] = unstringifyBigInts$1(o[k]); - }); - return res; - } else { - return o; - } -} - -function beBuff2int$1(buff) { - let res = bigInt__default['default'].zero; - for (let i=0; i=0)) { - let c = Number(r.and(bigInt__default['default']("255"))); - buff[o] = c; - o--; - r = r.shiftRight(8); - } - if (!r.eq(bigInt__default['default'].zero)) { - throw new Error("Number does not fit in this length"); - } - return buff; -} - - -function leBuff2int$1 (buff) { - let res = bigInt__default['default'].zero; - for (let i=0; i>=1; - } - return res; -} - -utils$1.bitReverse = function bitReverse(idx, bits) { - return ( - _revTable[idx >>> 24] | - (_revTable[(idx >>> 16) & 0xFF] << 8) | - (_revTable[(idx >>> 8) & 0xFF] << 16) | - (_revTable[idx & 0xFF] << 24) - ) >>> (32-bits); -}; - - -utils$1.log2 = function log2( V ) -{ - return( ( ( V & 0xFFFF0000 ) !== 0 ? ( V &= 0xFFFF0000, 16 ) : 0 ) | ( ( V & 0xFF00FF00 ) !== 0 ? ( V &= 0xFF00FF00, 8 ) : 0 ) | ( ( V & 0xF0F0F0F0 ) !== 0 ? ( V &= 0xF0F0F0F0, 4 ) : 0 ) | ( ( V & 0xCCCCCCCC ) !== 0 ? ( V &= 0xCCCCCCCC, 2 ) : 0 ) | ( ( V & 0xAAAAAAAA ) !== 0 ) ); -}; - -utils$1.buffReverseBits = function buffReverseBits(buff, eSize) { - const n = buff.byteLength /eSize; - const bits = utils$1.log2(n); - if (n != (1 << bits)) { - throw new Error("Invalid number of pointers"); - } - for (let i=0; ir) { - const tmp = buff.slice(i*eSize, (i+1)*eSize); - buff.set( buff.slice(r*eSize, (r+1)*eSize), i*eSize); - buff.set(tmp, r*eSize); - } - } -}; - -let { - bitReverse, - log2, - buffReverseBits, - stringifyBigInts, - unstringifyBigInts, - beBuff2int, - beInt2Buff, - leBuff2int, - leInt2Buff, -} = utils$1; - -var _utils = /*#__PURE__*/Object.freeze({ - __proto__: null, - bitReverse: bitReverse, - log2: log2, - buffReverseBits: buffReverseBits, - stringifyBigInts: stringifyBigInts, - unstringifyBigInts: unstringifyBigInts, - beBuff2int: beBuff2int, - beInt2Buff: beInt2Buff, - leBuff2int: leBuff2int, - leInt2Buff: leInt2Buff -}); - -const PAGE_SIZE = 1<<30; - -class BigBuffer { - - constructor(size) { - this.buffers = []; - this.byteLength = size; - for (let i=0; i0) { - // bytes to copy from this page - const l = (o+r > PAGE_SIZE) ? (PAGE_SIZE -o) : r; - const srcView = new Uint8Array(this.buffers[p].buffer, this.buffers[p].byteOffset+o, l); - if (l == len) return srcView.slice(); - if (!buff) { - if (len <= PAGE_SIZE) { - buff = new Uint8Array(len); - } else { - buff = new BigBuffer(len); - } - } - buff.set(srcView, len-r); - r = r-l; - p ++; - o = 0; - } - - 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) - return this.buffers[firstPage].set(buff, offset % PAGE_SIZE); - - - let p = firstPage; - let o = offset % PAGE_SIZE; - let r = len; - while (r>0) { - const l = (o+r > PAGE_SIZE) ? (PAGE_SIZE -o) : r; - const srcView = buff.slice( len -r, len -r+l); - const dstView = new Uint8Array(this.buffers[p].buffer, this.buffers[p].byteOffset + o, l); - dstView.set(srcView); - r = r-l; - p ++; - o = 0; - } - - } -} - -function buildBatchConvert(tm, fnName, sIn, sOut) { - return async function batchConvert(buffIn) { - const nPoints = Math.floor(buffIn.byteLength / sIn); - if ( nPoints * sIn !== buffIn.byteLength) { - throw new Error("Invalid buffer size"); - } - const pointsPerChunk = Math.floor(nPoints/tm.concurrency); - const opPromises = []; - for (let i=0; i=0; i--) { - this.w[i] = this.square(this.w[i+1]); - } - - if (!this.eq(this.w[0], this.one)) { - throw new Error("Error calculating roots of unity"); - } - - this.batchToMontgomery = buildBatchConvert(tm, prefix + "_batchToMontgomery", this.n8, this.n8); - this.batchFromMontgomery = buildBatchConvert(tm, prefix + "_batchFromMontgomery", this.n8, this.n8); - } - - - op2(opName, a, b) { - this.tm.setBuff(this.pOp1, a); - this.tm.setBuff(this.pOp2, b); - this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp2, this.pOp3); - return this.tm.getBuff(this.pOp3, this.n8); - } - - op2Bool(opName, a, b) { - this.tm.setBuff(this.pOp1, a); - this.tm.setBuff(this.pOp2, b); - return !!this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp2); - } - - op1(opName, a) { - this.tm.setBuff(this.pOp1, a); - this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp3); - return this.tm.getBuff(this.pOp3, this.n8); - } - - op1Bool(opName, a) { - this.tm.setBuff(this.pOp1, a); - return !!this.tm.instance.exports[this.prefix + opName](this.pOp1, this.pOp3); - } - - add(a,b) { - return this.op2("_add", a, b); - } - - - eq(a,b) { - return this.op2Bool("_eq", a, b); - } - - isZero(a) { - return this.op1Bool("_isZero", a); - } - - sub(a,b) { - return this.op2("_sub", a, b); - } - - neg(a) { - return this.op1("_neg", a); - } - - inv(a) { - return this.op1("_inverse", a); - } - - toMontgomery(a) { - return this.op1("_toMontgomery", a); - } - - fromMontgomery(a) { - return this.op1("_fromMontgomery", a); - } - - mul(a,b) { - return this.op2("_mul", a, b); - } - - div(a, b) { - this.tm.setBuff(this.pOp1, a); - this.tm.setBuff(this.pOp2, b); - this.tm.instance.exports[this.prefix + "_inverse"](this.pOp2, this.pOp2); - this.tm.instance.exports[this.prefix + "_mul"](this.pOp1, this.pOp2, this.pOp3); - return this.tm.getBuff(this.pOp3, this.n8); - } - - square(a) { - return this.op1("_square", a); - } - - isSquare(a) { - return this.op1Bool("_isSquare", a); - } - - sqrt(a) { - return this.op1("_sqrt", a); - } - - exp(a, b) { - if (!(b instanceof Uint8Array)) { - b = toLEBuff(e(b)); - } - this.tm.setBuff(this.pOp1, a); - this.tm.setBuff(this.pOp2, b); - this.tm.instance.exports[this.prefix + "_exp"](this.pOp1, this.pOp2, b.byteLength, this.pOp3); - return this.tm.getBuff(this.pOp3, this.n8); - } - - isNegative(a) { - return this.op1Bool("_isNegative", a); - } - - e(a, b) { - if (a instanceof Uint8Array) return a; - let ra = e(a, b); - if (isNegative(ra)) { - ra = neg(ra); - if (gt(ra, this.p)) { - ra = mod(ra, this.p); - } - ra = sub(this.p, ra); - } else { - if (gt(ra, this.p)) { - ra = mod(ra, this.p); - } - } - const buff = leInt2Buff(ra, this.n8); - return this.toMontgomery(buff); - } - - toString(a, radix) { - const an = this.fromMontgomery(a); - const s = fromRprLE(an, 0); - return toString(s, radix); - } - - fromRng(rng) { - let v; - const buff = new Uint8Array(this.n8); - do { - v = zero; - for (let i=0; i memory.buffer.byteLength) { - const currentPages = memory.buffer.byteLength / 0x10000; - let requiredPages = Math.floor((u32[0] + length) / 0x10000)+1; - if (requiredPages>MAXMEM) requiredPages=MAXMEM; - memory.grow(requiredPages-currentPages); - } - return res; - } - - function allocBuffer(buffer) { - const p = alloc(buffer.byteLength); - setBuffer(p, buffer); - return p; - } - - function getBuffer(pointer, length) { - const u8 = new Uint8Array(memory.buffer); - return new Uint8Array(u8.buffer, u8.byteOffset + pointer, length); - } - - function setBuffer(pointer, buffer) { - const u8 = new Uint8Array(memory.buffer); - u8.set(new Uint8Array(buffer), pointer); - } - - function runTask(task) { - if (task[0].cmd == "INIT") { - return init(task[0]); - } - const ctx = { - vars: [], - out: [] - }; - const u32a = new Uint32Array(memory.buffer, 0, 1); - const oldAlloc = u32a[0]; - for (let i=0; i. -*/ - -// const MEM_SIZE = 1000; // Memory size in 64K Pakes (512Mb) -const MEM_SIZE = 25; // Memory size in 64K Pakes (1600Kb) - -class Deferred { - constructor() { - this.promise = new Promise((resolve, reject)=> { - this.reject = reject; - this.resolve = resolve; - }); - } -} - -function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); -} - -function base64ToArrayBuffer(base64) { - if (process.browser) { - var binary_string = window.atob(base64); - var len = binary_string.length; - var bytes = new Uint8Array(len); - for (var i = 0; i < len; i++) { - bytes[i] = binary_string.charCodeAt(i); - } - return bytes; - } else { - return new Uint8Array(Buffer.from(base64, "base64")); - } -} - -function stringToBase64(str) { - if (process.browser) { - return window.btoa(str); - } else { - return Buffer.from(str).toString("base64"); - } -} - -const threadSource = stringToBase64("(" + thread.toString() + ")(self)"); -const workerSource = "data:application/javascript;base64," + threadSource; - - - -async function buildThreadManager(wasm, singleThread) { - const tm = new ThreadManager(); - - tm.memory = new WebAssembly.Memory({initial:MEM_SIZE}); - tm.u8 = new Uint8Array(tm.memory.buffer); - tm.u32 = new Uint32Array(tm.memory.buffer); - - const wasmModule = await WebAssembly.compile(base64ToArrayBuffer(wasm.code)); - - tm.instance = await WebAssembly.instantiate(wasmModule, { - env: { - "memory": tm.memory - } - }); - - tm.singleThread = singleThread; - tm.initalPFree = tm.u32[0]; // Save the Pointer to free space. - tm.pq = wasm.pq; - tm.pr = wasm.pr; - tm.pG1gen = wasm.pG1gen; - tm.pG1zero = wasm.pG1zero; - tm.pG2gen = wasm.pG2gen; - tm.pG2zero = wasm.pG2zero; - tm.pOneT = wasm.pOneT; - - // tm.pTmp0 = tm.alloc(curve.G2.F.n8*3); - // tm.pTmp1 = tm.alloc(curve.G2.F.n8*3); - - - if (singleThread) { - tm.code = base64ToArrayBuffer(wasm.code); - tm.taskManager = thread(); - await tm.taskManager([{ - cmd: "INIT", - init: MEM_SIZE, - code: tm.code.slice() - }]); - tm.concurrency = 1; - } else { - tm.workers = []; - tm.pendingDeferreds = []; - tm.working = []; - - let concurrency; - - if ((typeof(navigator) === "object") && navigator.hardwareConcurrency) { - concurrency = navigator.hardwareConcurrency; - } else { - concurrency = os__default['default'].cpus().length; - } - // Limit to 64 threads for memory reasons. - if (concurrency>64) concurrency=64; - tm.concurrency = concurrency; - - for (let i = 0; i 0); i++) { - if (this.working[i] == false) { - const work = this.actionQueue.shift(); - this.postAction(i, work.data, work.transfers, work.deferred); - } - } - } - - queueAction(actionData, transfers) { - const d = new Deferred(); - - if (this.singleThread) { - const res = this.taskManager(actionData); - d.resolve(res); - } else { - this.actionQueue.push({ - data: actionData, - transfers: transfers, - deferred: d - }); - this.processWorks(); - } - return d.promise; - } - - resetMemory() { - this.u32[0] = this.initalPFree; - } - - allocBuff(buff) { - const pointer = this.alloc(buff.byteLength); - this.setBuff(pointer, buff); - return pointer; - } - - getBuff(pointer, length) { - return this.u8.slice(pointer, pointer+ length); - } - - setBuff(pointer, buffer) { - this.u8.set(new Uint8Array(buffer), pointer); - } - - alloc(length) { - while (this.u32[0] & 3) this.u32[0]++; // Return always aligned pointers - const res = this.u32[0]; - this.u32[0] += length; - return res; - } - - async terminate() { - for (let i=0; i=0; i--) { - if (!G.isZero(res)) { - for (let j=0; jMAX_CHUNK_SIZE) chunkSize = MAX_CHUNK_SIZE; - if (chunkSize { - if (logger) logger.debug(`Multiexp end: ${logText}: ${i}/${nPoints}`); - return r; - })); - } - - const result = await Promise.all(opPromises); - - let res = G.zero; - for (let i=result.length-1; i>=0; i--) { - res = G.add(res, result[i]); - } +/* global BigInt */ +function stringifyBigInts$2(o) { + if ((typeof(o) == "bigint") || o.eq !== undefined) { + return o.toString(10); + } else if (o instanceof Uint8Array) { + return fromRprLE(o, 0); + } else if (Array.isArray(o)) { + return o.map(stringifyBigInts$2); + } else if (typeof o == "object") { + const res = {}; + const keys = Object.keys(o); + keys.forEach( (k) => { + res[k] = stringifyBigInts$2(o[k]); + }); return res; + } else { + return o; } - - 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 = curve.array2buffer(buff, sIn); - returnArray = true; - } - - 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 curve.buffer2array(buffOut, sOut); - } else { - return buffOut; - } - } - - let inv; - if (inverse) { - inv = Fr.inv(Fr.e(nPoints)); - } - - let buffOut; - - buffReverseBits(buff, sIn); - - let chunks; - let pointsInChunk = Math.min(1 << MAX_BITS_THREAD, nPoints); - let nChunks = nPoints / pointsInChunk; - - while ((nChunks < tm.concurrency)&&(pointsInChunk>=16)) { - nChunks *= 2; - pointsInChunk /= 2; - } - - const l2Chunk = log2(pointsInChunk); - - const promises = []; - for (let i = 0; i< nChunks; i++) { - if (logger) logger.debug(`${loggerTxt}: fft ${bits} mix start: ${i}/${nChunks}`); - const task = []; - task.push({cmd: "ALLOC", var: 0, len: sMid*pointsInChunk}); - const buffChunk = buff.slice( (pointsInChunk * i)*sIn, (pointsInChunk * (i+1))*sIn); - task.push({cmd: "SET", var: 0, buff: buffChunk}); - if (fnIn2Mid) { - task.push({cmd: "CALL", fnName:fnIn2Mid, params: [{var:0}, {val: pointsInChunk}, {var: 0}]}); - } - for (let j=1; j<=l2Chunk;j++) { - task.push({cmd: "CALL", fnName:fnFFTMix, params: [{var:0}, {val: pointsInChunk}, {val: j}]}); - } - - if (l2Chunk==bits) { - if (fnFFTFinal) { - task.push({cmd: "ALLOCSET", var: 1, buff: inv}); - task.push({cmd: "CALL", fnName: fnFFTFinal, params:[ - {var: 0}, - {val: pointsInChunk}, - {var: 1}, - ]}); - } - if (fnMid2Out) { - task.push({cmd: "CALL", fnName:fnMid2Out, params: [{var:0}, {val: pointsInChunk}, {var: 0}]}); - } - task.push({cmd: "GET", out: 0, var: 0, len: pointsInChunk*sOut}); - } else { - task.push({cmd: "GET", out:0, var: 0, len: sMid*pointsInChunk}); - } - promises.push(tm.queueAction(task).then( (r) => { - if (logger) logger.debug(`${loggerTxt}: fft ${bits} mix end: ${i}/${nChunks}`); - return r; - })); - } - - chunks = await Promise.all(promises); - for (let i = 0; i< nChunks; i++) chunks[i] = chunks[i][0]; - - for (let i = l2Chunk+1; i<=bits; i++) { - if (logger) logger.debug(`${loggerTxt}: fft ${bits} join: ${i}/${bits}`); - const nGroups = 1 << (bits - i); - const nChunksPerGroup = nChunks / nGroups; - const opPromises = []; - for (let j=0; j { - if (logger) logger.debug(`${loggerTxt}: fft ${bits} join ${i}/${bits} ${j+1}/${nGroups} ${k}/${nChunksPerGroup/2}`); - return r; - })); - } - } - - const res = await Promise.all(opPromises); - for (let j=0; j0; i--) { - buffOut.set(chunks[i], p); - p += pointsInChunk*sOut; - delete chunks[i]; // Liberate mem - } - buffOut.set(chunks[0].slice(0, (pointsInChunk-1)*sOut), p); - delete chunks[0]; - } else { - for (let i=0; i (1<<28)) { - buffOut = new BigBuffer(res1[0].byteLength*2); - } else { - buffOut = new Uint8Array(res1[0].byteLength*2); - } - - buffOut.set(res1[0]); - buffOut.set(res1[1], res1[0].byteLength); - - return buffOut; - } - - async function _fftExtInv(buff, inType, outType, logger, loggerTxt) { - let b1, b2; - b1 = buff.slice( 0 , buff.byteLength/2); - b2 = buff.slice( buff.byteLength/2, buff.byteLength); - - const promises = []; - - promises.push( _fft(b1, true, inType, "jacobian", logger, loggerTxt)); - promises.push( _fft(b2, true, inType, "jacobian", logger, loggerTxt)); - - [b1, b2] = await Promise.all(promises); - - const res1 = await _fftJoinExt(b1, b2, "fftJoinExtInv", Fr.one, Fr.shiftInv, "jacobian", outType, logger, loggerTxt); - - let buffOut; - if (res1[0].byteLength > (1<<28)) { - buffOut = new BigBuffer(res1[0].byteLength*2); - } else { - buffOut = new Uint8Array(res1[0].byteLength*2); - } - - buffOut.set(res1[0]); - buffOut.set(res1[1], res1[0].byteLength); - - return buffOut; - } - - - async function _fftJoinExt(buff1, buff2, fn, first, inc, inType, outType, logger, loggerTxt) { - const MAX_CHUNK_SIZE = 1<<16; - const MIN_CHUNK_SIZE = 1<<4; - - let fnName; - let fnIn2Mid, fnMid2Out; - let sOut, sIn, sMid; - - if (groupName == "G1") { - if (inType == "affine") { - sIn = G.F.n8*2; - fnIn2Mid = "g1m_batchToJacobian"; - } else { - sIn = G.F.n8*3; - } - sMid = G.F.n8*3; - fnName = "g1m_"+fn; - if (outType == "affine") { - fnMid2Out = "g1m_batchToAffine"; - sOut = G.F.n8*2; - } else { - sOut = G.F.n8*3; - } - } else if (groupName == "G2") { - if (inType == "affine") { - sIn = G.F.n8*2; - fnIn2Mid = "g2m_batchToJacobian"; - } else { - sIn = G.F.n8*3; - } - fnName = "g2m_"+fn; - sMid = G.F.n8*3; - if (outType == "affine") { - fnMid2Out = "g2m_batchToAffine"; - sOut = G.F.n8*2; - } else { - sOut = G.F.n8*3; - } - } else if (groupName == "Fr") { - sIn = Fr.n8; - sOut = Fr.n8; - sMid = Fr.n8; - fnName = "frm_" + fn; - } else { - throw new Error("Invalid group"); - } - - if (buff1.byteLength != buff2.byteLength) { - throw new Error("Invalid buffer size"); - } - const nPoints = Math.floor(buff1.byteLength / sIn); - if (nPoints != 1 << log2(nPoints)) { - throw new Error("Invalid number of points"); - } - - let chunkSize = Math.floor(nPoints /tm.concurrency); - if (chunkSize < MIN_CHUNK_SIZE) chunkSize = MIN_CHUNK_SIZE; - if (chunkSize > MAX_CHUNK_SIZE) chunkSize = MAX_CHUNK_SIZE; - - const opPromises = []; - - for (let i=0; i { - if (logger) logger.debug(`${loggerTxt}: fftJoinExt End: ${i}/${nPoints}`); - return r; - }) - ); - } - - const result = await Promise.all(opPromises); - - let fullBuffOut1; - let fullBuffOut2; - if (nPoints * sOut > 1<<28) { - fullBuffOut1 = new BigBuffer(nPoints*sOut); - fullBuffOut2 = new BigBuffer(nPoints*sOut); - } else { - fullBuffOut1 = new Uint8Array(nPoints*sOut); - fullBuffOut2 = new Uint8Array(nPoints*sOut); - } - - let p =0; - for (let i=0; i { + res[k] = unstringifyBigInts$2(o[k]); + }); + return res; + } else { + return o; } +} - - 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; i0) { + 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 { - throw new Error("Invalid group"); - } - - const nPoints = Math.floor(buff.byteLength / sG); - if (nPoints != 1 << log2(nPoints)) { - throw new Error("Invalid number of points"); + i -= 1; + res += BigInt(buffV.getUint8(i)) << BigInt(offset*8); + offset += 1; } + } + return res; +} - const pointsPerChunk = Math.floor(nPoints / tm.concurrency); - - const opPromises = []; - for (let i=0; i 0) { + if (o-4 >= 0) { + o -= 4; + buffV.setUint32(o, Number(r & BigInt(0xFFFFFFFF))); + r = r >> BigInt(32); + } else if (o-2 >= 0) { + o -= 2; + buffV.setUint16(o, Number(r & BigInt(0xFFFF))); + r = r >> BigInt(16); + } else { + o -= 1; + buffV.setUint8(o, Number(r & BigInt(0xFF))); + r = r >> BigInt(8); } + } + if (r) { + throw new Error("Number does not fit in this length"); + } + return buff; +} - const result = await Promise.all(opPromises); - let fullBuffOut; - if (buff instanceof BigBuffer) { - fullBuffOut = new BigBuffer(nPoints*sGout); +function leBuff2int$2(buff) { + let res = BigInt(0); + let i = 0; + const buffV = new DataView(buff.buffer, buff.byteOffset, buff.byteLength); + while (i=0; i--) { - fullBuffOut.set(result[i][0], p); - p+=result[i][0].byteLength; + res += BigInt(buffV.getUint8(i, true)) << BigInt( i*8); + i += 1; } - - return fullBuffOut; - }; + } + return res; } -async function buildEngine(params) { - - const tm = await buildThreadManager(params.wasm, params.singleThread); - - - const curve = {}; - - curve.q = e(params.wasm.q); - curve.r = e(params.wasm.r); - curve.name = params.name; - curve.tm = tm; - curve.prePSize = params.wasm.prePSize; - curve.preQSize = params.wasm.preQSize; - curve.Fr = new WasmField1(tm, "frm", params.n8r, params.r); - curve.F1 = new WasmField1(tm, "f1m", params.n8q, params.q); - curve.F2 = new WasmField2(tm, "f2m", curve.F1); - curve.G1 = new WasmCurve(tm, "g1m", curve.F1, params.wasm.pG1gen, params.wasm.pG1b, params.cofactorG1); - curve.G2 = new WasmCurve(tm, "g2m", curve.F2, params.wasm.pG2gen, params.wasm.pG2b, params.cofactorG2); - curve.F6 = new WasmField3(tm, "f6m", curve.F2); - curve.F12 = new WasmField2(tm, "ftm", curve.F6); - - curve.Gt = curve.F12; - - buildBatchApplyKey(curve, "G1"); - buildBatchApplyKey(curve, "G2"); - buildBatchApplyKey(curve, "Fr"); - - buildMultiexp(curve, "G1"); - buildMultiexp(curve, "G2"); - - buildFFT(curve, "G1"); - buildFFT(curve, "G2"); - buildFFT(curve, "Fr"); - - buildPairing(curve); - - curve.array2buffer = function(arr, sG) { - const buff = new Uint8Array(sG*arr.length); - - for (let i=0; i> BigInt(32); + } else if (o+2 <= len) { + buffV.setUint16(Number(o, r & BigInt(0xFFFF)), true ); + o += 2; + r = r >> BigInt(16); + } else { + buffV.setUint8(Number(o, r & BigInt(0xFF)), true ); + o += 1; + r = r >> BigInt(8); } + } + if (r) { + throw new Error("Number does not fit in this length"); + } + return buff; +} - return buff; - }; - - curve.buffer2array = function(buff , sG) { - const n= buff.byteLength / sG; - const arr = new Array(n); - for (let i=0; i { + res[k] = stringifyBigInts$1(o[k]); + }); + return res; + } else { + return o; + } } -global.curve_bn128 = null; +function unstringifyBigInts$1(o) { + if ((typeof(o) == "string") && (/^[0-9]+$/.test(o) )) { + return bigInt__default['default'](o); + } else if (Array.isArray(o)) { + return o.map(unstringifyBigInts$1); + } else if (typeof o == "object") { + const res = {}; + const keys = Object.keys(o); + keys.forEach( (k) => { + res[k] = unstringifyBigInts$1(o[k]); + }); + return res; + } else { + return o; + } +} -async function buildBn128(singleThread) { +function beBuff2int$1(buff) { + let res = bigInt__default['default'].zero; + for (let i=0; i=0)) { + let c = Number(r.and(bigInt__default['default']("255"))); + buff[o] = c; + o--; + r = r.shiftRight(8); + } + if (!r.eq(bigInt__default['default'].zero)) { + throw new Error("Number does not fit in this length"); + } + return buff; +} - const curve = await buildEngine(params); - curve.terminate = async function() { - if (!params.singleThread) { - global.curve_bn128 = null; - await this.tm.terminate(); - } - }; - if (!singleThread) { - global.curve_bn128 = curve; +function leBuff2int$1 (buff) { + let res = bigInt__default['default'].zero; + for (let i=0; i>=1; } - return curve; + return res; } -async function getCurveFromName(name, singleThread) { - let curve; - const normName = normalizeName(name); - if (["BN128", "BN254", "ALTBN128"].indexOf(normName) >= 0) { - curve = await buildBn128(singleThread); - } else if (["BLS12381"].indexOf(normName) >= 0) { - curve = await buildBn128(singleThread); - } else { - throw new Error(`Curve not supported: ${name}`); - } - return curve; +utils$1.bitReverse = function bitReverse(idx, bits) { + return ( + _revTable[idx >>> 24] | + (_revTable[(idx >>> 16) & 0xFF] << 8) | + (_revTable[(idx >>> 8) & 0xFF] << 16) | + (_revTable[idx & 0xFF] << 24) + ) >>> (32-bits); +}; + + +utils$1.log2 = function log2( V ) +{ + return( ( ( V & 0xFFFF0000 ) !== 0 ? ( V &= 0xFFFF0000, 16 ) : 0 ) | ( ( V & 0xFF00FF00 ) !== 0 ? ( V &= 0xFF00FF00, 8 ) : 0 ) | ( ( V & 0xF0F0F0F0 ) !== 0 ? ( V &= 0xF0F0F0F0, 4 ) : 0 ) | ( ( V & 0xCCCCCCCC ) !== 0 ? ( V &= 0xCCCCCCCC, 2 ) : 0 ) | ( ( V & 0xAAAAAAAA ) !== 0 ) ); +}; - function normalizeName(n) { - return n.toUpperCase().match(/[A-Za-z0-9]+/g).join(""); +utils$1.buffReverseBits = function buffReverseBits(buff, eSize) { + const n = buff.byteLength /eSize; + const bits = utils$1.log2(n); + if (n != (1 << bits)) { + throw new Error("Invalid number of pointers"); + } + for (let i=0; ir) { + const tmp = buff.slice(i*eSize, (i+1)*eSize); + buff.set( buff.slice(r*eSize, (r+1)*eSize), i*eSize); + buff.set(tmp, r*eSize); + } } +}; -} +let { + bitReverse, + log2, + buffReverseBits, + stringifyBigInts, + unstringifyBigInts, + beBuff2int, + beInt2Buff, + leBuff2int, + leInt2Buff, +} = utils$1; + +var _utils = /*#__PURE__*/Object.freeze({ + __proto__: null, + bitReverse: bitReverse, + log2: log2, + buffReverseBits: buffReverseBits, + stringifyBigInts: stringifyBigInts, + unstringifyBigInts: unstringifyBigInts, + beBuff2int: beBuff2int, + beInt2Buff: beInt2Buff, + leBuff2int: leBuff2int, + leInt2Buff: leInt2Buff +}); -const Scalar=_Scalar; +const Scalar = _Scalar; const utils = _utils; -exports.BigBuffer = BigBuffer; -exports.ChaCha = ChaCha; -exports.EC = EC; -exports.F1Field = F1Field; -exports.F2Field = F2Field; -exports.F3Field = F3Field; -exports.PolField = PolField; exports.Scalar = Scalar; exports.ZqField = F1Field; -exports.buildBls12381 = buildBls12381; -exports.buildBn128 = buildBn128; -exports.getCurveFromName = getCurveFromName; -exports.getCurveFromQ = getCurveFromQ; -exports.getCurveFromR = getCurveFromR; exports.utils = utils; diff --git a/main.js b/main.js index 1981557..3b24310 100644 --- a/main.js +++ b/main.js @@ -1,24 +1,7 @@ +import * as _Scalar from "./src/scalar.js"; +export const Scalar = _Scalar; -import * as _Scalar from "./src/scalar.js"; -export const Scalar=_Scalar; - -export {default as PolField} from "./src/polfield.js"; -export {default as F1Field} from "./src/f1field.js"; -export {default as F2Field} from "./src/f2field.js"; -export {default as F3Field} from "./src/f3field.js"; - -export {default as ZqField} from "./src/f1field.js"; - -export {default as EC} from "./src/ec.js"; - -export {default as buildBn128} from "./src/bn128.js"; -export {default as buildBls12381} from "./src/bls12381.js"; +export { default as ZqField } from "./src/f1field.js"; import * as _utils from "./src/utils.js"; export const utils = _utils; -export {default as ChaCha} from "./src/chacha.js"; - -export {default as BigBuffer} from "./src/bigbuffer.js"; - -export {getCurveFromR, getCurveFromQ, getCurveFromName} from "./src/curves.js"; - diff --git a/src/bigbuffer.js b/src/bigbuffer.js deleted file mode 100644 index 91fb93b..0000000 --- a/src/bigbuffer.js +++ /dev/null @@ -1,82 +0,0 @@ - -const PAGE_SIZE = 1<<30; - -export default class BigBuffer { - - constructor(size) { - this.buffers = []; - this.byteLength = size; - for (let i=0; i0) { - // bytes to copy from this page - const l = (o+r > PAGE_SIZE) ? (PAGE_SIZE -o) : r; - const srcView = new Uint8Array(this.buffers[p].buffer, this.buffers[p].byteOffset+o, l); - if (l == len) return srcView.slice(); - if (!buff) { - if (len <= PAGE_SIZE) { - buff = new Uint8Array(len); - } else { - buff = new BigBuffer(len); - } - } - buff.set(srcView, len-r); - r = r-l; - p ++; - o = 0; - } - - 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) - 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; - } - - } -} diff --git a/src/bls12381.js b/src/bls12381.js deleted file mode 100644 index f7a8e27..0000000 --- a/src/bls12381.js +++ /dev/null @@ -1,32 +0,0 @@ -import wasmcurves from "wasmcurves"; -import buildEngine from "./engine.js"; -import * as Scalar from "./scalar.js"; - -global.curve_bls12381 = null; - -export default async function buildBls12381(singleThread) { - - if ((!singleThread)&&(global.curve_bls12381)) return global.curve_bls12381; - const params = { - name: "bls12381", - wasm: wasmcurves.bls12381_wasm, - q: Scalar.e("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", 16), - r: Scalar.e("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", 16), - n8q: 48, - n8r: 32, - cofactorG1: Scalar.e("0x396c8c005555e1568c00aaab0000aaab", 16), - cofactorG2: Scalar.e("0x5d543a95414e7f1091d50792876a202cd91de4547085abaa68a205b2e5a7ddfa628f1cb4d9e82ef21537e293a6691ae1616ec6e786f0c70cf1c38e31c7238e5", 16), - singleThread: singleThread ? true : false - }; - - const curve = await buildEngine(params); - curve.terminate = async function() { - if (!params.singleThread) { - global.curve_bls12381 = null; - await this.tm.terminate(); - } - }; - - return curve; -} - diff --git a/src/bn128.js b/src/bn128.js deleted file mode 100644 index 90888bf..0000000 --- a/src/bn128.js +++ /dev/null @@ -1,35 +0,0 @@ -import wasmcurves from "wasmcurves"; -import buildEngine from "./engine.js"; -import * as Scalar from "./scalar.js"; - -global.curve_bn128 = null; - -export default async function buildBn128(singleThread) { - - if ((!singleThread)&&(global.curve_bn128)) return global.curve_bn128; - const params = { - name: "bn128", - wasm: wasmcurves.bn128_wasm, - q: Scalar.e("21888242871839275222246405745257275088696311157297823662689037894645226208583"), - r: Scalar.e("21888242871839275222246405745257275088548364400416034343698204186575808495617"), - n8q: 32, - n8r: 32, - cofactorG2: Scalar.e("30644e72e131a029b85045b68181585e06ceecda572a2489345f2299c0f9fa8d", 16), - singleThread: singleThread ? true : false - }; - - const curve = await buildEngine(params); - curve.terminate = async function() { - if (!params.singleThread) { - global.curve_bn128 = null; - await this.tm.terminate(); - } - }; - - if (!singleThread) { - global.curve_bn128 = curve; - } - - return curve; -} - diff --git a/src/curves.js b/src/curves.js deleted file mode 100644 index 806d01f..0000000 --- a/src/curves.js +++ /dev/null @@ -1,51 +0,0 @@ -import * as Scalar from "./scalar.js"; -import {default as buildBn128} from "./bn128.js"; -import {default as buildBls12381} from "./bn128.js"; - -const bls12381r = Scalar.e("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", 16); -const bn128r = Scalar.e("21888242871839275222246405745257275088548364400416034343698204186575808495617"); - -const bls12381q = Scalar.e("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", 16); -const bn128q = Scalar.e("21888242871839275222246405745257275088696311157297823662689037894645226208583"); - -export async function getCurveFromR(r, singleThread) { - let curve; - if (Scalar.eq(r, bn128r)) { - curve = await buildBn128(singleThread); - } else if (Scalar.eq(r, bls12381r)) { - curve = await buildBls12381(singleThread); - } else { - throw new Error(`Curve not supported: ${Scalar.toString(r)}`); - } - return curve; -} - -export async function getCurveFromQ(q, singleThread) { - let curve; - if (Scalar.eq(q, bn128q)) { - curve = await buildBn128(singleThread); - } else if (Scalar.eq(q, bls12381q)) { - curve = await buildBls12381(singleThread); - } else { - throw new Error(`Curve not supported: ${Scalar.toString(q)}`); - } - return curve; -} - -export async function getCurveFromName(name, singleThread) { - let curve; - const normName = normalizeName(name); - if (["BN128", "BN254", "ALTBN128"].indexOf(normName) >= 0) { - curve = await buildBn128(singleThread); - } else if (["BLS12381"].indexOf(normName) >= 0) { - curve = await buildBls12381(singleThread); - } else { - throw new Error(`Curve not supported: ${name}`); - } - return curve; - - function normalizeName(n) { - return n.toUpperCase().match(/[A-Za-z0-9]+/g).join(""); - } - -} diff --git a/src/ec.js b/src/ec.js deleted file mode 100644 index 0559006..0000000 --- a/src/ec.js +++ /dev/null @@ -1,437 +0,0 @@ -/* - 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 . -*/ - - - -import * as fUtils from "./futils.js"; -import * as Scalar from "./scalar.js"; - - -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 Scalar.gt(a, na); - } -} - - -export default 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 fUtils.mulScalar(this, base, e); - } - - mulScalar(base, e) { - return fUtils.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; - } - } - - -} - - diff --git a/src/engine.js b/src/engine.js deleted file mode 100644 index 1f8a25c..0000000 --- a/src/engine.js +++ /dev/null @@ -1,70 +0,0 @@ -import WasmField1 from "./wasm_field1.js"; -import WasmField2 from "./wasm_field2.js"; -import WasmField3 from "./wasm_field3.js"; -import WasmCurve from "./wasm_curve.js"; -import buildThreadManager from "./threadman.js"; -import * as Scalar from "./scalar.js"; -import buildBatchApplyKey from "./engine_applykey.js"; -import buildPairing from "./engine_pairing.js"; -import buildMultiExp from "./engine_multiexp.js"; -import buildFFT from "./engine_fft.js"; - -export default async function buildEngine(params) { - - const tm = await buildThreadManager(params.wasm, params.singleThread); - - - const curve = {}; - - curve.q = Scalar.e(params.wasm.q); - curve.r = Scalar.e(params.wasm.r); - curve.name = params.name; - curve.tm = tm; - curve.prePSize = params.wasm.prePSize; - curve.preQSize = params.wasm.preQSize; - curve.Fr = new WasmField1(tm, "frm", params.n8r, params.r); - curve.F1 = new WasmField1(tm, "f1m", params.n8q, params.q); - curve.F2 = new WasmField2(tm, "f2m", curve.F1); - curve.G1 = new WasmCurve(tm, "g1m", curve.F1, params.wasm.pG1gen, params.wasm.pG1b, params.cofactorG1); - curve.G2 = new WasmCurve(tm, "g2m", curve.F2, params.wasm.pG2gen, params.wasm.pG2b, params.cofactorG2); - curve.F6 = new WasmField3(tm, "f6m", curve.F2); - curve.F12 = new WasmField2(tm, "ftm", curve.F6); - - curve.Gt = curve.F12; - - buildBatchApplyKey(curve, "G1"); - buildBatchApplyKey(curve, "G2"); - buildBatchApplyKey(curve, "Fr"); - - buildMultiExp(curve, "G1"); - buildMultiExp(curve, "G2"); - - buildFFT(curve, "G1"); - buildFFT(curve, "G2"); - buildFFT(curve, "Fr"); - - buildPairing(curve); - - curve.array2buffer = function(arr, sG) { - const buff = new Uint8Array(sG*arr.length); - - for (let i=0; i=16)) { - nChunks *= 2; - pointsInChunk /= 2; - } - - const l2Chunk = log2(pointsInChunk); - - const promises = []; - for (let i = 0; i< nChunks; i++) { - if (logger) logger.debug(`${loggerTxt}: fft ${bits} mix start: ${i}/${nChunks}`); - const task = []; - task.push({cmd: "ALLOC", var: 0, len: sMid*pointsInChunk}); - const buffChunk = buff.slice( (pointsInChunk * i)*sIn, (pointsInChunk * (i+1))*sIn); - task.push({cmd: "SET", var: 0, buff: buffChunk}); - if (fnIn2Mid) { - task.push({cmd: "CALL", fnName:fnIn2Mid, params: [{var:0}, {val: pointsInChunk}, {var: 0}]}); - } - for (let j=1; j<=l2Chunk;j++) { - task.push({cmd: "CALL", fnName:fnFFTMix, params: [{var:0}, {val: pointsInChunk}, {val: j}]}); - } - - if (l2Chunk==bits) { - if (fnFFTFinal) { - task.push({cmd: "ALLOCSET", var: 1, buff: inv}); - task.push({cmd: "CALL", fnName: fnFFTFinal, params:[ - {var: 0}, - {val: pointsInChunk}, - {var: 1}, - ]}); - } - if (fnMid2Out) { - task.push({cmd: "CALL", fnName:fnMid2Out, params: [{var:0}, {val: pointsInChunk}, {var: 0}]}); - } - task.push({cmd: "GET", out: 0, var: 0, len: pointsInChunk*sOut}); - } else { - task.push({cmd: "GET", out:0, var: 0, len: sMid*pointsInChunk}); - } - promises.push(tm.queueAction(task).then( (r) => { - if (logger) logger.debug(`${loggerTxt}: fft ${bits} mix end: ${i}/${nChunks}`); - return r; - })); - } - - chunks = await Promise.all(promises); - for (let i = 0; i< nChunks; i++) chunks[i] = chunks[i][0]; - - for (let i = l2Chunk+1; i<=bits; i++) { - if (logger) logger.debug(`${loggerTxt}: fft ${bits} join: ${i}/${bits}`); - const nGroups = 1 << (bits - i); - const nChunksPerGroup = nChunks / nGroups; - const opPromises = []; - for (let j=0; j { - if (logger) logger.debug(`${loggerTxt}: fft ${bits} join ${i}/${bits} ${j+1}/${nGroups} ${k}/${nChunksPerGroup/2}`); - return r; - })); - } - } - - const res = await Promise.all(opPromises); - for (let j=0; j0; i--) { - buffOut.set(chunks[i], p); - p += pointsInChunk*sOut; - delete chunks[i]; // Liberate mem - } - buffOut.set(chunks[0].slice(0, (pointsInChunk-1)*sOut), p); - delete chunks[0]; - } else { - for (let i=0; i (1<<28)) { - buffOut = new BigBuffer(res1[0].byteLength*2); - } else { - buffOut = new Uint8Array(res1[0].byteLength*2); - } - - buffOut.set(res1[0]); - buffOut.set(res1[1], res1[0].byteLength); - - return buffOut; - } - - async function _fftExtInv(buff, inType, outType, logger, loggerTxt) { - let b1, b2; - b1 = buff.slice( 0 , buff.byteLength/2); - b2 = buff.slice( buff.byteLength/2, buff.byteLength); - - const promises = []; - - promises.push( _fft(b1, true, inType, "jacobian", logger, loggerTxt)); - promises.push( _fft(b2, true, inType, "jacobian", logger, loggerTxt)); - - [b1, b2] = await Promise.all(promises); - - const res1 = await _fftJoinExt(b1, b2, "fftJoinExtInv", Fr.one, Fr.shiftInv, "jacobian", outType, logger, loggerTxt); - - let buffOut; - if (res1[0].byteLength > (1<<28)) { - buffOut = new BigBuffer(res1[0].byteLength*2); - } else { - buffOut = new Uint8Array(res1[0].byteLength*2); - } - - buffOut.set(res1[0]); - buffOut.set(res1[1], res1[0].byteLength); - - return buffOut; - } - - - async function _fftJoinExt(buff1, buff2, fn, first, inc, inType, outType, logger, loggerTxt) { - const MAX_CHUNK_SIZE = 1<<16; - const MIN_CHUNK_SIZE = 1<<4; - - let fnName; - let fnIn2Mid, fnMid2Out; - let sOut, sIn, sMid; - - if (groupName == "G1") { - if (inType == "affine") { - sIn = G.F.n8*2; - fnIn2Mid = "g1m_batchToJacobian"; - } else { - sIn = G.F.n8*3; - } - sMid = G.F.n8*3; - fnName = "g1m_"+fn; - if (outType == "affine") { - fnMid2Out = "g1m_batchToAffine"; - sOut = G.F.n8*2; - } else { - sOut = G.F.n8*3; - } - } else if (groupName == "G2") { - if (inType == "affine") { - sIn = G.F.n8*2; - fnIn2Mid = "g2m_batchToJacobian"; - } else { - sIn = G.F.n8*3; - } - fnName = "g2m_"+fn; - sMid = G.F.n8*3; - if (outType == "affine") { - fnMid2Out = "g2m_batchToAffine"; - sOut = G.F.n8*2; - } else { - sOut = G.F.n8*3; - } - } else if (groupName == "Fr") { - sIn = Fr.n8; - sOut = Fr.n8; - sMid = Fr.n8; - fnName = "frm_" + fn; - } else { - throw new Error("Invalid group"); - } - - if (buff1.byteLength != buff2.byteLength) { - throw new Error("Invalid buffer size"); - } - const nPoints = Math.floor(buff1.byteLength / sIn); - if (nPoints != 1 << log2(nPoints)) { - throw new Error("Invalid number of points"); - } - - let chunkSize = Math.floor(nPoints /tm.concurrency); - if (chunkSize < MIN_CHUNK_SIZE) chunkSize = MIN_CHUNK_SIZE; - if (chunkSize > MAX_CHUNK_SIZE) chunkSize = MAX_CHUNK_SIZE; - - const opPromises = []; - - for (let i=0; i { - if (logger) logger.debug(`${loggerTxt}: fftJoinExt End: ${i}/${nPoints}`); - return r; - }) - ); - } - - const result = await Promise.all(opPromises); - - let fullBuffOut1; - let fullBuffOut2; - if (nPoints * sOut > 1<<28) { - fullBuffOut1 = new BigBuffer(nPoints*sOut); - fullBuffOut2 = new BigBuffer(nPoints*sOut); - } else { - fullBuffOut1 = new Uint8Array(nPoints*sOut); - fullBuffOut2 = new Uint8Array(nPoints*sOut); - } - - let p =0; - for (let i=0; i Fr.s+1) { - if (logger) logger.error("lagrangeEvaluations input too big"); - throw new Error("lagrangeEvaluations input too big"); - } - - let t0 = buff.slice(0, buff.byteLength/2); - let t1 = buff.slice(buff.byteLength/2, buff.byteLength); - - - const shiftToSmallM = Fr.exp(Fr.shift, nPoints/2); - const sConst = Fr.inv( Fr.sub(Fr.one, shiftToSmallM)); - - [t0, t1] = await _fftJoinExt(t0, t1, "prepareLagrangeEvaluation", sConst, Fr.shiftInv, inType, "jacobian", logger, loggerTxt + " prep"); - - const promises = []; - - promises.push( _fft(t0, true, "jacobian", outType, logger, loggerTxt + " t0")); - promises.push( _fft(t1, true, "jacobian", outType, logger, loggerTxt + " t1")); - - [t0, t1] = await Promise.all(promises); - - let buffOut; - if (t0.byteLength > (1<<28)) { - buffOut = new BigBuffer(t0.byteLength*2); - } else { - buffOut = new Uint8Array(t0.byteLength*2); - } - - buffOut.set(t0); - buffOut.set(t1, t0.byteLength); - - return buffOut; - }; - - G.fftMix = async function fftMix(buff) { - const sG = G.F.n8*3; - let fnName, fnFFTJoin; - if (groupName == "G1") { - fnName = "g1m_fftMix"; - fnFFTJoin = "g1m_fftJoin"; - } else if (groupName == "G2") { - fnName = "g2m_fftMix"; - fnFFTJoin = "g2m_fftJoin"; - } else if (groupName == "Fr") { - fnName = "frm_fftMix"; - fnFFTJoin = "frm_fftJoin"; - } else { - throw new Error("Invalid group"); - } - - const nPoints = Math.floor(buff.byteLength / sG); - const power = log2(nPoints); - - let nChunks = 1 << log2(tm.concurrency); - - if (nPoints <= nChunks*2) nChunks = 1; - - const pointsPerChunk = nPoints / nChunks; - - const powerChunk = log2(pointsPerChunk); - - const opPromises = []; - for (let i=0; i=0; i--) { - fullBuffOut.set(result[i][0], p); - p+=result[i][0].byteLength; - } - - return fullBuffOut; - }; -} diff --git a/src/engine_multiexp.js b/src/engine_multiexp.js deleted file mode 100644 index 3db5ac4..0000000 --- a/src/engine_multiexp.js +++ /dev/null @@ -1,154 +0,0 @@ -import { log2 } from "./utils.js"; - -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 -]; - -export default function buildMultiexp(curve, groupName) { - const G = curve[groupName]; - const tm = G.tm; - async function _multiExpChunk(buffBases, buffScalars, inType, logger, logText) { - if ( ! (buffBases instanceof Uint8Array) ) { - if (logger) logger.error(`${logText} _multiExpChunk buffBases is not Uint8Array`); - 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=0; i--) { - if (!G.isZero(res)) { - for (let j=0; jMAX_CHUNK_SIZE) chunkSize = MAX_CHUNK_SIZE; - if (chunkSize { - if (logger) logger.debug(`Multiexp end: ${logText}: ${i}/${nPoints}`); - return r; - })); - } - - const result = await Promise.all(opPromises); - - let res = G.zero; - for (let i=result.length-1; i>=0; i--) { - res = G.add(res, result[i]); - } - - return res; - } - - G.multiExp = async function multiExpAffine(buffBases, buffScalars, logger, logText) { - return await _multiExp(buffBases, buffScalars, "jacobian", logger, logText); - }; - G.multiExpAffine = async function multiExpAffine(buffBases, buffScalars, logger, logText) { - return await _multiExp(buffBases, buffScalars, "affine", logger, logText); - }; -} diff --git a/src/engine_pairing.js b/src/engine_pairing.js deleted file mode 100644 index 5a802ce..0000000 --- a/src/engine_pairing.js +++ /dev/null @@ -1,130 +0,0 @@ - -export default 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. -*/ - -import * as fUtils from "./futils.js"; -import buildSqrt from "./fsqrt.js"; - -export default 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 fUtils.mulScalar(this, base, e); - } - - pow(base, e) { - return fUtils.exp(this, base, e); - } - - exp(base, e) { - return fUtils.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]; - } - -} - diff --git a/src/f3field.js b/src/f3field.js deleted file mode 100644 index 3df2435..0000000 --- a/src/f3field.js +++ /dev/null @@ -1,281 +0,0 @@ -/* - 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 . -*/ - -import * as fUtils from "./futils.js"; - -export default 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 fUtils.mulScalar(this, base, e); - } - - pow(base, e) { - return fUtils.exp(this, base, e); - } - - exp(base, e) { - return fUtils.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]; - } - -} diff --git a/src/fft.js b/src/fft.js deleted file mode 100644 index 7e9f8af..0000000 --- a/src/fft.js +++ /dev/null @@ -1,148 +0,0 @@ -/* - 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 . -*/ - -/* - 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 ]. - */ - -export default class FFT { - constructor (G, F, opMulGF) { - this.F = F; - this.G = G; - this.opMulGF = opMulGF; - - let rem = F.sqrt_t; - let s = F.sqrt_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=0) && (!this.roots[i]); i--) { - let r = this.F.one; - const nroots = 1 << i; - const rootsi = new Array(nroots); - for (let j=0; j> 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. -*/ - -/* - 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 ]. - */ - -export default 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 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 a.length) { - [b, a] = [a, b]; - } - - if ((b.length <= 2) || (b.length < log2(a.length))) { - return this.mulNormal(a,b); - } else { - return this.mulFFT(a,b); - } - } - - mulNormal(a, b) { - let res = []; - for (let i=0; i0) { - 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> 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> 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; i0 && 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=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 - // 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(_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(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<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(V); - } -} - -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 __fft(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(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> 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>=1; - } - return res; -} - -function rev(idx, bits) { - return ( - _revTable[idx >>> 24] | - (_revTable[(idx >>> 16) & 0xFF] << 8) | - (_revTable[(idx >>> 8) & 0xFF] << 16) | - (_revTable[idx & 0xFF] << 24) - ) >>> (32-bits); -} - -function __bitReverse(p, bits) { - for (let k=0; kk) { - const tmp= p[k]; - p[k] = p[r]; - p[r] = tmp; - } - } - -} - - diff --git a/src/ratfield.js b/src/ratfield.js deleted file mode 100644 index 512396c..0000000 --- a/src/ratfield.js +++ /dev/null @@ -1,125 +0,0 @@ -/* - 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 . -*/ - -import * as fUtils from "./futils.js"; - -export default class RatField { - constructor(F) { - this.F = F; - this.zero = [F.zero, F.one]; - this.one = [F.one, F.one]; - this.two = [F.two, F.one]; - this.twoinv = [F.one, F.two]; - this.q = F.q; - } - - add(a,b) { - return [ - this.F.add( - this.F.mul(a[0], b[1]), - this.F.mul(a[1], b[0])), - this.F.mul(a[1], b[1])]; - } - - double(a) { - return [this.F.add(a[0], a[0]), a[1]]; - } - - sub(a,b) { - return [ - this.F.sub( - this.F.mul(a[0], b[1]), - this.F.mul(a[1], b[0])), - this.F.mul(a[1], b[1])]; - } - - neg(a) { - return [this.F.neg(a[0]), a[1]]; - } - - mul(a,b) { - return [ - this.F.mul(a[0], b[0]), - this.F.mul(a[1], b[1]), - ]; - } - - copy(a) { - return [a[0], a[1]]; - } - - div(a, b) { - return [ - this.F.mul(a[0], b[1]), - this.F.mul(a[1], b[0]), - ]; - } - - inv(a) { - return [a[1], a[0]]; - } - - square(a) { - return [ - this.F.square(a[0]), - this.F.square(a[1]) - ]; - } - - mulScalar(base, e) { - return [this.F.mulScalar(base[0], e) , base[1]]; - } - - exp(base, e) { - return fUtils.exp(this, base, e); - } - - eq(a, b) { - return this.F.eq( - this.F.mul(a[0], b[1]), - this.F.mul(a[1], b[0]) - ); - } - - isZero(a) { - return this.F.isZero(a[0]); - } - - affine(a) { - return [this.F.div(a[0], a[1]), this.F.one]; - } - - toString(a) { - const ca = this.affine(a); - return `"0x${ca[0].toString(16)}"`; - } - - random() { - return [this.F.random(), this.F.one]; - } - - fromF(a) { - return [a, this.F.one]; - } - - toF(a) { - return this.affine(a)[0]; - } -} - diff --git a/src/threadman.js b/src/threadman.js deleted file mode 100644 index e8ac5bc..0000000 --- a/src/threadman.js +++ /dev/null @@ -1,251 +0,0 @@ -/* global window, navigator, Blob, Worker, WebAssembly */ -/* - Copyright 2019 0KIMS association. - - This file is part of wasmsnark (Web Assembly zkSnark Prover). - - wasmsnark is a free software: you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - wasmsnark is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with wasmsnark. If not, see . -*/ - -// const MEM_SIZE = 1000; // Memory size in 64K Pakes (512Mb) -const MEM_SIZE = 25; // Memory size in 64K Pakes (1600Kb) - - -import thread from "./threadman_thread.js"; -import os from "os"; -import Worker from "web-worker"; - -class Deferred { - constructor() { - this.promise = new Promise((resolve, reject)=> { - this.reject = reject; - this.resolve = resolve; - }); - } -} - -function sleep(ms) { - return new Promise(resolve => setTimeout(resolve, ms)); -} - -function base64ToArrayBuffer(base64) { - if (process.browser) { - var binary_string = window.atob(base64); - var len = binary_string.length; - var bytes = new Uint8Array(len); - for (var i = 0; i < len; i++) { - bytes[i] = binary_string.charCodeAt(i); - } - return bytes; - } else { - return new Uint8Array(Buffer.from(base64, "base64")); - } -} - -function stringToBase64(str) { - if (process.browser) { - return window.btoa(str); - } else { - return Buffer.from(str).toString("base64"); - } -} - -const threadSource = stringToBase64("(" + thread.toString() + ")(self)"); -const workerSource = "data:application/javascript;base64," + threadSource; - - - -export default 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(base64ToArrayBuffer(wasm.code)); - - tm.instance = await WebAssembly.instantiate(wasmModule, { - env: { - "memory": tm.memory - } - }); - - tm.singleThread = singleThread; - tm.initalPFree = tm.u32[0]; // Save the Pointer to free space. - tm.pq = wasm.pq; - tm.pr = wasm.pr; - tm.pG1gen = wasm.pG1gen; - tm.pG1zero = wasm.pG1zero; - tm.pG2gen = wasm.pG2gen; - tm.pG2zero = wasm.pG2zero; - tm.pOneT = wasm.pOneT; - - // tm.pTmp0 = tm.alloc(curve.G2.F.n8*3); - // tm.pTmp1 = tm.alloc(curve.G2.F.n8*3); - - - if (singleThread) { - tm.code = base64ToArrayBuffer(wasm.code); - tm.taskManager = thread(); - await tm.taskManager([{ - cmd: "INIT", - init: MEM_SIZE, - code: tm.code.slice() - }]); - tm.concurrency = 1; - } else { - tm.workers = []; - tm.pendingDeferreds = []; - tm.working = []; - - let concurrency; - - if ((typeof(navigator) === "object") && navigator.hardwareConcurrency) { - concurrency = navigator.hardwareConcurrency; - } else { - concurrency = os.cpus().length; - } - // Limit to 64 threads for memory reasons. - if (concurrency>64) concurrency=64; - tm.concurrency = concurrency; - - for (let i = 0; i 0); i++) { - if (this.working[i] == false) { - const work = this.actionQueue.shift(); - this.postAction(i, work.data, work.transfers, work.deferred); - } - } - } - - queueAction(actionData, transfers) { - const d = new Deferred(); - - if (this.singleThread) { - const res = this.taskManager(actionData); - d.resolve(res); - } else { - this.actionQueue.push({ - data: actionData, - transfers: transfers, - deferred: d - }); - this.processWorks(); - } - return d.promise; - } - - resetMemory() { - this.u32[0] = this.initalPFree; - } - - allocBuff(buff) { - const pointer = this.alloc(buff.byteLength); - this.setBuff(pointer, buff); - return pointer; - } - - getBuff(pointer, length) { - return this.u8.slice(pointer, pointer+ length); - } - - setBuff(pointer, buffer) { - this.u8.set(new Uint8Array(buffer), pointer); - } - - alloc(length) { - while (this.u32[0] & 3) this.u32[0]++; // Return always aligned pointers - const res = this.u32[0]; - this.u32[0] += length; - return res; - } - - async terminate() { - for (let i=0; i 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=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 = Scalar.toLEBuff(Scalar.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 = Scalar.e(a, b); - if (Scalar.isNegative(ra)) { - ra = Scalar.neg(ra); - if (Scalar.gt(ra, this.p)) { - ra = Scalar.mod(ra, this.p); - } - ra = Scalar.sub(this.p, ra); - } else { - if (Scalar.gt(ra, this.p)) { - ra = Scalar.mod(ra, this.p); - } - } - const buff = utils.leInt2Buff(ra, this.n8); - return this.toMontgomery(buff); - } - - toString(a, radix) { - const an = this.fromMontgomery(a); - const s = Scalar.fromRprLE(an, 0); - return Scalar.toString(s, radix); - } - - fromRng(rng) { - let v; - const buff = new Uint8Array(this.n8); - do { - v = Scalar.zero; - for (let i=0; i. -*/ - -import chai from "chai"; - -import * as Scalar from "../src/scalar.js"; -import buildBn128 from "../src/bn128.js"; -import F1Field from "../src/f1field.js"; - -const assert = chai.assert; - - -describe("F1 testing", () => { - let bn128; - before( async() => { - bn128 = await buildBn128(); - }); - after( async() => { - bn128.terminate(); - }); - - it("Should compute euclidean", () => { - const F = new F1Field(Scalar.fromString("7")); - const res = F.inv(F.e(4)); - - assert(F.eq(res, F.e(2))); - }); - - it("Should multiply and divide in F1", () => { - const a = bn128.F1.e("1"); - const b = bn128.F1.e("-1"); - const c = bn128.F1.mul(a,b); - const d = bn128.F1.div(c,b); - - assert(bn128.F1.eq(a, d)); - }); - - it("Should compute sqrts", () => { - const F = new F1Field(bn128.r); - const a = F.e("4"); - let b = F.sqrt(a); - assert(F.eq(F.e(0), F.sqrt(F.e("0")))); - assert(F.eq(b, F.e("2"))); - // assert(F.sqrt(F.nqr) === null); - }); - - it("Should compute sqrt of 100 random numbers", () => { - const F = new F1Field(bn128.r); - for (let j=0;j<100; j++) { - let a = F.random(); - let s = F.sqrt(a); - if (s != null) { - assert(F.eq(F.square(s), a)); - } - } - }); -}); - -describe("Curve G1 Test", () => { - let bn128; - before( async() => { - bn128 = await buildBn128(); - }); - after( async() => { - bn128.terminate(); - }); - - it("r*one == 0", () => { - const res = bn128.G1.timesScalar(bn128.G1.g, bn128.r); - - assert(bn128.G1.eq(res, bn128.G1.zero), "G1 does not have range r"); - }); - - it("Should add match in various in G1", () => { - - const r1 = bn128.Fr.e(33); - const r2 = bn128.Fr.e(44); - - const gr1 = bn128.G1.timesFr(bn128.G1.g, r1); - const gr2 = bn128.G1.timesFr(bn128.G1.g, r2); - - const grsum1 = bn128.G1.add(gr1, gr2); - - const grsum2 = bn128.G1.timesFr(bn128.G1.g, bn128.Fr.add(r1, r2)); - - assert(bn128.G1.eq(grsum1, grsum2)); - }); -}); - -describe("Curve G2 Test", () => { - let bn128; - before( async() => { - bn128 = await buildBn128(); - }); - after( async() => { - bn128.terminate(); - }); - - it ("r*one == 0", () => { - const res = bn128.G2.timesScalar(bn128.G2.g, bn128.r); - - assert(bn128.G2.eq(res, bn128.G2.zero), "G2 does not have range r"); - }); - - it("Should add match in various in G2", () => { - const r1 = bn128.Fr.e(33); - const r2 = bn128.Fr.e(44); - - const gr1 = bn128.G2.timesFr(bn128.G2.g, r1); - const gr2 = bn128.G2.timesFr(bn128.G2.g, r2); - - const grsum1 = bn128.G2.add(gr1, gr2); - - const grsum2 = bn128.G2.timesFr(bn128.G2.g, bn128.Fr.add(r1, r2)); - - /* - console.log(G2.toString(grsum1)); - console.log(G2.toString(grsum2)); - */ - - assert(bn128.G2.eq(grsum1, grsum2)); - }); -}); - -describe("F6 testing", () => { - let bn128; - before( async() => { - bn128 = await buildBn128(); - }); - after( async() => { - bn128.terminate(); - }); - - it("Should multiply and divide in F6", () => { - - const a = bn128.F6.fromObject([ - [Scalar.e("1"), Scalar.e("2")], - [Scalar.e("3"), Scalar.e("4")], - [Scalar.e("5"), Scalar.e("6")] - ]); - const b = bn128.F6.fromObject([ - [Scalar.e("12"), Scalar.e("11")], - [Scalar.e("10"), Scalar.e("9")], - [Scalar.e("8"), Scalar.e("7")] - ]); - const c = bn128.F6.mul(a,b); - const d = bn128.F6.div(c,b); - - assert(bn128.F6.eq(a, d)); - }); -}); - -describe("F12 testing", () => { - let bn128; - before( async() => { - bn128 = await buildBn128(); - }); - after( async() => { - bn128.terminate(); - }); - - it("Should multiply and divide in F12", () => { - const a = bn128.Gt.fromObject([ - [ - [Scalar.e("1"), Scalar.e("2")], - [Scalar.e("3"), Scalar.e("4")], - [Scalar.e("5"), Scalar.e("6")] - ], - [ - [Scalar.e("7"), Scalar.e("8")], - [Scalar.e("9"), Scalar.e("10")], - [Scalar.e("11"), Scalar.e("12")] - ] - ]); - const b = bn128.Gt.fromObject([ - [ - [Scalar.e("12"), Scalar.e("11")], - [Scalar.e("10"), Scalar.e("9")], - [Scalar.e("8"), Scalar.e("7")] - ], - [ - [Scalar.e("6"), Scalar.e("5")], - [Scalar.e("4"), Scalar.e("3")], - [Scalar.e("2"), Scalar.e("1")] - ] - ]); - const c = bn128.F12.mul(a,b); - const d = bn128.F12.div(c,b); - - assert(bn128.F12.eq(a, d)); - }); -}); - -describe("Pairing", () => { - let bn128; - before( async() => { - bn128 = await buildBn128(); - }); - after( async() => { - bn128.terminate(); - }); - - /* - it("Should match pairing", () => { - for (let i=0; i<1; i++) { - const bn128 = new BN128(); - - const g1a = bn128.G1.mulScalar(bn128.G1.g, 25); - const g2a = bn128.G2.mulScalar(bn128.G2.g, 30); - - const g1b = bn128.G1.mulScalar(bn128.G1.g, 30); - const g2b = bn128.G2.mulScalar(bn128.G2.g, 25); - - const pre1a = bn128.prepareG1(g1a); - const pre2a = bn128.prepareG2(g2a); - const pre1b = bn128.prepareG1(g1b); - const pre2b = bn128.prepareG2(g2b); - - const r1 = bn128.millerLoop(pre1a, pre2a); - const r2 = bn128.millerLoop(pre1b, pre2b); - - const rbe = bn128.F12.mul(r1, bn128.F12.inverse(r2)); - - const res = bn128.finalExponentiation(rbe); - - assert(bn128.F12.eq(res, bn128.F12.one)); - } - }).timeout(10000); - */ - it("Should generate another pairing pairing", () => { - for (let i=0; i<1; i++) { - const g1a = bn128.G1.timesScalar(bn128.G1.g, 10); - const g2a = bn128.G2.timesScalar(bn128.G2.g, 1); - - const g1b = bn128.G1.timesScalar(bn128.G1.g, 1); - const g2b = bn128.G2.timesScalar(bn128.G2.g, 10); - - const pre1a = bn128.prepareG1(g1a); - const pre2a = bn128.prepareG2(g2a); - const pre1b = bn128.prepareG1(g1b); - const pre2b = bn128.prepareG2(g2b); - - const r1 = bn128.millerLoop(pre1a, pre2a); - const r2 = bn128.finalExponentiation(r1); - - const r3 = bn128.millerLoop(pre1b, pre2b); - - const r4 = bn128.finalExponentiation(r3); - - /* - console.log("ML1: " ,bn128.F12.toString(r1)); - console.log("FE1: " ,bn128.F12.toString(r2)); - console.log("ML2: " ,bn128.F12.toString(r3)); - console.log("FE2: " ,bn128.F12.toString(r4)); - */ - - assert(bn128.F12.eq(r2, r4)); - - - /* - const r2 = bn128.millerLoop(pre1b, pre2b); - - const rbe = bn128.F12.mul(r1, bn128.F12.inverse(r2)); - - const res = bn128.finalExponentiation(rbe); - - assert(bn128.F12.eq(res, bn128.F12.one)); - */ - } - }).timeout(10000); -}); - -describe("Compressed Form", () => { - let bn128; - before( async() => { - bn128 = await buildBn128(); - }); - after( async() => { - bn128.terminate(); - }); - - it("Should test rpr of G2", () => { - const P1 = bn128.G2.fromObject([ - [ - Scalar.e("1b2327ce7815d3358fe89fd8e5695305ed23682db29569f549ab8f48cae1f1c4",16), - Scalar.e("1ed41ca6b3edc06237af648f845c270ff83bcde333f17863c1b71a43b271b46d",16) - ], - [ - Scalar.e("122057912ab892abcf2e729f0f342baea3fe1b484840eb97c7d78cd7530f4ab5",16), - Scalar.e("2cb317fd40d56eeb17b0c1ff9443661a42ec00cea060012873b3f643f1a5bff8",16) - ], - [ - Scalar.one, - Scalar.zero - ] - ]); - const buff = new Uint8Array(64); - bn128.G2.toRprCompressed(buff, 0, P1); - - const P2 = bn128.G2.fromRprCompressed(buff, 0); - - /* - console.log(bn128.G2.toString(P1, 16)); - console.log(bn128.G2.toString(P2, 16)); - */ - - assert(bn128.G2.eq(P1,P2)); - }).timeout(10000); -}); diff --git a/test/bn128.js b/test/bn128.js deleted file mode 100644 index 79d0a74..0000000 --- a/test/bn128.js +++ /dev/null @@ -1,181 +0,0 @@ -import assert from "assert"; -import buildBn128 from "../src/bn128.js"; -import {log2} from "../src/utils.js"; -import BigBuffer from "../src/bigbuffer.js"; - -describe("bn128", async function () { - this.timeout(10000000); - - const logger = { - error: (msg) => { console.log("ERROR: "+msg); }, - warning: (msg) => { console.log("WARNING: "+msg); }, - info: (msg) => { console.log("INFO: "+msg); }, - debug: (msg) => { console.log("DEBUG: "+msg); }, - }; - - let bn128; - before( async() => { - bn128 = await buildBn128(); - }); - after( async() => { - bn128.terminate(); - }); - - it("It shoud do an inverse FFT in G1", async () => { - const Fr = bn128.Fr; - const G1 = bn128.G1; - - const a = []; - for (let i=0; i<8; i++) a[i] = Fr.e(i+1); - - const aG_expected = []; - for (let i=0; i<8; i++) aG_expected[i] = G1.timesFr(G1.g, a[i]); - - const A = await bn128.Fr.fft(a); - - - const AG = []; - for (let i=0; i<8; i++) AG[i] = G1.timesFr(G1.g, A[i]); - - const aG_calculated = await G1.ifft(AG, "jacobian", "jacobian"); - - for (let i=0; i<8; i++) { - assert(G1.eq(aG_calculated[i], aG_expected[i])); - } - }); - - - it("It shoud do a big FFT/IFFT in Fr", async () => { - const Fr = bn128.Fr; - - const N = 1<<10; - - const a = new BigBuffer(N*bn128.Fr.n8); - for (let i=0; i { - const Fr = bn128.Fr; - const N = 8192*16; - - const a = []; - for (let i=0; i { - const Fr = bn128.Fr; - const N = 16; - - const oldS = Fr.s; - Fr.s = log2(N)-1; // Force ext - - const a = []; - for (let i=0; i { - const Fr = bn128.Fr; - const G1 = bn128.G1; - const N = 512; - - const a = []; - for (let i=0; i { - const Fr = bn128.Fr; - const G1 = bn128.G1; - const N = 1<<13; - - const oldS = Fr.s; - Fr.s = log2(N)-1; - - const a = []; - for (let i=0; i { - const Fr = bn128.Fr; - const G1 = bn128.G1; - const N = 1 << 10; - - const scalars = new BigBuffer(N*bn128.Fr.n8); - const bases = new BigBuffer(N*G1.F.n8*2); - let acc = Fr.zero; - for (let i=0; i. -*/ - -import chai from "chai"; - -import * as Scalar from "../src/scalar.js"; -import PolField from "../src/polfield.js"; -import ZqField from "../src/f1field.js"; - -const assert = chai.assert; - -const r = Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617"); - -describe("Polynomial field", () => { - it("Should compute a multiplication", () => { - const PF = new PolField(new ZqField(r)); - - const a = [PF.F.e(1), PF.F.e(2), PF.F.e(3)]; - const b = [PF.F.e(1), PF.F.e(2), PF.F.e(3)]; - const res = PF.mul(a,b); - - assert(PF.eq(res, [PF.F.e(1), PF.F.e(4), PF.F.e(10), PF.F.e(12), PF.F.e(9)])); - }); - it("Should compute a multiplication 2", () => { - const PF = new PolField(new ZqField(r)); - - const a = [PF.F.e(5), PF.F.e(1)]; - const b = [PF.F.e(-5), PF.F.e(1)]; - const res = PF.mul(a,b); - - assert(PF.eq(res, [PF.F.e(-25), PF.F.e(0), PF.F.e(1)])); - }); - it("Should compute an addition", () => { - const PF = new PolField(new ZqField(r)); - - const a = [PF.F.e(5), PF.F.e(1)]; - const b = [PF.F.e(-5), PF.F.e(1)]; - const res = PF.add(a,b); - - assert(PF.eq(res, [PF.F.e(0), PF.F.e(2)])); - }); - it("Should compute a substraction", () => { - const PF = new PolField(new ZqField(r)); - - const a = [PF.F.e(5), PF.F.e(3), PF.F.e(4)]; - const b = [PF.F.e(5), PF.F.e(1)]; - const res = PF.sub(a,b); - - assert(PF.eq(res, [PF.F.e(0), PF.F.e(2), PF.F.e(4)])); - }); - it("Should compute reciprocal", () => { - const PF = new PolField(new ZqField(r)); - - const a = PF.normalize([PF.F.e(4), PF.F.e(1), PF.F.e(-3), PF.F.e(-1), PF.F.e(2),PF.F.e(1), PF.F.e(-1), PF.F.e(1)]); - const res = PF._reciprocal(a, 3, 0); - - assert(PF.eq(res, PF.normalize([PF.F.e(12), PF.F.e(15), PF.F.e(3), PF.F.e(-4), PF.F.e(-3), PF.F.e(0), PF.F.e(1), PF.F.e(1)]))); - }); - it("Should div2", () => { - const PF = new PolField(new ZqField(r)); - - // x^6 - const a = [PF.F.e(0), PF.F.e(0), PF.F.e(0), PF.F.e(0), PF.F.e(0),PF.F.e(0), PF.F.e(1)]; - // x^5 - const b = [PF.F.e(0), PF.F.e(0), PF.F.e(0), PF.F.e(0), PF.F.e(0), PF.F.e(1)]; - - const res = PF._div2(6, b); - assert(PF.eq(res, [PF.F.e(0), PF.F.e(1)])); - - const res2 = PF.div(a,b); - assert(PF.eq(res2, [PF.F.e(0), PF.F.e(1)])); - }); - it("Should div", () => { - const PF = new PolField(new ZqField(r)); - - const a = [PF.F.e(1), PF.F.e(2), PF.F.e(3), PF.F.e(4), PF.F.e(5),PF.F.e(6), PF.F.e(7)]; - const b = [PF.F.e(8), PF.F.e(9), PF.F.e(10), PF.F.e(11), PF.F.e(12), PF.F.e(13)]; - - const c = PF.mul(a,b); - const d = PF.div(c,b); - - assert(PF.eq(a, d)); - }); - it("Should div big/small", () => { - const PF = new PolField(new ZqField(r)); - - const a = [PF.F.e(1), PF.F.e(2), PF.F.e(3), PF.F.e(4), PF.F.e(5),PF.F.e(6), PF.F.e(7)]; - const b = [PF.F.e(8), PF.F.e(9)]; - - const c = PF.mul(a,b); - const d = PF.div(c,b); - - assert(PF.eq(a, d)); - }); - it("Should div random big", () => { - const PF = new PolField(new ZqField(r)); - - let a = []; - let b = []; - for (let i=0; i<1000; i++) a.push(PF.F.e(Math.floor(Math.random()*100000) -500000)); - for (let i=0; i<900; i++) b.push(PF.F.e(Math.floor(Math.random()*100000) -500000)); - - a = PF.normalize(a); - b = PF.normalize(a); - - const c = PF.mul(a,b); - - const d = PF.div(c,b); - - assert(PF.eq(a, d)); - }).timeout(10000); - it("Should evaluate and zero", () => { - const PF = new PolField(new ZqField(r)); - const p = [PF.F.neg(PF.F.e(2)), PF.F.e(1)]; - const v = PF.eval(p, PF.F.e(2)); - assert(PF.F.eq(v, PF.F.e(0))); - }); - it("Should evaluate bigger number", () => { - const PF = new PolField(new ZqField(r)); - const p = [PF.F.e(1), PF.F.e(2), PF.F.e(3)]; - const v = PF.eval(p, PF.F.e(2)); - assert(PF.F.eq(v, PF.F.e(17))); - }); - it("Should create lagrange polynomial minmal", () => { - const PF = new PolField(new ZqField(r)); - - const points=[]; - points.push([PF.F.e(1), PF.F.e(1)]); - points.push([PF.F.e(2), PF.F.e(2)]); - points.push([PF.F.e(3), PF.F.e(5)]); - - const p=PF.lagrange(points); - - for (let i=0; i { - const PF = new PolField(new ZqField(r)); - - const points=[]; - points.push([PF.F.e(1), PF.F.e(2)]); - points.push([PF.F.e(2), PF.F.e(-2)]); - points.push([PF.F.e(3), PF.F.e(0)]); - points.push([PF.F.e(4), PF.F.e(453345)]); - - const p=PF.lagrange(points); - - for (let i=0; i { - const PF = new PolField(new ZqField(r)); - const a = [PF.F.e(1), PF.F.e(2), PF.F.e(3), PF.F.e(4), PF.F.e(5),PF.F.e(6), PF.F.e(7)]; - - const b = PF.mul(a, [PF.F.e(-7), PF.F.e(1)]); - const c = PF.ruffini(b, PF.F.e(7)); - - assert(PF.eq(a, c)); - }); - it("Should test roots", () => { - const PF = new PolField(new ZqField(r)); - let rt; - - - rt = PF.oneRoot(256, 16); - for (let i=0; i<8; i++) { - rt = PF.F.mul(rt, rt); - } - assert(PF.F.eq(rt, PF.F.one)); - - rt = PF.oneRoot(256, 15); - for (let i=0; i<8; i++) { - rt = PF.F.mul(rt, rt); - } - assert(PF.F.eq(rt, PF.F.one)); - - rt = PF.oneRoot(8, 3); - for (let i=0; i<3; i++) { - rt = PF.F.mul(rt, rt); - } - assert(PF.F.eq(rt, PF.F.one)); - - rt = PF.oneRoot(8, 0); - assert(PF.F.eq(rt, PF.F.one)); - - }); - it("Should create a polynomial with values at roots with fft", () => { - const PF = new PolField(new ZqField(r)); - const a = [PF.F.e(1), PF.F.e(2), PF.F.e(3), PF.F.e(4), PF.F.e(5),PF.F.e(6), PF.F.e(7)]; - - const p = PF.ifft(a); - - for (let i=0; i. -*/ - -import chai from "chai"; - -import * as Scalar from "../src/scalar.js"; -import ZqField from "../src/f1field.js"; -import RatField from "../src/ratfield.js"; - -const q = Scalar.fromString("21888242871839275222246405745257275088548364400416034343698204186575808495617"); -const Z = new ZqField(q); -const R = new RatField(Z); - -const assert = chai.assert; - -function r(a,b) { - return [Z.e(a), Z.e(b)]; -} - - -describe("Rational zq Field", () => { - it("Should compare correctly", () => { - assert( R.eq(r(3,5), r(6,10))); - assert(!R.eq(r(3,5), r(6,11))); - }); - it("Should add correctly", () => { - const a = r(7,4); - const b = r(5,12); - - assert(R.eq( R.add(a,b), r(13, 6))); - }); - it("Should substract", () => { - const a = r(7,4); - const b = r(5,12); - - assert(R.eq( R.sub(a,b), r(4, 3))); - }); - it("Should multiply", () => { - const a = r(7,4); - const b = r(5,12); - - assert(R.eq( R.mul(a,b), r(35, 48))); - }); - it("Should div", () => { - const a = r(7,4); - const b = r(5,12); - - assert(R.eq( R.div(a,b), r(7*12, 5*4))); - }); - it("Should square", () => { - const a = r(7,4); - - assert(R.eq( R.square(a), r(49, 16))); - }); - it("Should affine", () => { - const a = r(12,4); - const aa = R.affine(a); - assert(Z.eq( aa[0], Z.e(3))); - assert(Z.eq( aa[1], Z.one)); - }); - it("Should convert from Z to R", () => { - const vz = Z.e(34); - const vr = R.fromF(vz); - - assert(R.eq( vr, r(34,1))); - }); - it("Should convert from R to Z", () => { - const vr = r(32, 2); - const vz = R.toF(vr); - - assert(Z.eq( vz, Z.e(16))); - }); -}); diff --git a/test/sqrt.js b/test/sqrt.js deleted file mode 100644 index 7cb25fc..0000000 --- a/test/sqrt.js +++ /dev/null @@ -1,95 +0,0 @@ -/* - Copyright 2018 0kims association. - - This file is part of zksnark JavaScript library. - - zksnark JavaScript library 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. - - zksnark JavaScript library 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 - zksnark JavaScript library. If not, see . -*/ - -import chai from "chai"; - -import * as Scalar from "../src/scalar.js"; -import buildBn128 from "../src/bn128.js"; -import F1Field from "../src/f1field.js"; - -const assert = chai.assert; - - -describe("Sqrt testing", () => { - let bn128; - before( async() => { - bn128 = await buildBn128(); - }); - after( async() => { - bn128.terminate(); - }); - -/* - it("Should compute sqrts", () => { - const F = new F1Field(bn128.r); - const a = F.e(2); - const b = F.sqrt_v(a); - console.log(F.toString(b)); - }); -*/ - it("Should compute basic sqrts", () => { - const F = new F1Field(bn128.r); - assert(F.eq(F.e(0), F.sqrt(F.e("0")))); - const a = F.e("9"); - let b = F.sqrt(a); - assert(F.eq(b, F.e("3"))); - assert(F.sqrt(F.sqrt_z) === null); - }); - it("Should compute sqrt p%4 = 1", () => { - const F = new F1Field(bn128.r); - const e = Scalar.div(Scalar.pow(F.p, F.m), 2); - for (let i=0; i<100; i++) { - const x2 = F.random(); - const x = F.sqrt(x2); - if (x==null) { - assert(F.eq( F.pow(x2, e), F.negone)); - } else { - assert(F.eq(F.square(x), x2)); - } - } - }); - it("Should compute sqrt p%4 = 3", () => { - const F = new F1Field(bn128.q); - const e = Scalar.div(Scalar.pow(F.p, F.m), 2); - for (let i=0; i<100; i++) { - const x2 = F.random(); - const x = F.sqrt(x2); - if (x==null) { - assert(F.eq( F.pow(x2, e), F.negone)); - } else { - assert(F.eq(F.square(x), x2)); - } - } - }); - it("Should compute sqrt m=2 p%4 = 3", () => { - const F = bn128.F2; - const e = Scalar.div(Scalar.exp(F.F.p, F.m), 2); - for (let i=0; i<100; i++) { - const x2 = F.random(); - if (!F.isSquare(x2)) { - assert(F.eq( F.exp(x2, e), F.negone)); - } else { - const x = F.sqrt(x2); - assert(F.eq(F.square(x), x2)); - } - } - }); - -}); -