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