snarkjs/src/setup.js
src/setup.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 bigInt = require("./bigint.js");
21
22const BN128 = require("./bn128.js");
23const PolField = require("./polfield.js");
24const ZqField = require("./zqfield.js");
25
26const bn128 = new BN128();
27const G1 = bn128.G1;
28const G2 = bn128.G2;
29const PolF = new PolField(new ZqField(bn128.r));
30const F = new ZqField(bn128.r);
31
32module.exports = function setup(circuit) {
33 const setup = {
34 vk_proof : {
35 nVars: circuit.nVars,
36 nPublic: circuit.nPubInputs + circuit.nOutputs
37 },
38 vk_verifier: {
39 nPublic: circuit.nPubInputs + circuit.nOutputs
40 },
41 toxic: {}
42 };
43
44
45 setup.vk_proof.domainBits = PolF.log2(circuit.nConstraints + circuit.nPubInputs + circuit.nOutputs +1 -1) +1;
46 setup.vk_proof.domainSize = 1 << setup.vk_proof.domainBits;
47
48 calculatePolinomials(setup, circuit);
49 setup.toxic.t = F.random();
50 calculateEncriptedValuesAtT(setup, circuit);
51 calculateHexps(setup, circuit);
52
53 return setup;
54};
55
56
57function calculatePolinomials(setup, circuit) {
58
59 setup.vk_proof.polsA = new Array(circuit.nVars);
60 setup.vk_proof.polsB = new Array(circuit.nVars);
61 setup.vk_proof.polsC = new Array(circuit.nVars);
62 for (let i=0; i<circuit.nVars; i++) {
63 setup.vk_proof.polsA[i] = {};
64 setup.vk_proof.polsB[i] = {};
65 setup.vk_proof.polsC[i] = {};
66 }
67 for (let c=0; c<circuit.nConstraints; c++) {
68
69 for (let s in circuit.constraints[c][0]) {
70 setup.vk_proof.polsA[s][c] = bigInt(circuit.constraints[c][0][s]);
71 }
72 for (let s in circuit.constraints[c][1]) {
73 setup.vk_proof.polsB[s][c] = bigInt(circuit.constraints[c][1][s]);
74 }
75 for (let s in circuit.constraints[c][2]) {
76 setup.vk_proof.polsC[s][c] = bigInt(circuit.constraints[c][2][s]);
77 }
78 }
79
80 /**
81 * add and process the constraints
82 * input_i * 0 = 0
83 * to ensure soundness of input consistency
84 */
85 for (let i = 0; i < circuit.nPubInputs + circuit.nOutputs + 1; ++i)
86 {
87 setup.vk_proof.polsA[i][circuit.nConstraints + i] = F.one;
88 }
89}
90
91function calculateValuesAtT(setup, circuit) {
92 const z_t = PolF.computeVanishingPolinomial(setup.vk_proof.domainBits, setup.toxic.t);
93 const u = PolF.evaluateLagrangePolynomials(setup.vk_proof.domainBits, setup.toxic.t);
94
95 const a_t = new Array(circuit.nVars).fill(F.zero);
96 const b_t = new Array(circuit.nVars).fill(F.zero);
97 const c_t = new Array(circuit.nVars).fill(F.zero);
98
99 // TODO: substitute setup.polsA for coeficients
100 for (let s=0; s<circuit.nVars; s++) {
101 for (let c in setup.vk_proof.polsA[s]) {
102 a_t[s] = F.add(a_t[s], F.mul(u[c], setup.vk_proof.polsA[s][c]));
103 }
104 for (let c in setup.vk_proof.polsB[s]) {
105 b_t[s] = F.add(b_t[s], F.mul(u[c], setup.vk_proof.polsB[s][c]));
106 }
107 for (let c in setup.vk_proof.polsC[s]) {
108 c_t[s] = F.add(c_t[s], F.mul(u[c], setup.vk_proof.polsC[s][c]));
109 }
110 }
111
112 return {a_t, b_t, c_t, z_t};
113
114}
115
116
117
118
119function calculateEncriptedValuesAtT(setup, circuit) {
120
121 const v = calculateValuesAtT(setup, circuit);
122 setup.vk_proof.A = new Array(circuit.nVars+1);
123 setup.vk_proof.B = new Array(circuit.nVars+1);
124 setup.vk_proof.C = new Array(circuit.nVars+1);
125 setup.vk_proof.Ap = new Array(circuit.nVars+1);
126 setup.vk_proof.Bp = new Array(circuit.nVars+1);
127 setup.vk_proof.Cp = new Array(circuit.nVars+1);
128 setup.vk_proof.Kp = new Array(circuit.nVars+3);
129 setup.vk_verifier.A = new Array(circuit.nPublic);
130
131 setup.toxic.ka = F.random();
132 setup.toxic.kb = F.random();
133 setup.toxic.kc = F.random();
134 setup.toxic.ra = F.random();
135 setup.toxic.rb = F.random();
136 setup.toxic.rc = F.mul(setup.toxic.ra, setup.toxic.rb);
137 setup.toxic.kbeta = F.random();
138 setup.toxic.kgamma = F.random();
139
140 const gb = F.mul(setup.toxic.kbeta, setup.toxic.kgamma);
141
142 setup.vk_verifier.vk_a = G2.affine(G2.mulScalar( G2.g, setup.toxic.ka));
143 setup.vk_verifier.vk_b = G1.affine(G1.mulScalar( G1.g, setup.toxic.kb));
144 setup.vk_verifier.vk_c = G2.affine(G2.mulScalar( G2.g, setup.toxic.kc));
145 setup.vk_verifier.vk_gb_1 = G1.affine(G1.mulScalar( G1.g, gb));
146 setup.vk_verifier.vk_gb_2 = G2.affine(G2.mulScalar( G2.g, gb));
147 setup.vk_verifier.vk_g = G2.affine(G2.mulScalar( G2.g, setup.toxic.kgamma));
148
149 for (let s=0; s<circuit.nVars; s++) {
150
151 // A[i] = G1 * polA(t)
152 const raat = F.mul(setup.toxic.ra, v.a_t[s]);
153 const A = G1.affine(G1.mulScalar(G1.g, raat));
154
155 setup.vk_proof.A[s] = A;
156
157 if (s <= setup.vk_proof.nPublic) {
158 setup.vk_verifier.A[s]=A;
159 }
160
161
162 // B1[i] = G1 * polB(t)
163 const rbbt = F.mul(setup.toxic.rb, v.b_t[s]);
164 const B1 = G1.affine(G1.mulScalar(G1.g, rbbt));
165
166 // B2[i] = G2 * polB(t)
167 const B2 = G2.affine(G2.mulScalar(G2.g, rbbt));
168
169 setup.vk_proof.B[s]=B2;
170
171 // C[i] = G1 * polC(t)
172 const rcct = F.mul(setup.toxic.rc, v.c_t[s]);
173 const C = G1.affine(G1.mulScalar( G1.g, rcct));
174 setup.vk_proof.C[s] =C;
175
176 // K = G1 * (A+B+C)
177
178 const kt = F.affine(F.add(F.add(raat, rbbt), rcct));
179 const K = G1.affine(G1.mulScalar( G1.g, kt));
180
181 /*
182 // Comment this lines to improve the process
183 const Ktest = G1.affine(G1.add(G1.add(A, B1), C));
184
185 if (!G1.equals(K, Ktest)) {
186 console.log ("=====FAIL======");
187 }
188 */
189
190
191 setup.vk_proof.Ap[s] = G1.affine(G1.mulScalar(A, setup.toxic.ka));
192 setup.vk_proof.Bp[s] = G1.affine(G1.mulScalar(B1, setup.toxic.kb));
193 setup.vk_proof.Cp[s] = G1.affine(G1.mulScalar(C, setup.toxic.kc));
194 setup.vk_proof.Kp[s] = G1.affine(G1.mulScalar(K, setup.toxic.kbeta));
195 }
196
197 // Extra coeficients
198 const A = G1.mulScalar( G1.g, F.mul(setup.toxic.ra, v.z_t));
199 setup.vk_proof.A[circuit.nVars] = G1.affine(A);
200 setup.vk_proof.Ap[circuit.nVars] = G1.affine(G1.mulScalar(A, setup.toxic.ka));
201
202 const B1 = G1.mulScalar( G1.g, F.mul(setup.toxic.rb, v.z_t));
203 const B2 = G2.mulScalar( G2.g, F.mul(setup.toxic.rb, v.z_t));
204 setup.vk_proof.B[circuit.nVars] = G2.affine(B2);
205 setup.vk_proof.Bp[circuit.nVars] = G1.affine(G1.mulScalar(B1, setup.toxic.kb));
206
207 const C = G1.mulScalar( G1.g, F.mul(setup.toxic.rc, v.z_t));
208 setup.vk_proof.C[circuit.nVars] = G1.affine(C);
209 setup.vk_proof.Cp[circuit.nVars] = G1.affine(G1.mulScalar(C, setup.toxic.kc));
210
211 setup.vk_proof.Kp[circuit.nVars ] = G1.affine(G1.mulScalar(A, setup.toxic.kbeta));
212 setup.vk_proof.Kp[circuit.nVars+1] = G1.affine(G1.mulScalar(B1, setup.toxic.kbeta));
213 setup.vk_proof.Kp[circuit.nVars+2] = G1.affine(G1.mulScalar(C, setup.toxic.kbeta));
214
215// setup.vk_verifier.A[0] = G1.affine(G1.add(setup.vk_verifier.A[0], setup.vk_proof.A[circuit.nVars]));
216
217 // vk_z
218 setup.vk_verifier.vk_z = G2.affine(G2.mulScalar(
219 G2.g,
220 F.mul(setup.toxic.rc, v.z_t)));
221}
222
223function calculateHexps(setup) {
224
225 const maxH = setup.vk_proof.domainSize+1;
226
227 setup.vk_proof.hExps = new Array(maxH);
228 setup.vk_proof.hExps[0] = G1.g;
229 let eT = setup.toxic.t;
230 for (let i=1; i<maxH; i++) {
231 setup.vk_proof.hExps[i] = G1.affine(G1.mulScalar(G1.g, eT));
232 eT = F.mul(eT, setup.toxic.t);
233 }
234}
235