snarkjs/test/zksnark.js
test/zksnark.jsRaw
1/*
2 Copyright 2018 0kims association.
3
4 This file is part of zksnark JavaScript library.
5
6 zksnark JavaScript library is a free software: you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as published by the
8 Free Software Foundation, either version 3 of the License, or (at your option)
9 any later version.
10
11 zksnark JavaScript library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 more details.
15
16 You should have received a copy of the GNU General Public License along with
17 zksnark JavaScript library. If not, see <https://www.gnu.org/licenses/>.
18*/
19
20const chai = require("chai");
21const fs = require("fs");
22const path = require("path");
23const bigInt = require("../src/bigint.js");
24
25const Circuit = require("../src/circuit.js");
26const zkSnark = require("../index.js");
27const BN128 = require("../src/bn128.js");
28const PolField = require("../src/polfield.js");
29const ZqField = require("../src/zqfield.js");
30const bn128 = new BN128();
31const PolF = new PolField(new ZqField(bn128.r));
32const G1 = bn128.G1;
33const G2 = bn128.G2;
34
35const assert = chai.assert;
36
37
38function stringifyBigInts(o) {
39 if ((typeof(o) == "bigint") || (o instanceof bigInt)) {
40 return o.toString(10);
41 } else if (Array.isArray(o)) {
42 return o.map(stringifyBigInts);
43 } else if (typeof o == "object") {
44 const res = {};
45 for (let k in o) {
46 res[k] = stringifyBigInts(o[k]);
47 }
48 return res;
49 } else {
50 return o;
51 }
52}
53
54function unstringifyBigInts(o) {
55 if ((typeof(o) == "string") && (/^[0-9]+$/.test(o) )) {
56 return bigInt(o);
57 } else if (Array.isArray(o)) {
58 return o.map(unstringifyBigInts);
59 } else if (typeof o == "object") {
60 const res = {};
61 for (let k in o) {
62 res[k] = unstringifyBigInts(o[k]);
63 }
64 return res;
65 } else {
66 return o;
67 }
68}
69
70
71describe("zkSnark", () => {
72 it("Load a circuit, create trusted setup, create a proof and validate it", () => {
73
74
75 const cirDef = JSON.parse(fs.readFileSync(path.join(__dirname, "circuit", "sum.json"), "utf8"));
76 const cir = new Circuit(cirDef);
77
78 const setup = zkSnark.setup(cir);
79 const strSetup = stringifyBigInts(setup);
80 fs.writeFileSync("vk_proof.json", JSON.stringify(strSetup.vk_proof), "utf-8");
81 fs.writeFileSync("vk_verifier.json", JSON.stringify(strSetup.vk_verifier), "utf-8");
82
83
84 function polT2S(p) {
85 const p_T = new Array(setup.vk_proof.domainSize).fill(bigInt(0));
86
87 for (let c in p) {
88 p_T[c] = p[c];
89 }
90
91 return PolF.ifft(p_T);
92 }
93
94/*
95 const setup = {};
96 setup.vk_proof = unstringifyBigInts(JSON.parse(fs.readFileSync("vk_proof.json", "utf8")));
97 setup.vk_verifier = unstringifyBigInts(JSON.parse(fs.readFileSync("vk_verifier.json", "utf8")));
98*/
99 const witness = cir.calculateWitness({"a": "33", "b": "34"});
100
101 const {proof, publicSignals} = zkSnark.genProof(setup.vk_proof, witness);
102
103/*
104 const polA = new Array(cir.nVars);
105 const polB = new Array(cir.nVars);
106 const polC = new Array(cir.nVars);
107 for (let i=0; i<cir.nVars; i++) {
108 polA[i] = polT2S(setup.vk_proof.polsA[i]);
109 polB[i] = polT2S(setup.vk_proof.polsB[i]);
110 polC[i] = polT2S(setup.vk_proof.polsC[i]);
111 }
112
113 PolF._setRoots(setup.vk_proof.domainBits);
114 for (let c=0; c<setup.vk_proof.domainSize; c++) {
115 let A = bigInt(0);
116 let B = bigInt(0);
117 let C = bigInt(0);
118 for (let s=0; s<cir.nVars; s++) {
119 A = PolF.F.add(A, PolF.F.mul(PolF.eval(polA[s], PolF.roots[setup.vk_proof.domainBits][c]), witness[s]));
120 B = PolF.F.add(B, PolF.F.mul(PolF.eval(polB[s], PolF.roots[setup.vk_proof.domainBits][c]), witness[s]));
121 C = PolF.F.add(C, PolF.F.mul(PolF.eval(polC[s], PolF.roots[setup.vk_proof.domainBits][c]), witness[s]));
122 }
123 assert(PolF.F.equals(PolF.F.mul(A,B), C));
124 }
125
126 let A = bigInt(0);
127 let B = bigInt(0);
128 let C = bigInt(0);
129 for (let s=0; s<cir.nVars; s++) {
130 A = PolF.F.add(A, PolF.F.mul(PolF.eval(polA[s], setup.toxic.t), witness[s]));
131 B = PolF.F.add(B, PolF.F.mul(PolF.eval(polB[s], setup.toxic.t), witness[s]));
132 C = PolF.F.add(C, PolF.F.mul(PolF.eval(polC[s], setup.toxic.t), witness[s]));
133 }
134
135 let A2 = bigInt(0);
136 let B2 = bigInt(0);
137 let C2 = bigInt(0);
138 const u = PolF.evaluateLagrangePolynomials(setup.vk_proof.domainBits, setup.toxic.t);
139 for (let s=0; s<cir.nVars; s++) {
140 let at = PolF.F.zero;
141 for (let c in setup.vk_proof.polsA[s]) {
142 at = PolF.F.add(at, PolF.F.mul(u[c], setup.vk_proof.polsA[s][c]));
143 }
144 A2 = PolF.F.add(A2, PolF.F.mul(at, witness[s]));
145
146 let bt = PolF.F.zero;
147 for (let c in setup.vk_proof.polsB[s]) {
148 bt = PolF.F.add(bt, PolF.F.mul(u[c], setup.vk_proof.polsB[s][c]));
149 }
150 B2 = PolF.F.add(B2, PolF.F.mul(bt, witness[s]));
151
152 let ct = PolF.F.zero;
153 for (let c in setup.vk_proof.polsC[s]) {
154 ct = PolF.F.add(ct, PolF.F.mul(u[c], setup.vk_proof.polsC[s][c]));
155 }
156 C2 = PolF.F.add(C2, PolF.F.mul(ct, witness[s]));
157 }
158
159 A=PolF.F.affine(A);
160 B=PolF.F.affine(B);
161 C=PolF.F.affine(C);
162 A2=PolF.F.affine(A2);
163 B2=PolF.F.affine(B2);
164 C2=PolF.F.affine(C2);
165
166 assert(PolF.F.equals(C,C2));
167 assert(PolF.F.equals(B,B2));
168 assert(PolF.F.equals(A,A2));
169 const ABC = PolF.F.affine(PolF.F.sub(PolF.F.mul(A,B), C));
170
171
172
173 assert.equal(witness[cir.getSignalIdx("main.out")].toString(), "67");
174
175 const H = PolF.eval(proof.h, setup.toxic.t).affine();
176
177 const Z = PolF.F.sub(PolF.F.exp(setup.toxic.t, setup.vk_proof.domainSize), bigInt(1));
178
179 const HZ = PolF.F.affine(PolF.F.mul(H,Z));
180 assert(PolF.F.equals(ABC, HZ));
181
182
183 const gH = G1.affine(G1.mulScalar( G1.g, H));
184 const gZ = G2.affine(G2.mulScalar( G2.g, Z));
185 const gA = G1.affine(G1.mulScalar( G1.g, A));
186 const gB = G2.affine(G2.mulScalar( G2.g, B));
187 const gC = G1.affine(G1.mulScalar( G1.g, C));
188
189 assert(G1.equals(gH, proof.pi_h));
190 assert(G2.equals(gZ, setup.vk_verifier.vk_z));
191 assert(G2.equals(gB, proof.pi_b));
192 assert(G1.equals(gC, proof.pi_c));
193// assert(G1.equals(gA, proof.pi_a));
194*/
195 assert( zkSnark.isValid(setup.vk_verifier, proof, publicSignals));
196 }).timeout(10000000);
197
198 it("validate sha256_2", () => {
199
200 const cirDef = JSON.parse(fs.readFileSync(path.join(__dirname, "circuit", "sha256_2.json"), "utf8"));
201 const cir = new Circuit(cirDef);
202
203 console.log("Start setup: "+Date().toString());
204 const setup = zkSnark.setup(cir);
205 const strSetup = stringifyBigInts(setup);
206 fs.writeFileSync("sha256_2_vk_proof.json", JSON.stringify(strSetup.vk_proof), "utf-8");
207 fs.writeFileSync("sha256_2_vk_verifier.json", JSON.stringify(strSetup.vk_verifier), "utf-8");
208
209
210// const setup = {};
211// setup.vk_proof = unstringifyBigInts(JSON.parse(fs.readFileSync("vk_proof.json", "utf8")));
212// setup.vk_verifier = unstringifyBigInts(JSON.parse(fs.readFileSync("vk_verifier.json", "utf8")));
213
214 const witness = cir.calculateWitness({"a": "1", "b": "2"});
215
216// assert.equal(witness[cir.getSignalIdx("main.out")].toString(), "67");
217
218 console.log("Start calculating the proof: "+Date().toString());
219 const {proof, publicSignals} = zkSnark.genProof(setup.vk_proof, witness);
220
221 console.log("Start verifiying: "+ Date().toString());
222 assert( zkSnark.isValid(setup.vk_verifier, proof, publicSignals));
223 }).timeout(10000000);
224
225
226});