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