Polynomial division done
This commit is contained in:
parent
8bc1bb610b
commit
0270ceada6
66
aux/calculate2roots.js
Normal file
66
aux/calculate2roots.js
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
|
||||||
|
const bigInt = require("../src/bigint.js");
|
||||||
|
const ZqField = require("../src/zqfield.js");
|
||||||
|
|
||||||
|
|
||||||
|
const r = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||||
|
const s = 28;
|
||||||
|
const nqr_to_t = bigInt("19103219067921713944291392827692070036145651957329286315305642004821462161904");
|
||||||
|
const t_minus_1_over_2 = bigInt("40770029410420498293352137776570907027550720424234931066070132305055");
|
||||||
|
const root_unity = bigInt("19103219067921713944291392827692070036145651957329286315305642004821462161904");
|
||||||
|
const t = bigInt("81540058820840996586704275553141814055101440848469862132140264610111");
|
||||||
|
|
||||||
|
const F = new ZqField(r);
|
||||||
|
|
||||||
|
function sqrt(a) {
|
||||||
|
|
||||||
|
let v = s;
|
||||||
|
let z = nqr_to_t;
|
||||||
|
let w = F.exp(a, t_minus_1_over_2);
|
||||||
|
let x = F.mul(a, w);
|
||||||
|
let b = F.mul(x, w);
|
||||||
|
|
||||||
|
|
||||||
|
// compute square root with Tonelli--Shanks
|
||||||
|
// (does not terminate if not a square!)
|
||||||
|
|
||||||
|
while (!F.equals(b, F.one))
|
||||||
|
{
|
||||||
|
let m = 0;
|
||||||
|
let b2m = b;
|
||||||
|
while (!F.equals(b2m, F.one))
|
||||||
|
{
|
||||||
|
/* invariant: b2m = b^(2^m) after entering this loop */
|
||||||
|
b2m = F.square(b2m);
|
||||||
|
m += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let j = v-m-1;
|
||||||
|
w = z;
|
||||||
|
while (j > 0)
|
||||||
|
{
|
||||||
|
w = F.square(w);
|
||||||
|
--j;
|
||||||
|
} // w = z^2^(v-m-1)
|
||||||
|
|
||||||
|
z = F.square(w);
|
||||||
|
b = F.mul(b, z);
|
||||||
|
x = F.mul(x, w);
|
||||||
|
v = m;
|
||||||
|
}
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
const p_minus1= F.sub(r,bigInt(1));
|
||||||
|
const gen = bigInt(bigInt(5));
|
||||||
|
const twoto28= F.exp(bigInt(2), bigInt(28));
|
||||||
|
const rem = F.div(p_minus1, twoto28);
|
||||||
|
const w28 = F.exp(gen, rem);
|
||||||
|
|
||||||
|
const one = F.exp(w28, twoto28);
|
||||||
|
|
||||||
|
|
||||||
|
console.log(F.toString(w28));
|
||||||
|
console.log(w28.toString(10));
|
||||||
|
console.log(F.toString(one));
|
260
file%3a/Users/jbaylina/git/personal/zksnark/src/polfield.js
Normal file
260
file%3a/Users/jbaylina/git/personal/zksnark/src/polfield.js
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
/*
|
||||||
|
This library do operations on polinomials where their coefficients are in field F
|
||||||
|
|
||||||
|
The polynomial P(x) = p0 + p1 * x + p2 * x^2 + p3 * x^3, ...
|
||||||
|
is represented by the array [ p0, p1, p2, p3, ... ]
|
||||||
|
*/
|
||||||
|
|
||||||
|
const bigInt = require("./bigInt");
|
||||||
|
const ZqField = require("./zqfield");
|
||||||
|
|
||||||
|
class PolFieldZq {
|
||||||
|
constructor (q) {
|
||||||
|
this.F = new ZqField(q);
|
||||||
|
|
||||||
|
let rem = q.sub(bigInt(1));
|
||||||
|
let s = 0;
|
||||||
|
while (!rem.isOdd()) {
|
||||||
|
s ++;
|
||||||
|
rem = rem.shiftRight(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.w = new Array(s+1);
|
||||||
|
this.wi = new Array(s+1);
|
||||||
|
this.w[s] = this.F.exp(bigInt(5), rem);
|
||||||
|
this.wi[s] = this.F.inverse(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--;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
add(a, b) {
|
||||||
|
const m = Math.max(a.length, b.length);
|
||||||
|
const res = new Array(m);
|
||||||
|
for (let i=0; i<m; i++) {
|
||||||
|
res[i] = this.F.add(a[i] || this.F.zero, b[i] || this.F.zero);
|
||||||
|
}
|
||||||
|
return this.reduce(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
double(a) {
|
||||||
|
return this.add(a,a);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub(a, b) {
|
||||||
|
const m = Math.max(a.length, b.length);
|
||||||
|
const res = new Array(m);
|
||||||
|
for (let i=0; i<m; i++) {
|
||||||
|
res[i] = this.F.sub(a[i] || this.F.zero, b[i] || this.F.zero);
|
||||||
|
}
|
||||||
|
return this.reduce(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
mulEscalar(a, b) {
|
||||||
|
if (this.F.isZero(b)) return [];
|
||||||
|
const res = new Array(a.length);
|
||||||
|
for (let i=0; i<a.length; i++) {
|
||||||
|
res[i] = this.F.mul(a[i], b);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
mul(a, b) {
|
||||||
|
if (a.length == 0) return [];
|
||||||
|
if (b.length == 0) return [];
|
||||||
|
if (a.length == 1) return this.mulEscalar(b, a[0]);
|
||||||
|
if (b.length == 1) return this.mulEscalar(a, b[0]);
|
||||||
|
|
||||||
|
const longestN = Math.max(a.length, b.length);
|
||||||
|
const bitsResult = log2(longestN-1)+2;
|
||||||
|
const m = 1 << bitsResult;
|
||||||
|
const ea = this.extend(a,m);
|
||||||
|
const eb = this.extend(b,m);
|
||||||
|
|
||||||
|
const ta = this._fft(ea, bitsResult, 0, 1, false);
|
||||||
|
const tb = this._fft(eb, bitsResult, 0, 1, false);
|
||||||
|
|
||||||
|
const tres = new Array(m);
|
||||||
|
|
||||||
|
for (let i=0; i<m; i++) {
|
||||||
|
tres[i] = this.F.mul(ta[i], tb[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = this._fft(tres, bitsResult, 0, 1, true);
|
||||||
|
|
||||||
|
const twoinvm = this.F.inverse(bigInt(m));
|
||||||
|
const resn = new Array(m);
|
||||||
|
for (let i=0; i<m; i++) {
|
||||||
|
resn[i] = this.F.mul(res[(m-i)%m], twoinvm);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.reduce(this.affine(resn));
|
||||||
|
}
|
||||||
|
|
||||||
|
square(a) {
|
||||||
|
return this.mul(a,a);
|
||||||
|
}
|
||||||
|
|
||||||
|
scaleX(p, n) {
|
||||||
|
if (n==0) {
|
||||||
|
return p;
|
||||||
|
} else if (n>0) {
|
||||||
|
const z = new Array(n).fill(this.F.zero);
|
||||||
|
return z.concat(p);
|
||||||
|
} else {
|
||||||
|
return p.slice(-n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div(a, b) {
|
||||||
|
throw new Error("Not Implementted");
|
||||||
|
}
|
||||||
|
|
||||||
|
eval(p, x) {
|
||||||
|
let v = this.F.zero;
|
||||||
|
let ix = this.F.one;
|
||||||
|
for (let i=0; i<p.length; i++) {
|
||||||
|
v = this.F.add(v, this.F.mul(p[i], ix));
|
||||||
|
ix = this.F.mul(ix, x);
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
lagrange(points) {
|
||||||
|
throw new Error("Not Implementted");
|
||||||
|
}
|
||||||
|
|
||||||
|
_fft(pall, bits, offset, step) {
|
||||||
|
|
||||||
|
const n = 1 << bits;
|
||||||
|
if (n==1) {
|
||||||
|
return [ pall[offset] ];
|
||||||
|
}
|
||||||
|
|
||||||
|
const ndiv2 = n >> 1;
|
||||||
|
const p1 = this._fft(pall, bits-1, offset, step*2);
|
||||||
|
const p2 = this._fft(pall, bits-1, offset+step, step*2);
|
||||||
|
|
||||||
|
const out = new Array(n);
|
||||||
|
|
||||||
|
let m= bigInt(1);
|
||||||
|
for (let i=0; i<ndiv2; i++) {
|
||||||
|
out[i] = this.F.add(p1[i], this.F.mul(m, p2[i]));
|
||||||
|
out[i+ndiv2] = this.F.sub(p1[i], this.F.mul(m, p2[i]));
|
||||||
|
m = this.F.mul(m, this.w[bits]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
extend(p, e) {
|
||||||
|
if (e == p.length) return p;
|
||||||
|
const z = new Array(e-p.length).fill(this.F.zero);
|
||||||
|
|
||||||
|
return p.concat(z);
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce(p) {
|
||||||
|
if (p.length == 0) return p;
|
||||||
|
if (! this.F.isZero(p[p.length-1]) ) return p;
|
||||||
|
let i=p.length-1;
|
||||||
|
while( i>0 && this.F.isZero(p[i]) ) i--;
|
||||||
|
return p.slice(0, i+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
affine(p) {
|
||||||
|
for (let i=0; i<p.length; i++) {
|
||||||
|
p[i] = this.F.affine(p[i]);
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
equals(a, b) {
|
||||||
|
const pa = this.reduce(this.affine(a));
|
||||||
|
const pb = this.reduce(this.affine(b));
|
||||||
|
|
||||||
|
if (pa.length != pb.length) return false;
|
||||||
|
for (let i=0; i<pb.length; i++) {
|
||||||
|
if (!this.F.equals(pa[i], pb[i])) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_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.affine(p);
|
||||||
|
let S = "";
|
||||||
|
for (let i=ap.length-1; i>=0; i--) {
|
||||||
|
if (!this.F.isZero(p[i])) {
|
||||||
|
if (S!="") S += " + ";
|
||||||
|
S = S + p[i].toString(10);
|
||||||
|
if (i>0) {
|
||||||
|
S = S + "x";
|
||||||
|
if (i>1) {
|
||||||
|
S = S + "^" +i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return S;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_reciprocal(p, bits) {
|
||||||
|
const k = 1 << bits;
|
||||||
|
if (k==1) {
|
||||||
|
return [ this.F.inverse(p[0]) ];
|
||||||
|
}
|
||||||
|
const np = this.scaleX(p, -k/2);
|
||||||
|
const q = this._reciprocal(np, bits-1);
|
||||||
|
const a = this.scaleX(this.double(q), 3*k/2-2);
|
||||||
|
const b = this.mul( this.square(q), p);
|
||||||
|
|
||||||
|
return this.scaleX(this.sub(a,b), -(k-2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// divides x^m / v
|
||||||
|
_div2(m, v) {
|
||||||
|
const kbits = log2(v.length-1)+1;
|
||||||
|
const k = 1 << kbits;
|
||||||
|
|
||||||
|
const scaleV = k - v.length;
|
||||||
|
|
||||||
|
// rec = x^(k - 2) / v* x^scaleV =>
|
||||||
|
// rec = x^(k-2-scaleV)/ v
|
||||||
|
//
|
||||||
|
// res = x^m/v = x^(m +(2k-2-scaleV) -(2k-2-scaleV)) /v =>
|
||||||
|
// res = rec * x^(m - (2k-2-scaleV)) =>
|
||||||
|
// res = rec * x^(m - 2k +2 + scaleV)
|
||||||
|
|
||||||
|
const rec = this._reciprocal(this.scaleX(v, scaleV), kbits);
|
||||||
|
const res = this.scaleX(rec, m - k*2 +2+scaleV);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = PolFieldZq;
|
@ -3,8 +3,6 @@ const bigInt = require("big-integer");
|
|||||||
|
|
||||||
let wBigInt;
|
let wBigInt;
|
||||||
|
|
||||||
console.log("XXX");
|
|
||||||
|
|
||||||
if (typeof(BigInt) != "undefined") {
|
if (typeof(BigInt) != "undefined") {
|
||||||
wBigInt = BigInt;
|
wBigInt = BigInt;
|
||||||
wBigInt.one = wBigInt(1);
|
wBigInt.one = wBigInt(1);
|
||||||
|
281
src/polfield.js
281
src/polfield.js
@ -5,46 +5,291 @@
|
|||||||
is represented by the array [ p0, p1, p2, p3, ... ]
|
is represented by the array [ p0, p1, p2, p3, ... ]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class PolField {
|
const bigInt = require("./bigInt");
|
||||||
constructor (F) {
|
const ZqField = require("./zqfield");
|
||||||
this.F = F;
|
|
||||||
|
class PolFieldZq {
|
||||||
|
constructor (q) {
|
||||||
|
this.F = new ZqField(q);
|
||||||
|
|
||||||
|
let rem = q.sub(bigInt(1));
|
||||||
|
let s = 0;
|
||||||
|
while (!rem.isOdd()) {
|
||||||
|
s ++;
|
||||||
|
rem = rem.shiftRight(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.w = new Array(s+1);
|
||||||
|
this.wi = new Array(s+1);
|
||||||
|
this.w[s] = this.F.exp(bigInt(5), rem);
|
||||||
|
this.wi[s] = this.F.inverse(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--;
|
||||||
}
|
}
|
||||||
|
|
||||||
_reduce(a) {
|
|
||||||
let i = a.length-1;
|
|
||||||
while ((i>=0) && (this.F.isZero(a[i])) ) i--;
|
|
||||||
return (i < a.length-1) ? a.slice(0, i+1) : a;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
add(a, b) {
|
add(a, b) {
|
||||||
const maxGrade = Math.max(a.length, b.length);
|
const m = Math.max(a.length, b.length);
|
||||||
const res = new Array(maxGrade);
|
const res = new Array(m);
|
||||||
for (let i=0; i<maxGrade; i++) {
|
for (let i=0; i<m; i++) {
|
||||||
res[i] = this.F.add(a[i], b[i]);
|
res[i] = this.F.add(a[i] || this.F.zero, b[i] || this.F.zero);
|
||||||
}
|
}
|
||||||
return this._reduce(res);
|
return this.reduce(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
double(a) {
|
||||||
|
return this.add(a,a);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub(a, b) {
|
sub(a, b) {
|
||||||
throw new Error("Not Implementted");
|
const m = Math.max(a.length, b.length);
|
||||||
|
const res = new Array(m);
|
||||||
|
for (let i=0; i<m; i++) {
|
||||||
|
res[i] = this.F.sub(a[i] || this.F.zero, b[i] || this.F.zero);
|
||||||
|
}
|
||||||
|
return this.reduce(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
mulEscalar(a, b) {
|
||||||
|
if (this.F.isZero(b)) return [];
|
||||||
|
const res = new Array(a.length);
|
||||||
|
for (let i=0; i<a.length; i++) {
|
||||||
|
res[i] = this.F.mul(a[i], b);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
mul(a, b) {
|
mul(a, b) {
|
||||||
throw new Error("Not Implementted");
|
if (a.length == 0) return [];
|
||||||
|
if (b.length == 0) return [];
|
||||||
|
if (a.length == 1) return this.mulEscalar(b, a[0]);
|
||||||
|
if (b.length == 1) return this.mulEscalar(a, b[0]);
|
||||||
|
|
||||||
|
const longestN = Math.max(a.length, b.length);
|
||||||
|
const bitsResult = log2(longestN-1)+2;
|
||||||
|
const m = 1 << bitsResult;
|
||||||
|
const ea = this.extend(a,m);
|
||||||
|
const eb = this.extend(b,m);
|
||||||
|
|
||||||
|
const ta = this._fft(ea, bitsResult, 0, 1, false);
|
||||||
|
const tb = this._fft(eb, bitsResult, 0, 1, false);
|
||||||
|
|
||||||
|
const tres = new Array(m);
|
||||||
|
|
||||||
|
for (let i=0; i<m; i++) {
|
||||||
|
tres[i] = this.F.mul(ta[i], tb[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
div(a, b) {
|
const res = this._fft(tres, bitsResult, 0, 1, true);
|
||||||
throw new Error("Not Implementted");
|
|
||||||
|
const twoinvm = this.F.inverse(bigInt(m));
|
||||||
|
const resn = new Array(m);
|
||||||
|
for (let i=0; i<m; i++) {
|
||||||
|
resn[i] = this.F.mul(res[(m-i)%m], twoinvm);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.reduce(this.affine(resn));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
square(a) {
|
||||||
|
return this.mul(a,a);
|
||||||
|
}
|
||||||
|
|
||||||
|
scaleX(p, n) {
|
||||||
|
if (n==0) {
|
||||||
|
return p;
|
||||||
|
} else if (n>0) {
|
||||||
|
const z = new Array(n).fill(this.F.zero);
|
||||||
|
return z.concat(p);
|
||||||
|
} else {
|
||||||
|
if (-n >= p.length) return [];
|
||||||
|
return p.slice(-n);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
eval(p, x) {
|
eval(p, x) {
|
||||||
throw new Error("Not Implementted");
|
let v = this.F.zero;
|
||||||
|
let ix = this.F.one;
|
||||||
|
for (let i=0; i<p.length; i++) {
|
||||||
|
v = this.F.add(v, this.F.mul(p[i], ix));
|
||||||
|
ix = this.F.mul(ix, x);
|
||||||
|
}
|
||||||
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
lagrange(points) {
|
lagrange(points) {
|
||||||
throw new Error("Not Implementted");
|
throw new Error("Not Implementted");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_fft(pall, bits, offset, step) {
|
||||||
|
|
||||||
|
const n = 1 << bits;
|
||||||
|
if (n==1) {
|
||||||
|
return [ pall[offset] ];
|
||||||
|
}
|
||||||
|
|
||||||
|
const ndiv2 = n >> 1;
|
||||||
|
const p1 = this._fft(pall, bits-1, offset, step*2);
|
||||||
|
const p2 = this._fft(pall, bits-1, offset+step, step*2);
|
||||||
|
|
||||||
|
const out = new Array(n);
|
||||||
|
|
||||||
|
let m= bigInt(1);
|
||||||
|
for (let i=0; i<ndiv2; i++) {
|
||||||
|
out[i] = this.F.add(p1[i], this.F.mul(m, p2[i]));
|
||||||
|
out[i+ndiv2] = this.F.sub(p1[i], this.F.mul(m, p2[i]));
|
||||||
|
m = this.F.mul(m, this.w[bits]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
extend(p, e) {
|
||||||
|
if (e == p.length) return p;
|
||||||
|
const z = new Array(e-p.length).fill(this.F.zero);
|
||||||
|
|
||||||
|
return p.concat(z);
|
||||||
|
}
|
||||||
|
|
||||||
|
reduce(p) {
|
||||||
|
if (p.length == 0) return p;
|
||||||
|
if (! this.F.isZero(p[p.length-1]) ) return p;
|
||||||
|
let i=p.length-1;
|
||||||
|
while( i>0 && this.F.isZero(p[i]) ) i--;
|
||||||
|
return p.slice(0, i+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
affine(p) {
|
||||||
|
for (let i=0; i<p.length; i++) {
|
||||||
|
p[i] = this.F.affine(p[i]);
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
equals(a, b) {
|
||||||
|
const pa = this.reduce(this.affine(a));
|
||||||
|
const pb = this.reduce(this.affine(b));
|
||||||
|
|
||||||
|
if (pa.length != pb.length) return false;
|
||||||
|
for (let i=0; i<pb.length; i++) {
|
||||||
|
if (!this.F.equals(pa[i], pb[i])) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_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.affine(p);
|
||||||
|
let S = "";
|
||||||
|
for (let i=ap.length-1; i>=0; i--) {
|
||||||
|
if (!this.F.isZero(p[i])) {
|
||||||
|
if (S!="") S += " + ";
|
||||||
|
S = S + p[i].toString(10);
|
||||||
|
if (i>0) {
|
||||||
|
S = S + "x";
|
||||||
|
if (i>1) {
|
||||||
|
S = S + "^" +i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return S;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
module.exports = PolField;
|
_reciprocal(p, bits) {
|
||||||
|
const k = 1 << bits;
|
||||||
|
if (k==1) {
|
||||||
|
return [ this.F.inverse(p[0]) ];
|
||||||
|
}
|
||||||
|
const np = this.scaleX(p, -k/2);
|
||||||
|
const q = this._reciprocal(np, bits-1);
|
||||||
|
const a = this.scaleX(this.double(q), 3*k/2-2);
|
||||||
|
const b = this.mul( this.square(q), p);
|
||||||
|
|
||||||
|
return this.scaleX(this.sub(a,b), -(k-2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// divides x^m / v
|
||||||
|
_div2(m, v) {
|
||||||
|
const kbits = log2(v.length-1)+1;
|
||||||
|
const k = 1 << kbits;
|
||||||
|
|
||||||
|
const scaleV = k - v.length;
|
||||||
|
|
||||||
|
// rec = x^(k - 2) / v* x^scaleV =>
|
||||||
|
// rec = x^(k-2-scaleV)/ v
|
||||||
|
//
|
||||||
|
// res = x^m/v = x^(m + (2*k-2 - scaleV) - (2*k-2 - scaleV)) /v =>
|
||||||
|
// res = rec * x^(m - (2*k-2 - scaleV)) =>
|
||||||
|
// res = rec * x^(m - 2*k + 2 + scaleV)
|
||||||
|
|
||||||
|
const rec = this._reciprocal(this.scaleX(v, scaleV), kbits);
|
||||||
|
const res = this.scaleX(rec, m - 2*k + 2 + scaleV);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
div(_u, _v) {
|
||||||
|
if (_u.length < _v.length) return [];
|
||||||
|
const kbits = log2(_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([bigInt(1)], 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = PolFieldZq;
|
||||||
|
@ -16,6 +16,8 @@ class ZqField {
|
|||||||
this.equals = bigInt.genEquals(q);
|
this.equals = bigInt.genEquals(q);
|
||||||
this.affine = bigInt.genAffine(q);
|
this.affine = bigInt.genAffine(q);
|
||||||
this.isZero = bigInt.genIsZero(q);
|
this.isZero = bigInt.genIsZero(q);
|
||||||
|
this.two = this.add(this.one, this.one);
|
||||||
|
this.twoinv = this.inverse(this.two);
|
||||||
}
|
}
|
||||||
|
|
||||||
copy(a) {
|
copy(a) {
|
||||||
|
@ -154,7 +154,6 @@ describe("Pairing", () => {
|
|||||||
const g1b = bn128.G1.mulEscalar(bn128.G1.g, 30);
|
const g1b = bn128.G1.mulEscalar(bn128.G1.g, 30);
|
||||||
const g2b = bn128.G2.mulEscalar(bn128.G2.g, 25);
|
const g2b = bn128.G2.mulEscalar(bn128.G2.g, 25);
|
||||||
|
|
||||||
|
|
||||||
const pre1a = bn128.precomputeG1(g1a);
|
const pre1a = bn128.precomputeG1(g1a);
|
||||||
const pre2a = bn128.precomputeG2(g2a);
|
const pre2a = bn128.precomputeG2(g2a);
|
||||||
const pre1b = bn128.precomputeG1(g1b);
|
const pre1b = bn128.precomputeG1(g1b);
|
||||||
|
107
test/pols.js
Normal file
107
test/pols.js
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
const chai = require("chai");
|
||||||
|
|
||||||
|
const bigInt = require("../src/bigint.js");
|
||||||
|
const PolField = require("../src/polfield.js");
|
||||||
|
|
||||||
|
const assert = chai.assert;
|
||||||
|
|
||||||
|
const r = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
|
||||||
|
|
||||||
|
describe("Polinomial field", () => {
|
||||||
|
it("Should compute a multiplication", () => {
|
||||||
|
const PF = new PolField(r);
|
||||||
|
|
||||||
|
const a = [bigInt(1), bigInt(2), bigInt(3)];
|
||||||
|
const b = [bigInt(1), bigInt(2), bigInt(3)];
|
||||||
|
const res = PF.mul(a,b);
|
||||||
|
|
||||||
|
assert(PF.equals(res, [bigInt(1), bigInt(4), bigInt(10), bigInt(12), bigInt(9)]));
|
||||||
|
});
|
||||||
|
it("Should compute a multiplication 2", () => {
|
||||||
|
const PF = new PolField(r);
|
||||||
|
|
||||||
|
const a = [bigInt(5), bigInt(1)];
|
||||||
|
const b = [bigInt(-5), bigInt(1)];
|
||||||
|
const res = PF.mul(a,b);
|
||||||
|
|
||||||
|
assert(PF.equals(res, [bigInt(-25), bigInt(0), bigInt(1)]));
|
||||||
|
});
|
||||||
|
it("Should compute an addition", () => {
|
||||||
|
const PF = new PolField(r);
|
||||||
|
|
||||||
|
const a = [bigInt(5), bigInt(1)];
|
||||||
|
const b = [bigInt(-5), bigInt(1)];
|
||||||
|
const res = PF.add(a,b);
|
||||||
|
|
||||||
|
assert(PF.equals(res, [bigInt(0), bigInt(2)]));
|
||||||
|
});
|
||||||
|
it("Should compute a substraction", () => {
|
||||||
|
const PF = new PolField(r);
|
||||||
|
|
||||||
|
const a = [bigInt(5), bigInt(3), bigInt(4)];
|
||||||
|
const b = [bigInt(5), bigInt(1)];
|
||||||
|
const res = PF.sub(a,b);
|
||||||
|
|
||||||
|
assert(PF.equals(res, [bigInt(0), bigInt(2), bigInt(4)]));
|
||||||
|
});
|
||||||
|
it("Should compute reciprocal", () => {
|
||||||
|
const PF = new PolField(r);
|
||||||
|
|
||||||
|
const a = [bigInt(4), bigInt(1), bigInt(-3), bigInt(-1), bigInt(2),bigInt(1), bigInt(-1), bigInt(1)];
|
||||||
|
const res = PF._reciprocal(a, 3, 0);
|
||||||
|
|
||||||
|
assert(PF.equals(res, [bigInt(12), bigInt(15), bigInt(3), bigInt(-4), bigInt(-3), bigInt(0), bigInt(1), bigInt(1)]));
|
||||||
|
});
|
||||||
|
it("Should div2", () => {
|
||||||
|
const PF = new PolField(r);
|
||||||
|
|
||||||
|
// x^6
|
||||||
|
const a = [bigInt(0), bigInt(0), bigInt(0), bigInt(0), bigInt(0),bigInt(0), bigInt(1)];
|
||||||
|
// x^5
|
||||||
|
const b = [bigInt(0), bigInt(0), bigInt(0), bigInt(0), bigInt(0), bigInt(1)];
|
||||||
|
|
||||||
|
const res = PF._div2(6, b);
|
||||||
|
assert(PF.equals(res, [bigInt(0), bigInt(1)]));
|
||||||
|
|
||||||
|
const res2 = PF.div(a,b);
|
||||||
|
assert(PF.equals(res2, [bigInt(0), bigInt(1)]));
|
||||||
|
});
|
||||||
|
it("Should div", () => {
|
||||||
|
const PF = new PolField(r);
|
||||||
|
|
||||||
|
const a = [bigInt(1), bigInt(2), bigInt(3), bigInt(4), bigInt(5),bigInt(6), bigInt(7)];
|
||||||
|
const b = [bigInt(8), bigInt(9), bigInt(10), bigInt(11), bigInt(12), bigInt(13)];
|
||||||
|
|
||||||
|
const c = PF.mul(a,b);
|
||||||
|
const d = PF.div(c,b);
|
||||||
|
|
||||||
|
assert(PF.equals(a, d));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should div big/small", () => {
|
||||||
|
const PF = new PolField(r);
|
||||||
|
|
||||||
|
const a = [bigInt(1), bigInt(2), bigInt(3), bigInt(4), bigInt(5),bigInt(6), bigInt(7)];
|
||||||
|
const b = [bigInt(8), bigInt(9)];
|
||||||
|
|
||||||
|
const c = PF.mul(a,b);
|
||||||
|
const d = PF.div(c,b);
|
||||||
|
|
||||||
|
assert(PF.equals(a, d));
|
||||||
|
});
|
||||||
|
it("Should div random big", () => {
|
||||||
|
const PF = new PolField(r);
|
||||||
|
|
||||||
|
const a = [];
|
||||||
|
const b = [];
|
||||||
|
for (let i=0; i<1000; i++) a.push(bigInt(Math.floor(Math.random()*100000) -500000));
|
||||||
|
for (let i=0; i<300; i++) b.push(bigInt(Math.floor(Math.random()*100000) -500000));
|
||||||
|
|
||||||
|
const c = PF.mul(a,b);
|
||||||
|
|
||||||
|
const d = PF.div(c,b);
|
||||||
|
|
||||||
|
assert(PF.equals(a, d));
|
||||||
|
}).timeout(10000000);
|
||||||
|
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user