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