arnaucube
arnaucube/circomPublic Self-hosted repository
circom/ports/wasm/witness_calculator.js
ports/wasm/witness_calculator.jsRaw
  1/* globals WebAssembly */
  2
  3const fs = require("fs");
  4const utils = require("../../src/utils");
  5const bigInt = require("big-integer");
  6
  7module.exports.fromFile = async function(file) {
  8
  9
 10    const code = await fs.promises.readFile(file);
 11
 12    return await module.exports.fromBuffer(code);
 13};
 14
 15module.exports.fromBuffer = async function(code) {
 16
 17    const memory = new WebAssembly.Memory({initial:20000});
 18    const wasmModule = await WebAssembly.compile(code);
 19
 20    const instance = await WebAssembly.instantiate(wasmModule, {
 21        env: {
 22            "memory": memory
 23        },
 24        runtime: {
 25            err: function(code, pstr) {
 26                console.log("ERROR", code, p2str(pstr));
 27            },
 28            err1: function(code, pstr, a) {
 29                console.log("ERROR: ", code, p2str(pstr), a);
 30            },
 31            err2: function(code, pstr, a, b) {
 32                console.log("ERROR: ", code, p2str(pstr), a, b);
 33            },
 34            err3: function(code, pstr, a, b, c) {
 35                console.log("ERROR: ", code, p2str(pstr), a, b, c);
 36            },
 37            err4: function(code, pstr, a,b,c,d) {
 38                console.log("ERROR: ", code, p2str(pstr), a, b, c, d);
 39            },
 40        }
 41    });
 42
 43    return new WitnessCalculator(memory, instance);
 44
 45    function p2str(p) {
 46        return "TODO"+p;
 47    }
 48};
 49
 50class WitnessCalculator {
 51    constructor(memory, instance) {
 52        this.memory = memory;
 53        this.i32 = new Uint32Array(memory.buffer);
 54        this.instance = instance;
 55
 56        this.n32 = (this.instance.exports.getFrLen() >> 2) - 2;
 57        const pRawPrime = this.instance.exports.getPRawPrime();
 58
 59        this.prime = bigInt(0);
 60        for (let i=this.n32-1; i>=0; i--) {
 61            this.prime = this.prime.shiftLeft(32);
 62            this.prime = this.prime.add(bigInt(this.i32[(pRawPrime >> 2) + i]));
 63        }
 64
 65        this.mask32 = bigInt("FFFFFFFF", 16);
 66        this.NVars = this.instance.exports.getNVars();
 67        this.n64 = Math.floor((this.prime.bitLength() - 1) / 64)+1;
 68        this.R = bigInt.one.shiftLeft(this.n64*64);
 69        this.RInv = this.R.modInv(this.prime);
 70
 71    }
 72
 73    async calculateWitness(input) {
 74        const w = [];
 75        const old0 = this.i32[0];
 76        this.instance.exports.init();
 77        const pSigOffset = this.allocInt();
 78        const pFr = this.allocFr();
 79        for (let k in input) {
 80            const h = utils.fnvHash(k);
 81            const hMSB = parseInt(h.slice(0,8), 16);
 82            const hLSB = parseInt(h.slice(8,16), 16);
 83            this.instance.exports.getSignalOffset32(pSigOffset, 0, hMSB, hLSB);
 84            const sigOffset = this.getInt(pSigOffset);
 85            const fArr = utils.flatArray(input[k]);
 86            for (let i=0; i<fArr.length; i++) {
 87                this.setFr(pFr, fArr[i]);
 88                this.instance.exports.setSignal(0, 0, sigOffset + i, pFr);
 89            }
 90        }
 91
 92
 93        for (let i=0; i<this.NVars; i++) {
 94            const pWitness = this.instance.exports.getPWitness(i);
 95            w.push(this.getFr(pWitness));
 96        }
 97
 98        this.i32[0] = old0;
 99        return w;
100    }
101
102    allocInt() {
103        const p = this.i32[0];
104        this.i32[0] = p+8;
105        return p;
106    }
107
108    allocFr() {
109        const p = this.i32[0];
110        this.i32[0] = p+this.n32*4 + 8;
111        return p;
112    }
113
114    getInt(p) {
115        return this.i32[p>>2];
116    }
117
118    setInt(p, v) {
119        this.i32[p>>2] = v;
120    }
121
122    getFr(p) {
123        const idx = (p>>2);
124
125        if (this.i32[idx + 1] & 0x80000000) {
126            let res= bigInt(0);
127            for (let i=this.n32-1; i>=0; i--) {
128                res = res.shiftLeft(32);
129                res = res.add(bigInt(this.i32[idx+2+i]));
130            }
131            if (this.i32[idx + 1] & 0x40000000) {
132                return fromMontgomery(res);
133            } else {
134                return res;
135            }
136
137        } else {
138            if (this.i32[idx] & 0x80000000) {
139                return this.prime.add( bigInt(this.i32[idx]).minus(bigInt(0x100000000)) );
140            } else {
141                return bigInt(this.i32[idx]);
142            }
143        }
144
145        function fromMontgomery(n) {
146            return n.times(this.RInv).mod(this.prime);
147        }
148
149    }
150
151
152    setFr(p, v) {
153        const self = this;
154        v = bigInt(v);
155
156        if (v.lt(bigInt("80000000", 16)) ) {
157            return setShortPositive(v);
158        }
159        if (v.geq(self.prime.minus(bigInt("80000000", 16))) ) {
160            return setShortNegative(v);
161        }
162        return setLongNormal(v);
163
164        function setShortPositive(a) {
165            self.i32[(p >> 2)] = parseInt(a);
166            self.i32[(p >> 2) + 1] = 0;
167        }
168
169        function setShortNegative(a) {
170            const b = bigInt("80000000", 16 ).add(a.minus(  self.prime.minus(bigInt("80000000", 16 ))));
171            self.i32[(p >> 2)] = parseInt(b);
172            self.i32[(p >> 2) + 1] = 0;
173        }
174
175        function setLongNormal(a) {
176            self.i32[(p >> 2)] = 0;
177            self.i32[(p >> 2) + 1] = 0x80000000;
178            for (let i=0; i<self.n32; i++) {
179                self.i32[(p >> 2) + 2 + i] = a.shiftRight(i*32).and(self.mask32);
180            }
181        }
182    }
183}
184
185
186