arnaucube
arnaucube/circomPublic Self-hosted repository
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