circom/c/calcwit.cpp
c/calcwit.cppRaw
1#include <string>
2#include <stdexcept>
3#include <sstream>
4#include <iostream>
5#include <iomanip>
6#include <stdlib.h>
7#include <gmp.h>
8#include <assert.h>
9#include <thread>
10#include "calcwit.h"
11#include "utils.h"
12
13Circom_CalcWit::Circom_CalcWit(Circom_Circuit *aCircuit) {
14 circuit = aCircuit;
15
16#ifdef SANITY_CHECK
17 signalAssigned = new bool[circuit->NSignals];
18 signalAssigned[0] = true;
19#endif
20
21 mutexes = new std::mutex[NMUTEXES];
22 cvs = new std::condition_variable[NMUTEXES];
23 inputSignalsToTrigger = new int[circuit->NComponents];
24 signalValues = new BigInt[circuit->NSignals];
25
26 // Set one signal
27 mpz_init_set_ui(signalValues[0], 1);
28
29 // Initialize remaining signals
30 for (int i=1; i<circuit->NSignals; i++) mpz_init2(signalValues[i], 256);
31
32 BigInt p;
33 mpz_init_set_str(p, circuit->P, 10);
34 field = new ZqField(&p);
35 mpz_clear(p);
36
37 reset();
38}
39
40
41Circom_CalcWit::~Circom_CalcWit() {
42 delete field;
43
44#ifdef SANITY_CHECK
45 delete signalAssigned;
46#endif
47
48 delete[] cvs;
49 delete[] mutexes;
50
51 for (int i=0; i<circuit->NSignals; i++) mpz_clear(signalValues[i]);
52
53 delete[] signalValues;
54 delete[] inputSignalsToTrigger;
55
56}
57
58void Circom_CalcWit::syncPrintf(const char *format, ...) {
59 va_list args;
60 va_start(args, format);
61
62 printf_mutex.lock();
63 vprintf(format, args);
64 printf_mutex.unlock();
65
66 va_end(args);
67}
68
69void Circom_CalcWit::reset() {
70
71#ifdef SANITY_CHECK
72 for (int i=1; i<circuit->NComponents; i++) signalAssigned[i] = false;
73#endif
74
75 for (int i=0; i<circuit->NComponents; i++) {
76 inputSignalsToTrigger[i] = circuit->components[i].inputSignals;
77 if (inputSignalsToTrigger[i] == 0) triggerComponent(i);
78 }
79}
80
81
82int Circom_CalcWit::getSubComponentOffset(int cIdx, u64 hash) {
83 int hIdx;
84 for(hIdx = int(hash & 0xFF); hash!=circuit->components[cIdx].hashTable[hIdx].hash; hIdx++) {
85 if (!circuit->components[cIdx].hashTable[hIdx].hash) throw std::runtime_error("hash not found: " + int_to_hex(hash));
86 }
87 int entryPos = circuit->components[cIdx].hashTable[hIdx].pos;
88 if (circuit->components[cIdx].entries[entryPos].type != _typeComponent) {
89 throw std::runtime_error("invalid type");
90 }
91 return circuit->components[cIdx].entries[entryPos].offset;
92}
93
94
95Circom_Sizes Circom_CalcWit::getSubComponentSizes(int cIdx, u64 hash) {
96 int hIdx;
97 for(hIdx = int(hash & 0xFF); hash!=circuit->components[cIdx].hashTable[hIdx].hash; hIdx++) {
98 if (!circuit->components[cIdx].hashTable[hIdx].hash) throw std::runtime_error("hash not found: " + int_to_hex(hash));
99 }
100 int entryPos = circuit->components[cIdx].hashTable[hIdx].pos;
101 if (circuit->components[cIdx].entries[entryPos].type != _typeComponent) {
102 throw std::runtime_error("invalid type");
103 }
104 return circuit->components[cIdx].entries[entryPos].sizes;
105}
106
107int Circom_CalcWit::getSignalOffset(int cIdx, u64 hash) {
108 int hIdx;
109 for(hIdx = int(hash & 0xFF); hash!=circuit->components[cIdx].hashTable[hIdx].hash; hIdx++) {
110 if (!circuit->components[cIdx].hashTable[hIdx].hash) throw std::runtime_error("hash not found: " + int_to_hex(hash));
111 }
112 int entryPos = circuit->components[cIdx].hashTable[hIdx].pos;
113 if (circuit->components[cIdx].entries[entryPos].type != _typeSignal) {
114 throw std::runtime_error("invalid type");
115 }
116 return circuit->components[cIdx].entries[entryPos].offset;
117}
118
119Circom_Sizes Circom_CalcWit::getSignalSizes(int cIdx, u64 hash) {
120 int hIdx;
121 for(hIdx = int(hash & 0xFF); hash!=circuit->components[cIdx].hashTable[hIdx].hash; hIdx++) {
122 if (!circuit->components[cIdx].hashTable[hIdx].hash) throw std::runtime_error("hash not found: " + int_to_hex(hash));
123 }
124 int entryPos = circuit->components[cIdx].hashTable[hIdx].pos;
125 if (circuit->components[cIdx].entries[entryPos].type != _typeSignal) {
126 throw std::runtime_error("invalid type");
127 }
128 return circuit->components[cIdx].entries[entryPos].sizes;
129}
130
131PBigInt Circom_CalcWit::allocBigInts(int n) {
132 PBigInt res = new BigInt[n];
133 for (int i=0; i<n; i++) mpz_init2(res[i], 256);
134 return res;
135}
136
137void Circom_CalcWit::freeBigInts(PBigInt bi, int n) {
138 for (int i=0; i<n; i++) mpz_clear(bi[i]);
139 delete[] bi;
140}
141
142void Circom_CalcWit::getSignal(int currentComponentIdx, int cIdx, int sIdx, PBigInt value) {
143 // syncPrintf("getSignal: %d\n", sIdx);
144 if (currentComponentIdx != cIdx) {
145 std::unique_lock<std::mutex> lk(mutexes[cIdx % NMUTEXES]);
146 while (inputSignalsToTrigger[cIdx] != -1) {
147 cvs[cIdx % NMUTEXES].wait(lk);
148 }
149 // cvs[cIdx % NMUTEXES].wait(lk, [&]{return inputSignalsToTrigger[cIdx] == -1;});
150 lk.unlock();
151 }
152#ifdef SANITY_CHECK
153 if (signalAssigned[sIdx] == false) {
154 fprintf(stderr, "Accessing a not assigned signal: %d\n", sIdx);
155 assert(false);
156 }
157#endif
158 mpz_set(*value, signalValues[sIdx]);
159 /*
160 char *valueStr = mpz_get_str(0, 10, *value);
161 syncPrintf("%d, Get %d --> %s\n", currentComponentIdx, sIdx, valueStr);
162 free(valueStr);
163 */
164}
165
166void Circom_CalcWit::finished(int cIdx) {
167 {
168 std::lock_guard<std::mutex> lk(mutexes[cIdx % NMUTEXES]);
169 inputSignalsToTrigger[cIdx] = -1;
170 }
171 // syncPrintf("Finished: %d\n", cIdx);
172 cvs[cIdx % NMUTEXES].notify_all();
173}
174
175void Circom_CalcWit::setSignal(int currentComponentIdx, int cIdx, int sIdx, PBigInt value) {
176 // syncPrintf("setSignal: %d\n", sIdx);
177
178#ifdef SANITY_CHECK
179 if (signalAssigned[sIdx] == true) {
180 fprintf(stderr, "Signal assigned twice: %d\n", sIdx);
181 assert(false);
182 }
183 signalAssigned[sIdx] = true;
184#endif
185 // Log assignement
186 /*
187 char *valueStr = mpz_get_str(0, 10, *value);
188 syncPrintf("%d, Set %d --> %s\n", currentComponentIdx, sIdx, valueStr);
189 free(valueStr);
190 */
191 mpz_set(signalValues[sIdx], *value);
192 if ( BITMAP_ISSET(circuit->mapIsInput, sIdx) ) {
193 if (inputSignalsToTrigger[cIdx]>0) {
194 inputSignalsToTrigger[cIdx]--;
195 if (inputSignalsToTrigger[cIdx] == 0) triggerComponent(cIdx);
196 }
197 }
198
199}
200
201void Circom_CalcWit::checkConstraint(int currentComponentIdx, PBigInt value1, PBigInt value2, char const *err) {
202#ifdef SANITY_CHECK
203 if (mpz_cmp(*value1, *value2) != 0) {
204 char *pcV1 = mpz_get_str(0, 10, *value1);
205 char *pcV2 = mpz_get_str(0, 10, *value2);
206 // throw std::runtime_error(std::to_string(currentComponentIdx) + std::string(", Constraint doesn't match, ") + err + ". " + sV1 + " != " + sV2 );
207 fprintf(stderr, "Constraint doesn't match, %s: %s != %s", err, pcV1, pcV2);
208 free(pcV1);
209 free(pcV2);
210 assert(false);
211 }
212#endif
213}
214
215
216void Circom_CalcWit::triggerComponent(int newCIdx) {
217 //int oldCIdx = cIdx;
218 // cIdx = newCIdx;
219 if (circuit->components[newCIdx].newThread) {
220 // syncPrintf("Triggered: %d\n", newCIdx);
221 std::thread t(circuit->components[newCIdx].fn, this, newCIdx);
222 // t.join();
223 t.detach();
224 } else {
225 (*(circuit->components[newCIdx].fn))(this, newCIdx);
226 }
227 // cIdx = oldCIdx;
228}
229
230void Circom_CalcWit::log(PBigInt value) {
231 char *pcV = mpz_get_str(0, 10, *value);
232 syncPrintf("Log: %s\n", pcV);
233 free(pcV);
234}
235
236void Circom_CalcWit::join() {
237 for (int i=0; i<circuit->NComponents; i++) {
238 std::unique_lock<std::mutex> lk(mutexes[i % NMUTEXES]);
239 while (inputSignalsToTrigger[i] != -1) {
240 cvs[i % NMUTEXES].wait(lk);
241 }
242 // cvs[i % NMUTEXES].wait(lk, [&]{return inputSignalsToTrigger[i] == -1;});
243 lk.unlock();
244 // syncPrintf("Joined: %d\n", i);
245 }
246
247}
248
249