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