snarks part done
This commit is contained in:
parent
e03abd7cf9
commit
c0312e5d83
107
README
Normal file
107
README
Normal file
@ -0,0 +1,107 @@
|
||||
# javascript implementation of zkSnark
|
||||
|
||||
This is a javascript implementation of zkSnarks.
|
||||
|
||||
This library allows to do the trusted setup, generate proofs and verify the proofs.
|
||||
|
||||
This library uses the compiled circuits generated by the jaz compiler.
|
||||
|
||||
## Install
|
||||
|
||||
```
|
||||
npm install zkSnark
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### import
|
||||
|
||||
```
|
||||
const zkSnark = require("zksnark");
|
||||
```
|
||||
|
||||
### Load a circuit.
|
||||
|
||||
```
|
||||
// "myCircuit.cir" is the output of the jaz compiler
|
||||
|
||||
const circuitDef = JSON.parse(fs.readFileSync("myCircuit.cir", "utf8"));
|
||||
const circuit = new zkSnark.Circuit(circuitDef);
|
||||
```
|
||||
|
||||
### Inspect the circuit.
|
||||
|
||||
```
|
||||
// `signalId` can always be a number or an alias string
|
||||
|
||||
circuit.m; // number of constrains
|
||||
circuit.n; // number of signals
|
||||
circuit.p; // number of public signals (nPublicInputs + nOutputs)
|
||||
|
||||
// The array of signals is always sorted in this order:
|
||||
// [ outputs, publicInputs, privedInputs, internalSignals, constants]
|
||||
|
||||
// returns a,b and c coeficients of the `signalId` on a given `constrain`
|
||||
circuit.a(constrain, signalId)
|
||||
circuit.b(constrain, signalId)
|
||||
circuit.c(constrain, signalId)
|
||||
|
||||
circuit.nOutputs // number of public outputs
|
||||
circuit.nPublicInputs // number of public inputs
|
||||
circuit.nPrivateInputs // number of private inputs
|
||||
circuit.nInputs // number of inputs ( nPublicInputs + nPrivateInputs)
|
||||
|
||||
circuit.outputIdx(i) // returns the index of the i'th output
|
||||
circuit.inputIdx(i) // returns the index of the i'th input
|
||||
circuit.inputPublicIdx(i) // returns the index of the i'th public input
|
||||
circuit.inputPrivateIdx(i) // returns the index of the i'th private input
|
||||
|
||||
// returns signal Idx given a signalId
|
||||
// if the idx >= n , it is a constant
|
||||
// if the idx == -1, the signal does not exist
|
||||
circuit.signalId2idx(signalId);
|
||||
|
||||
// returns an array aliases names for a given signalId
|
||||
circuit.signalNames(signalId)
|
||||
|
||||
// input is a key value object where keys are the signal names
|
||||
// of all the inputs (public and private)
|
||||
// returns an array of values that represent the witness
|
||||
circuit.generateWitness(input)
|
||||
```
|
||||
|
||||
### Trusted setup
|
||||
|
||||
```
|
||||
const setup = zkSnark.setup(circuit);
|
||||
fs.writeFileSink("myCircuit.vk_proof", JSON.stringify(setup.vk_proof), "utf8");
|
||||
fs.writeFileSink("myCircuit.vk_verifier", JSON.stringify(setup.vk_verifier), "utf8");
|
||||
setup.toxic // Must be discarded.
|
||||
```
|
||||
|
||||
### Generate proof
|
||||
|
||||
```
|
||||
const circuitDef = JSON.parse(fs.readFileSync("myCircuit.cir", "utf8"));
|
||||
const circuit = new zkSnark.Circuit(circuitDef);
|
||||
const input = {
|
||||
"main.pubIn1": "123",
|
||||
"main.out1": "456"
|
||||
}
|
||||
const witness = circuit.generateWitness(input);
|
||||
const vk_proof = JSON.parse(fs.readFileSync("myCircuit.vk_proof", "utf8"));
|
||||
|
||||
const {proof, publicSignals} = zkSnark.genProof(vk_proof, witness);
|
||||
```
|
||||
|
||||
### Verifier
|
||||
|
||||
```
|
||||
const vk_verifier = JSON.parse(fs.readFileSync("myCircuit.vk_verifier", "utf8"));
|
||||
|
||||
if (zkSnark.isValid(vk_verifier, proof, publicSignals)) {
|
||||
console.log("The proof is valid");
|
||||
} else {
|
||||
console.log("The proof is not valid");
|
||||
}
|
||||
```
|
@ -34,9 +34,9 @@ const circuit = new zkSnark.Circuit(circuitDef);
|
||||
```
|
||||
// `signalId` can always be a number or an alias string
|
||||
|
||||
circuit.m; // number of constrains
|
||||
circuit.n; // number of signals
|
||||
circuit.p; // number of public signals (nPublicInputs + nOutputs)
|
||||
circuit.nConstrains; // number of constrains
|
||||
circuit.nSignals; // number of signals
|
||||
circuit.nPublic; // number of public signals (nOutputs + nPublicInputs)
|
||||
|
||||
// The array of signals is always sorted in this order:
|
||||
// [ outputs, publicInputs, privedInputs, internalSignals, constants]
|
||||
|
20
src/gt.js
Normal file
20
src/gt.js
Normal file
@ -0,0 +1,20 @@
|
||||
const bigInt = require("big-integer");
|
||||
const ZnField = require("./znfield.js");
|
||||
|
||||
module.eports = class Gt {
|
||||
|
||||
constructor() {
|
||||
// TODO
|
||||
throw new Error("Not Implementted");
|
||||
}
|
||||
|
||||
mul(p1, p2) {
|
||||
// TODO
|
||||
throw new Error("Not Implementted");
|
||||
}
|
||||
|
||||
equal(p1, p2) {
|
||||
// TODO
|
||||
throw new Error("Not Implementted");
|
||||
}
|
||||
};
|
@ -5,6 +5,8 @@ This module calculate the pairing of p1 and p2 where p1 in G1 and p2 in G2
|
||||
const bigInt = require("big-integer");
|
||||
|
||||
module.exports = function pairing(p1, p2) {
|
||||
|
||||
|
||||
// TODO
|
||||
throw new Error("Not Implementted");
|
||||
};
|
||||
|
@ -37,6 +37,10 @@ class PolField {
|
||||
throw new Error("Not Implementted");
|
||||
}
|
||||
|
||||
eval(p, x) {
|
||||
throw new Error("Not Implementted");
|
||||
}
|
||||
|
||||
lagrange(points) {
|
||||
throw new Error("Not Implementted");
|
||||
}
|
@ -1,5 +1,86 @@
|
||||
const bigInt = require("big-integer");
|
||||
|
||||
const ZnField = require("./znfield.js");
|
||||
const G1Curve = require("./g1curve");
|
||||
const G2Curve = require("./g2curve");
|
||||
const PolField = require("./polfield.js");
|
||||
|
||||
const F = new ZnField(bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"));
|
||||
const G1 = new G1Curve();
|
||||
const G2 = new G2Curve();
|
||||
const PolF = new PolField(F);
|
||||
|
||||
|
||||
module.exports = function genProof(vk_proof, witness) {
|
||||
|
||||
}
|
||||
const proof = {};
|
||||
|
||||
proof.pi_a = G1.zero();
|
||||
proof.pi_ap = G1.zero();
|
||||
proof.pi_b = G2.zero();
|
||||
proof.pi_bp = G2.zero();
|
||||
proof.pi_c = G1.zero();
|
||||
proof.pi_cp = G1.zero();
|
||||
proof.pi_kp = G1.zero();
|
||||
proof.pi_h = G1.zero();
|
||||
|
||||
|
||||
for (let s= vk_proof.nPublic; s< vk_proof.nSignals; s++) {
|
||||
|
||||
// pi_a = pi_a + A[s] * witness[s];
|
||||
proof.pi_a = G1.add( proof.pi_a, G1.mulEscalar( vk_proof.A[s], witness[s]));
|
||||
|
||||
// pi_ap = pi_ap + Ap[s] * witness[s];
|
||||
proof.pi_ap = G1.add( proof.pi_ap, G1.mulEscalar( vk_proof.Ap[s], witness[s]));
|
||||
}
|
||||
|
||||
for (let s= 0; s< vk_proof.nSignals; s++) {
|
||||
// pi_a = pi_a + A[s] * witness[s];
|
||||
proof.pi_b = G2.add( proof.pi_b, G1.mulEscalar( vk_proof.B[s], witness[s]));
|
||||
|
||||
// pi_ap = pi_ap + Ap[s] * witness[s];
|
||||
proof.pi_bp = G1.add( proof.pi_bp, G1.mulEscalar( vk_proof.Bp[s], witness[s]));
|
||||
|
||||
// pi_a = pi_a + A[s] * witness[s];
|
||||
proof.pi_c = G1.add( proof.pi_c, G1.mulEscalar( vk_proof.C[s], witness[s]));
|
||||
|
||||
// pi_ap = pi_ap + Ap[s] * witness[s];
|
||||
proof.pi_cp = G1.add( proof.pi_cp, G1.mulEscalar( vk_proof.Cp[s], witness[s]));
|
||||
|
||||
// pi_ap = pi_ap + Ap[s] * witness[s];
|
||||
proof.pi_kp = G1.add( proof.pi_kp, G1.mulEscalar( vk_proof.Kp[s], witness[s]));
|
||||
}
|
||||
|
||||
let polA = [];
|
||||
let polB = [];
|
||||
let polC = [];
|
||||
|
||||
for (let s= 0; s< vk_proof.nSignals; s++) {
|
||||
polA = PolF.add(
|
||||
polA,
|
||||
PolF.mul(
|
||||
vk_proof.polsA[s],
|
||||
[witness[s]] ));
|
||||
|
||||
polB = PolF.add(
|
||||
polB,
|
||||
PolF.mul(
|
||||
vk_proof.polsB[s],
|
||||
[witness[s]] ));
|
||||
|
||||
polC = PolF.add(
|
||||
polC,
|
||||
PolF.mul(
|
||||
vk_proof.polsC[s],
|
||||
[witness[s]] ));
|
||||
}
|
||||
|
||||
let polFull = PolF.sub(PolF.mul( polA, polB), polC);
|
||||
|
||||
const h = PolF.div(polFull, vk_proof.polZ );
|
||||
|
||||
for (let i = 0; i < h.length; i++) {
|
||||
proof.pi_h = G1.add( proof.pi_h, G1.mulEscalar( vk_proof.hExps[i], h[i]));
|
||||
}
|
||||
|
||||
};
|
||||
|
155
src/setup.js
155
src/setup.js
@ -1,5 +1,160 @@
|
||||
const bigInt = require("big-integer");
|
||||
|
||||
const ZnField = require("./znfield.js");
|
||||
const PolField = require("./polfield.js");
|
||||
const G1Curve = require("./g1curve");
|
||||
const G2Curve = require("./g2curve");
|
||||
|
||||
const F = new ZnField(bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"));
|
||||
const PolF = new PolField(F);
|
||||
const G1 = new G1Curve();
|
||||
const G2 = new G2Curve();
|
||||
|
||||
module.exports = function setup(circuit) {
|
||||
const setup = {
|
||||
vk_proof : {
|
||||
nSignals: circuit.nSignals,
|
||||
nPublic: circuit.nPublic
|
||||
},
|
||||
vk_verifier: {
|
||||
nPublic: circuit.nPublic
|
||||
},
|
||||
toxic: {}
|
||||
};
|
||||
|
||||
calculatePolinomials(setup, circuit);
|
||||
setup.toxic.t = F.random();
|
||||
calculateEncriptedValuesAtT(setup, circuit);
|
||||
calculateHexps(setup, circuit);
|
||||
};
|
||||
|
||||
function calculatePolinomials(setup, circuit) {
|
||||
// Calculate the points that must cross each polinomial
|
||||
const aPoints = [];
|
||||
const bPoints = [];
|
||||
const cPoints = [];
|
||||
for (let s = 0; circuit.nSignals; s++) {
|
||||
aPoints[s] = [];
|
||||
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)]);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the polinomials using Lagrange
|
||||
setup.vk_proof.polsA = [];
|
||||
setup.vk_proof.polsB = [];
|
||||
setup.vk_proof.polsC = [];
|
||||
for (let s=0; s<circuit.nSignals; s++) {
|
||||
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] ));
|
||||
}
|
||||
|
||||
// Calculate Z polinomial
|
||||
// Z = 1
|
||||
setup.vk_proof.polZ = [bigInt(1)];
|
||||
for (let c=0; c<circuit.nConstrains; c++) {
|
||||
// Z = Z * (x - p_c)
|
||||
setup.vk_proof.polZ = PolF.mul(
|
||||
setup.vk_proof.polZ,
|
||||
[F.neg(bigInt(c)), bigInt(1)] );
|
||||
}
|
||||
}
|
||||
|
||||
function calculateEncriptedValuesAtT(setup, circuit) {
|
||||
setup.vk_proof.A = [];
|
||||
setup.vk_proof.B = [];
|
||||
setup.vk_proof.C = [];
|
||||
setup.vk_proof.Ap = [];
|
||||
setup.vk_proof.Bp = [];
|
||||
setup.vk_proof.Cp = [];
|
||||
setup.vk_proof.Kp = [];
|
||||
setup.vk_verifier.A = [];
|
||||
|
||||
setup.toxic.ka = F.random();
|
||||
setup.toxic.kb = F.random();
|
||||
setup.toxic.kc = F.random();
|
||||
setup.toxic.kbeta = F.random();
|
||||
setup.toxic.kgamma = F.random();
|
||||
|
||||
const gb = F.mul(setup.toxic.kbeta, setup.toxic.kgamma);
|
||||
|
||||
setup.vk_verifier.vk_a = G2.mulEscalar( G2.g, setup.toxic.ka);
|
||||
setup.vk_verifier.vk_b = G1.mulEscalar( G1.g, setup.toxic.kb);
|
||||
setup.vk_verifier.vk_c = G2.mulEscalar( G2.g, setup.toxic.kc);
|
||||
setup.vk_verifier.vk_gb_1 = G1.mulEscalar( G1.g, gb);
|
||||
setup.vk_verifier.vk_gb_2 = G2.mulEscalar( G2.g, gb);
|
||||
setup.vk_verifier.vk_g = G2.mulEscalar( G2.g, setup.toxic.kgamma);
|
||||
|
||||
for (let s=0; s<circuit.nSignals; s++) {
|
||||
|
||||
// A[i] = G1 * polA(t)
|
||||
const A = G1.mulEscalar(
|
||||
G1.g,
|
||||
PolF.eval(setup.vk_proof.polsA[s], setup.vk_proof.t));
|
||||
setup.vk_proof.A.push(A);
|
||||
|
||||
if (s < circuit.nPublicSignals) {
|
||||
setup.vk_verifier.A.pusj(A);
|
||||
}
|
||||
|
||||
// B1[i] = G1 * polB(t)
|
||||
const B1 = G1.mulEscalar(
|
||||
G1.g,
|
||||
PolF.eval(setup.vk_proof.polsB[s], setup.vk_proof.t));
|
||||
|
||||
// B2[i] = G2 * polB(t)
|
||||
const B2 = G2.mulEscalar(
|
||||
G2.g,
|
||||
PolF.eval(setup.vk_proof.polsB[s], setup.vk_proof.t));
|
||||
setup.vk_proof.B.push(B2);
|
||||
|
||||
// C[i] = G1 * polC(t)
|
||||
const C = G1.mulEscalar(
|
||||
G1.g,
|
||||
PolF.eval(setup.vk_proof.polsC[s], setup.vk_proof.t));
|
||||
setup.vk_proof.C.push (C);
|
||||
|
||||
// K = G1 * (A+B+C)
|
||||
const K = G1.mulEscalar(
|
||||
G1.g,
|
||||
G1.add(G1.add(A, B1), C));
|
||||
|
||||
setup.vk_proof.Ap.push(G1.mulEscalar(A, setup.toxic.ka));
|
||||
setup.vk_proof.Bp.push(G1.mulEscalar(B1, setup.toxic.kb));
|
||||
setup.vk_proof.Cp.push(G1.mulEscalar(C, setup.toxic.kc));
|
||||
setup.vk_proof.Kp.push(G1.mulEscalar(K, setup.toxic.beta));
|
||||
}
|
||||
|
||||
setup.vk_verifier.vk_z = G2.mulEscalar(
|
||||
G2.g,
|
||||
PolF.eval(setup.vk_proof.polZ, setup.vk_proof.t));
|
||||
}
|
||||
|
||||
function calculateHexps(setup, circuit) {
|
||||
let maxA = 0;
|
||||
let maxB = 0;
|
||||
let maxC = 0;
|
||||
for (let s=0; s<circuit.nSignals; s++) {
|
||||
maxA = Math.max(maxA, setup.vk_proof.polsA[s]);
|
||||
maxB = Math.max(maxB, setup.vk_proof.polsB[s]);
|
||||
maxC = Math.max(maxC, setup.vk_proof.polsC[s]);
|
||||
}
|
||||
|
||||
let maxFull = Math.max(maxA * maxB - 1, maxC);
|
||||
|
||||
const maxH = maxFull - setup.vk_proof.polZ.length + 1;
|
||||
|
||||
setup.vk_proof.hExps = new Array(maxH);
|
||||
setup.vk_proof.hExps[0] = G1.g;
|
||||
let eT = setup.toxic.t;
|
||||
for (let i=1; i<maxH; i++) {
|
||||
setup.vk_proof.hExps[i] = G1.mulEscalar(G1.g, eT);
|
||||
eT = F.mul(eT, setup.toxic.t);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,52 @@
|
||||
const G1Curve = require("./g1curve");
|
||||
const G2Curve = require("./g2curve");
|
||||
const GT = require("./gt");
|
||||
|
||||
const G1 = new G1Curve();
|
||||
const G2 = new G2Curve();
|
||||
const Gt = new GT();
|
||||
|
||||
const pairing = require("./pairing");
|
||||
|
||||
module.exports = function isValid(vk_verifier, proof, publicSignals) {
|
||||
|
||||
}
|
||||
let full_pi_a = proof.pi_a;
|
||||
for (let s= 0; s< vk_verifier.nPublic; s++) {
|
||||
|
||||
full_pi_a = G1.add( full_pi_a, G1.mulEscalar( vk_verifier.A[s], publicSignals[s]));
|
||||
}
|
||||
|
||||
if (! Gt.equal(
|
||||
pairing( proof.pi_a , vk_verifier.vk_a ),
|
||||
pairing( proof.pi_ap , G2.g )))
|
||||
return false;
|
||||
|
||||
if (! Gt.equal(
|
||||
pairing( vk_verifier.vk_b, proof.pi_b ),
|
||||
pairing( proof.pi_ap , G2.g )))
|
||||
return false;
|
||||
|
||||
if (! Gt.equal(
|
||||
pairing( proof.pi_c , vk_verifier.vk_c ),
|
||||
pairing( proof.pi_cp , G2.g )))
|
||||
return false;
|
||||
|
||||
if (! Gt.equal(
|
||||
pairing( full_pi_a , proof.pi_b ),
|
||||
Gt.mul(
|
||||
pairing( proof.pi_h , vk_verifier.vk_z ),
|
||||
pairing( proof.pi_b , G2.g ),
|
||||
),
|
||||
pairing( proof.pi_kp , vk_verifier.vk_g )))
|
||||
return false;
|
||||
|
||||
if (! Gt.equal(
|
||||
Gt.mul(
|
||||
pairing( G1.add(full_pi_a, proof.pi_c) , vk_verifier.vk_gb_2 ),
|
||||
pairing( vk_verifier.vk_gb_1 , proof.pi_b ),
|
||||
),
|
||||
pairing( proof.pi_kp , vk_verifier.vk_g )))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
@ -19,6 +19,11 @@ class ZnField {
|
||||
throw new Error("Not Implementted");
|
||||
}
|
||||
|
||||
neg(a) {
|
||||
// TODO
|
||||
throw new Error("Not Implementted");
|
||||
}
|
||||
|
||||
mul(a, b) {
|
||||
// TODO
|
||||
throw new Error("Not Implementted");
|
||||
@ -34,6 +39,16 @@ class ZnField {
|
||||
throw new Error("Not Implementted");
|
||||
}
|
||||
|
||||
isZero(a) {
|
||||
// TODO
|
||||
throw new Error("Not Implementted");
|
||||
}
|
||||
|
||||
random() {
|
||||
// TODO
|
||||
throw new Error("Not Implementted");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = ZnField;
|
||||
|
Loading…
Reference in New Issue
Block a user