diff --git a/build/lib.cjs/main.js b/build/lib.cjs/main.js new file mode 100644 index 0000000..9823eb8 --- /dev/null +++ b/build/lib.cjs/main.js @@ -0,0 +1,10 @@ +'use strict'; + +var scalar = require('./src/scalar.js'); +var f1field = require('./src/f1field.js'); + +const Scalar = scalar; + +exports.F1Field = f1field; +exports.ZqField = f1field; +exports.Scalar = Scalar; diff --git a/build/lib.cjs/src/f1field.js b/build/lib.cjs/src/f1field.js new file mode 100644 index 0000000..4dad3d8 --- /dev/null +++ b/build/lib.cjs/src/f1field.js @@ -0,0 +1,367 @@ +'use strict'; + +var scalar = require('./scalar.js'); +var futils = require('./futils.js'); +var fsqrt = require('./fsqrt.js'); +var random = require('./random.js'); +var fft = require('./fft.js'); + +/* global BigInt */ + +class ZqField { + constructor(p) { + this.type = "F1"; + this.one = BigInt(1); + this.zero = BigInt(0); + this.p = BigInt(p); + this.m = 1; + this.negone = this.p - this.one; + this.two = BigInt(2); + this.half = this.p >> this.one; + this.bitLength = scalar.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; + } + + this.nqr_to_t = this.pow(this.nqr, this.t); + + fsqrt(this); + + this.FFT = new fft(this, this, this.mul.bind(this)); + + this.fft = this.FFT.fft.bind(this.FFT); + this.ifft = this.FFT.ifft.bind(this.FFT); + this.w = this.FFT.w; + this.wi = this.FFT.wi; + + this.shift = this.square(this.nqr); + this.k = this.exp(this.nqr, 2 ** this.s); + } + + e(a, b) { + let res; + if (!b) { + res = BigInt(a); + } else if (b == 16) { + res = BigInt("0x" + a); + } + if (res < 0) { + let nres = -res; + if (nres >= this.p) nres = nres % this.p; + return this.p - nres; + } else { + return res >= this.p ? res % this.p : res; + } + } + + add(a, b) { + const res = a + b; + return res >= this.p ? res - this.p : res; + } + + sub(a, b) { + return a >= b ? a - b : this.p - b + a; + } + + neg(a) { + return a ? this.p - a : a; + } + + mul(a, b) { + return (a * b) % this.p; + } + + mulScalar(base, s) { + return (base * this.e(s)) % this.p; + } + + square(a) { + return (a * a) % this.p; + } + + eq(a, b) { + return a == b; + } + + neq(a, b) { + return a != b; + } + + lt(a, b) { + const aa = a > this.half ? a - this.p : a; + const bb = b > this.half ? b - this.p : b; + return aa < bb; + } + + gt(a, b) { + const aa = a > this.half ? a - this.p : a; + const bb = b > this.half ? b - this.p : b; + return aa > bb; + } + + leq(a, b) { + const aa = a > this.half ? a - this.p : a; + const bb = b > this.half ? b - this.p : b; + return aa <= bb; + } + + geq(a, b) { + const aa = a > this.half ? a - this.p : a; + const bb = b > this.half ? b - this.p : b; + return aa >= bb; + } + + div(a, b) { + return this.mul(a, this.inv(b)); + } + + idiv(a, b) { + if (!b) throw new Error("Division by zero"); + return a / b; + } + + inv(a) { + if (!a) throw new Error("Division by zero"); + + let t = this.zero; + let r = this.p; + let newt = this.one; + let newr = a % this.p; + while (newr) { + let q = r / newr; + [t, newt] = [newt, t - q * newt]; + [r, newr] = [newr, r - q * newr]; + } + if (t < this.zero) t += this.p; + return t; + } + + mod(a, b) { + return a % b; + } + + pow(b, e) { + return futils.exp(this, b, e); + } + + exp(b, e) { + return futils.exp(this, b, e); + } + + band(a, b) { + const res = a & b & this.mask; + return res >= this.p ? res - this.p : res; + } + + bor(a, b) { + const res = (a | b) & this.mask; + return res >= this.p ? res - this.p : res; + } + + bxor(a, b) { + const res = (a ^ b) & this.mask; + return res >= this.p ? res - this.p : res; + } + + bnot(a) { + const res = a ^ this.mask; + return res >= this.p ? res - this.p : res; + } + + shl(a, b) { + if (Number(b) < this.bitLength) { + const res = (a << b) & this.mask; + return res >= this.p ? res - this.p : res; + } else { + const nb = this.p - b; + if (Number(nb) < this.bitLength) { + return a >> nb; + } else { + return this.zero; + } + } + } + + shr(a, b) { + if (Number(b) < this.bitLength) { + return a >> b; + } else { + const nb = this.p - b; + if (Number(nb) < this.bitLength) { + const res = (a << nb) & this.mask; + return res >= this.p ? res - this.p : res; + } else { + return 0; + } + } + } + + land(a, b) { + return a && b ? this.one : this.zero; + } + + lor(a, b) { + return a || b ? this.one : this.zero; + } + + lnot(a) { + return a ? this.zero : this.one; + } + + sqrt_old(n) { + if (n == this.zero) return this.zero; + + // Test that have solution + const res = this.pow(n, this.negone >> this.one); + if (res != this.one) return null; + + let m = this.s; + let c = this.nqr_to_t; + let t = this.pow(n, this.t); + let r = this.pow(n, this.add(this.t, this.one) >> this.one); + + while (t != this.one) { + let sq = this.square(t); + let i = 1; + while (sq != this.one) { + i++; + sq = this.square(sq); + } + + // b = c ^ m-i-1 + let b = c; + for (let j = 0; j < m - i - 1; j++) b = this.square(b); + + m = i; + c = this.square(b); + t = this.mul(t, c); + r = this.mul(r, b); + } + + if (r > this.p >> this.one) { + r = this.neg(r); + } + + return r; + } + + normalize(a, b) { + a = BigInt(a, b); + if (a < 0) { + let na = -a; + if (na >= this.p) na = na % this.p; + return this.p - na; + } else { + return a >= this.p ? a % this.p : a; + } + } + + random() { + const nBytes = (this.bitLength * 2) / 8; + let res = this.zero; + for (let i = 0; i < nBytes; i++) { + res = (res << BigInt(8)) + BigInt(random.getRandomBytes(1)[0]); + } + return res % this.p; + } + + toString(a, base) { + base = base || 10; + let vs; + if (a > this.half && base == 10) { + const v = this.p - a; + vs = "-" + v.toString(base); + } else { + vs = a.toString(base); + } + return vs; + } + + isZero(a) { + return a == this.zero; + } + + fromRng(rng) { + let v; + do { + v = this.zero; + for (let i = 0; i < this.n64; i++) { + v += rng.nextU64() << BigInt(64 * i); + } + v &= this.mask; + } while (v >= this.p); + v = (v * this.Ri) % this.p; // Convert from montgomery + return v; + } + + fft(a) { + return this.FFT.fft(a); + } + + ifft(a) { + return this.FFT.ifft(a); + } + + // Returns a buffer with Little Endian Representation + toRprLE(buff, o, e) { + scalar.toRprLE(buff, o, e, this.n64 * 8); + } + + // Returns a buffer with Big Endian Representation + toRprBE(buff, o, e) { + scalar.toRprBE(buff, o, e, this.n64 * 8); + } + + // Returns a buffer with Big Endian Montgomery Representation + toRprBEM(buff, o, e) { + return this.toRprBE(buff, o, this.mul(this.R, e)); + } + + toRprLEM(buff, o, e) { + return this.toRprLE(buff, o, this.mul(this.R, e)); + } + + // Pases a buffer with Little Endian Representation + fromRprLE(buff, o) { + return scalar.fromRprLE(buff, o, this.n8); + } + + // Pases a buffer with Big Endian Representation + fromRprBE(buff, o) { + return scalar.fromRprBE(buff, o, this.n8); + } + + fromRprLEM(buff, o) { + return this.mul(this.fromRprLE(buff, o), this.Ri); + } + + fromRprBEM(buff, o) { + return this.mul(this.fromRprBE(buff, o), this.Ri); + } + + toObject(a) { + return a; + } +} + +module.exports = ZqField; diff --git a/build/lib.cjs/src/fft.js b/build/lib.cjs/src/fft.js new file mode 100644 index 0000000..5256ff1 --- /dev/null +++ b/build/lib.cjs/src/fft.js @@ -0,0 +1,148 @@ +'use strict'; + +/* + 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 ]. + */ + +class FFT { + constructor(G, F, opMulGF) { + this.F = F; + this.G = G; + this.opMulGF = opMulGF; + + let rem = F.sqrt_t || F.t; + let s = F.sqrt_s || F.s; + + let nqr = F.one; + while (F.eq(F.pow(nqr, F.half), F.one)) nqr = F.add(nqr, F.one); + + this.w = new Array(s + 1); + this.wi = new Array(s + 1); + this.w[s] = this.F.pow(nqr, rem); + this.wi[s] = this.F.inv(this.w[s]); + + let n = s - 1; + while (n >= 0) { + this.w[n] = this.F.square(this.w[n + 1]); + this.wi[n] = this.F.square(this.wi[n + 1]); + n--; + } + + this.roots = []; + /* + for (let i=0; i<16; i++) { + let r = this.F.one; + n = 1 << i; + const rootsi = new Array(n); + for (let j=0; j= 0 && !this.roots[i]; i--) { + let r = this.F.one; + const nroots = 1 << i; + const rootsi = new Array(nroots); + for (let j = 0; j < nroots; j++) { + rootsi[j] = r; + r = this.F.mul(r, this.w[i]); + } + + this.roots[i] = rootsi; + } + } + + fft(p) { + if (p.length <= 1) return p; + const bits = log2(p.length - 1) + 1; + this._setRoots(bits); + + const m = 1 << bits; + if (p.length != m) { + throw new Error("Size must be multiple of 2"); + } + const res = __fft(this, p, bits, 0, 1); + return res; + } + + ifft(p) { + if (p.length <= 1) return p; + const bits = log2(p.length - 1) + 1; + this._setRoots(bits); + const m = 1 << bits; + if (p.length != m) { + throw new Error("Size must be multiple of 2"); + } + const res = __fft(this, p, bits, 0, 1); + const twoinvm = this.F.inv(this.F.mulScalar(this.F.one, m)); + const resn = new Array(m); + for (let i = 0; i < m; i++) { + resn[i] = this.opMulGF(res[(m - i) % m], twoinvm); + } + + return resn; + } +} + +function log2(V) { + return ( + ((V & 0xffff0000) !== 0 ? ((V &= 0xffff0000), 16) : 0) | + ((V & 0xff00ff00) !== 0 ? ((V &= 0xff00ff00), 8) : 0) | + ((V & 0xf0f0f0f0) !== 0 ? ((V &= 0xf0f0f0f0), 4) : 0) | + ((V & 0xcccccccc) !== 0 ? ((V &= 0xcccccccc), 2) : 0) | + ((V & 0xaaaaaaaa) !== 0) + ); +} + +function __fft(PF, pall, bits, offset, step) { + const n = 1 << bits; + if (n == 1) { + return [pall[offset]]; + } else if (n == 2) { + return [PF.G.add(pall[offset], pall[offset + step]), PF.G.sub(pall[offset], pall[offset + step])]; + } + + const ndiv2 = n >> 1; + const p1 = __fft(PF, pall, bits - 1, offset, step * 2); + const p2 = __fft(PF, pall, bits - 1, offset + step, step * 2); + + const out = new Array(n); + + for (let i = 0; i < ndiv2; i++) { + out[i] = PF.G.add(p1[i], PF.opMulGF(p2[i], PF.roots[bits][i])); + out[i + ndiv2] = PF.G.sub(p1[i], PF.opMulGF(p2[i], PF.roots[bits][i])); + } + + return out; +} + +module.exports = FFT; diff --git a/build/lib.cjs/src/fsqrt.js b/build/lib.cjs/src/fsqrt.js new file mode 100644 index 0000000..2468612 --- /dev/null +++ b/build/lib.cjs/src/fsqrt.js @@ -0,0 +1,167 @@ +'use strict'; + +var scalar = require('./scalar.js'); + +// Check here: https://eprint.iacr.org/2012/685.pdf + +function buildSqrt(F) { + if (F.m % 2 == 1) { + if (scalar.eq(scalar.mod(F.p, 4), 1)) { + if (scalar.eq(scalar.mod(F.p, 8), 1)) { + if (scalar.eq(scalar.mod(F.p, 16), 1)) { + // alg7_muller(F); + alg5_tonelliShanks(F); + } else if (scalar.eq(scalar.mod(F.p, 16), 9)) { + alg4_kong(F); + } else { + throw new Error("Field withot sqrt"); + } + } else if (scalar.eq(scalar.mod(F.p, 8), 5)) { + alg3_atkin(F); + } else { + throw new Error("Field withot sqrt"); + } + } else if (scalar.eq(scalar.mod(F.p, 4), 3)) { + alg2_shanks(F); + } + } else { + const pm2mod4 = scalar.mod(scalar.pow(F.p, F.m / 2), 4); + if (pm2mod4 == 1) { + alg10_adj(F); + } else if (pm2mod4 == 3) { + alg9_adj(F); + } else { + alg8_complex(F); + } + } +} + +function alg5_tonelliShanks(F) { + F.sqrt_q = scalar.pow(F.p, F.m); + + F.sqrt_s = 0; + F.sqrt_t = scalar.sub(F.sqrt_q, 1); + + while (!scalar.isOdd(F.sqrt_t)) { + F.sqrt_s = F.sqrt_s + 1; + F.sqrt_t = scalar.div(F.sqrt_t, 2); + } + + let c0 = F.one; + + while (F.eq(c0, F.one)) { + const c = F.random(); + F.sqrt_z = F.pow(c, F.sqrt_t); + c0 = F.pow(F.sqrt_z, 2 ** (F.sqrt_s - 1)); + } + + F.sqrt_tm1d2 = scalar.div(scalar.sub(F.sqrt_t, 1), 2); + + F.sqrt = function (a) { + const F = this; + if (F.isZero(a)) return F.zero; + let w = F.pow(a, F.sqrt_tm1d2); + const a0 = F.pow(F.mul(F.square(w), a), 2 ** (F.sqrt_s - 1)); + if (F.eq(a0, F.negone)) return null; + + let v = F.sqrt_s; + let x = F.mul(a, w); + let b = F.mul(x, w); + let z = F.sqrt_z; + while (!F.eq(b, F.one)) { + let b2k = F.square(b); + let k = 1; + while (!F.eq(b2k, F.one)) { + b2k = F.square(b2k); + k++; + } + + w = z; + for (let i = 0; i < v - k - 1; i++) { + w = F.square(w); + } + z = F.square(w); + b = F.mul(b, z); + x = F.mul(x, w); + v = k; + } + return F.geq(x, F.zero) ? x : F.neg(x); + }; +} + +function alg4_kong(F) { + F.sqrt = function () { + throw new Error("Sqrt alg 4 not implemented"); + }; +} + +function alg3_atkin(F) { + F.sqrt = function () { + throw new Error("Sqrt alg 3 not implemented"); + }; +} + +function alg2_shanks(F) { + F.sqrt_q = scalar.pow(F.p, F.m); + F.sqrt_e1 = scalar.div(scalar.sub(F.sqrt_q, 3), 4); + + F.sqrt = function (a) { + if (this.isZero(a)) return this.zero; + + // Test that have solution + const a1 = this.pow(a, this.sqrt_e1); + + const a0 = this.mul(this.square(a1), a); + + if (this.eq(a0, this.negone)) return null; + + const x = this.mul(a1, a); + + return F.geq(x, F.zero) ? x : F.neg(x); + }; +} + +function alg10_adj(F) { + F.sqrt = function () { + throw new Error("Sqrt alg 10 not implemented"); + }; +} + +function alg9_adj(F) { + F.sqrt_q = scalar.pow(F.p, F.m / 2); + F.sqrt_e34 = scalar.div(scalar.sub(F.sqrt_q, 3), 4); + F.sqrt_e12 = scalar.div(scalar.sub(F.sqrt_q, 1), 2); + + F.frobenius = function (n, x) { + if (n % 2 == 1) { + return F.conjugate(x); + } else { + return x; + } + }; + + F.sqrt = function (a) { + const F = this; + const a1 = F.pow(a, F.sqrt_e34); + const alfa = F.mul(F.square(a1), a); + const a0 = F.mul(F.frobenius(1, alfa), alfa); + if (F.eq(a0, F.negone)) return null; + const x0 = F.mul(a1, a); + let x; + if (F.eq(alfa, F.negone)) { + x = F.mul(x0, [F.F.zero, F.F.one]); + } else { + const b = F.pow(F.add(F.one, alfa), F.sqrt_e12); + x = F.mul(b, x0); + } + return F.geq(x, F.zero) ? x : F.neg(x); + }; +} + +function alg8_complex(F) { + F.sqrt = function () { + throw new Error("Sqrt alg 8 not implemented"); + }; +} + +module.exports = buildSqrt; diff --git a/build/lib.cjs/src/futils.js b/build/lib.cjs/src/futils.js new file mode 100644 index 0000000..c9b9402 --- /dev/null +++ b/build/lib.cjs/src/futils.js @@ -0,0 +1,63 @@ +'use strict'; + +var scalar = require('./scalar.js'); + +/* + 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 . +*/ + + +/* +exports.mulScalar = (F, base, e) =>{ + let res = F.zero; + let rem = bigInt(e); + let exp = base; + + while (! rem.eq(bigInt.zero)) { + if (rem.and(bigInt.one).eq(bigInt.one)) { + res = F.add(res, exp); + } + exp = F.double(exp); + rem = rem.shiftRight(1); + } + + return res; +}; +*/ + +function exp(F, base, e) { + if (scalar.isZero(e)) return F.one; + + const n = scalar.bits(e); + + if (n.length == 0) return F.one; + + let res = base; + + for (let i = n.length - 2; i >= 0; i--) { + res = F.square(res); + + if (n[i]) { + res = F.mul(res, base); + } + } + + return res; +} + +exports.exp = exp; diff --git a/build/lib.cjs/src/random.js b/build/lib.cjs/src/random.js new file mode 100644 index 0000000..a14767b --- /dev/null +++ b/build/lib.cjs/src/random.js @@ -0,0 +1,18 @@ +'use strict'; + +function getRandomBytes(n) { + let array = new Uint8Array(n); + // Browser & Node + if (typeof globalThis.crypto !== "undefined") { + // Supported + globalThis.crypto.getRandomValues(array); + } else { + // fallback + for (let i = 0; i < n; i++) { + array[i] = (Math.random() * 4294967296) >>> 0; + } + } + return array; +} + +exports.getRandomBytes = getRandomBytes; diff --git a/build/lib.cjs/src/scalar.js b/build/lib.cjs/src/scalar.js new file mode 100644 index 0000000..0f7479d --- /dev/null +++ b/build/lib.cjs/src/scalar.js @@ -0,0 +1,294 @@ +'use strict'; + +/* global BigInt */ +const hexLen = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]; + +function fromString(s, radix) { + if (!radix || radix == 10) { + return BigInt(s); + } else if (radix == 16) { + if (s.slice(0, 2) == "0x") { + return BigInt(s); + } else { + return BigInt("0x" + s); + } + } +} + +const e = fromString; + +function fromArray(a, radix) { + let acc = BigInt(0); + radix = BigInt(radix); + for (let i = 0; i < a.length; i++) { + acc = acc * radix + BigInt(a[i]); + } + return acc; +} + +function bitLength(a) { + const aS = a.toString(16); + return (aS.length - 1) * 4 + hexLen[parseInt(aS[0], 16)]; +} + +function isNegative(a) { + return BigInt(a) < BigInt(0); +} + +function isZero(a) { + return !a; +} + +function shiftLeft(a, n) { + return BigInt(a) << BigInt(n); +} + +function shiftRight(a, n) { + return BigInt(a) >> BigInt(n); +} + +const shl = shiftLeft; +const shr = shiftRight; + +function isOdd(a) { + return (BigInt(a) & BigInt(1)) == BigInt(1); +} + +function naf(n) { + let E = BigInt(n); + const res = []; + while (E) { + if (E & BigInt(1)) { + const z = 2 - Number(E % BigInt(4)); + res.push(z); + E = E - BigInt(z); + } else { + res.push(0); + } + E = E >> BigInt(1); + } + return res; +} + +function bits(n) { + let E = BigInt(n); + const res = []; + while (E) { + if (E & BigInt(1)) { + res.push(1); + } else { + res.push(0); + } + E = E >> BigInt(1); + } + return res; +} + +function toNumber(s) { + if (s > BigInt(Number.MAX_SAFE_INTEGER)) { + throw new Error("Number too big"); + } + return Number(s); +} + +function toArray(s, radix) { + const res = []; + let rem = BigInt(s); + radix = BigInt(radix); + while (rem) { + res.unshift(Number(rem % radix)); + rem = rem / radix; + } + return res; +} + +function add(a, b) { + return BigInt(a) + BigInt(b); +} + +function sub(a, b) { + return BigInt(a) - BigInt(b); +} + +function neg(a) { + return -BigInt(a); +} + +function mul(a, b) { + return BigInt(a) * BigInt(b); +} + +function square(a) { + return BigInt(a) * BigInt(a); +} + +function pow(a, b) { + return BigInt(a) ** BigInt(b); +} + +function exp(a, b) { + return BigInt(a) ** BigInt(b); +} + +function abs(a) { + return BigInt(a) >= 0 ? BigInt(a) : -BigInt(a); +} + +function div(a, b) { + return BigInt(a) / BigInt(b); +} + +function mod(a, b) { + return BigInt(a) % BigInt(b); +} + +function eq(a, b) { + return BigInt(a) == BigInt(b); +} + +function neq(a, b) { + return BigInt(a) != BigInt(b); +} + +function lt(a, b) { + return BigInt(a) < BigInt(b); +} + +function gt(a, b) { + return BigInt(a) > BigInt(b); +} + +function leq(a, b) { + return BigInt(a) <= BigInt(b); +} + +function geq(a, b) { + return BigInt(a) >= BigInt(b); +} + +function band(a, b) { + return BigInt(a) & BigInt(b); +} + +function bor(a, b) { + return BigInt(a) | BigInt(b); +} + +function bxor(a, b) { + return BigInt(a) ^ BigInt(b); +} + +function land(a, b) { + return BigInt(a) && BigInt(b); +} + +function lor(a, b) { + return BigInt(a) || BigInt(b); +} + +function lnot(a) { + return !BigInt(a); +} + +// Returns a buffer with Little Endian Representation +function toRprLE(buff, o, e, n8) { + const s = "0000000" + e.toString(16); + const v = new Uint32Array(buff.buffer, o, n8 / 4); + const l = (((s.length - 7) * 4 - 1) >> 5) + 1; // Number of 32bit words; + for (let i = 0; i < l; i++) v[i] = parseInt(s.substring(s.length - 8 * i - 8, s.length - 8 * i), 16); + for (let i = l; i < v.length; i++) v[i] = 0; + for (let i = v.length * 4; i < n8; i++) buff[i] = toNumber(band(shiftRight(e, i * 8), 0xff)); +} + +// Returns a buffer with Big Endian Representation +function toRprBE(buff, o, e, n8) { + const s = "0000000" + e.toString(16); + const v = new DataView(buff.buffer, buff.byteOffset + o, n8); + const l = (((s.length - 7) * 4 - 1) >> 5) + 1; // Number of 32bit words; + for (let i = 0; i < l; i++) v.setUint32(n8 - i * 4 - 4, parseInt(s.substring(s.length - 8 * i - 8, s.length - 8 * i), 16), false); + for (let i = 0; i < n8 / 4 - l; i++) v[i] = 0; +} + +// Pases a buffer with Little Endian Representation +function fromRprLE(buff, o, n8) { + n8 = n8 || buff.byteLength; + o = o || 0; + const v = new Uint32Array(buff.buffer, o, n8 / 4); + const a = new Array(n8 / 4); + v.forEach((ch, i) => (a[a.length - i - 1] = ch.toString(16).padStart(8, "0"))); + return fromString(a.join(""), 16); +} + +// Pases a buffer with Big Endian Representation +function fromRprBE(buff, o, n8) { + n8 = n8 || buff.byteLength; + o = o || 0; + const v = new DataView(buff.buffer, buff.byteOffset + o, n8); + const a = new Array(n8 / 4); + for (let i = 0; i < n8 / 4; i++) { + a[i] = v + .getUint32(i * 4, false) + .toString(16) + .padStart(8, "0"); + } + return fromString(a.join(""), 16); +} + +function toString(a, radix) { + return a.toString(radix); +} + +function toLEBuff(a) { + const buff = new Uint8Array(Math.floor((bitLength(a) - 1) / 8) + 1); + toRprLE(buff, 0, a, buff.byteLength); + return buff; +} + +const zero = e(0); +const one = e(1); + +exports.abs = abs; +exports.add = add; +exports.band = band; +exports.bitLength = bitLength; +exports.bits = bits; +exports.bor = bor; +exports.bxor = bxor; +exports.div = div; +exports.e = e; +exports.eq = eq; +exports.exp = exp; +exports.fromArray = fromArray; +exports.fromRprBE = fromRprBE; +exports.fromRprLE = fromRprLE; +exports.fromString = fromString; +exports.geq = geq; +exports.gt = gt; +exports.isNegative = isNegative; +exports.isOdd = isOdd; +exports.isZero = isZero; +exports.land = land; +exports.leq = leq; +exports.lnot = lnot; +exports.lor = lor; +exports.lt = lt; +exports.mod = mod; +exports.mul = mul; +exports.naf = naf; +exports.neg = neg; +exports.neq = neq; +exports.one = one; +exports.pow = pow; +exports.shiftLeft = shiftLeft; +exports.shiftRight = shiftRight; +exports.shl = shl; +exports.shr = shr; +exports.square = square; +exports.sub = sub; +exports.toArray = toArray; +exports.toLEBuff = toLEBuff; +exports.toNumber = toNumber; +exports.toRprBE = toRprBE; +exports.toRprLE = toRprLE; +exports.toString = toString; +exports.zero = zero; diff --git a/build/lib.esm/main.js b/build/lib.esm/main.js new file mode 100644 index 0000000..5c2792a --- /dev/null +++ b/build/lib.esm/main.js @@ -0,0 +1,6 @@ +import * as scalar from './src/scalar.js'; +export { default as F1Field, default as ZqField } from './src/f1field.js'; + +const Scalar = scalar; + +export { Scalar }; diff --git a/build/lib.esm/src/f1field.js b/build/lib.esm/src/f1field.js new file mode 100644 index 0000000..7aa0f3e --- /dev/null +++ b/build/lib.esm/src/f1field.js @@ -0,0 +1,365 @@ +import { bitLength, toRprLE, toRprBE, fromRprLE, fromRprBE } from './scalar.js'; +import { exp } from './futils.js'; +import buildSqrt from './fsqrt.js'; +import { getRandomBytes } from './random.js'; +import FFT from './fft.js'; + +/* global BigInt */ + +class ZqField { + constructor(p) { + this.type = "F1"; + this.one = BigInt(1); + this.zero = BigInt(0); + this.p = BigInt(p); + this.m = 1; + this.negone = this.p - this.one; + this.two = BigInt(2); + this.half = this.p >> this.one; + this.bitLength = bitLength(this.p); + this.mask = (this.one << BigInt(this.bitLength)) - this.one; + + this.n64 = Math.floor((this.bitLength - 1) / 64) + 1; + this.n32 = this.n64 * 2; + this.n8 = this.n64 * 8; + this.R = this.e(this.one << BigInt(this.n64 * 64)); + this.Ri = this.inv(this.R); + + const e = this.negone >> this.one; + this.nqr = this.two; + let r = this.pow(this.nqr, e); + while (!this.eq(r, this.negone)) { + this.nqr = this.nqr + this.one; + r = this.pow(this.nqr, e); + } + + this.s = 0; + this.t = this.negone; + + while ((this.t & this.one) == this.zero) { + this.s = this.s + 1; + this.t = this.t >> this.one; + } + + this.nqr_to_t = this.pow(this.nqr, this.t); + + buildSqrt(this); + + this.FFT = new FFT(this, this, this.mul.bind(this)); + + this.fft = this.FFT.fft.bind(this.FFT); + this.ifft = this.FFT.ifft.bind(this.FFT); + this.w = this.FFT.w; + this.wi = this.FFT.wi; + + this.shift = this.square(this.nqr); + this.k = this.exp(this.nqr, 2 ** this.s); + } + + e(a, b) { + let res; + if (!b) { + res = BigInt(a); + } else if (b == 16) { + res = BigInt("0x" + a); + } + if (res < 0) { + let nres = -res; + if (nres >= this.p) nres = nres % this.p; + return this.p - nres; + } else { + return res >= this.p ? res % this.p : res; + } + } + + add(a, b) { + const res = a + b; + return res >= this.p ? res - this.p : res; + } + + sub(a, b) { + return a >= b ? a - b : this.p - b + a; + } + + neg(a) { + return a ? this.p - a : a; + } + + mul(a, b) { + return (a * b) % this.p; + } + + mulScalar(base, s) { + return (base * this.e(s)) % this.p; + } + + square(a) { + return (a * a) % this.p; + } + + eq(a, b) { + return a == b; + } + + neq(a, b) { + return a != b; + } + + lt(a, b) { + const aa = a > this.half ? a - this.p : a; + const bb = b > this.half ? b - this.p : b; + return aa < bb; + } + + gt(a, b) { + const aa = a > this.half ? a - this.p : a; + const bb = b > this.half ? b - this.p : b; + return aa > bb; + } + + leq(a, b) { + const aa = a > this.half ? a - this.p : a; + const bb = b > this.half ? b - this.p : b; + return aa <= bb; + } + + geq(a, b) { + const aa = a > this.half ? a - this.p : a; + const bb = b > this.half ? b - this.p : b; + return aa >= bb; + } + + div(a, b) { + return this.mul(a, this.inv(b)); + } + + idiv(a, b) { + if (!b) throw new Error("Division by zero"); + return a / b; + } + + inv(a) { + if (!a) throw new Error("Division by zero"); + + let t = this.zero; + let r = this.p; + let newt = this.one; + let newr = a % this.p; + while (newr) { + let q = r / newr; + [t, newt] = [newt, t - q * newt]; + [r, newr] = [newr, r - q * newr]; + } + if (t < this.zero) t += this.p; + return t; + } + + mod(a, b) { + return a % b; + } + + pow(b, e) { + return exp(this, b, e); + } + + exp(b, e) { + return exp(this, b, e); + } + + band(a, b) { + const res = a & b & this.mask; + return res >= this.p ? res - this.p : res; + } + + bor(a, b) { + const res = (a | b) & this.mask; + return res >= this.p ? res - this.p : res; + } + + bxor(a, b) { + const res = (a ^ b) & this.mask; + return res >= this.p ? res - this.p : res; + } + + bnot(a) { + const res = a ^ this.mask; + return res >= this.p ? res - this.p : res; + } + + shl(a, b) { + if (Number(b) < this.bitLength) { + const res = (a << b) & this.mask; + return res >= this.p ? res - this.p : res; + } else { + const nb = this.p - b; + if (Number(nb) < this.bitLength) { + return a >> nb; + } else { + return this.zero; + } + } + } + + shr(a, b) { + if (Number(b) < this.bitLength) { + return a >> b; + } else { + const nb = this.p - b; + if (Number(nb) < this.bitLength) { + const res = (a << nb) & this.mask; + return res >= this.p ? res - this.p : res; + } else { + return 0; + } + } + } + + land(a, b) { + return a && b ? this.one : this.zero; + } + + lor(a, b) { + return a || b ? this.one : this.zero; + } + + lnot(a) { + return a ? this.zero : this.one; + } + + sqrt_old(n) { + if (n == this.zero) return this.zero; + + // Test that have solution + const res = this.pow(n, this.negone >> this.one); + if (res != this.one) return null; + + let m = this.s; + let c = this.nqr_to_t; + let t = this.pow(n, this.t); + let r = this.pow(n, this.add(this.t, this.one) >> this.one); + + while (t != this.one) { + let sq = this.square(t); + let i = 1; + while (sq != this.one) { + i++; + sq = this.square(sq); + } + + // b = c ^ m-i-1 + let b = c; + for (let j = 0; j < m - i - 1; j++) b = this.square(b); + + m = i; + c = this.square(b); + t = this.mul(t, c); + r = this.mul(r, b); + } + + if (r > this.p >> this.one) { + r = this.neg(r); + } + + return r; + } + + normalize(a, b) { + a = BigInt(a, b); + if (a < 0) { + let na = -a; + if (na >= this.p) na = na % this.p; + return this.p - na; + } else { + return a >= this.p ? a % this.p : a; + } + } + + random() { + const nBytes = (this.bitLength * 2) / 8; + let res = this.zero; + for (let i = 0; i < nBytes; i++) { + res = (res << BigInt(8)) + BigInt(getRandomBytes(1)[0]); + } + return res % this.p; + } + + toString(a, base) { + base = base || 10; + let vs; + if (a > this.half && base == 10) { + const v = this.p - a; + vs = "-" + v.toString(base); + } else { + vs = a.toString(base); + } + return vs; + } + + isZero(a) { + return a == this.zero; + } + + fromRng(rng) { + let v; + do { + v = this.zero; + for (let i = 0; i < this.n64; i++) { + v += rng.nextU64() << BigInt(64 * i); + } + v &= this.mask; + } while (v >= this.p); + v = (v * this.Ri) % this.p; // Convert from montgomery + return v; + } + + fft(a) { + return this.FFT.fft(a); + } + + ifft(a) { + return this.FFT.ifft(a); + } + + // Returns a buffer with Little Endian Representation + toRprLE(buff, o, e) { + toRprLE(buff, o, e, this.n64 * 8); + } + + // Returns a buffer with Big Endian Representation + toRprBE(buff, o, e) { + toRprBE(buff, o, e, this.n64 * 8); + } + + // Returns a buffer with Big Endian Montgomery Representation + toRprBEM(buff, o, e) { + return this.toRprBE(buff, o, this.mul(this.R, e)); + } + + toRprLEM(buff, o, e) { + return this.toRprLE(buff, o, this.mul(this.R, e)); + } + + // Pases a buffer with Little Endian Representation + fromRprLE(buff, o) { + return fromRprLE(buff, o, this.n8); + } + + // Pases a buffer with Big Endian Representation + fromRprBE(buff, o) { + return fromRprBE(buff, o, this.n8); + } + + fromRprLEM(buff, o) { + return this.mul(this.fromRprLE(buff, o), this.Ri); + } + + fromRprBEM(buff, o) { + return this.mul(this.fromRprBE(buff, o), this.Ri); + } + + toObject(a) { + return a; + } +} + +export { ZqField as default }; diff --git a/build/lib.esm/src/fft.js b/build/lib.esm/src/fft.js new file mode 100644 index 0000000..c1db886 --- /dev/null +++ b/build/lib.esm/src/fft.js @@ -0,0 +1,146 @@ +/* + 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 ]. + */ + +class FFT { + constructor(G, F, opMulGF) { + this.F = F; + this.G = G; + this.opMulGF = opMulGF; + + let rem = F.sqrt_t || F.t; + let s = F.sqrt_s || F.s; + + let nqr = F.one; + while (F.eq(F.pow(nqr, F.half), F.one)) nqr = F.add(nqr, F.one); + + this.w = new Array(s + 1); + this.wi = new Array(s + 1); + this.w[s] = this.F.pow(nqr, rem); + this.wi[s] = this.F.inv(this.w[s]); + + let n = s - 1; + while (n >= 0) { + this.w[n] = this.F.square(this.w[n + 1]); + this.wi[n] = this.F.square(this.wi[n + 1]); + n--; + } + + this.roots = []; + /* + for (let i=0; i<16; i++) { + let r = this.F.one; + n = 1 << i; + const rootsi = new Array(n); + for (let j=0; j= 0 && !this.roots[i]; i--) { + let r = this.F.one; + const nroots = 1 << i; + const rootsi = new Array(nroots); + for (let j = 0; j < nroots; j++) { + rootsi[j] = r; + r = this.F.mul(r, this.w[i]); + } + + this.roots[i] = rootsi; + } + } + + fft(p) { + if (p.length <= 1) return p; + const bits = log2(p.length - 1) + 1; + this._setRoots(bits); + + const m = 1 << bits; + if (p.length != m) { + throw new Error("Size must be multiple of 2"); + } + const res = __fft(this, p, bits, 0, 1); + return res; + } + + ifft(p) { + if (p.length <= 1) return p; + const bits = log2(p.length - 1) + 1; + this._setRoots(bits); + const m = 1 << bits; + if (p.length != m) { + throw new Error("Size must be multiple of 2"); + } + const res = __fft(this, p, bits, 0, 1); + const twoinvm = this.F.inv(this.F.mulScalar(this.F.one, m)); + const resn = new Array(m); + for (let i = 0; i < m; i++) { + resn[i] = this.opMulGF(res[(m - i) % m], twoinvm); + } + + return resn; + } +} + +function log2(V) { + return ( + ((V & 0xffff0000) !== 0 ? ((V &= 0xffff0000), 16) : 0) | + ((V & 0xff00ff00) !== 0 ? ((V &= 0xff00ff00), 8) : 0) | + ((V & 0xf0f0f0f0) !== 0 ? ((V &= 0xf0f0f0f0), 4) : 0) | + ((V & 0xcccccccc) !== 0 ? ((V &= 0xcccccccc), 2) : 0) | + ((V & 0xaaaaaaaa) !== 0) + ); +} + +function __fft(PF, pall, bits, offset, step) { + const n = 1 << bits; + if (n == 1) { + return [pall[offset]]; + } else if (n == 2) { + return [PF.G.add(pall[offset], pall[offset + step]), PF.G.sub(pall[offset], pall[offset + step])]; + } + + const ndiv2 = n >> 1; + const p1 = __fft(PF, pall, bits - 1, offset, step * 2); + const p2 = __fft(PF, pall, bits - 1, offset + step, step * 2); + + const out = new Array(n); + + for (let i = 0; i < ndiv2; i++) { + out[i] = PF.G.add(p1[i], PF.opMulGF(p2[i], PF.roots[bits][i])); + out[i + ndiv2] = PF.G.sub(p1[i], PF.opMulGF(p2[i], PF.roots[bits][i])); + } + + return out; +} + +export { FFT as default }; diff --git a/build/lib.esm/src/fsqrt.js b/build/lib.esm/src/fsqrt.js new file mode 100644 index 0000000..080e94e --- /dev/null +++ b/build/lib.esm/src/fsqrt.js @@ -0,0 +1,165 @@ +import { eq, mod, pow, sub, isOdd, div } from './scalar.js'; + +// Check here: https://eprint.iacr.org/2012/685.pdf + +function buildSqrt(F) { + if (F.m % 2 == 1) { + if (eq(mod(F.p, 4), 1)) { + if (eq(mod(F.p, 8), 1)) { + if (eq(mod(F.p, 16), 1)) { + // alg7_muller(F); + alg5_tonelliShanks(F); + } else if (eq(mod(F.p, 16), 9)) { + alg4_kong(F); + } else { + throw new Error("Field withot sqrt"); + } + } else if (eq(mod(F.p, 8), 5)) { + alg3_atkin(F); + } else { + throw new Error("Field withot sqrt"); + } + } else if (eq(mod(F.p, 4), 3)) { + alg2_shanks(F); + } + } else { + const pm2mod4 = mod(pow(F.p, F.m / 2), 4); + if (pm2mod4 == 1) { + alg10_adj(F); + } else if (pm2mod4 == 3) { + alg9_adj(F); + } else { + alg8_complex(F); + } + } +} + +function alg5_tonelliShanks(F) { + F.sqrt_q = pow(F.p, F.m); + + F.sqrt_s = 0; + F.sqrt_t = sub(F.sqrt_q, 1); + + while (!isOdd(F.sqrt_t)) { + F.sqrt_s = F.sqrt_s + 1; + F.sqrt_t = div(F.sqrt_t, 2); + } + + let c0 = F.one; + + while (F.eq(c0, F.one)) { + const c = F.random(); + F.sqrt_z = F.pow(c, F.sqrt_t); + c0 = F.pow(F.sqrt_z, 2 ** (F.sqrt_s - 1)); + } + + F.sqrt_tm1d2 = div(sub(F.sqrt_t, 1), 2); + + F.sqrt = function (a) { + const F = this; + if (F.isZero(a)) return F.zero; + let w = F.pow(a, F.sqrt_tm1d2); + const a0 = F.pow(F.mul(F.square(w), a), 2 ** (F.sqrt_s - 1)); + if (F.eq(a0, F.negone)) return null; + + let v = F.sqrt_s; + let x = F.mul(a, w); + let b = F.mul(x, w); + let z = F.sqrt_z; + while (!F.eq(b, F.one)) { + let b2k = F.square(b); + let k = 1; + while (!F.eq(b2k, F.one)) { + b2k = F.square(b2k); + k++; + } + + w = z; + for (let i = 0; i < v - k - 1; i++) { + w = F.square(w); + } + z = F.square(w); + b = F.mul(b, z); + x = F.mul(x, w); + v = k; + } + return F.geq(x, F.zero) ? x : F.neg(x); + }; +} + +function alg4_kong(F) { + F.sqrt = function () { + throw new Error("Sqrt alg 4 not implemented"); + }; +} + +function alg3_atkin(F) { + F.sqrt = function () { + throw new Error("Sqrt alg 3 not implemented"); + }; +} + +function alg2_shanks(F) { + F.sqrt_q = pow(F.p, F.m); + F.sqrt_e1 = div(sub(F.sqrt_q, 3), 4); + + F.sqrt = function (a) { + if (this.isZero(a)) return this.zero; + + // Test that have solution + const a1 = this.pow(a, this.sqrt_e1); + + const a0 = this.mul(this.square(a1), a); + + if (this.eq(a0, this.negone)) return null; + + const x = this.mul(a1, a); + + return F.geq(x, F.zero) ? x : F.neg(x); + }; +} + +function alg10_adj(F) { + F.sqrt = function () { + throw new Error("Sqrt alg 10 not implemented"); + }; +} + +function alg9_adj(F) { + F.sqrt_q = pow(F.p, F.m / 2); + F.sqrt_e34 = div(sub(F.sqrt_q, 3), 4); + F.sqrt_e12 = div(sub(F.sqrt_q, 1), 2); + + F.frobenius = function (n, x) { + if (n % 2 == 1) { + return F.conjugate(x); + } else { + return x; + } + }; + + F.sqrt = function (a) { + const F = this; + const a1 = F.pow(a, F.sqrt_e34); + const alfa = F.mul(F.square(a1), a); + const a0 = F.mul(F.frobenius(1, alfa), alfa); + if (F.eq(a0, F.negone)) return null; + const x0 = F.mul(a1, a); + let x; + if (F.eq(alfa, F.negone)) { + x = F.mul(x0, [F.F.zero, F.F.one]); + } else { + const b = F.pow(F.add(F.one, alfa), F.sqrt_e12); + x = F.mul(b, x0); + } + return F.geq(x, F.zero) ? x : F.neg(x); + }; +} + +function alg8_complex(F) { + F.sqrt = function () { + throw new Error("Sqrt alg 8 not implemented"); + }; +} + +export { buildSqrt as default }; diff --git a/build/lib.esm/src/futils.js b/build/lib.esm/src/futils.js new file mode 100644 index 0000000..7119a60 --- /dev/null +++ b/build/lib.esm/src/futils.js @@ -0,0 +1,61 @@ +import { isZero, bits } from './scalar.js'; + +/* + 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 . +*/ + + +/* +exports.mulScalar = (F, base, e) =>{ + let res = F.zero; + let rem = bigInt(e); + let exp = base; + + while (! rem.eq(bigInt.zero)) { + if (rem.and(bigInt.one).eq(bigInt.one)) { + res = F.add(res, exp); + } + exp = F.double(exp); + rem = rem.shiftRight(1); + } + + return res; +}; +*/ + +function exp(F, base, e) { + if (isZero(e)) return F.one; + + const n = bits(e); + + if (n.length == 0) return F.one; + + let res = base; + + for (let i = n.length - 2; i >= 0; i--) { + res = F.square(res); + + if (n[i]) { + res = F.mul(res, base); + } + } + + return res; +} + +export { exp }; diff --git a/build/lib.esm/src/random.js b/build/lib.esm/src/random.js new file mode 100644 index 0000000..1215d08 --- /dev/null +++ b/build/lib.esm/src/random.js @@ -0,0 +1,16 @@ +function getRandomBytes(n) { + let array = new Uint8Array(n); + // Browser & Node + if (typeof globalThis.crypto !== "undefined") { + // Supported + globalThis.crypto.getRandomValues(array); + } else { + // fallback + for (let i = 0; i < n; i++) { + array[i] = (Math.random() * 4294967296) >>> 0; + } + } + return array; +} + +export { getRandomBytes }; diff --git a/build/lib.esm/src/scalar.js b/build/lib.esm/src/scalar.js new file mode 100644 index 0000000..81e9b74 --- /dev/null +++ b/build/lib.esm/src/scalar.js @@ -0,0 +1,248 @@ +/* global BigInt */ +const hexLen = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]; + +function fromString(s, radix) { + if (!radix || radix == 10) { + return BigInt(s); + } else if (radix == 16) { + if (s.slice(0, 2) == "0x") { + return BigInt(s); + } else { + return BigInt("0x" + s); + } + } +} + +const e = fromString; + +function fromArray(a, radix) { + let acc = BigInt(0); + radix = BigInt(radix); + for (let i = 0; i < a.length; i++) { + acc = acc * radix + BigInt(a[i]); + } + return acc; +} + +function bitLength(a) { + const aS = a.toString(16); + return (aS.length - 1) * 4 + hexLen[parseInt(aS[0], 16)]; +} + +function isNegative(a) { + return BigInt(a) < BigInt(0); +} + +function isZero(a) { + return !a; +} + +function shiftLeft(a, n) { + return BigInt(a) << BigInt(n); +} + +function shiftRight(a, n) { + return BigInt(a) >> BigInt(n); +} + +const shl = shiftLeft; +const shr = shiftRight; + +function isOdd(a) { + return (BigInt(a) & BigInt(1)) == BigInt(1); +} + +function naf(n) { + let E = BigInt(n); + const res = []; + while (E) { + if (E & BigInt(1)) { + const z = 2 - Number(E % BigInt(4)); + res.push(z); + E = E - BigInt(z); + } else { + res.push(0); + } + E = E >> BigInt(1); + } + return res; +} + +function bits(n) { + let E = BigInt(n); + const res = []; + while (E) { + if (E & BigInt(1)) { + res.push(1); + } else { + res.push(0); + } + E = E >> BigInt(1); + } + return res; +} + +function toNumber(s) { + if (s > BigInt(Number.MAX_SAFE_INTEGER)) { + throw new Error("Number too big"); + } + return Number(s); +} + +function toArray(s, radix) { + const res = []; + let rem = BigInt(s); + radix = BigInt(radix); + while (rem) { + res.unshift(Number(rem % radix)); + rem = rem / radix; + } + return res; +} + +function add(a, b) { + return BigInt(a) + BigInt(b); +} + +function sub(a, b) { + return BigInt(a) - BigInt(b); +} + +function neg(a) { + return -BigInt(a); +} + +function mul(a, b) { + return BigInt(a) * BigInt(b); +} + +function square(a) { + return BigInt(a) * BigInt(a); +} + +function pow(a, b) { + return BigInt(a) ** BigInt(b); +} + +function exp(a, b) { + return BigInt(a) ** BigInt(b); +} + +function abs(a) { + return BigInt(a) >= 0 ? BigInt(a) : -BigInt(a); +} + +function div(a, b) { + return BigInt(a) / BigInt(b); +} + +function mod(a, b) { + return BigInt(a) % BigInt(b); +} + +function eq(a, b) { + return BigInt(a) == BigInt(b); +} + +function neq(a, b) { + return BigInt(a) != BigInt(b); +} + +function lt(a, b) { + return BigInt(a) < BigInt(b); +} + +function gt(a, b) { + return BigInt(a) > BigInt(b); +} + +function leq(a, b) { + return BigInt(a) <= BigInt(b); +} + +function geq(a, b) { + return BigInt(a) >= BigInt(b); +} + +function band(a, b) { + return BigInt(a) & BigInt(b); +} + +function bor(a, b) { + return BigInt(a) | BigInt(b); +} + +function bxor(a, b) { + return BigInt(a) ^ BigInt(b); +} + +function land(a, b) { + return BigInt(a) && BigInt(b); +} + +function lor(a, b) { + return BigInt(a) || BigInt(b); +} + +function lnot(a) { + return !BigInt(a); +} + +// Returns a buffer with Little Endian Representation +function toRprLE(buff, o, e, n8) { + const s = "0000000" + e.toString(16); + const v = new Uint32Array(buff.buffer, o, n8 / 4); + const l = (((s.length - 7) * 4 - 1) >> 5) + 1; // Number of 32bit words; + for (let i = 0; i < l; i++) v[i] = parseInt(s.substring(s.length - 8 * i - 8, s.length - 8 * i), 16); + for (let i = l; i < v.length; i++) v[i] = 0; + for (let i = v.length * 4; i < n8; i++) buff[i] = toNumber(band(shiftRight(e, i * 8), 0xff)); +} + +// Returns a buffer with Big Endian Representation +function toRprBE(buff, o, e, n8) { + const s = "0000000" + e.toString(16); + const v = new DataView(buff.buffer, buff.byteOffset + o, n8); + const l = (((s.length - 7) * 4 - 1) >> 5) + 1; // Number of 32bit words; + for (let i = 0; i < l; i++) v.setUint32(n8 - i * 4 - 4, parseInt(s.substring(s.length - 8 * i - 8, s.length - 8 * i), 16), false); + for (let i = 0; i < n8 / 4 - l; i++) v[i] = 0; +} + +// Pases a buffer with Little Endian Representation +function fromRprLE(buff, o, n8) { + n8 = n8 || buff.byteLength; + o = o || 0; + const v = new Uint32Array(buff.buffer, o, n8 / 4); + const a = new Array(n8 / 4); + v.forEach((ch, i) => (a[a.length - i - 1] = ch.toString(16).padStart(8, "0"))); + return fromString(a.join(""), 16); +} + +// Pases a buffer with Big Endian Representation +function fromRprBE(buff, o, n8) { + n8 = n8 || buff.byteLength; + o = o || 0; + const v = new DataView(buff.buffer, buff.byteOffset + o, n8); + const a = new Array(n8 / 4); + for (let i = 0; i < n8 / 4; i++) { + a[i] = v + .getUint32(i * 4, false) + .toString(16) + .padStart(8, "0"); + } + return fromString(a.join(""), 16); +} + +function toString(a, radix) { + return a.toString(radix); +} + +function toLEBuff(a) { + const buff = new Uint8Array(Math.floor((bitLength(a) - 1) / 8) + 1); + toRprLE(buff, 0, a, buff.byteLength); + return buff; +} + +const zero = e(0); +const one = e(1); + +export { abs, add, band, bitLength, bits, bor, bxor, div, e, eq, exp, fromArray, fromRprBE, fromRprLE, fromString, geq, gt, isNegative, isOdd, isZero, land, leq, lnot, lor, lt, mod, mul, naf, neg, neq, one, pow, shiftLeft, shiftRight, shl, shr, square, sub, toArray, toLEBuff, toNumber, toRprBE, toRprLE, toString, zero }; diff --git a/build/main.cjs b/build/main.cjs index 7ba9ac3..c0a0c92 100644 --- a/build/main.cjs +++ b/build/main.cjs @@ -1,7 +1,5 @@ 'use strict'; -var crypto = require('crypto'); - /* global BigInt */ const hexLen = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]; @@ -520,20 +518,15 @@ function alg8_complex(F) { function getRandomBytes(n) { let array = new Uint8Array(n); - if (process.browser) { - // Browser - if (typeof globalThis.crypto !== "undefined") { - // Supported - globalThis.crypto.getRandomValues(array); - } else { - // fallback - for (let i = 0; i < n; i++) { - array[i] = (Math.random() * 4294967296) >>> 0; - } - } + // Browser & Node + if (typeof globalThis.crypto !== "undefined") { + // Supported + globalThis.crypto.getRandomValues(array); } else { - // NodeJS - crypto.randomFillSync(array); + // fallback + for (let i = 0; i < n; i++) { + array[i] = (Math.random() * 4294967296) >>> 0; + } } return array; } diff --git a/build/main.esm.js b/build/main.esm.js index 182e480..4fb647f 100644 --- a/build/main.esm.js +++ b/build/main.esm.js @@ -1,5 +1,3 @@ -import crypto from 'crypto'; - /* global BigInt */ const hexLen = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]; @@ -518,20 +516,15 @@ function alg8_complex(F) { function getRandomBytes(n) { let array = new Uint8Array(n); - if (process.browser) { - // Browser - if (typeof globalThis.crypto !== "undefined") { - // Supported - globalThis.crypto.getRandomValues(array); - } else { - // fallback - for (let i = 0; i < n; i++) { - array[i] = (Math.random() * 4294967296) >>> 0; - } - } + // Browser & Node + if (typeof globalThis.crypto !== "undefined") { + // Supported + globalThis.crypto.getRandomValues(array); } else { - // NodeJS - crypto.randomFillSync(array); + // fallback + for (let i = 0; i < n; i++) { + array[i] = (Math.random() * 4294967296) >>> 0; + } } return array; } diff --git a/build/main.umd.min.js b/build/main.umd.min.js index 02835ed..ad0c5ff 100644 --- a/build/main.umd.min.js +++ b/build/main.umd.min.js @@ -1 +1 @@ -!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("crypto")):"function"==typeof define&&define.amd?define(["exports","crypto"],n):n((t="undefined"!=typeof globalThis?globalThis:t||self).Ffjavascript={},t.crypto)}(this,(function(t,n){"use strict";const i=[0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4];function r(t,n){return n&&10!=n?16==n?"0x"==t.slice(0,2)?BigInt(t):BigInt("0x"+t):void 0:BigInt(t)}const s=r;function e(t){const n=t.toString(16);return 4*(n.length-1)+i[parseInt(n[0],16)]}function o(t){return!t}function h(t,n){return BigInt(t)<>BigInt(n)}const f=h,l=u;function g(t){return(BigInt(t)&BigInt(1))==BigInt(1)}function p(t){let n=BigInt(t);const i=[];for(;n;)n&BigInt(1)?i.push(1):i.push(0),n>>=BigInt(1);return i}function c(t){if(t>BigInt(Number.MAX_SAFE_INTEGER))throw new Error("Number too big");return Number(t)}function a(t,n){return BigInt(t)-BigInt(n)}function q(t,n){return BigInt(t)**BigInt(n)}function B(t,n){return BigInt(t)/BigInt(n)}function m(t,n){return BigInt(t)%BigInt(n)}function I(t,n){return BigInt(t)==BigInt(n)}function w(t,n){return BigInt(t)&BigInt(n)}function b(t,n,i,r){const s="0000000"+i.toString(16),e=new Uint32Array(t.buffer,n,r/4),o=1+(4*(s.length-7)-1>>5);for(let t=0;t>5);for(let t=0;te[e.length-n-1]=t.toString(16).padStart(8,"0"))),r(e.join(""),16)}function F(t,n,i){i=i||t.byteLength,n=n||0;const s=new DataView(t.buffer,t.byteOffset+n,i),e=new Array(i/4);for(let t=0;t=0?BigInt(t):-BigInt(t)},add:function(t,n){return BigInt(t)+BigInt(n)},band:w,bitLength:e,bits:p,bor:function(t,n){return BigInt(t)|BigInt(n)},bxor:function(t,n){return BigInt(t)^BigInt(n)},div:B,e:s,eq:I,exp:function(t,n){return BigInt(t)**BigInt(n)},fromArray:function(t,n){let i=BigInt(0);n=BigInt(n);for(let r=0;r=BigInt(n)},gt:function(t,n){return BigInt(t)>BigInt(n)},isNegative:function(t){return BigInt(t)>=BigInt(1)}return i},neg:function(t){return-BigInt(t)},neq:function(t,n){return BigInt(t)!=BigInt(n)},one:R,pow:q,shiftLeft:h,shiftRight:u,shl:f,shr:l,square:function(t){return BigInt(t)*BigInt(t)},sub:a,toArray:function(t,n){const i=[];let r=BigInt(t);for(n=BigInt(n);r;)i.unshift(Number(r%n)),r/=n;return i},toLEBuff:function(t){const n=new Uint8Array(Math.floor((e(t)-1)/8)+1);return b(n,0,t,n.byteLength),n},toNumber:c,toRprBE:d,toRprLE:b,toString:function(t,n){return t.toString(n)},zero:E});function z(t,n,i){if(o(i))return t.one;const r=p(i);if(0==r.length)return t.one;let s=n;for(let i=r.length-2;i>=0;i--)s=t.square(s),r[i]&&(s=t.mul(s,n));return s}function S(t){if(t.m%2==1)if(I(m(t.p,4),1))if(I(m(t.p,8),1))if(I(m(t.p,16),1))!function(t){t.sqrt_q=q(t.p,t.m),t.sqrt_s=0,t.sqrt_t=a(t.sqrt_q,1);for(;!g(t.sqrt_t);)t.sqrt_s=t.sqrt_s+1,t.sqrt_t=B(t.sqrt_t,2);let n=t.one;for(;t.eq(n,t.one);){const i=t.random();t.sqrt_z=t.pow(i,t.sqrt_t),n=t.pow(t.sqrt_z,2**(t.sqrt_s-1))}t.sqrt_tm1d2=B(a(t.sqrt_t,1),2),t.sqrt=function(t){const n=this;if(n.isZero(t))return n.zero;let i=n.pow(t,n.sqrt_tm1d2);const r=n.pow(n.mul(n.square(i),t),2**(n.sqrt_s-1));if(n.eq(r,n.negone))return null;let s=n.sqrt_s,e=n.mul(t,i),o=n.mul(e,i),h=n.sqrt_z;for(;!n.eq(o,n.one);){let t=n.square(o),r=1;for(;!n.eq(t,n.one);)t=n.square(t),r++;i=h;for(let t=0;t>>0;else n.randomFillSync(i);return i}class v{constructor(t,n,i){this.F=n,this.G=t,this.opMulGF=i;let r=n.sqrt_t||n.t,s=n.sqrt_s||n.s,e=n.one;for(;n.eq(n.pow(e,n.half),n.one);)e=n.add(e,n.one);this.w=new Array(s+1),this.wi=new Array(s+1),this.w[s]=this.F.pow(e,r),this.wi[s]=this.F.inv(this.w[s]);let o=s-1;for(;o>=0;)this.w[o]=this.F.square(this.w[o+1]),this.wi[o]=this.F.square(this.wi[o+1]),o--;this.roots=[],this._setRoots(Math.min(s,15))}_setRoots(t){for(let n=t;n>=0&&!this.roots[n];n--){let t=this.F.one;const i=1<>1,h=T(t,n,i-1,r,2*s),u=T(t,n,i-1,r+s,2*s),f=new Array(e);for(let n=0;n>this.one,this.bitLength=e(this.p),this.mask=(this.one<>this.one;this.nqr=this.two;let i=this.pow(this.nqr,n);for(;!this.eq(i,this.negone);)this.nqr=this.nqr+this.one,i=this.pow(this.nqr,n);for(this.s=0,this.t=this.negone;(this.t&this.one)==this.zero;)this.s=this.s+1,this.t=this.t>>this.one;this.nqr_to_t=this.pow(this.nqr,this.t),S(this),this.FFT=new v(this,this,this.mul.bind(this)),this.fft=this.FFT.fft.bind(this.FFT),this.ifft=this.FFT.ifft.bind(this.FFT),this.w=this.FFT.w,this.wi=this.FFT.wi,this.shift=this.square(this.nqr),this.k=this.exp(this.nqr,2**this.s)}e(t,n){let i;if(n?16==n&&(i=BigInt("0x"+t)):i=BigInt(t),i<0){let t=-i;return t>=this.p&&(t%=this.p),this.p-t}return i>=this.p?i%this.p:i}add(t,n){const i=t+n;return i>=this.p?i-this.p:i}sub(t,n){return t>=n?t-n:this.p-n+t}neg(t){return t?this.p-t:t}mul(t,n){return t*n%this.p}mulScalar(t,n){return t*this.e(n)%this.p}square(t){return t*t%this.p}eq(t,n){return t==n}neq(t,n){return t!=n}lt(t,n){return(t>this.half?t-this.p:t)<(n>this.half?n-this.p:n)}gt(t,n){return(t>this.half?t-this.p:t)>(n>this.half?n-this.p:n)}leq(t,n){return(t>this.half?t-this.p:t)<=(n>this.half?n-this.p:n)}geq(t,n){return(t>this.half?t-this.p:t)>=(n>this.half?n-this.p:n)}div(t,n){return this.mul(t,this.inv(n))}idiv(t,n){if(!n)throw new Error("Division by zero");return t/n}inv(t){if(!t)throw new Error("Division by zero");let n=this.zero,i=this.p,r=this.one,s=t%this.p;for(;s;){let t=i/s;[n,r]=[r,n-t*r],[i,s]=[s,i-t*s]}return n=this.p?i-this.p:i}bor(t,n){const i=(t|n)&this.mask;return i>=this.p?i-this.p:i}bxor(t,n){const i=(t^n)&this.mask;return i>=this.p?i-this.p:i}bnot(t){const n=t^this.mask;return n>=this.p?n-this.p:n}shl(t,n){if(Number(n)=this.p?i-this.p:i}{const i=this.p-n;return Number(i)>i:this.zero}}shr(t,n){if(Number(n)>n;{const i=this.p-n;if(Number(i)=this.p?n-this.p:n}return 0}}land(t,n){return t&&n?this.one:this.zero}lor(t,n){return t||n?this.one:this.zero}lnot(t){return t?this.zero:this.one}sqrt_old(t){if(t==this.zero)return this.zero;if(this.pow(t,this.negone>>this.one)!=this.one)return null;let n=this.s,i=this.nqr_to_t,r=this.pow(t,this.t),s=this.pow(t,this.add(this.t,this.one)>>this.one);for(;r!=this.one;){let t=this.square(r),e=1;for(;t!=this.one;)e++,t=this.square(t);let o=i;for(let t=0;tthis.p>>this.one&&(s=this.neg(s)),s}normalize(t,n){if((t=BigInt(t,n))<0){let n=-t;return n>=this.p&&(n%=this.p),this.p-n}return t>=this.p?t%this.p:t}random(){const t=2*this.bitLength/8;let n=this.zero;for(let i=0;ithis.half&&10==n){i="-"+(this.p-t).toString(n)}else i=t.toString(n);return i}isZero(t){return t==this.zero}fromRng(t){let n;do{n=this.zero;for(let i=0;i=this.p);return n=n*this.Ri%this.p,n}fft(t){return this.FFT.fft(t)}ifft(t){return this.FFT.ifft(t)}toRprLE(t,n,i){b(t,n,i,8*this.n64)}toRprBE(t,n,i){d(t,n,i,8*this.n64)}toRprBEM(t,n,i){return this.toRprBE(t,n,this.mul(this.R,i))}toRprLEM(t,n,i){return this.toRprLE(t,n,this.mul(this.R,i))}fromRprLE(t,n){return _(t,n,this.n8)}fromRprBE(t,n){return F(t,n,this.n8)}fromRprLEM(t,n){return this.mul(this.fromRprLE(t,n),this.Ri)}fromRprBEM(t,n){return this.mul(this.fromRprBE(t,n),this.Ri)}toObject(t){return t}}const x=y;t.F1Field=M,t.Scalar=x,t.ZqField=M})); +!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((t="undefined"!=typeof globalThis?globalThis:t||self).Ffjavascript={})}(this,(function(t){"use strict";const n=[0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4];function i(t,n){return n&&10!=n?16==n?"0x"==t.slice(0,2)?BigInt(t):BigInt("0x"+t):void 0:BigInt(t)}const r=i;function s(t){const i=t.toString(16);return 4*(i.length-1)+n[parseInt(i[0],16)]}function e(t){return!t}function o(t,n){return BigInt(t)<>BigInt(n)}const u=o,f=h;function l(t){return(BigInt(t)&BigInt(1))==BigInt(1)}function g(t){let n=BigInt(t);const i=[];for(;n;)n&BigInt(1)?i.push(1):i.push(0),n>>=BigInt(1);return i}function p(t){if(t>BigInt(Number.MAX_SAFE_INTEGER))throw new Error("Number too big");return Number(t)}function c(t,n){return BigInt(t)-BigInt(n)}function a(t,n){return BigInt(t)**BigInt(n)}function q(t,n){return BigInt(t)/BigInt(n)}function B(t,n){return BigInt(t)%BigInt(n)}function m(t,n){return BigInt(t)==BigInt(n)}function I(t,n){return BigInt(t)&BigInt(n)}function w(t,n,i,r){const s="0000000"+i.toString(16),e=new Uint32Array(t.buffer,n,r/4),o=1+(4*(s.length-7)-1>>5);for(let t=0;t>5);for(let t=0;te[e.length-n-1]=t.toString(16).padStart(8,"0"))),i(e.join(""),16)}function _(t,n,r){r=r||t.byteLength,n=n||0;const s=new DataView(t.buffer,t.byteOffset+n,r),e=new Array(r/4);for(let t=0;t=0?BigInt(t):-BigInt(t)},add:function(t,n){return BigInt(t)+BigInt(n)},band:I,bitLength:s,bits:g,bor:function(t,n){return BigInt(t)|BigInt(n)},bxor:function(t,n){return BigInt(t)^BigInt(n)},div:q,e:r,eq:m,exp:function(t,n){return BigInt(t)**BigInt(n)},fromArray:function(t,n){let i=BigInt(0);n=BigInt(n);for(let r=0;r=BigInt(n)},gt:function(t,n){return BigInt(t)>BigInt(n)},isNegative:function(t){return BigInt(t)>=BigInt(1)}return i},neg:function(t){return-BigInt(t)},neq:function(t,n){return BigInt(t)!=BigInt(n)},one:E,pow:a,shiftLeft:o,shiftRight:h,shl:u,shr:f,square:function(t){return BigInt(t)*BigInt(t)},sub:c,toArray:function(t,n){const i=[];let r=BigInt(t);for(n=BigInt(n);r;)i.unshift(Number(r%n)),r/=n;return i},toLEBuff:function(t){const n=new Uint8Array(Math.floor((s(t)-1)/8)+1);return w(n,0,t,n.byteLength),n},toNumber:p,toRprBE:b,toRprLE:w,toString:function(t,n){return t.toString(n)},zero:F});function z(t,n,i){if(e(i))return t.one;const r=g(i);if(0==r.length)return t.one;let s=n;for(let i=r.length-2;i>=0;i--)s=t.square(s),r[i]&&(s=t.mul(s,n));return s}function y(t){if(t.m%2==1)if(m(B(t.p,4),1))if(m(B(t.p,8),1))if(m(B(t.p,16),1))!function(t){t.sqrt_q=a(t.p,t.m),t.sqrt_s=0,t.sqrt_t=c(t.sqrt_q,1);for(;!l(t.sqrt_t);)t.sqrt_s=t.sqrt_s+1,t.sqrt_t=q(t.sqrt_t,2);let n=t.one;for(;t.eq(n,t.one);){const i=t.random();t.sqrt_z=t.pow(i,t.sqrt_t),n=t.pow(t.sqrt_z,2**(t.sqrt_s-1))}t.sqrt_tm1d2=q(c(t.sqrt_t,1),2),t.sqrt=function(t){const n=this;if(n.isZero(t))return n.zero;let i=n.pow(t,n.sqrt_tm1d2);const r=n.pow(n.mul(n.square(i),t),2**(n.sqrt_s-1));if(n.eq(r,n.negone))return null;let s=n.sqrt_s,e=n.mul(t,i),o=n.mul(e,i),h=n.sqrt_z;for(;!n.eq(o,n.one);){let t=n.square(o),r=1;for(;!n.eq(t,n.one);)t=n.square(t),r++;i=h;for(let t=0;t>>0;return n}class L{constructor(t,n,i){this.F=n,this.G=t,this.opMulGF=i;let r=n.sqrt_t||n.t,s=n.sqrt_s||n.s,e=n.one;for(;n.eq(n.pow(e,n.half),n.one);)e=n.add(e,n.one);this.w=new Array(s+1),this.wi=new Array(s+1),this.w[s]=this.F.pow(e,r),this.wi[s]=this.F.inv(this.w[s]);let o=s-1;for(;o>=0;)this.w[o]=this.F.square(this.w[o+1]),this.wi[o]=this.F.square(this.wi[o+1]),o--;this.roots=[],this._setRoots(Math.min(s,15))}_setRoots(t){for(let n=t;n>=0&&!this.roots[n];n--){let t=this.F.one;const i=1<>1,h=A(t,n,i-1,r,2*s),u=A(t,n,i-1,r+s,2*s),f=new Array(e);for(let n=0;n>this.one,this.bitLength=s(this.p),this.mask=(this.one<>this.one;this.nqr=this.two;let i=this.pow(this.nqr,n);for(;!this.eq(i,this.negone);)this.nqr=this.nqr+this.one,i=this.pow(this.nqr,n);for(this.s=0,this.t=this.negone;(this.t&this.one)==this.zero;)this.s=this.s+1,this.t=this.t>>this.one;this.nqr_to_t=this.pow(this.nqr,this.t),y(this),this.FFT=new L(this,this,this.mul.bind(this)),this.fft=this.FFT.fft.bind(this.FFT),this.ifft=this.FFT.ifft.bind(this.FFT),this.w=this.FFT.w,this.wi=this.FFT.wi,this.shift=this.square(this.nqr),this.k=this.exp(this.nqr,2**this.s)}e(t,n){let i;if(n?16==n&&(i=BigInt("0x"+t)):i=BigInt(t),i<0){let t=-i;return t>=this.p&&(t%=this.p),this.p-t}return i>=this.p?i%this.p:i}add(t,n){const i=t+n;return i>=this.p?i-this.p:i}sub(t,n){return t>=n?t-n:this.p-n+t}neg(t){return t?this.p-t:t}mul(t,n){return t*n%this.p}mulScalar(t,n){return t*this.e(n)%this.p}square(t){return t*t%this.p}eq(t,n){return t==n}neq(t,n){return t!=n}lt(t,n){return(t>this.half?t-this.p:t)<(n>this.half?n-this.p:n)}gt(t,n){return(t>this.half?t-this.p:t)>(n>this.half?n-this.p:n)}leq(t,n){return(t>this.half?t-this.p:t)<=(n>this.half?n-this.p:n)}geq(t,n){return(t>this.half?t-this.p:t)>=(n>this.half?n-this.p:n)}div(t,n){return this.mul(t,this.inv(n))}idiv(t,n){if(!n)throw new Error("Division by zero");return t/n}inv(t){if(!t)throw new Error("Division by zero");let n=this.zero,i=this.p,r=this.one,s=t%this.p;for(;s;){let t=i/s;[n,r]=[r,n-t*r],[i,s]=[s,i-t*s]}return n=this.p?i-this.p:i}bor(t,n){const i=(t|n)&this.mask;return i>=this.p?i-this.p:i}bxor(t,n){const i=(t^n)&this.mask;return i>=this.p?i-this.p:i}bnot(t){const n=t^this.mask;return n>=this.p?n-this.p:n}shl(t,n){if(Number(n)=this.p?i-this.p:i}{const i=this.p-n;return Number(i)>i:this.zero}}shr(t,n){if(Number(n)>n;{const i=this.p-n;if(Number(i)=this.p?n-this.p:n}return 0}}land(t,n){return t&&n?this.one:this.zero}lor(t,n){return t||n?this.one:this.zero}lnot(t){return t?this.zero:this.one}sqrt_old(t){if(t==this.zero)return this.zero;if(this.pow(t,this.negone>>this.one)!=this.one)return null;let n=this.s,i=this.nqr_to_t,r=this.pow(t,this.t),s=this.pow(t,this.add(this.t,this.one)>>this.one);for(;r!=this.one;){let t=this.square(r),e=1;for(;t!=this.one;)e++,t=this.square(t);let o=i;for(let t=0;tthis.p>>this.one&&(s=this.neg(s)),s}normalize(t,n){if((t=BigInt(t,n))<0){let n=-t;return n>=this.p&&(n%=this.p),this.p-n}return t>=this.p?t%this.p:t}random(){const t=2*this.bitLength/8;let n=this.zero;for(let i=0;ithis.half&&10==n){i="-"+(this.p-t).toString(n)}else i=t.toString(n);return i}isZero(t){return t==this.zero}fromRng(t){let n;do{n=this.zero;for(let i=0;i=this.p);return n=n*this.Ri%this.p,n}fft(t){return this.FFT.fft(t)}ifft(t){return this.FFT.ifft(t)}toRprLE(t,n,i){w(t,n,i,8*this.n64)}toRprBE(t,n,i){b(t,n,i,8*this.n64)}toRprBEM(t,n,i){return this.toRprBE(t,n,this.mul(this.R,i))}toRprLEM(t,n,i){return this.toRprLE(t,n,this.mul(this.R,i))}fromRprLE(t,n){return d(t,n,this.n8)}fromRprBE(t,n){return _(t,n,this.n8)}fromRprLEM(t,n){return this.mul(this.fromRprLE(t,n),this.Ri)}fromRprBEM(t,n){return this.mul(this.fromRprBE(t,n),this.Ri)}toObject(t){return t}}const M=R;t.F1Field=T,t.Scalar=M,t.ZqField=T})); diff --git a/package.json b/package.json index 2d63d72..e67911a 100644 --- a/package.json +++ b/package.json @@ -3,8 +3,8 @@ "type": "module", "version": "1.0.0", "description": "Finite Field Library in Javascript", - "main": "./build/main.cjs", - "module": "./build/main.esm.js", + "main": "./build/lib.cjs/main.js", + "module": "./build/lib.esm/main.js", "unpkg": "./build/main.umd.min.js", "jsdelivr": "./build/main.umd.min.js", "files": [ diff --git a/rollup.config.js b/rollup.config.js index e258b6e..144c0f1 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -19,6 +19,16 @@ export default [ file: "build/main.esm.js", format: "esm", }, + { + dir: "build/lib.cjs", + format: "cjs", + preserveModules: true, + }, + { + dir: "build/lib.esm", + format: "esm", + preserveModules: true, + }, ], external: [...Object.keys(pkg.dependencies || {})], }, diff --git a/src/random.js b/src/random.js index 9d0e213..a411329 100644 --- a/src/random.js +++ b/src/random.js @@ -1,21 +1,14 @@ -import crypto from "crypto"; - export function getRandomBytes(n) { let array = new Uint8Array(n); - if (process.browser) { - // Browser - if (typeof globalThis.crypto !== "undefined") { - // Supported - globalThis.crypto.getRandomValues(array); - } else { - // fallback - for (let i = 0; i < n; i++) { - array[i] = (Math.random() * 4294967296) >>> 0; - } - } + // Browser & Node + if (typeof globalThis.crypto !== "undefined") { + // Supported + globalThis.crypto.getRandomValues(array); } else { - // NodeJS - crypto.randomFillSync(array); + // fallback + for (let i = 0; i < n; i++) { + array[i] = (Math.random() * 4294967296) >>> 0; + } } return array; }