arnaucube
arnaucube/circomPublic Self-hosted repository
circom/src/calculateWitness.js
src/calculateWitness.jsRaw
  1const bigInt = require("big-integer");
  2
  3module.exports = calculateWitness;
  4
  5function calculateWitness(circuit, inputSignals) {
  6    const ctx = new RTCtx(circuit);
  7
  8    function iterateSelector(values, sels, cb) {
  9        if (!Array.isArray(values)) {
 10            return cb(sels, values);
 11        }
 12        for (let i=0; i<values.length; i++) {
 13            sels.push(i);
 14            iterateSelector(values[i], sels, cb);
 15            sels.pop(i);
 16        }
 17    }
 18
 19    ctx.setSignal("one", [], bigInt(1));
 20
 21    for (let c in ctx.notInitSignals) {
 22        if (ctx.notInitSignals[c] == 0) ctx.triggerComponent(c);
 23    }
 24
 25    for (let s in inputSignals) {
 26        ctx.currentComponent = "main";
 27        iterateSelector(inputSignals[s], [], function(selector, value) {
 28            ctx.setSignal(s, selector, bigInt(value));
 29        });
 30    }
 31
 32    for (let i=0; i<ctx.witness.length; i++) {
 33        if (typeof(ctx.witness[i]) == "undefined") {
 34            throw("Signal not assigned: " + ctx.circuit.witnessNames[i].join(", "));
 35        }
 36        console.log(ctx.circuit.witnessNames[i].join(",") + " --> " + ctx.witness[i].toString());
 37    }
 38    return ctx.witness;
 39}
 40
 41class RTCtx {
 42    constructor(circuit) {
 43        this.scopes = [];
 44        this.circuit = circuit;
 45        this.witness = [];
 46        this.notInitSignals = {};
 47        for (let c in this.circuit.components) {
 48            this.notInitSignals[c] = this.circuit.components[c].inputSignals;
 49            if (this.notInitSignals == 0) {
 50                this.currentComponent = c;
 51                this.components.calc(this);
 52                this.currentComponent = null;
 53            }
 54        }
 55    }
 56
 57    _sels2str(sels) {
 58        let res = "";
 59        for (let i=0; i<sels.length; i++) {
 60            res += `[${sels[i]}]`;
 61        }
 62        return res;
 63    }
 64
 65    setPin(componentName, componentSels, signalName, signalSels, value) {
 66        let fullName = componentName=="one" ? "one" : this.currentComponent + "." + componentName;
 67        fullName += this._sels2str(componentSels) +
 68                    "."+
 69                    signalName+
 70                    this._sels2str(signalSels);
 71        this.setSignalFullName(fullName, value);
 72    }
 73
 74    setSignal(name, sels, value) {
 75        let fullName = this.currentComponent ? this.currentComponent + "." + name : name;
 76        fullName += this._sels2str(sels);
 77        this.setSignalFullName(fullName, value);
 78    }
 79
 80    triggerComponent(c) {
 81        console.log("Component Treiggered: " + c);
 82
 83        // Set notInitSignals to -1 to not initialize again
 84        this.notInitSignals[c] --;
 85        const oldComponent = this.currentComponent;
 86        this.currentComponent = c;
 87        const template = this.circuit.components[c].template;
 88
 89        const newScope = {};
 90        for (let p in this.circuit.components[c].params) {
 91            newScope[p] = this.circuit.components[c].params[p];
 92        }
 93
 94        const oldScope = this.scopes;
 95        this.scopes = [ this.scopes[0], newScope ];
 96
 97        // TODO set params.
 98
 99        this.circuit.templates[template](this);
100        this.scopes = oldScope;
101        this.currentComponent = oldComponent;
102    }
103
104    callFunction(functionName, params) {
105
106        const newScope = {};
107        for (let p=0; p<this.circuit.functionParams[functionName].length; p++) {
108            const paramName = this.circuit.functionParams[functionName][p];
109            newScope[paramName] = params[p];
110        }
111
112        const oldScope = this.scopes;
113        this.scopes = [ this.scopes[0], newScope ];
114
115        // TODO set params.
116
117        const res = this.circuit.functions[functionName](this);
118        this.scopes = oldScope;
119
120        return res;
121    }
122
123    setSignalFullName(fullName, value) {
124        console.log("set " + fullName + " <-- " + value.toString());
125        const sId = this.circuit.signals[fullName].id;
126        let firstInit =false;
127        if (!this.witness[sId]) {
128            firstInit = true;
129        }
130        this.witness[sId] = value;
131        const callComponents = [];
132        for (let i=0; i<this.circuit.witnessNames[sId].length; i++) {
133            const ss = this.circuit.witnessNames[sId][i];
134            if (this.circuit.signals[ss].direction == "IN") {
135                if (firstInit) this.notInitSignals[ this.circuit.signals[ss].component] --;
136                callComponents.push(this.circuit.signals[ss].component);
137            }
138        }
139        for (let i in callComponents) {
140            const c= callComponents[i];
141            if (this.notInitSignals[c] == 0) this.triggerComponent(c);
142        }
143        return value;
144    }
145
146    setVar(name, sels, value) {
147        function setVarArray(a, sels2, value) {
148            if (sels2.length == 1) {
149                a[sels2[0]] = value;
150            } else {
151                if (typeof(a[sels2[0]]) == "undefined") a[sels2[0]] = [];
152                setVarArray(a[sels2[0]], sels2.slice(1), value);
153            }
154        }
155        const scope = this.scopes[this.scopes.length-1];
156        if (sels.length == 0) {
157            scope[name] = value;
158        } else {
159            if (typeof(scope[name]) == "undefined") scope[name] = [];
160            setVarArray(scope[name], sels, value);
161        }
162        return value;
163    }
164
165    getVar(name, sels) {
166        function select(a, sels2) {
167            return  (sels2.length == 0) ? a : select(a[sels2[0]], sels2.slice(1));
168        }
169        for (let i=this.scopes.length-1; i>=0; i--) {
170            if (typeof(this.scopes[i][name]) != "undefined") return select(this.scopes[i][name], sels);
171        }
172        throw new Error("Variable not defined: " + name);
173    }
174
175    getSignal(name, sels) {
176        let fullName = name=="one" ? "one" : this.currentComponent + "." + name;
177        fullName += this._sels2str(sels);
178        return this.getSignalFullName(fullName);
179    }
180
181
182    getPin(componentName, componentSels, signalName, signalSels) {
183        let fullName = componentName=="one" ? "one" : this.currentComponent + "." + componentName;
184        fullName += this._sels2str(componentSels) +
185                    "."+
186                    signalName+
187                    this._sels2str(signalSels);
188        return this.getSignalFullName(fullName);
189    }
190
191    getSignalFullName(fullName) {
192        const sId = this.circuit.signals[fullName].id;
193        if (typeof(this.witness[sId]) == "undefined") {
194            throw new Error("Signal not initialized: "+fullName);
195        }
196        console.log("get --->" + fullName + " = " + this.witness[sId].toString() );
197        return this.witness[sId];
198    }
199
200    assert(a,b) {
201        const ba = bigInt(a);
202        const bb = bigInt(b);
203        if (!ba.equals(bb)) {
204            throw new Error("Constrain doesn't match: " + ba.toString() + " != " + bb.toString());
205        }
206    }
207
208
209}