C generation

This commit is contained in:
Jordi Baylina
2019-11-23 19:12:58 +01:00
parent 51ff27b9c6
commit 66291a0efe
31 changed files with 3295 additions and 239 deletions

155
c/calcwit.cpp Normal file
View File

@@ -0,0 +1,155 @@
#include <string>
#include <stdexcept>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <stdlib.h>
#include <gmp.h>
#include "calcwit.h"
#include "utils.h"
Circom_CalcWit::Circom_CalcWit(Circom_Circuit *aCircuit) {
circuit = aCircuit;
#ifdef SANITY_CHECK
signalAssigned = new bool[circuit->NSignals];
signalAssigned[0] = true;
#endif
inputSignalsToTrigger = new int[circuit->NComponents];
signalValues = new BigInt[circuit->NSignals];
// Set one signal
mpz_init_set_ui(signalValues[0], 1);
// Initialize remaining signals
for (int i=1; i<circuit->NSignals; i++) mpz_init2(signalValues[i], 256);
reset();
}
void Circom_CalcWit::reset() {
#ifdef SANITY_CHECK
for (int i=1; i<circuit->NComponents; i++) signalAssigned[i] = false;
#endif
for (int i=0; i<circuit->NComponents; i++) {
inputSignalsToTrigger[i] = circuit->components[i].inputSignals;
if (inputSignalsToTrigger[i] == 0) triggerComponent(i);
}
}
Circom_CalcWit::~Circom_CalcWit() {
#ifdef SANITY_CHECK
delete signalAssigned;
#endif
for (int i=0; i<circuit->NSignals; i++) mpz_clear(signalValues[i]);
delete[] signalValues;
delete inputSignalsToTrigger;
}
int Circom_CalcWit::getSubComponentOffset(int cIdx, u64 hash) {
int hIdx;
for(hIdx = int(hash & 0xFF); hash!=circuit->components[cIdx].hashTable[hIdx].hash; hIdx++) {
if (!circuit->components[cIdx].hashTable[hIdx].hash) throw std::runtime_error("hash not found: " + int_to_hex(hash));
}
int entryPos = circuit->components[cIdx].hashTable[hIdx].pos;
if (circuit->components[cIdx].entries[entryPos].type != _typeComponent) {
throw std::runtime_error("invalid type");
}
return circuit->components[cIdx].entries[entryPos].offset;
}
Circom_Sizes Circom_CalcWit::getSubComponentSizes(int cIdx, u64 hash) {
int hIdx;
for(hIdx = int(hash & 0xFF); hash!=circuit->components[cIdx].hashTable[hIdx].hash; hIdx++) {
if (!circuit->components[cIdx].hashTable[hIdx].hash) throw std::runtime_error("hash not found: " + int_to_hex(hash));
}
int entryPos = circuit->components[cIdx].hashTable[hIdx].pos;
if (circuit->components[cIdx].entries[entryPos].type != _typeComponent) {
throw std::runtime_error("invalid type");
}
return circuit->components[cIdx].entries[entryPos].sizes;
}
int Circom_CalcWit::getSignalOffset(int cIdx, u64 hash) {
int hIdx;
for(hIdx = int(hash & 0xFF); hash!=circuit->components[cIdx].hashTable[hIdx].hash; hIdx++) {
if (!circuit->components[cIdx].hashTable[hIdx].hash) throw std::runtime_error("hash not found: " + int_to_hex(hash));
}
int entryPos = circuit->components[cIdx].hashTable[hIdx].pos;
if (circuit->components[cIdx].entries[entryPos].type != _typeSignal) {
throw std::runtime_error("invalid type");
}
return circuit->components[cIdx].entries[entryPos].offset;
}
Circom_Sizes Circom_CalcWit::getSignalSizes(int cIdx, u64 hash) {
int hIdx;
for(hIdx = int(hash & 0xFF); hash!=circuit->components[cIdx].hashTable[hIdx].hash; hIdx++) {
if (!circuit->components[cIdx].hashTable[hIdx].hash) throw std::runtime_error("hash not found: " + int_to_hex(hash));
}
int entryPos = circuit->components[cIdx].hashTable[hIdx].pos;
if (circuit->components[cIdx].entries[entryPos].type != _typeSignal) {
throw std::runtime_error("invalid type");
}
return circuit->components[cIdx].entries[entryPos].sizes;
}
PBigInt Circom_CalcWit::allocBigInts(Circom_Sizes sizes) {
PBigInt res = new BigInt[sizes[0]];
for (int i=0; i<sizes[0]; i++) mpz_init2(res[i], 256);
return res;
}
void Circom_CalcWit::freeBigInts(PBigInt bi, Circom_Sizes sizes) {
for (int i=0; i<sizes[0]; i++) mpz_clear(bi[i]);
delete[] bi;
}
void Circom_CalcWit::getSignal(int cIdx, int sIdx, PBigInt value) {
mpz_set(*value, signalValues[sIdx]);
}
void Circom_CalcWit::setSignal(int cIdx, int sIdx, PBigInt value) {
#ifdef SANITY_CHECK
assert(signalAssigned[sIdx] == false);
signalAssigned[sIdx] = true;
#endif
mpz_set(signalValues[sIdx], *value);
if ( BITMAP_ISSET(circuit->mapIsInput, sIdx) ) {
inputSignalsToTrigger[cIdx]--;
if (inputSignalsToTrigger[cIdx] == 0) triggerComponent(cIdx);
}
}
void Circom_CalcWit::checkConstraint(PBigInt value1, PBigInt value2, char const *err) {
#ifdef SANITY_CHECK
if (mpz_cmp(*value1, *value2) != 0) {
char *pcV1 = mpz_get_str(0, 10, *value1);
char *pcV2 = mpz_get_str(0, 10, *value1);
std::string sV1 = std::string(pcV1);
std::string sV2 = std::string(pcV2);
free(pcV1);
free(pcV2);
throw std::runtime_error(std::string("Constraint does not match,") + err + ". " + sV1 + " != " + sV2 );
}
#endif
}
void Circom_CalcWit::triggerComponent(int newCIdx) {
int oldCIdx = cIdx;
cIdx = newCIdx;
(*(circuit->components[newCIdx].fn))(this);
cIdx = oldCIdx;
}

61
c/calcwit.h Normal file
View File

@@ -0,0 +1,61 @@
#ifndef CIRCOM_CALCWIT_H
#define CIRCOM_CALCWIT_H
#include "circom.h"
class Circom_CalcWit {
#ifdef SANITY_CHECK
bool *signalAssigned;
#endif
// componentStatus -> For each component
// >0 Signals required to trigger
// == 0 Component triggered
int *inputSignalsToTrigger;
BigInt *signalValues;
Circom_Circuit *circuit;
void triggerComponent(int newCIdx);
void calculateWitness(void *input, void *output);
public:
int cIdx;
// Functions called by the circuit
Circom_CalcWit(Circom_Circuit *aCircuit);
~Circom_CalcWit();
int getSubComponentOffset(int cIdx, u64 hash);
Circom_Sizes getSubComponentSizes(int cIdx, u64 hash);
int getSignalOffset(int cIdx, u64 hash);
Circom_Sizes getSignalSizes(int cIdx, u64 hash);
PBigInt allocBigInts(Circom_Sizes sizes);
void freeBigInts(PBigInt bi, Circom_Sizes sizes);
void getSignal(int cIdx, int sIdx, PBigInt value);
void setSignal(int cIdx, int sIdx, PBigInt value);
void checkConstraint(PBigInt value1, PBigInt value2, char const *err);
// Public functions
inline void setInput(int idx, PBigInt val) {
setSignal(0, circuit->wit2sig[idx], val);
}
inline void getWitness(int idx, PBigInt val) {
mpz_set(*val, signalValues[circuit->wit2sig[idx]]);
}
void reset();
};
#endif // CIRCOM_CALCWIT_H

56
c/circom.h Normal file
View File

@@ -0,0 +1,56 @@
#ifndef __CIRCOM_H
#define __CIRCOM_H
#include <gmp.h>
#include <stdint.h>
class Circom_CalcWit;
typedef unsigned long long u64;
typedef uint32_t u32;
typedef uint8_t u8;
typedef mpz_t BigInt;
typedef BigInt *PBigInt;
typedef int Circom_Size;
typedef Circom_Size *Circom_Sizes;
struct Circom_HashEntry {
u64 hash;
int pos;
};
typedef Circom_HashEntry *Circom_HashTable;
typedef enum { _typeSignal, _typeComponent} Circom_EntryType;
struct Circom_ComponentEntry {
int offset;
Circom_Sizes sizes;
Circom_EntryType type;
};
typedef Circom_ComponentEntry *Circom_ComponentEntries;
typedef void (*Circom_ComponentFunction)(Circom_CalcWit *ctx);
struct Circom_Component {
Circom_HashTable hashTable;
Circom_ComponentEntries entries;
Circom_ComponentFunction fn;
int inputSignals;
};
class Circom_Circuit {
public:
int NSignals;
int NComponents;
int NInputs;
int NOutputs;
int NVars;
int *wit2sig;
Circom_Component *components;
u32 *mapIsInput;
};
#define BITMAP_ISSET(m, b) (m[b>>5] & (1 << (b&0x1F)))
extern struct Circom_Circuit _circuit;
#endif

196
c/main.cpp Normal file
View File

@@ -0,0 +1,196 @@
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <gmp.h>
#include <unistd.h>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
#include "calcwit.h"
#include "circom.h"
#include "utils.h"
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
void loadBin(Circom_CalcWit *ctx, std::string filename) {
int fd;
struct stat sb;
// map input
fd = open(filename.c_str(), O_RDONLY);
if (fd == -1)
handle_error("open");
if (fstat(fd, &sb) == -1) /* To obtain file size */
handle_error("fstat");
u8 *in;
in = (u8 *)mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
if (in == MAP_FAILED)
handle_error("mmap");
close(fd);
BigInt v;
mpz_init2(v, 256);
u8 *p = in;
for (int i=0; i<_circuit.NInputs; i++) {
int len = *(u8 *)p;
p++;
mpz_import(v,len , -1 , 1, 0, 0, p);
p+=len;
ctx->setSignal(0, _circuit.wit2sig[1 + _circuit.NOutputs + i], &v);
}
}
typedef void (*ItFunc)(Circom_CalcWit *ctx, int idx, json val);
void iterateArr(Circom_CalcWit *ctx, int o, Circom_Sizes sizes, json jarr, ItFunc f) {
if (!jarr.is_array()) {
assert((sizes[0] == 1)&&(sizes[1] == 0));
f(ctx, o, jarr);
} else {
int n = sizes[0] / sizes[1];
for (int i=0; i<n; i++) {
iterateArr(ctx, o + i*sizes[1], sizes+1, jarr[i], f);
}
}
}
void itFunc(Circom_CalcWit *ctx, int o, json val) {
BigInt v;
mpz_init2(v, 256);
std::string s;
if (val.is_string()) {
s = val.get<std::string>();
} else if (val.is_number()) {
double vd = val.get<double>();
std::stringstream stream;
stream << std::fixed << std::setprecision(0) << vd;
s = stream.str();
} else {
handle_error("Invalid JSON type");
}
mpz_set_str (v, s.c_str(), 10);
ctx->setSignal(0, o, &v);
}
void loadJson(Circom_CalcWit *ctx, std::string filename) {
std::ifstream inStream(filename);
json j;
inStream >> j;
for (json::iterator it = j.begin(); it != j.end(); ++it) {
// std::cout << it.key() << " => " << it.value() << '\n';
u64 h = fnv1a(it.key());
int o = ctx->getSignalOffset(0, h);
Circom_Sizes sizes = ctx->getSignalSizes(0, h);
iterateArr(ctx, o, sizes, it.value(), itFunc);
}
}
void writeOutBin(Circom_CalcWit *ctx, std::string filename) {
FILE *write_ptr;
write_ptr = fopen(filename.c_str(),"wb");
BigInt v;
mpz_init2(v, 256);
u8 buffOut[256];
for (int i=0;i<_circuit.NVars;i++) {
size_t size=256;
ctx->getWitness(i, &v);
mpz_export(buffOut+1, &size, -1, 1, -1, 0, v);
*buffOut = (u8)size;
fwrite(buffOut, size+1, 1, write_ptr);
}
fclose(write_ptr);
}
void writeOutJson(Circom_CalcWit *ctx, std::string filename) {
std::ofstream outFile;
outFile.open (filename);
outFile << "[\n";
BigInt v;
mpz_init2(v, 256);
char pcV[256];
for (int i=0;i<_circuit.NVars;i++) {
ctx->getWitness(i, &v);
mpz_get_str(pcV, 10, v);
std::string sV = std::string(pcV);
outFile << (i ? "," : " ") << "\"" << sV << "\"\n";
}
outFile << "]\n";
outFile.close();
}
bool hasEnding (std::string const &fullString, std::string const &ending) {
if (fullString.length() >= ending.length()) {
return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending));
} else {
return false;
}
}
int main(int argc, char *argv[]) {
if (argc!=3) {
std::string cl = argv[0];
std::string base_filename = cl.substr(cl.find_last_of("/\\") + 1);
std::cout << "Usage: " << base_filename << " <input.<bin|json>> <output.<bin|json>>\n";
} else {
// open output
Circom_CalcWit *ctx = new Circom_CalcWit(&_circuit);
std::string infilename = argv[1];
if (hasEnding(infilename, std::string(".bin"))) {
loadBin(ctx, infilename);
} else if (hasEnding(infilename, std::string(".json"))) {
loadJson(ctx, infilename);
} else {
handle_error("Invalid input extension (.bin / .json)");
}
std::string outfilename = argv[2];
if (hasEnding(outfilename, std::string(".bin"))) {
writeOutBin(ctx, outfilename);
} else if (hasEnding(outfilename, std::string(".json"))) {
writeOutJson(ctx, outfilename);
} else {
handle_error("Invalid output extension (.bin / .json)");
}
delete ctx;
exit(EXIT_SUCCESS);
}
}

BIN
c/mainjson Normal file

Binary file not shown.

47
c/mainjson.cpp Normal file
View File

@@ -0,0 +1,47 @@
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
#include "utils.h"
#include "circom.h"
#include "calcwit.h"
auto j = R"(
{
"in": "314"
}
)"_json;
typedef void (*ItFunc)(int idx, json val);
void iterateArr(int o, Circom_Sizes sizes, json jarr, ItFunc f) {
if (!jarr.is_array()) {
assert((sizes[0] == 1)&&(sizes[1] == 0));
f(o, jarr);
} else {
int n = sizes[0] / sizes[1];
for (int i=0; i<n; i++) {
iterateArr(o + i*sizes[1], sizes+1, jarr[i], f);
}
}
}
void itFunc(int o, json v) {
std::cout << o << " <-- " << v << '\n';
}
int main(int argc, char **argv) {
Circom_CalcWit *ctx = new Circom_CalcWit(&_circuit);
for (json::iterator it = j.begin(); it != j.end(); ++it) {
// std::cout << it.key() << " => " << it.value() << '\n';
u64 h = fnv1a(it.key());
int o = ctx->getSignalOffset(0, h);
Circom_Sizes sizes = ctx->getSignalSizes(0, h);
iterateArr(o, sizes, it.value(), itFunc);
}
}

25
c/utils.cpp Normal file
View File

@@ -0,0 +1,25 @@
#include <string>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <stdlib.h>
#include "utils.h"
std::string int_to_hex( u64 i )
{
std::stringstream stream;
stream << "0x"
<< std::setfill ('0') << std::setw(16)
<< std::hex << i;
return stream.str();
}
u64 fnv1a(std::string s) {
u64 hash = 0xCBF29CE484222325LL;
for(char& c : s) {
hash ^= u64(c);
hash *= 0x100000001B3LL;
}
return hash;
}

10
c/utils.h Normal file
View File

@@ -0,0 +1,10 @@
#ifndef __UTILS_H
#define __UTILS_H
#include "circom.h"
std::string int_to_hex( u64 i );
u64 fnv1a(std::string s);
#endif // __UTILS_H