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