snarkjs/src/circuit.js
src/circuit.jsRaw
1/*
2 Copyright 2018 0kims association.
3
4 This file is part of snarkjs.
5
6 snarkjs 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 snarkjs 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 snarkjs. If not, see <https://www.gnu.org/licenses/>.
18*/
19
20const bigInt = require("./bigint.js");
21
22const __P__ = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617");
23const __MASK__ = bigInt("28948022309329048855892746252171976963317496166410141009864396001978282409983"); // 0x3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
24const calculateWitness = require("./calculateWitness.js");
25
26module.exports = class Circuit {
27 constructor(circuitDef) {
28 this.nPubInputs = circuitDef.nPubInputs;
29 this.nPrvInputs = circuitDef.nPrvInputs;
30 this.nInputs = circuitDef.nInputs;
31 this.nOutputs = circuitDef.nOutputs;
32 this.nVars = circuitDef.nVars;
33 this.nSignals = circuitDef.nSignals;
34 this.nConstants = circuitDef.nConstants;
35
36 this.nConstraints = circuitDef.constraints.length;
37
38 this.signalName2Idx = circuitDef.signalName2Idx;
39 this.components = circuitDef.components;
40 this.componentName2Idx = circuitDef.componentName2Idx;
41 this.signals = circuitDef.signals;
42 this.constraints = circuitDef.constraints;
43
44 this.templates = {};
45 for (let t in circuitDef.templates) {
46 this.templates[t] = eval(" const __f= " +circuitDef.templates[t] + "\n__f");
47 }
48
49 this.functions = {};
50 for (let f in circuitDef.functions) {
51 this.functions[f] = {
52 params: circuitDef.functions[f].params,
53 func: eval(" const __f= " +circuitDef.functions[f].func + "\n__f;")
54 };
55 }
56 }
57
58 calculateWitness(input, log) {
59 return calculateWitness(this, input, log);
60 }
61
62 checkWitness(w) {
63 const evalLC = (lc, w) => {
64 let acc = bigInt(0);
65 for (let k in lc) {
66 acc= acc.add(bigInt(w[k]).mul(bigInt(lc[k]))).mod(__P__);
67 }
68 return acc;
69 }
70
71 const checkConstraint = (ct, w) => {
72 const a=evalLC(ct[0],w);
73 const b=evalLC(ct[1],w);
74 const c=evalLC(ct[2],w);
75 const res = (a.mul(b).sub(c)).affine(__P__);
76 if (!res.isZero()) return false;
77 return true;
78 }
79
80
81 for (let i=0; i<this.constraints.length; i++) {
82 if (!checkConstraint(this.constraints[i], w)) {
83 this.printCostraint(this.constraints[i]);
84 return false;
85 }
86 }
87
88 return true;
89
90 }
91
92 printCostraint(c) {
93 const lc2str = (lc) => {
94 let S = "";
95 for (let k in lc) {
96 let name = this.signals[k].names[0];
97 if (name == "one") name = "";
98 let v = bigInt(lc[k]);
99 let vs;
100 if (!v.lesserOrEquals(__P__.shr(bigInt(1)))) {
101 v = __P__.sub(v);
102 vs = "-"+v.toString();
103 } else {
104 if (S!="") {
105 vs = "+"+v.toString();
106 } else {
107 vs = "";
108 }
109 if (vs!="1") {
110 vs = vs + v.toString();;
111 }
112 }
113
114 S= S + " " + vs + name;
115 }
116 return S;
117 };
118 const S = `[ ${lc2str(c[0])} ] * [ ${lc2str(c[1])} ] - [ ${lc2str(c[2])} ] = 0`;
119 console.log(S);
120 }
121
122 printConstraints() {
123 for (let i=0; i<this.constraints.length; i++) {
124 this.printCostraint(this.constraints[i]);
125 }
126 }
127
128 getSignalIdx(name) {
129 if (typeof(this.signalName2Idx[name]) != "undefined") return this.signalName2Idx[name];
130 if (!isNaN(name)) return Number(name);
131 throw new Error("Invalid signal identifier: ", name);
132 }
133
134 // returns the index of the i'th output
135 outputIdx(i) {
136 if (i>=this.nOutputs) throw new Error("Accessing an invalid output: "+i);
137 return i+1;
138 }
139
140 // returns the index of the i'th input
141 inputIdx(i) {
142 if (i>=this.nInputs) throw new Error("Accessing an invalid input: "+i);
143 return this.nOutputs + 1 + i;
144 }
145
146 // returns the index of the i'th public input
147 pubInputIdx(i) {
148 if (i>=this.nPubInputs) throw new Error("Accessing an invalid pubInput: "+i);
149 return this.inputIdx(i);
150 }
151
152 // returns the index of the i'th private input
153 prvInputIdx(i) {
154 if (i>=this.nPrvInputs) throw new Error("Accessing an invalid prvInput: "+i);
155 return this.inputIdx(this.nPubInputs + i);
156 }
157
158 // returns the index of the i'th variable
159 varIdx(i) {
160 if (i>=this.nVars) throw new Error("Accessing an invalid variable: "+i);
161 return i;
162 }
163
164 // returns the index of the i'th constant
165 constantIdx(i) {
166 if (i>=this.nConstants) throw new Error("Accessing an invalid constant: "+i);
167 return this.nVars + i;
168 }
169
170 // returns the index of the i'th signal
171 signalIdx(i) {
172 if (i>=this.nSignls) throw new Error("Accessing an invalid signal: "+i);
173 return i;
174 }
175
176 signalNames(i) {
177 return this.signals[ this.getSignalIdx(i) ].names.join(", ");
178 }
179
180 a(constraint, signalIdx) {
181 return bigInt(this.constraints[constraint][0][signalIdx] || 0 );
182 }
183
184 b(constraint, signalIdx) {
185 return bigInt(this.constraints[constraint][1][signalIdx] || 0);
186 }
187
188 c(constraint, signalIdx) {
189 return bigInt(this.constraints[constraint][2][signalIdx] || 0);
190 }
191};