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//        Not needed
 84//        this.instance.exports.getRawPrime();
 85//        const arr = new Array(this.n32);
 86//        for (let i=0; i<this.n32; i++) {
 87//            arr[this.n32-1-i] = this.instance.exports.readSharedRWMemory(i);
 88//        }
 89//        this.prime = utils.fromArray32(arr);
 90
 91        this.witnessSize = this.instance.exports.getWitnessSize();
 92
 93        this.sanityCheck = sanityCheck;
 94    }
 95    
 96    async _doCalculateWitness(input, sanityCheck) {
 97	//input is assumed to be a map from signals to arrays of bigints
 98        this.instance.exports.init((this.sanityCheck || sanityCheck) ? 1 : 0);
 99        const keys = Object.keys(input);
100        keys.forEach( (k) => {
101            const h = utils.fnvHash(k);
102            const hMSB = parseInt(h.slice(0,8), 16);
103            const hLSB = parseInt(h.slice(8,16), 16);
104            const fArr = utils.flatArray(input[k]);
105            for (let i=0; i<fArr.length; i++) {
106		const arrFr = utils.toArray32(fArr[i],this.n32)
107		for (let j=0; j<this.n32; j++) {
108		    this.instance.exports.writeSharedRWMemory(j,arrFr[this.n32-1-j]);
109		}
110		try {
111                    this.instance.exports.setInputSignal(hMSB, hLSB,i);
112		} catch (err) {
113		    // console.log(`After adding signal ${i} of ${k}`)
114                    throw new Error(err);
115		}
116            }
117
118        });
119    }
120
121    async calculateWitness(input, sanityCheck) {
122
123        const w = [];
124
125        await this._doCalculateWitness(input, sanityCheck);
126
127        for (let i=0; i<this.witnessSize; i++) {
128            this.instance.exports.getWitness(i);
129	    const arr = new Uint32Array(this.n32);
130            for (let j=0; j<this.n32; j++) {
131            arr[this.n32-1-j] = this.instance.exports.readSharedRWMemory(j);
132            }
133            w.push(utils.fromArray32(arr));
134        }
135
136        return w;
137    }
138    
139
140    async calculateBinWitness(input, sanityCheck) {
141
142        const buff32 = new Uint32Array(this.witnessSize*this.n32);
143	const buff = new  Uint8Array( buff32.buffer);
144        await this._doCalculateWitness(input, sanityCheck);
145
146        for (let i=0; i<this.witnessSize; i++) {
147            this.instance.exports.getWitness(i);
148	    const pos = i*this.n32;
149            for (let j=0; j<this.n32; j++) {
150		buff32[pos+j] = this.instance.exports.readSharedRWMemory(j);
151            }
152        }
153
154	return buff;
155    }
156    
157
158    async calculateWTNSBin(input, sanityCheck) {
159
160        const buff32 = new Uint32Array(this.witnessSize*this.n32+this.n32+11);
161	const buff = new  Uint8Array( buff32.buffer);
162        await this._doCalculateWitness(input, sanityCheck);
163  
164	//"wtns"
165	buff[0] = "w".charCodeAt(0)
166	buff[1] = "t".charCodeAt(0)
167	buff[2] = "n".charCodeAt(0)
168	buff[3] = "s".charCodeAt(0)
169
170	//version 2
171	buff32[1] = 2;
172
173	//number of sections: 2
174	buff32[2] = 2;
175
176	//id section 1
177	buff32[3] = 1;
178
179	const n8 = this.n32*4;
180	//id section 1 length in 64bytes
181	const idSection1length = 8 + n8;
182	const idSection1lengthHex = idSection1length.toString(16);
183        buff32[4] = parseInt(idSection1lengthHex.slice(0,8), 16);
184        buff32[5] = parseInt(idSection1lengthHex.slice(8,16), 16);
185
186	//this.n32
187	buff32[6] = n8;
188
189	//prime number
190	this.instance.exports.getRawPrime();
191
192	var pos = 7;
193        for (let j=0; j<this.n32; j++) {
194	    buff32[pos+j] = this.instance.exports.readSharedRWMemory(j);
195        }
196	pos += this.n32;
197
198	// witness size
199	buff32[pos] = this.witnessSize;
200	pos++;
201
202	//id section 2
203	buff32[pos] = 2;
204	pos++;
205
206	// section 2 length
207	const idSection2length = n8*this.witnessSize;
208	const idSection2lengthHex = idSection2length.toString(16);
209        buff32[pos] = parseInt(idSection2lengthHex.slice(0,8), 16);
210        buff32[pos+1] = parseInt(idSection2lengthHex.slice(8,16), 16);
211
212	pos += 2;
213        for (let i=0; i<this.witnessSize; i++) {
214            this.instance.exports.getWitness(i);
215            for (let j=0; j<this.n32; j++) {
216		buff32[pos+j] = this.instance.exports.readSharedRWMemory(j);
217            }
218	    pos += this.n32;
219        }
220
221	return buff;
222    }
223
224}
225
226
227