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