#include #include #include #include #include #include #include #include #include #include #include using json = nlohmann::json; #include "calcwit.hpp" #include "circom.hpp" #define handle_error(msg) \ do { perror(msg); exit(EXIT_FAILURE); } while (0) Circom_Circuit* loadCircuit(std::string const &datFileName) { Circom_Circuit *circuit = new Circom_Circuit; int fd; struct stat sb; fd = open(datFileName.c_str(), O_RDONLY); if (fd == -1) { std::cout << ".dat file not found: " << datFileName << "\n"; throw std::system_error(errno, std::generic_category(), "open"); } if (fstat(fd, &sb) == -1) { /* To obtain file size */ throw std::system_error(errno, std::generic_category(), "fstat"); } u8* bdata = (u8*)mmap(NULL, sb.st_size, PROT_READ , MAP_PRIVATE, fd, 0); close(fd); circuit->InputHashMap = new HashSignalInfo[get_size_of_input_hashmap()]; uint dsize = get_size_of_input_hashmap()*sizeof(HashSignalInfo); memcpy((void *)(circuit->InputHashMap), (void *)bdata, dsize); circuit->witness2SignalList = new u64[get_size_of_witness()]; uint inisize = dsize; dsize = get_size_of_witness()*sizeof(u64); memcpy((void *)(circuit->witness2SignalList), (void *)(bdata+inisize), dsize); circuit->circuitConstants = new FrElement[get_size_of_constants()]; if (get_size_of_constants()>0) { inisize += dsize; dsize = get_size_of_constants()*sizeof(FrElement); memcpy((void *)(circuit->circuitConstants), (void *)(bdata+inisize), dsize); } std::map templateInsId2IOSignalInfo1; if (get_size_of_io_map()>0) { u32 index[get_size_of_io_map()]; inisize += dsize; dsize = get_size_of_io_map()*sizeof(u32); memcpy((void *)index, (void *)(bdata+inisize), dsize); inisize += dsize; assert(inisize % sizeof(u32) == 0); assert(sb.st_size % sizeof(u32) == 0); u32 dataiomap[(sb.st_size-inisize)/sizeof(u32)]; memcpy((void *)dataiomap, (void *)(bdata+inisize), sb.st_size-inisize); u32* pu32 = dataiomap; for (int i = 0; i < get_size_of_io_map(); i++) { u32 n = *pu32; IODefPair p; p.len = n; IODef defs[n]; pu32 += 1; for (u32 j = 0; j templateInsId2IOSignalInfo = move(templateInsId2IOSignalInfo1); munmap(bdata, sb.st_size); return circuit; } bool check_valid_number(std::string & s, uint base){ bool is_valid = true; if (base == 16){ for (uint i = 0; i < s.size(); i++){ is_valid &= ( ('0' <= s[i] && s[i] <= '9') || ('a' <= s[i] && s[i] <= 'f') || ('A' <= s[i] && s[i] <= 'F') ); } } else{ for (uint i = 0; i < s.size(); i++){ is_valid &= ('0' <= s[i] && s[i] < char(int('0') + base)); } } return is_valid; } void json2FrElements (json val, std::vector & vval){ if (!val.is_array()) { FrElement v; std::string s_aux, s; uint base; if (val.is_string()) { s_aux = val.get(); std::string possible_prefix = s_aux.substr(0, 2); if (possible_prefix == "0b" || possible_prefix == "0B"){ s = s_aux.substr(2, s_aux.size() - 2); base = 2; } else if (possible_prefix == "0o" || possible_prefix == "0O"){ s = s_aux.substr(2, s_aux.size() - 2); base = 8; } else if (possible_prefix == "0x" || possible_prefix == "0X"){ s = s_aux.substr(2, s_aux.size() - 2); base = 16; } else{ s = s_aux; base = 10; } if (!check_valid_number(s, base)){ std::ostringstream errStrStream; errStrStream << "Invalid number in JSON input: " << s_aux << "\n"; throw std::runtime_error(errStrStream.str() ); } } else if (val.is_number()) { double vd = val.get(); std::stringstream stream; stream << std::fixed << std::setprecision(0) << vd; s = stream.str(); base = 10; } else { std::ostringstream errStrStream; errStrStream << "Invalid JSON type\n"; throw std::runtime_error(errStrStream.str() ); } Fr_str2element (&v, s.c_str(), base); vval.push_back(v); } else { for (uint i = 0; i < val.size(); i++) { json2FrElements (val[i], vval); } } } void loadJson(Circom_CalcWit *ctx, std::string filename) { std::ifstream inStream(filename); json j; inStream >> j; u64 nItems = j.size(); // printf("Items : %llu\n",nItems); if (nItems == 0){ ctx->tryRunCircuit(); } for (json::iterator it = j.begin(); it != j.end(); ++it) { // std::cout << it.key() << " => " << it.value() << '\n'; u64 h = fnv1a(it.key()); std::vector v; json2FrElements(it.value(),v); uint signalSize = ctx->getInputSignalSize(h); if (v.size() < signalSize) { std::ostringstream errStrStream; errStrStream << "Error loading signal " << it.key() << ": Not enough values\n"; throw std::runtime_error(errStrStream.str() ); } if (v.size() > signalSize) { std::ostringstream errStrStream; errStrStream << "Error loading signal " << it.key() << ": Too many values\n"; throw std::runtime_error(errStrStream.str() ); } for (uint i = 0; i " << Fr_element2str(&(v[i])) << '\n'; ctx->setInputSignal(h,i,v[i]); } catch (std::runtime_error e) { std::ostringstream errStrStream; errStrStream << "Error setting signal: " << it.key() << "\n" << e.what(); throw std::runtime_error(errStrStream.str() ); } } } } void writeBinWitness(Circom_CalcWit *ctx, std::string wtnsFileName) { FILE *write_ptr; write_ptr = fopen(wtnsFileName.c_str(),"wb"); fwrite("wtns", 4, 1, write_ptr); u32 version = 2; fwrite(&version, 4, 1, write_ptr); u32 nSections = 2; fwrite(&nSections, 4, 1, write_ptr); // Header u32 idSection1 = 1; fwrite(&idSection1, 4, 1, write_ptr); u32 n8 = Fr_N64*8; u64 idSection1length = 8 + n8; fwrite(&idSection1length, 8, 1, write_ptr); fwrite(&n8, 4, 1, write_ptr); fwrite(Fr_q.longVal, Fr_N64*8, 1, write_ptr); uint Nwtns = get_size_of_witness(); u32 nVars = (u32)Nwtns; fwrite(&nVars, 4, 1, write_ptr); // Data u32 idSection2 = 2; fwrite(&idSection2, 4, 1, write_ptr); u64 idSection2length = (u64)n8*(u64)Nwtns; fwrite(&idSection2length, 8, 1, write_ptr); FrElement v; for (int i=0;igetWitness(i, &v); Fr_toLongNormal(&v, &v); fwrite(v.longVal, Fr_N64*8, 1, write_ptr); } fclose(write_ptr); } int main (int argc, char *argv[]) { std::string cl(argv[0]); if (argc!=3) { std::cout << "Usage: " << cl << " \n"; } else { std::string datfile = cl + ".dat"; std::string jsonfile(argv[1]); std::string wtnsfile(argv[2]); // auto t_start = std::chrono::high_resolution_clock::now(); Circom_Circuit *circuit = loadCircuit(datfile); Circom_CalcWit *ctx = new Circom_CalcWit(circuit); loadJson(ctx, jsonfile); if (ctx->getRemaingInputsToBeSet()!=0) { std::cerr << "Not all inputs have been set. Only " << get_main_input_signal_no()-ctx->getRemaingInputsToBeSet() << " out of " << get_main_input_signal_no() << std::endl; assert(false); } /* for (uint i = 0; igetWitness(i, &x); std::cout << i << ": " << Fr_element2str(&x) << std::endl; } */ //auto t_mid = std::chrono::high_resolution_clock::now(); //std::cout << std::chrono::duration(t_mid-t_start).count()<(t_end-t_mid).count()<