Browse Source

Use ruffini for calculatig lagrange polinomials

master
Jordi Baylina 6 years ago
parent
commit
2cf2803019
No known key found for this signature in database GPG Key ID: 7480C80C1BE43112
9 changed files with 63 additions and 290 deletions
  1. +0
    -260
      file%3a/Users/jbaylina/git/personal/zksnark/src/polfield.js
  2. +2
    -2
      src/bigint.js
  3. +20
    -11
      src/polfield.js
  4. +2
    -2
      src/ratfield.js
  5. +26
    -11
      src/setup.js
  6. +9
    -0
      test/pols.js
  7. +2
    -2
      test/ratzqfield.js
  8. +1
    -1
      vk_proof.json
  9. +1
    -1
      vk_verifier.json

+ 0
- 260
file%3a/Users/jbaylina/git/personal/zksnark/src/polfield.js

@ -1,260 +0,0 @@
/*
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);
}
mulScalar(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.mulScalar(b, a[0]);
if (b.length == 1) return this.mulScalar(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;

+ 2
- 2
src/bigint.js

@ -17,8 +17,8 @@ if (typeof(BigInt) != "undefined") {
if (aux <= nq) {
aux = aux % q;
}
if (aux.isNegative()) {
aux = aux.add(q);
if (aux < wBigInt.zero) {
aux = aux + q;
}
} else {
if (aux >= q) {

+ 20
- 11
src/polfield.js

@ -5,14 +5,14 @@
is represented by the array [ p0, p1, p2, p3, ... ]
*/
const bigInt = require("./bigInt");
const bigInt = require("./bigint.js");
class PolFieldZq {
class PolField {
constructor (F) {
this.F = F;
const q = this.F.q;
let rem = q.sub(this.F.one);
let rem = q.sub(bigInt(1));
let s = 0;
while (!rem.isOdd()) {
s ++;
@ -79,7 +79,7 @@ class PolFieldZq {
[b, a] = [a, b];
}
if (b.length < log2(a.length)) {
if ((b.length <= 2) || (b.length < log2(a.length))) {
return this.mulNormal(a,b);
} else {
return this.mulFFT(a,b);
@ -151,14 +151,14 @@ class PolFieldZq {
}
lagrange(points) {
let roots = [this.F.one];
for (let i=0; i<points.length; i++) {
roots = this.mul(roots, [this.F.neg(points[i][0]), this.F.one]);
}
let sum = [];
for (let i=0; i<points.length; i++) {
let mpol = [this.F.one];
for (let j=0;j<points.length;j++) {
if (i!=j) {
mpol = this.mul(mpol, [this.F.neg(points[j][0]), this.F.one]);
}
}
let mpol = this.ruffini(roots, points[i][0]);
const factor =
this.F.mul(
this.F.inverse(this.eval(mpol, points[i][0])),
@ -226,6 +226,15 @@ class PolFieldZq {
return true;
}
ruffini(p, r) {
const res = new Array(p.length-1);
res[res.length-1] = p[p.length-1];
for (let i = res.length-2; i>=0; i--) {
res[i] = this.F.add(this.F.mul(res[i+1], r), p[i+1]);
}
return res;
}
_next2Power(v) {
v--;
v |= v >> 1;
@ -333,4 +342,4 @@ 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;
module.exports = PolField;

src/ratzqfield.js → src/ratfield.js

@ -1,6 +1,6 @@
const fUtils = require("./futils.js");
class RatZqField {
class RatField {
constructor(F) {
this.F = F;
this.zero = [F.zero, F.one];
@ -105,4 +105,4 @@ class RatZqField {
}
module.exports = RatZqField;
module.exports = RatField;

+ 26
- 11
src/setup.js

@ -3,11 +3,13 @@ const bigInt = require("./bigint.js");
const BN128 = require("./BN128.js");
const PolField = require("./polfield.js");
const ZqField = require("./zqfield.js");
const RatField = require("./ratfield.js");
const bn128 = new BN128();
const G1 = bn128.G1;
const G2 = bn128.G2;
const PolF = new PolField(new ZqField(bn128.r));
const RatPolF = new PolField(new RatField(new ZqField(bn128.r)));
const F = new ZqField(bn128.r);
module.exports = function setup(circuit) {
@ -40,9 +42,9 @@ function calculatePolinomials(setup, circuit) {
bPoints[s] = [];
cPoints[s] = [];
for (let c=0; c<circuit.nConstrains; c++) {
aPoints[s].push([bigInt(c), circuit.a(c, s)]);
bPoints[s].push([bigInt(c), circuit.b(c, s)]);
cPoints[s].push([bigInt(c), circuit.c(c, s)]);
aPoints[s].push([[bigInt(c), F.one], [circuit.a(c, s), F.one]]);
bPoints[s].push([[bigInt(c), F.one], [circuit.b(c, s), F.one]]);
cPoints[s].push([[bigInt(c), F.one], [circuit.c(c, s), F.one]]);
}
}
@ -51,10 +53,15 @@ function calculatePolinomials(setup, circuit) {
setup.vk_proof.polsB = [];
setup.vk_proof.polsC = [];
for (let s=0; s<circuit.nSignals; s++) {
console.log(`Caclcualte Pol ${s}/${circuit.nSignals}`);
setup.vk_proof.polsA.push(PolF.lagrange( aPoints[s] ));
setup.vk_proof.polsB.push(PolF.lagrange( bPoints[s] ));
setup.vk_proof.polsC.push(PolF.lagrange( cPoints[s] ));
// console.log(`Caclcualte Pol ${s}/${circuit.nSignals}`);
const pA = RatPolF.lagrange( aPoints[s] );
const pB = RatPolF.lagrange( bPoints[s] );
const pC = RatPolF.lagrange( cPoints[s] );
setup.vk_proof.polsA.push( unrat(pA) );
setup.vk_proof.polsB.push( unrat(pB) );
setup.vk_proof.polsC.push( unrat(pC) );
}
// Calculate Z polinomial
@ -96,7 +103,7 @@ function calculateEncriptedValuesAtT(setup, circuit) {
for (let s=0; s<circuit.nSignals; s++) {
// A[i] = G1 * polA(t)
const at = PolF.eval(setup.vk_proof.polsA[s], setup.toxic.t);
const at = F.affine(PolF.eval(setup.vk_proof.polsA[s], setup.toxic.t));
const A = G1.affine(G1.mulScalar(G1.g, at));
setup.vk_proof.A.push(A);
@ -107,7 +114,7 @@ function calculateEncriptedValuesAtT(setup, circuit) {
// B1[i] = G1 * polB(t)
const bt = PolF.eval(setup.vk_proof.polsB[s], setup.toxic.t);
const bt = F.affine(PolF.eval(setup.vk_proof.polsB[s], setup.toxic.t));
const B1 = G1.affine(G1.mulScalar(G1.g, bt));
// B2[i] = G2 * polB(t)
@ -116,13 +123,13 @@ function calculateEncriptedValuesAtT(setup, circuit) {
setup.vk_proof.B.push(B2);
// C[i] = G1 * polC(t)
const ct = PolF.eval(setup.vk_proof.polsC[s], setup.toxic.t);
const ct = F.affine(PolF.eval(setup.vk_proof.polsC[s], setup.toxic.t));
const C = G1.affine(G1.mulScalar( G1.g, ct));
setup.vk_proof.C.push (C);
// K = G1 * (A+B+C)
const kt = F.add(F.add(at, bt), ct);
const kt = F.affine(F.add(F.add(at, bt), ct));
const K = G1.affine(G1.mulScalar( G1.g, kt));
@ -169,3 +176,11 @@ function calculateHexps(setup, circuit) {
}
}
function unrat(p) {
const res = new Array(p.length);
for (let i=0; i<p.length; i++) {
res[i] = RatPolF.F.toF(p[i]);
}
return res;
}

+ 9
- 0
test/pols.js

@ -141,5 +141,14 @@ describe("Polinomial field", () => {
assert(PF.F.equals(v, points[i][1]));
}
});
it("Should test ruffini", () => {
const PF = new PolField(new ZqField(r));
const a = [bigInt(1), bigInt(2), bigInt(3), bigInt(4), bigInt(5),bigInt(6), bigInt(7)];
const b = PF.mul(a, [bigInt(-7), bigInt(1)]);
const c = PF.ruffini(b, bigInt(7));
assert(PF.equals(a, c));
});
});

+ 2
- 2
test/ratzqfield.js

@ -2,11 +2,11 @@ const chai = require("chai");
const bigInt = require("../src/bigint.js");
const ZqField = require("../src/zqfield.js");
const RatZqField = require("../src/ratzqfield.js");
const RatField = require("../src/ratfield.js");
const q = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
const Z = new ZqField(q);
const R = new RatZqField(Z);
const R = new RatField(Z);
const assert = chai.assert;

+ 1
- 1
vk_proof.json
File diff suppressed because it is too large
View File


+ 1
- 1
vk_verifier.json

@ -1 +1 @@
{"nPublic":2,"A":[["0","1","0"],["0","1","0"],["0","1","0"]],"vk_a":[["10910302893854256300335313159192947444388132687074523434871198422054676751347","7128911999163755080071576365381312078199150810378083348330952764137111826309"],["18631850238317279011886579705479432506796416675676074259923090354119752710032","11613125271011748641588689311610150724463404115865535933368983811438235418330"],["1","0"]],"vk_b":["14021005419725675778621050747090735283429719877068464218769467811976154477903","13400327218680122582347155709033494654797979408389561950304209881074672567956","1"],"vk_c":[["3096051994409557504719773510360462097114704303646108617318273214347944304327","21060178932557065464613441158524747948458716806166605021180362439829514495363"],["13711469505507426929293229841903695489923719718740047084134989818704335937579","16689306268247690470861364441748198782838298216373469479699367433528545900642"],["1","0"]],"vk_gb_1":["6323076061844787963801699179984388237278671131058334789970950232032140773376","1289442623160734848462556712373448525459100416297212719395950333399658173112","1"],"vk_gb_2":[["14738403669696391106523308033989669531459082697567002658683173458264070358472","7115351592298265627577071367133297887460251153742186717064165044604072075208"],["5684452168257595880393745672144928966665179424697978770339950828964351397925","16005652883870491274891326398599328665806046577140362628567012925774147115231"],["1","0"]],"vk_g":[["13057967944664071939530697379611124014113572609236714070685841838860689079766","4921285704318374954421284662839198492272478322335189504342768676294475453825"],["16821731243154385058674189668904278548308574642868092417486261078313511500423","14329710484989081757569399730710287771777297111484092478685760712065088557056"],["1","0"]],"vk_z":[["9830782349217318574531840014041507435528173882006141768847850813321843762209","908701408738093737682928637200323566556898851221230193697915803980061312337"],["18420854262130852746249857908832658786725598484918874058527841900342812415992","11905336095877065527602013373361492354917686666454749599264218906638347950295"],["1","0"]]}
{"nPublic":2,"A":[["0","1","0"],["0","1","0"],["0","1","0"]],"vk_a":[["1114178395252120380395835212597801981089399905319368502910322038327297636405","5033894282647920143094588130989706038816118666385188297428164028250802121541"],["11204369287866566481790440577452570863155384959741708497053387501206022041196","5804122404011709706164213043421176877293761551268564612957682946191385948083"],["1","0"]],"vk_b":["21502216352809485080540484588657130416201550918596561744135679102208461442666","2868090884426856501439409534931120005724644305621622228858085860168686686429","1"],"vk_c":[["6132826916796173784201732531285327915041466217971374202416165094662772918168","21745292514182636990945632198433440675390812739972912576130340262689749324094"],["771505583294284223449947888751235336787816998120918568114562783124678603668","3393096609476927450002720393920165677184260635403434210470312068614019743097"],["1","0"]],"vk_gb_1":["12719499470261599561309259431682387098359700522807496275922119401706283527128","16621363578670067280062291944220200497396193306084620768371306905372731356597","1"],"vk_gb_2":[["10964959780919004944755595440619126945893196497479441585015855710878271674269","2128708169016642077859536709142486990439502854897055565299822951071887976085"],["2388598870284376494192851636260646163256895248220461084487594797988889825261","20110295053122713144819603341600445626597656441687959152080135372786154275292"],["1","0"]],"vk_g":[["12255811247188042732673820469397127953046292441028573933507149762907917860381","7279942967825808009089038706789890489125264289371774766033392871666671678200"],["7190249513755559992931891810866588807891969433945206422275821065594394539722","21314329220359655301619987728101583897798145529926111725521967279053488865751"],["1","0"]],"vk_z":[["17586236151988045592673833893440158242030817616966567700538296220528189715389","3551310632722212929105681060373481610723584194504089389345599320999381324165"],["9267522905249404702171212401947711344560303757795853174593820034048921438294","6158557086581678490843952132823078409925994557584598523494082907032631181314"],["1","0"]]}

Loading…
Cancel
Save