circom/c/main.cpp
c/main.cppRaw
1#include <iostream>
2#include <fstream>
3#include <sstream>
4#include <string>
5#include <iomanip>
6#include <sys/types.h>
7#include <sys/stat.h>
8#include <sys/mman.h>
9#include <fcntl.h>
10#include <gmp.h>
11#include <unistd.h>
12#include <nlohmann/json.hpp>
13using json = nlohmann::json;
14
15#include "calcwit.h"
16#include "circom.h"
17#include "utils.h"
18
19#define handle_error(msg) \
20 do { perror(msg); exit(EXIT_FAILURE); } while (0)
21
22void loadBin(Circom_CalcWit *ctx, std::string filename) {
23 int fd;
24 struct stat sb;
25
26 // map input
27 fd = open(filename.c_str(), O_RDONLY);
28 if (fd == -1)
29 handle_error("open");
30
31 if (fstat(fd, &sb) == -1) /* To obtain file size */
32 handle_error("fstat");
33
34
35 u8 *in;
36
37 in = (u8 *)mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
38 if (in == MAP_FAILED)
39 handle_error("mmap");
40
41 close(fd);
42
43 BigInt v;
44 mpz_init2(v, 256);
45 u8 *p = in;
46 for (int i=0; i<_circuit.NInputs; i++) {
47 int len = *(u8 *)p;
48 p++;
49 mpz_import(v,len , -1 , 1, 0, 0, p);
50 p+=len;
51 ctx->setSignal(0, 0, _circuit.wit2sig[1 + _circuit.NOutputs + i], &v);
52 }
53}
54
55
56typedef void (*ItFunc)(Circom_CalcWit *ctx, int idx, json val);
57
58void iterateArr(Circom_CalcWit *ctx, int o, Circom_Sizes sizes, json jarr, ItFunc f) {
59 if (!jarr.is_array()) {
60 assert((sizes[0] == 1)&&(sizes[1] == 0));
61 f(ctx, o, jarr);
62 } else {
63 int n = sizes[0] / sizes[1];
64 for (int i=0; i<n; i++) {
65 iterateArr(ctx, o + i*sizes[1], sizes+1, jarr[i], f);
66 }
67 }
68}
69
70void itFunc(Circom_CalcWit *ctx, int o, json val) {
71
72 BigInt v;
73 mpz_init2(v, 256);
74
75 std::string s;
76
77 if (val.is_string()) {
78 s = val.get<std::string>();
79 } else if (val.is_number()) {
80
81 double vd = val.get<double>();
82 std::stringstream stream;
83 stream << std::fixed << std::setprecision(0) << vd;
84 s = stream.str();
85 } else {
86 handle_error("Invalid JSON type");
87 }
88
89 mpz_set_str (v, s.c_str(), 10);
90
91 ctx->setSignal(0, 0, o, &v);
92}
93
94
95void loadJson(Circom_CalcWit *ctx, std::string filename) {
96 std::ifstream inStream(filename);
97 json j;
98 inStream >> j;
99
100 for (json::iterator it = j.begin(); it != j.end(); ++it) {
101// std::cout << it.key() << " => " << it.value() << '\n';
102 u64 h = fnv1a(it.key());
103 int o;
104 try {
105 o = ctx->getSignalOffset(0, h);
106 } catch (std::runtime_error e) {
107 std::ostringstream errStrStream;
108 errStrStream << "Error loadin variable: " << it.key() << "\n" << e.what();
109 throw std::runtime_error(errStrStream.str() );
110 }
111 Circom_Sizes sizes = ctx->getSignalSizes(0, h);
112 iterateArr(ctx, o, sizes, it.value(), itFunc);
113 }
114
115}
116
117
118void writeOutBin(Circom_CalcWit *ctx, std::string filename) {
119 FILE *write_ptr;
120
121 write_ptr = fopen(filename.c_str(),"wb");
122
123 BigInt v;
124 mpz_init2(v, 256);
125
126 u8 buffOut[256];
127 for (int i=0;i<_circuit.NVars;i++) {
128 size_t size=256;
129 ctx->getWitness(i, &v);
130 mpz_export(buffOut+1, &size, -1, 1, -1, 0, v);
131 *buffOut = (u8)size;
132 fwrite(buffOut, size+1, 1, write_ptr);
133 }
134 fclose(write_ptr);
135
136}
137
138
139void writeOutJson(Circom_CalcWit *ctx, std::string filename) {
140
141 std::ofstream outFile;
142 outFile.open (filename);
143
144 outFile << "[\n";
145
146 BigInt v;
147 mpz_init2(v, 256);
148
149 char pcV[256];
150
151 for (int i=0;i<_circuit.NVars;i++) {
152 ctx->getWitness(i, &v);
153 mpz_get_str(pcV, 10, v);
154 std::string sV = std::string(pcV);
155 outFile << (i ? "," : " ") << "\"" << sV << "\"\n";
156 }
157
158 outFile << "]\n";
159 outFile.close();
160}
161
162bool hasEnding (std::string const &fullString, std::string const &ending) {
163 if (fullString.length() >= ending.length()) {
164 return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending));
165 } else {
166 return false;
167 }
168}
169
170int main(int argc, char *argv[]) {
171 if (argc!=3) {
172 std::string cl = argv[0];
173 std::string base_filename = cl.substr(cl.find_last_of("/\\") + 1);
174 std::cout << "Usage: " << base_filename << " <input.<bin|json>> <output.<bin|json>>\n";
175 } else {
176
177 // open output
178 Circom_CalcWit *ctx = new Circom_CalcWit(&_circuit);
179
180 std::string infilename = argv[1];
181
182 if (hasEnding(infilename, std::string(".bin"))) {
183 loadBin(ctx, infilename);
184 } else if (hasEnding(infilename, std::string(".json"))) {
185 loadJson(ctx, infilename);
186 } else {
187 handle_error("Invalid input extension (.bin / .json)");
188 }
189
190 ctx->join();
191
192 std::string outfilename = argv[2];
193
194 if (hasEnding(outfilename, std::string(".bin"))) {
195 writeOutBin(ctx, outfilename);
196 } else if (hasEnding(outfilename, std::string(".json"))) {
197 writeOutJson(ctx, outfilename);
198 } else {
199 handle_error("Invalid output extension (.bin / .json)");
200 }
201
202 delete ctx;
203 exit(EXIT_SUCCESS);
204 }
205}