UNPKG

@toruslabs/ffjavascript

Version:

Finite Field Library in Javascript

340 lines (336 loc) 8.91 kB
'use strict'; var _defineProperty = require('@babel/runtime/helpers/defineProperty'); var fft = require('./fft.js'); var fsqrt = require('./fsqrt.js'); var futils = require('./futils.js'); var random = require('./random.js'); var scalar = require('./scalar.js'); class ZqField { constructor(p) { _defineProperty(this, "type", void 0); _defineProperty(this, "one", void 0); _defineProperty(this, "zero", void 0); _defineProperty(this, "p", void 0); _defineProperty(this, "m", void 0); _defineProperty(this, "negone", void 0); _defineProperty(this, "two", void 0); _defineProperty(this, "half", void 0); _defineProperty(this, "bitLength", void 0); _defineProperty(this, "mask", void 0); _defineProperty(this, "n64", void 0); _defineProperty(this, "n32", void 0); _defineProperty(this, "n8", void 0); _defineProperty(this, "R", void 0); _defineProperty(this, "Ri", void 0); _defineProperty(this, "nqr", void 0); _defineProperty(this, "s", void 0); _defineProperty(this, "t", void 0); _defineProperty(this, "nqr_to_t", void 0); _defineProperty(this, "FFT", void 0); _defineProperty(this, "w", void 0); _defineProperty(this, "wi", void 0); _defineProperty(this, "shift", void 0); _defineProperty(this, "k", void 0); // sqrt-related properties (set by buildSqrt) _defineProperty(this, "sqrt_q", void 0); _defineProperty(this, "sqrt_s", void 0); _defineProperty(this, "sqrt_t", void 0); _defineProperty(this, "sqrt_z", void 0); _defineProperty(this, "sqrt_tm1d2", void 0); _defineProperty(this, "sqrt_e1", void 0); _defineProperty(this, "sqrt_e34", void 0); _defineProperty(this, "sqrt_e12", void 0); _defineProperty(this, "sqrt", void 0); _defineProperty(this, "frobenius", void 0); 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.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); } else { res = BigInt(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) { const 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 this.zero; } } } 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) { const v = BigInt(a); if (v < 0) { let na = -v; if (na >= this.p) na = na % this.p; return this.p - na; } else { return v >= this.p ? v % this.p : v; } } 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)); } // Parses a buffer with Little Endian Representation fromRprLE(buff, o) { return scalar.fromRprLE(buff, o, this.n8); } // Parses 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;