arnaucube
arnaucube/snarkjsPublic Self-hosted repository
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};