arnaucube
arnaucube/circom_testerPublic Self-hosted repository
circom_tester/wasm/witness_calculator.js
wasm/witness_calculator.jsRaw
  1const utils = require("./utils");
  2
  3module.exports = async function builder(code, options) {
  4
  5    options = options || {};
  6
  7    const wasmModule = await WebAssembly.compile(code);
  8
  9    let wc;
 10
 11    
 12    const instance = await WebAssembly.instantiate(wasmModule, {
 13        runtime: {
 14            exceptionHandler : function(code) {
 15                let errStr;
 16                if (code == 1) {
 17                    errStr= "Signal not found. ";
 18                } else if (code == 2) {
 19                    errStr= "Too many signals set. ";
 20                } else if (code == 3) {
 21                    errStr= "Signal already set. ";
 22		} else if (code == 4) {
 23                    errStr= "Assert Failed. ";
 24		} else if (code == 5) {
 25                    errStr= "Not enough memory. ";
 26		} else {
 27		    errStr= "Unknown error\n";
 28                }
 29		// get error message from wasm
 30		errStr += getMessage();
 31                throw new Error(errStr);
 32            },
 33	    showSharedRWMemory: function() {
 34		printSharedRWMemory ();
 35            }
 36
 37        }
 38    });
 39
 40    const sanityCheck =
 41        options
 42//        options &&
 43//        (
 44//            options.sanityCheck ||
 45//            options.logGetSignal ||
 46//            options.logSetSignal ||
 47//            options.logStartComponent ||
 48//            options.logFinishComponent
 49//        );
 50
 51    
 52    wc = new WitnessCalculator(instance, sanityCheck);
 53    return wc;
 54
 55    function getMessage() {
 56        var message = "";
 57	var c = instance.exports.getMessageChar();
 58        while ( c != 0 ) {
 59	    message += String.fromCharCode(c);
 60	    c = instance.exports.getMessageChar();
 61	}
 62        return message;
 63    }
 64	
 65    function printSharedRWMemory () {
 66	const shared_rw_memory_size = instance.exports.getFieldNumLen32();
 67	const arr = new Uint32Array(shared_rw_memory_size);
 68	for (let j=0; j<shared_rw_memory_size; j++) {
 69	    arr[shared_rw_memory_size-1-j] = instance.exports.readSharedRWMemory(j);
 70	}
 71	console.log(utils.fromArray32(arr));
 72    }
 73
 74};
 75
 76class WitnessCalculator {
 77    constructor(instance, sanityCheck) {
 78        this.instance = instance;
 79
 80	this.version = this.instance.exports.getVersion();
 81        this.n32 = this.instance.exports.getFieldNumLen32();
 82
 83        this.instance.exports.getRawPrime();
 84        const arr = new Array(this.n32);
 85        for (let i=0; i<this.n32; i++) {
 86            arr[this.n32-1-i] = this.instance.exports.readSharedRWMemory(i);
 87        }
 88        this.prime = utils.fromArray32(arr);
 89
 90        this.witnessSize = this.instance.exports.getWitnessSize();
 91
 92        this.sanityCheck = sanityCheck;
 93    }
 94    
 95    circom_version() {
 96	return this.instance.exports.getVersion();
 97    }
 98
 99    async _doCalculateWitness(input, sanityCheck) {
100	//input is assumed to be a map from signals to arrays of bigints
101        this.instance.exports.init((this.sanityCheck || sanityCheck) ? 1 : 0);
102        const keys = Object.keys(input);
103        keys.forEach( (k) => {
104            const h = utils.fnvHash(k);
105            const hMSB = parseInt(h.slice(0,8), 16);
106            const hLSB = parseInt(h.slice(8,16), 16);
107            const fArr = utils.flatArray(input[k]);
108            for (let i=0; i<fArr.length; i++) {
109		const arrFr = utils.toArray32(fArr[i],this.n32)
110		for (let j=0; j<this.n32; j++) {
111		    this.instance.exports.writeSharedRWMemory(j,arrFr[this.n32-1-j]);
112		}
113		try {
114                    this.instance.exports.setInputSignal(hMSB, hLSB,i);
115		} catch (err) {
116		    // console.log(`After adding signal ${i} of ${k}`)
117                    throw new Error(err);
118		}
119            }
120
121        });
122    }
123
124    async calculateWitness(input, sanityCheck) {
125
126        const w = [];
127
128        await this._doCalculateWitness(input, sanityCheck);
129
130        for (let i=0; i<this.witnessSize; i++) {
131            this.instance.exports.getWitness(i);
132	    const arr = new Uint32Array(this.n32);
133            for (let j=0; j<this.n32; j++) {
134            arr[this.n32-1-j] = this.instance.exports.readSharedRWMemory(j);
135            }
136            w.push(utils.fromArray32(arr));
137        }
138
139        return w;
140    }
141    
142
143    async calculateBinWitness(input, sanityCheck) {
144
145        const buff32 = new Uint32Array(this.witnessSize*this.n32);
146	const buff = new  Uint8Array( buff32.buffer);
147        await this._doCalculateWitness(input, sanityCheck);
148
149        for (let i=0; i<this.witnessSize; i++) {
150            this.instance.exports.getWitness(i);
151	    const pos = i*this.n32;
152            for (let j=0; j<this.n32; j++) {
153		buff32[pos+j] = this.instance.exports.readSharedRWMemory(j);
154            }
155        }
156
157	return buff;
158    }
159    
160
161    async calculateWTNSBin(input, sanityCheck) {
162
163        const buff32 = new Uint32Array(this.witnessSize*this.n32+this.n32+11);
164	const buff = new  Uint8Array( buff32.buffer);
165        await this._doCalculateWitness(input, sanityCheck);
166  
167	//"wtns"
168	buff[0] = "w".charCodeAt(0)
169	buff[1] = "t".charCodeAt(0)
170	buff[2] = "n".charCodeAt(0)
171	buff[3] = "s".charCodeAt(0)
172
173	//version 2
174	buff32[1] = 2;
175
176	//number of sections: 2
177	buff32[2] = 2;
178
179	//id section 1
180	buff32[3] = 1;
181
182	const n8 = this.n32*4;
183	//id section 1 length in 64bytes
184	const idSection1length = 8 + n8;
185	const idSection1lengthHex = idSection1length.toString(16);
186        buff32[4] = parseInt(idSection1lengthHex.slice(0,8), 16);
187        buff32[5] = parseInt(idSection1lengthHex.slice(8,16), 16);
188
189	//this.n32
190	buff32[6] = n8;
191
192	//prime number
193	this.instance.exports.getRawPrime();
194
195	var pos = 7;
196        for (let j=0; j<this.n32; j++) {
197	    buff32[pos+j] = this.instance.exports.readSharedRWMemory(j);
198        }
199	pos += this.n32;
200
201	// witness size
202	buff32[pos] = this.witnessSize;
203	pos++;
204
205	//id section 2
206	buff32[pos] = 2;
207	pos++;
208
209	// section 2 length
210	const idSection2length = n8*this.witnessSize;
211	const idSection2lengthHex = idSection2length.toString(16);
212        buff32[pos] = parseInt(idSection2lengthHex.slice(0,8), 16);
213        buff32[pos+1] = parseInt(idSection2lengthHex.slice(8,16), 16);
214
215	pos += 2;
216        for (let i=0; i<this.witnessSize; i++) {
217            this.instance.exports.getWitness(i);
218            for (let j=0; j<this.n32; j++) {
219		buff32[pos+j] = this.instance.exports.readSharedRWMemory(j);
220            }
221	    pos += this.n32;
222        }
223
224	return buff;
225    }
226
227}
228
229
230