forked from iden3/ffjavascript
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
18a5abd
commit af2dea3
Showing
20 changed files
with
2,111 additions
and
48 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; |
Oops, something went wrong.