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 <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