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