├── .gitignore ├── depends └── CMakeLists.txt ├── zksnark_element ├── r1cs.json ├── proof.json └── vk.json ├── .gitmodules ├── src ├── CMakeLists.txt ├── ZoKrates │ ├── wraplibsnark.hpp │ └── wraplibsnark.cpp └── main.cpp ├── README.md ├── LICENSE └── CMakeLists.txt /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | build -------------------------------------------------------------------------------- /depends/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(libsnark) -------------------------------------------------------------------------------- /zksnark_element/r1cs.json: -------------------------------------------------------------------------------- 1 | 2 | {"variables":["ONE", "res", "A_0", "A_1", "A_2", "B_0", "B_1", "B_2"], 3 | "constraints":[[{"2":1},{"5":1},{"0":0,"8":1}], 4 | [{"3":1},{"6":1},{"8":-1,"9":1}], 5 | [{"4":1},{"7":1},{"9":-1,"1":1}] 6 | ]} -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "depends/libsnark"] 2 | path = depends/libsnark 3 | url = https://github.com/scipr-lab/libsnark.git 4 | [submodule "snarkWrapper"] 5 | path = snarkWrapper 6 | url = https://github.com/barryWhiteHat/snarkWrapper 7 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories(.) 2 | 3 | add_executable( 4 | main 5 | 6 | main.cpp 7 | ) 8 | target_link_libraries( 9 | main 10 | 11 | snark 12 | ) 13 | target_include_directories( 14 | main 15 | 16 | PUBLIC 17 | ${DEPENDS_DIR}/libsnark 18 | ${DEPENDS_DIR}/libsnark/depends/libfqfft 19 | ) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # libsnark-ethereum-tutorial 2 | Ethereum Wrapper libsnark zksnarks 3 | 4 | ## build instructions: 5 | See https://github.com/howardwu/libsnark-tutorial#build-guide for build instructions 6 | 7 | After building libsnark `cd snarkWrapper` and `npm install` 8 | 9 | ## Deploy contract: 10 | To deploy contract `cd ./snarkWrapper` and run `node deploy.js` 11 | 12 | ## To rebuild zksnark\_element: 13 | `cd ./zksnark_element` and run `../build/src/main` this will create `vk.json` and `proof.json` 14 | which are used by the sample contract. 15 | -------------------------------------------------------------------------------- /src/ZoKrates/wraplibsnark.hpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file wraplibsnark.hpp 3 | * @author Jacob Eberhardt 5 | * @date 2017 6 | */ 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | #include 13 | #include 14 | 15 | bool _setup(const uint8_t* A, 16 | const uint8_t* B, 17 | const uint8_t* C, 18 | int constraints, 19 | int variables, 20 | int inputs, 21 | const char* pk_path, 22 | const char* vk_path 23 | ); 24 | 25 | bool _generate_proof(const char* pk_path, 26 | const uint8_t* public_inputs, 27 | int public_inputs_length, 28 | const uint8_t* private_inputs, 29 | int private_inputs_length 30 | ); 31 | 32 | #ifdef __cplusplus 33 | } // extern "C" 34 | #endif 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Howard Wu. 2 | 3 | All files, with the exceptions below, are released under the MIT License: 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /zksnark_element/proof.json: -------------------------------------------------------------------------------- 1 | { 2 | "a" :["0x1658d91966889cbe2317e556b3d6877accc8618380fc4a836e124826dfee7134", "0x238d2170e3aa7bb0d24e3b369d66eb187849532f03da1acec324e502217f003c"], 3 | "a_p" :["0x6f512885080b0d141cd8947b91b9c9004c3046056523596bc9515af616d742d", "0x1754c4b483076c313b4f33ebac2a7c5d983b613b81c996a235ce814da4dddf18"], 4 | "b" :[["0xe87cefc960536d2d16202f3ab2d954fda96c389a882286201067ba1b1e1635a", "0x278ff31a55535bad0b31845c090f618ee21ac7b13dd62d81458916154b5fdfb2"], 5 | ["0x2cb2abb1ecb897fad9600486f7721e5f832b530d0384ddef279fd11e7a6fb829", "0x20427d470926e28b91cf6a3260098d498f3c40867b0b3527021a96213e4f372c"]], 6 | "b_p" :["0x244f91c73526295c3f6f4592e68848bf2d0aa0a76e143954a040ad66495326d9", "0x16dfeb6954e686c3b12dd7e60bb6132abe590cf91a33f715ba12023c263dfa69"], 7 | "c" :["0x1e4665bde13328a77bf280aee3ae192f0e7a4af34c110d97a9a92ef160504fbe", "0x13b37e3b143542249a0880fb9f1dcf77797340b939850cd8794ac8769b393a4a"], 8 | "c_p" :["0x2bfa52556f76ef1adfab77344adfbf4f916f04e46b0694432d084171be1c15f0", "0xd32ed32cc48090a64b2618c99272ed0726ef7e70131919b93abce3fb9b5cfd2"], 9 | "h" :["0x1f14f12f46a44f14e50f4ca05f131d379c3396135f3095829641bbfeb528c42d", "0x175a66f267684b5cd111f7c431b404a40432a2d398e99af99947d158289b42c9"], 10 | "k" :["0x23a46de191fc4ed6cb51841241ac02fbcb058d80fa71f46a731a443bdcb95b32", "0x1c0ca2760d841963056cbea1d7cdcefc363799692d72cdf1ca9f47bf713f0b2d"], 11 | "input" :[]} -------------------------------------------------------------------------------- /zksnark_element/vk.json: -------------------------------------------------------------------------------- 1 | { 2 | "a" :[["0x242e43bc45e05276c720a96b4d738d339883354aa3c3a5dbc3de3e6250ae8333", "0x65c54f4d311a12c76de28ccd4508662bed836fac6b47b0bf8c7d3f34c48c63f"], 3 | ["0x299367c994dcc751a5a9dbba0ce36ab796dc8f7a2f04f90ac26e1b2e0d5fb020", "0xdf1e1234efe8eb562f395b2b281d6ffa5f62d5ea5e4250948e48f837c565bb4"]], 4 | "b" :["0x2bc33bd98ce60a609a60bf7cd71dcd43f3e81a37638437993a015a009d7a17bc", "0x108b85dd66cb4241fac48bc56b77ecc54e3ebb3b5aeb1bcd29c57e7f9799286e"], 5 | "c" :[["0x1d237500bcc33b3b0b4a4d8bcc1b8ce060ec806a06d4b650ef223b0673b03db2", "0x221569ad8eebf16c2b5236bae8eee2ee80abf7b91b48e3afedd271010d011e4e"], 6 | ["0x29d17e7a11589aae7b7348f333a85a0f3e103e8a3444f346b4ba4f10622bf8f", "0x769087cefd134097804eead7e76f55e06307ca0cec82518ca0e3f7feb4281eb"]], 7 | "g" :[["0x14df17af6839edad49b75f0bfe405031a40aed971958d729a1a982fd332cde25", "0x2943024d09c5f31e7a18f65a50b8679535ad17ab03652eeccf1b3d0ac7a9c113"], 8 | ["0x10d036b9d34086d2e33cf83d861994faabe62d6da639ccee0dde08f6f40da4cd", "0x258e0210a4a06ec9063963cd38f970545a2eccdae950c5177cdde87597a09c9e"]], 9 | "gb1" :["0x18b567fd183a6ddf497eebb42f674aeab677b501c9e57861ebd2042c42dbcd57", "0x19a08bb502dba837f6f90de171aec5a60f8be1d03aa5dd1ed0e629aa67935447"], 10 | "gb2" :[["0x16f58751fe4004d4901c23bf21e21e3de1ef9c8847c647d73de0f0ca5fc014af", "0x2ae7a257d5111b0298c3519a1bcc8ed9a79d913c16aa496c24b4d894d2d728a1"], 11 | ["0xaec6c1b33e1f13ebfb5fc1c758f9629dc8036c5cc50bf365cb9c3acb43249d9", "0xba45c5584f51514039842b50a2611c49efad09ef4214676ed39a293ca60338e"]], 12 | "z" :[["0x15167588aeec3980edf88724fd583813a06337b5bfb84b99ea5fdfd47bf7a356", "0x9f1ba1d1cec0e6242926ae44ea9d9cd62687d62566f8a820dcb398d5641f983"], 13 | ["0xa08f2167b8871ea31a7365bd4d1e9f6ed8a55b03a449ba77b92c41ebfaf2a8c", "0xa30bdc139c43ea198efd3947209a47ca3214777fb0dab47b9f18c85bee52ba8"]], 14 | "IC" :["0x27ea6401daef0cc382a4548ae301204a8d6a49af84aa1f67b8390c1b45c5d546", "0x174e0b0bd2d8028f12487455d488a76c7e1d8e237f3bef7718131a804ad6711b","0x81eff5b1af87f37f20b2a101776d978c3acc0cdf66279cd80f0b79bbbfd926e", "0xe9a67fd9ac9dc04d9135c243bf92871958f51ecf8921c7a7287898e0d10b026"]} -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | project(libsnark-tutorial) 4 | 5 | set( 6 | CURVE 7 | "ALT_BN128" 8 | CACHE 9 | STRING 10 | "Default curve: one of ALT_BN128, BN128, EDWARDS, MNT4, MNT6" 11 | ) 12 | 13 | set( 14 | DEPENDS_DIR 15 | "${CMAKE_CURRENT_SOURCE_DIR}/depends" 16 | CACHE 17 | STRING 18 | "Optionally specify the dependency installation directory relative to the source directory (default: inside dependency folder)" 19 | ) 20 | 21 | set( 22 | OPT_FLAGS 23 | "" 24 | CACHE 25 | STRING 26 | "Override C++ compiler optimization flags" 27 | ) 28 | 29 | option( 30 | MULTICORE 31 | "Enable parallelized execution, using OpenMP" 32 | OFF 33 | ) 34 | 35 | option( 36 | WITH_PROCPS 37 | "Use procps for memory profiling" 38 | ON 39 | ) 40 | 41 | option( 42 | VERBOSE 43 | "Print internal messages" 44 | ON 45 | ) 46 | 47 | option( 48 | DEBUG 49 | "Enable debugging mode" 50 | OFF 51 | ) 52 | 53 | option( 54 | CPPDEBUG 55 | "Enable debugging of C++ STL (does not imply DEBUG)" 56 | ON 57 | ) 58 | 59 | if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") 60 | # Common compilation flags and warning configuration 61 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wextra -Wfatal-errors -pthread") 62 | 63 | if("${MULTICORE}") 64 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp") 65 | endif() 66 | 67 | # Default optimizations flags (to override, use -DOPT_FLAGS=...) 68 | if("${OPT_FLAGS}" STREQUAL "") 69 | set(OPT_FLAGS "-ggdb3 -O2 -march=native -mtune=native") 70 | endif() 71 | endif() 72 | 73 | add_definitions(-DCURVE_${CURVE}) 74 | 75 | if(${CURVE} STREQUAL "BN128") 76 | add_definitions(-DBN_SUPPORT_SNARK=1) 77 | endif() 78 | 79 | if("${VERBOSE}") 80 | add_definitions(-DVERBOSE=1) 81 | endif() 82 | 83 | if("${MULTICORE}") 84 | add_definitions(-DMULTICORE=1) 85 | endif() 86 | 87 | 88 | add_definitions(-DDEBUG=1) 89 | 90 | 91 | if("${CPPDEBUG}") 92 | add_definitions(-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC) 93 | endif() 94 | 95 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OPT_FLAGS}") 96 | 97 | include(FindPkgConfig) 98 | if("${WITH_PROCPS}") 99 | pkg_check_modules(PROCPS REQUIRED libprocps) 100 | else() 101 | add_definitions(-DNO_PROCPS) 102 | endif() 103 | 104 | include_directories(.) 105 | 106 | add_subdirectory(depends) 107 | add_subdirectory(src) 108 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | //hash 4 | #include 5 | 6 | //key gen 7 | #include "libff/algebra/curves/alt_bn128/alt_bn128_pp.hpp" //hold key 8 | 9 | // ZoKrates 10 | #include 11 | 12 | 13 | using namespace libsnark; 14 | using namespace libff; 15 | 16 | /** 17 | * The code below provides an example of all stages of running a R1CS GG-ppzkSNARK. 18 | * 19 | * Of course, in a real-life scenario, we would have three distinct entities, 20 | * mangled into one in the demonstration below. The three entities are as follows. 21 | * (1) The "generator", which runs the ppzkSNARK generator on input a given 22 | * constraint system CS to create a proving and a verification key for CS. 23 | * (2) The "prover", which runs the ppzkSNARK prover on input the proving key, 24 | * a primary input for CS, and an auxiliary input for CS. 25 | * (3) The "verifier", which runs the ppzkSNARK verifier on input the verification key, 26 | * a primary input for CS, and a proof. 27 | */ 28 | 29 | template 30 | void constraint_to_json(linear_combination constraints, std::stringstream &ss) 31 | { 32 | ss << "{"; 33 | uint count = 0; 34 | for (const linear_term& lt : constraints.terms) 35 | { 36 | if (count != 0) { 37 | ss << ","; 38 | } 39 | if (lt.coeff != 0 && lt.coeff != 1) { 40 | ss << '"' << lt.index << '"' << ":" << "-1"; 41 | } 42 | else { 43 | ss << '"' << lt.index << '"' << ":" << lt.coeff; 44 | } 45 | count++; 46 | } 47 | ss << "}"; 48 | } 49 | 50 | template 51 | void array_to_json(protoboard pb, uint input_variables, std::string path) 52 | { 53 | 54 | std::stringstream ss; 55 | std::ofstream fh; 56 | fh.open(path, std::ios::binary); 57 | 58 | r1cs_variable_assignment values = pb.full_variable_assignment(); 59 | ss << "\n{\"TestVariables\":["; 60 | 61 | for (size_t i = 0; i < values.size(); ++i) 62 | { 63 | 64 | ss << values[i].as_bigint(); 65 | if (i < values.size() - 1) { ss << ",";} 66 | } 67 | 68 | ss << "]}\n"; 69 | ss.rdbuf()->pubseekpos(0, std::ios_base::out); 70 | 71 | fh << ss.rdbuf(); 72 | fh.flush(); 73 | fh.close(); 74 | } 75 | 76 | template 77 | void r1cs_to_json(protoboard pb, uint input_variables, std::string path) 78 | { 79 | // output inputs, right now need to compile with debug flag so that the `variable_annotations` 80 | // exists. Having trouble setting that up so will leave for now. 81 | r1cs_constraint_system constraints = pb.get_constraint_system(); 82 | std::stringstream ss; 83 | std::ofstream fh; 84 | fh.open(path, std::ios::binary); 85 | 86 | ss << "\n{\"variables\":["; 87 | 88 | for (size_t i = 0; i < input_variables + 1; ++i) 89 | { 90 | ss << '"' << constraints.variable_annotations[i].c_str() << '"'; 91 | if (i < input_variables ) { 92 | ss << ", "; 93 | } 94 | } 95 | ss << "],\n"; 96 | ss << "\"constraints\":["; 97 | 98 | for (size_t c = 0; c < constraints.num_constraints(); ++c) 99 | { 100 | ss << "[";// << "\"A\"="; 101 | constraint_to_json(constraints.constraints[c].a, ss); 102 | ss << ",";// << "\"B\"="; 103 | constraint_to_json(constraints.constraints[c].b, ss); 104 | ss << ",";// << "\"A\"=";; 105 | constraint_to_json(constraints.constraints[c].c, ss); 106 | if (c == constraints.num_constraints()-1 ) { 107 | ss << "]\n"; 108 | } else { 109 | ss << "],\n"; 110 | } 111 | } 112 | ss << "]}"; 113 | ss.rdbuf()->pubseekpos(0, std::ios_base::out); 114 | fh << ss.rdbuf(); 115 | fh.flush(); 116 | fh.close(); 117 | } 118 | 119 | template 120 | void exportInput(r1cs_primary_input input){ 121 | cout << "\tInput in Solidity compliant format:{" << endl; 122 | for (size_t i = 0; i < input.size(); ++i) 123 | { 124 | cout << "\t\tinput[" << i << "] = " << HexStringFromLibsnarkBigint(input[i].as_bigint()) << ";" << endl; 125 | } 126 | cout << "\t\t}" << endl; 127 | } 128 | 129 | bool replace(std::string& str, const std::string& from, const std::string& to) { 130 | size_t start_pos = str.find(from); 131 | if(start_pos == std::string::npos) 132 | return false; 133 | str.replace(start_pos, from.length(), to); 134 | return true; 135 | } 136 | 137 | void proof_to_json(r1cs_ppzksnark_proof proof) { 138 | std::cout << "proof.A = Pairing.G1Point(" << outputPointG1AffineAsHex(proof.g_A.g)<< ");" << endl; 139 | std::cout << "proof.A_p = Pairing.G1Point(" << outputPointG1AffineAsHex(proof.g_A.h)<< ");" << endl; 140 | std::cout << "proof.B = Pairing.G2Point(" << outputPointG2AffineAsHex(proof.g_B.g)<< ");" << endl; 141 | std::cout << "proof.B_p = Pairing.G1Point(" << outputPointG1AffineAsHex(proof.g_B.h)<<");" << endl; 142 | std::cout << "proof.C = Pairing.G1Point(" << outputPointG1AffineAsHex(proof.g_C.g)<< ");" << endl; 143 | std::cout << "proof.C_p = Pairing.G1Point(" << outputPointG1AffineAsHex(proof.g_C.h)<<");" << endl; 144 | std::cout << "proof.H = Pairing.G1Point(" << outputPointG1AffineAsHex(proof.g_H)<<");"<< endl; 145 | std::cout << "proof.K = Pairing.G1Point(" << outputPointG1AffineAsHex(proof.g_K)<<");"<< endl; 146 | 147 | 148 | std::string path = "proof.json"; 149 | std::stringstream ss; 150 | std::ofstream fh; 151 | fh.open(path, std::ios::binary); 152 | 153 | ss << "{\n"; 154 | ss << " \"a\" :[" << outputPointG1AffineAsHex(proof.g_A.g) << "],\n"; 155 | ss << " \"a_p\" :[" << outputPointG1AffineAsHex(proof.g_A.h)<< "],\n"; 156 | ss << " \"b\" :[" << outputPointG2AffineAsHex(proof.g_B.g)<< "],\n"; 157 | ss << " \"b_p\" :[" << outputPointG1AffineAsHex(proof.g_B.h)<< "],\n"; 158 | ss << " \"c\" :[" << outputPointG1AffineAsHex(proof.g_C.g)<< "],\n"; 159 | ss << " \"c_p\" :[" << outputPointG1AffineAsHex(proof.g_C.h)<< "],\n"; 160 | ss << " \"h\" :[" << outputPointG1AffineAsHex(proof.g_H)<< "],\n"; 161 | ss << " \"k\" :[" << outputPointG1AffineAsHex(proof.g_K)<< "],\n"; 162 | ss << " \"input\" :" << "[]"; //TODO: add inputs 163 | ss << "}"; 164 | ss.rdbuf()->pubseekpos(0, std::ios_base::out); 165 | fh << ss.rdbuf(); 166 | fh.flush(); 167 | fh.close(); 168 | 169 | } 170 | 171 | void buildVerificationContract(r1cs_ppzksnark_keypair keypair, std::string path ) { 172 | 173 | std::stringstream ss; 174 | std::ofstream fh; 175 | fh.open(path, std::ios::binary); 176 | unsigned icLength = keypair.vk.encoded_IC_query.rest.indices.size() + 1; 177 | 178 | ss << "{\n"; 179 | ss << " \"a\" :[" << outputPointG2AffineAsHex(keypair.vk.alphaA_g2) << "],\n"; 180 | ss << " \"b\" :[" << outputPointG1AffineAsHex(keypair.vk.alphaB_g1) << "],\n"; 181 | ss << " \"c\" :[" << outputPointG2AffineAsHex(keypair.vk.alphaC_g2) << "],\n"; 182 | ss << " \"g\" :[" << outputPointG2AffineAsHex(keypair.vk.gamma_g2)<< "],\n"; 183 | ss << " \"gb1\" :[" << outputPointG1AffineAsHex(keypair.vk.gamma_beta_g1)<< "],\n"; 184 | ss << " \"gb2\" :[" << outputPointG2AffineAsHex(keypair.vk.gamma_beta_g2)<< "],\n"; 185 | ss << " \"z\" :[" << outputPointG2AffineAsHex(keypair.vk.rC_Z_g2)<< "],\n"; 186 | 187 | ss << "\"IC\" :[" << outputPointG1AffineAsHex(keypair.vk.encoded_IC_query.first); 188 | 189 | for (size_t i = 1; i < icLength; ++i) 190 | { 191 | auto vkICi = outputPointG1AffineAsHex(keypair.vk.encoded_IC_query.rest.values[i - 1]); 192 | ss << "," << vkICi; 193 | } 194 | ss << "]"; 195 | 196 | 197 | ss << "}"; 198 | ss.rdbuf()->pubseekpos(0, std::ios_base::out); 199 | fh << ss.rdbuf(); 200 | fh.flush(); 201 | fh.close(); 202 | 203 | 204 | } 205 | 206 | template 207 | //void dump_key(r1cs_constraint_system cs) 208 | void dump_key(protoboard pb, std::string path) 209 | { 210 | 211 | r1cs_constraint_system constraints = pb.get_constraint_system(); 212 | std::stringstream ss; 213 | std::ofstream fh; 214 | fh.open(path, std::ios::binary); 215 | 216 | 217 | r1cs_ppzksnark_keypair keypair = generateKeypair(pb.get_constraint_system()); 218 | serializeProvingKeyToFile(keypair.pk, "pk_path"); 219 | serializeVerificationKeyToFile(keypair.vk, "vk_path"); 220 | 221 | pb.primary_input(); 222 | pb.auxiliary_input(); 223 | 224 | r1cs_primary_input primary_input = pb.primary_input(); 225 | r1cs_auxiliary_input auxiliary_input = pb.auxiliary_input(); 226 | ss << "primaryinputs" << primary_input; 227 | ss << "aux input" << auxiliary_input; 228 | 229 | r1cs_ppzksnark_proof proof = r1cs_ppzksnark_prover(keypair.pk, primary_input, auxiliary_input); 230 | 231 | buildVerificationContract(keypair, "vk.json"); 232 | proof_to_json (proof); 233 | 234 | ss.rdbuf()->pubseekpos(0, std::ios_base::out); 235 | fh << ss.rdbuf(); 236 | fh.flush(); 237 | fh.close(); 238 | 239 | } 240 | 241 | 242 | template 243 | void test_r1cs_ppzksnark(size_t num_constraints) 244 | { 245 | const size_t new_num_constraints = num_constraints - 1; 246 | protoboard> pb; 247 | // create variable A 248 | pb_variable_array > A; 249 | // Create variable B 250 | pb_variable_array > B; 251 | // Create variable res 252 | pb_variable > res; 253 | 254 | res.allocate(pb, "res"); 255 | A.allocate(pb, new_num_constraints, "A"); 256 | B.allocate(pb, new_num_constraints, "B"); 257 | pb.set_input_sizes(1); 258 | // where s = [1, A , B ] 259 | // compute_inner_product generates `a`, `b`, `c` so that s . a * s . b - s . c = 0 260 | // note a!=A && b!=B 261 | inner_product_gadget > compute_inner_product(pb, A, B, res, "compute_inner_product"); 262 | 263 | compute_inner_product.generate_r1cs_constraints(); 264 | 265 | for (size_t i = 0; i < new_num_constraints; ++i) 266 | { 267 | // set all inputs to 1 except for the first and last. 268 | pb.val(A[i]) = 1; 269 | pb.val(B[i]) = 1; 270 | } 271 | // Gernerate a witness for these values. 272 | compute_inner_product.generate_r1cs_witness(); 273 | compute_inner_product.generate_r1cs_witness(); 274 | assert(pb.is_satisfied()); 275 | std::cout << "num vars: " << pb.num_variables() << "\n"; // output r1cs as json 276 | r1cs_to_json(pb, 7, "r1cs.json"); 277 | array_to_json(pb, 7, "tests.json"); 278 | // output input variable for testing 279 | // dump_key(pb, "key.json"); 280 | r1cs_primary_input > primary_input = pb.primary_input(); 281 | r1cs_auxiliary_input > auxiliary_input = pb.auxiliary_input(); 282 | 283 | 284 | exportInput(primary_input); 285 | exportInput(auxiliary_input); 286 | 287 | 288 | } 289 | 290 | int main () { 291 | 292 | libff::alt_bn128_pp::init_public_params(); 293 | test_r1cs_ppzksnark(4); 294 | 295 | return 0; 296 | } 297 | -------------------------------------------------------------------------------- /src/ZoKrates/wraplibsnark.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @file wraplibsnark.cpp 3 | * @author Jacob Eberhardt 5 | * @date 2017 6 | */ 7 | 8 | #include "wraplibsnark.hpp" 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | // contains definition of alt_bn128 ec public parameters 15 | //#include "libsnark/libsnark/algebra/curves/alt_bn128/alt_bn128_pp.hpp" 16 | #include "libff/algebra/curves/alt_bn128/alt_bn128_pp.hpp" 17 | // contains required interfaces and types (keypair, proof, generator, prover, verifier) 18 | #include 19 | 20 | typedef long integer_coeff_t; 21 | 22 | using namespace std; 23 | using namespace libsnark; 24 | 25 | // conversion byte[32] <-> libsnark bigint. 26 | libff::bigint libsnarkBigintFromBytes(const uint8_t* _x) 27 | { 28 | libff::bigint x; 29 | 30 | for (unsigned i = 0; i < 4; i++) { 31 | for (unsigned j = 0; j < 8; j++) { 32 | x.data[3 - i] |= uint64_t(_x[i * 8 + j]) << (8 * (7-j)); 33 | } 34 | } 35 | return x; 36 | } 37 | 38 | std::string HexStringFromLibsnarkBigint(libff::bigint _x){ 39 | uint8_t x[32]; 40 | for (unsigned i = 0; i < 4; i++) 41 | for (unsigned j = 0; j < 8; j++) 42 | x[i * 8 + j] = uint8_t(uint64_t(_x.data[3 - i]) >> (8 * (7 - j))); 43 | 44 | std::stringstream ss; 45 | ss << std::setfill('0'); 46 | for (unsigned i = 0; i<32; i++) { 47 | ss << std::hex << std::setw(2) << (int)x[i]; 48 | } 49 | 50 | std:string str = ss.str(); 51 | return str.erase(0, min(str.find_first_not_of('0'), str.size()-1)); 52 | } 53 | 54 | std::string outputPointG1AffineAsHex(libff::alt_bn128_G1 _p) 55 | { 56 | libff::alt_bn128_G1 aff = _p; 57 | aff.to_affine_coordinates(); 58 | return 59 | "\"0x" + 60 | HexStringFromLibsnarkBigint(aff.X.as_bigint()) + 61 | "\", \"0x" + 62 | HexStringFromLibsnarkBigint(aff.Y.as_bigint()) + 63 | "\""; 64 | } 65 | 66 | std::string outputPointG2AffineAsHex(libff::alt_bn128_G2 _p) 67 | { 68 | libff::alt_bn128_G2 aff = _p; 69 | aff.to_affine_coordinates(); 70 | return 71 | "[\"0x" + 72 | HexStringFromLibsnarkBigint(aff.X.c1.as_bigint()) + "\", \"0x" + 73 | HexStringFromLibsnarkBigint(aff.X.c0.as_bigint()) + "\"],\n [\"0x" + 74 | HexStringFromLibsnarkBigint(aff.Y.c1.as_bigint()) + "\", \"0x" + 75 | HexStringFromLibsnarkBigint(aff.Y.c0.as_bigint()) + "\"]"; 76 | } 77 | 78 | //takes input and puts it into constraint system 79 | r1cs_ppzksnark_constraint_system createConstraintSystem(const uint8_t* A, const uint8_t* B, const uint8_t* C, int constraints, int variables, int inputs) 80 | { 81 | r1cs_ppzksnark_constraint_system cs; 82 | cs.primary_input_size = inputs; 83 | cs.auxiliary_input_size = variables - inputs - 1; // ~one not included 84 | 85 | cout << "num variables: " << variables < lin_comb_A, lin_comb_B, lin_comb_C; 91 | 92 | for (int idx=0; idx value = libsnarkBigintFromBytes(A+row*variables*32 + idx*32); 94 | libff::alt_bn128_pp::init_public_params(); 95 | cout << "C entry " << idx << " in row " << row << ": " << value << endl; 96 | if (!value.is_zero()) { 97 | //cout << "A(" << idx << ", " << value << ")" << endl; 98 | //lin_comb_A.add_term(idx,value); 99 | //linear_term(0); 100 | } 101 | } 102 | for (int idx=0; idx value = libsnarkBigintFromBytes(B+row*variables*32 + idx*32); 104 | cout << "B entry " << idx << " in row " << row << ": " << value << endl; 105 | if (!value.is_zero()) { 106 | cout << "B(" << idx << ", " << value << ")" << endl; 107 | //lin_comb_B.add_term(idx, value); 108 | } 109 | } 110 | for (int idx=0; idx value = libsnarkBigintFromBytes(C+row*variables*32 + idx*32); 112 | // cout << "C entry " << idx << " in row " << row << ": " << value << endl; 113 | if (!value.is_zero()) { 114 | // cout << "C(" << idx << ", " << value << ")" << endl; 115 | //lin_comb_C.add_term(idx, value); 116 | } 117 | } 118 | //cs.add_constraint(r1cs_constraint(lin_comb_A, lin_comb_B, lin_comb_C)); 119 | } 120 | return cs; 121 | } 122 | 123 | // keypair generateKeypair(constraints) 124 | r1cs_ppzksnark_keypair generateKeypair(const r1cs_ppzksnark_constraint_system &cs){ 125 | // from r1cs_ppzksnark.hpp 126 | return r1cs_ppzksnark_generator(cs); 127 | } 128 | 129 | template 130 | void writeToFile(std::string path, T& obj) { 131 | std::stringstream ss; 132 | ss << obj; 133 | std::ofstream fh; 134 | fh.open(path, std::ios::binary); 135 | ss.rdbuf()->pubseekpos(0, std::ios_base::out); 136 | fh << ss.rdbuf(); 137 | fh.flush(); 138 | fh.close(); 139 | } 140 | 141 | template 142 | T loadFromFile(std::string path) { 143 | std::stringstream ss; 144 | std::ifstream fh(path, std::ios::binary); 145 | 146 | assert(fh.is_open()); 147 | 148 | ss << fh.rdbuf(); 149 | fh.close(); 150 | 151 | ss.rdbuf()->pubseekpos(0, std::ios_base::in); 152 | 153 | T obj; 154 | ss >> obj; 155 | 156 | return obj; 157 | } 158 | 159 | void serializeProvingKeyToFile(r1cs_ppzksnark_proving_key pk, const char* pk_path){ 160 | writeToFile(pk_path, pk); 161 | } 162 | 163 | r1cs_ppzksnark_proving_key deserializeProvingKeyFromFile(const char* pk_path){ 164 | return loadFromFile>(pk_path); 165 | } 166 | 167 | void serializeVerificationKeyToFile(r1cs_ppzksnark_verification_key vk, const char* vk_path){ 168 | std::stringstream ss; 169 | 170 | unsigned icLength = vk.encoded_IC_query.rest.indices.size() + 1; 171 | 172 | ss << "\t\tvk.A = " << outputPointG2AffineAsHex(vk.alphaA_g2) << endl; 173 | ss << "\t\tvk.B = " << outputPointG1AffineAsHex(vk.alphaB_g1) << endl; 174 | ss << "\t\tvk.C = " << outputPointG2AffineAsHex(vk.alphaC_g2) << endl; 175 | ss << "\t\tvk.gamma = " << outputPointG2AffineAsHex(vk.gamma_g2) << endl; 176 | ss << "\t\tvk.gammaBeta1 = " << outputPointG1AffineAsHex(vk.gamma_beta_g1) << endl; 177 | ss << "\t\tvk.gammaBeta2 = " << outputPointG2AffineAsHex(vk.gamma_beta_g2) << endl; 178 | ss << "\t\tvk.Z = " << outputPointG2AffineAsHex(vk.rC_Z_g2) << endl; 179 | ss << "\t\tvk.IC.len() = " << icLength << endl; 180 | ss << "\t\tvk.IC[0] = " << outputPointG1AffineAsHex(vk.encoded_IC_query.first) << endl; 181 | for (size_t i = 1; i < icLength; ++i) 182 | { 183 | auto vkICi = outputPointG1AffineAsHex(vk.encoded_IC_query.rest.values[i - 1]); 184 | ss << "\t\tvk.IC[" << i << "] = " << vkICi << endl; 185 | } 186 | 187 | std::ofstream fh; 188 | fh.open(vk_path, std::ios::binary); 189 | ss.rdbuf()->pubseekpos(0, std::ios_base::out); 190 | fh << ss.rdbuf(); 191 | fh.flush(); 192 | fh.close(); 193 | } 194 | 195 | // compliant with solidty verification example 196 | void exportVerificationKey(r1cs_ppzksnark_keypair keypair){ 197 | unsigned icLength = keypair.vk.encoded_IC_query.rest.indices.size() + 1; 198 | 199 | cout << "\tVerification key in Solidity compliant format:{" << endl; 200 | cout << "\t\tvk.A = Pairing.G2Point(" << outputPointG2AffineAsHex(keypair.vk.alphaA_g2) << ");" << endl; 201 | cout << "\t\tvk.B = Pairing.G1Point(" << outputPointG1AffineAsHex(keypair.vk.alphaB_g1) << ");" << endl; 202 | cout << "\t\tvk.C = Pairing.G2Point(" << outputPointG2AffineAsHex(keypair.vk.alphaC_g2) << ");" << endl; 203 | cout << "\t\tvk.gamma = Pairing.G2Point(" << outputPointG2AffineAsHex(keypair.vk.gamma_g2) << ");" << endl; 204 | cout << "\t\tvk.gammaBeta1 = Pairing.G1Point(" << outputPointG1AffineAsHex(keypair.vk.gamma_beta_g1) << ");" << endl; 205 | cout << "\t\tvk.gammaBeta2 = Pairing.G2Point(" << outputPointG2AffineAsHex(keypair.vk.gamma_beta_g2) << ");" << endl; 206 | cout << "\t\tvk.Z = Pairing.G2Point(" << outputPointG2AffineAsHex(keypair.vk.rC_Z_g2) << ");" << endl; 207 | cout << "\t\tvk.IC = new Pairing.G1Point[](" << icLength << ");" << endl; 208 | cout << "\t\tvk.IC[0] = Pairing.G1Point(" << outputPointG1AffineAsHex(keypair.vk.encoded_IC_query.first) << ");" << endl; 209 | for (size_t i = 1; i < icLength; ++i) 210 | { 211 | auto vkICi = outputPointG1AffineAsHex(keypair.vk.encoded_IC_query.rest.values[i - 1]); 212 | cout << "\t\tvk.IC[" << i << "] = Pairing.G1Point(" << vkICi << ");" << endl; 213 | } 214 | cout << "\t\t}" << endl; 215 | 216 | } 217 | 218 | // compliant with solidty verification example 219 | /* 220 | void exportInput(r1cs_primary_input input){ 221 | cout << "\tInput in Solidity compliant format:{" << endl; 222 | for (size_t i = 0; i < input.size(); ++i) 223 | { 224 | cout << "\t\tinput[" << i << "] = " << HexStringFromLibsnarkBigint(input[i].as_bigint()) << ";" << endl; 225 | } 226 | cout << "\t\t}" << endl; 227 | } */ 228 | 229 | 230 | void printProof(r1cs_ppzksnark_proof proof){ 231 | cout << "Proof:"<< endl; 232 | cout << "proof.A = Pairing.G1Point(" << outputPointG1AffineAsHex(proof.g_A.g)<< ");" << endl; 233 | cout << "proof.A_p = Pairing.G1Point(" << outputPointG1AffineAsHex(proof.g_A.h)<< ");" << endl; 234 | cout << "proof.B = Pairing.G2Point(" << outputPointG2AffineAsHex(proof.g_B.g)<< ");" << endl; 235 | cout << "proof.B_p = Pairing.G1Point(" << outputPointG1AffineAsHex(proof.g_B.h)<<");" << endl; 236 | cout << "proof.C = Pairing.G1Point(" << outputPointG1AffineAsHex(proof.g_C.g)<< ");" << endl; 237 | cout << "proof.C_p = Pairing.G1Point(" << outputPointG1AffineAsHex(proof.g_C.h)<<");" << endl; 238 | cout << "proof.H = Pairing.G1Point(" << outputPointG1AffineAsHex(proof.g_H)<<");"<< endl; 239 | cout << "proof.K = Pairing.G1Point(" << outputPointG1AffineAsHex(proof.g_K)<<");"<< endl; 240 | } 241 | 242 | /*bool _setup(const uint8_t* A, const uint8_t* B, const uint8_t* C, int constraints, int variables, int inputs, const char* pk_path, const char* vk_path) 243 | { 244 | //libsnark::inhibit_profiling_info = true; 245 | //libsnark::inhibit_profiling_counters = true; 246 | 247 | //initialize curve parameters 248 | libff::alt_bn128_pp::init_public_params(); 249 | 250 | r1cs_constraint_system cs; 251 | cs = createConstraintSystem(A, B ,C , constraints, variables, inputs); 252 | 253 | assert(cs.num_variables() >= inputs); 254 | assert(cs.num_inputs() == inputs); 255 | assert(cs.num_constraints() == constraints); 256 | 257 | // create keypair 258 | r1cs_ppzksnark_keypair keypair = r1cs_ppzksnark_generator(cs); 259 | 260 | // Export vk and pk to files 261 | serializeProvingKeyToFile(keypair.pk, pk_path); 262 | serializeVerificationKeyToFile(keypair.vk, vk_path); 263 | 264 | // Print VerificationKey in Solidity compatible format 265 | exportVerificationKey(keypair); 266 | 267 | return true; 268 | }*/ 269 | /* 270 | bool _generate_proof(const char* pk_path, const uint8_t* public_inputs, int public_inputs_length, const uint8_t* private_inputs, int private_inputs_length) 271 | { 272 | // libsnark::inhibit_profiling_info = true; 273 | // libsnark::inhibit_profiling_counters = true; 274 | 275 | //initialize curve parameters 276 | libff::alt_bn128_pp::init_public_params(); 277 | r1cs_ppzksnark_proving_key pk = deserializeProvingKeyFromFile(pk_path); 278 | 279 | // assign variables based on witness values, excludes ~one 280 | r1cs_variable_assignment full_variable_assignment; 281 | for (int i = 1; i < public_inputs_length; i++) { 282 | full_variable_assignment.push_back(libff::alt_bn128_pp(libsnarkBigintFromBytes(public_inputs + i*32))); 283 | } 284 | for (int i = 0; i < private_inputs_length; i++) { 285 | full_variable_assignment.push_back((libsnarkBigintFromBytes(private_inputs + i*32))); 286 | } 287 | 288 | // split up variables into primary and auxiliary inputs. Does *NOT* include the constant 1 289 | // Public variables belong to primary input, private variables are auxiliary input. 290 | r1cs_primary_input primary_input(full_variable_assignment.begin(), full_variable_assignment.begin() + public_inputs_length-1); 291 | r1cs_primary_input auxiliary_input(full_variable_assignment.begin() + public_inputs_length-1, full_variable_assignment.end()); 292 | 293 | // for debugging 294 | // cout << "full variable assignment:"<< endl << full_variable_assignment; 295 | // cout << "primary input:"<< endl << primary_input; 296 | // cout << "auxiliary input:"<< endl << auxiliary_input; 297 | 298 | // Proof Generation 299 | r1cs_ppzksnark_proof proof = r1cs_ppzksnark_prover(pk, primary_input, auxiliary_input); 300 | 301 | // print proof 302 | printProof(proof); 303 | // TODO? print inputs 304 | 305 | return true; 306 | } */ 307 | --------------------------------------------------------------------------------