├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── gen_tests ├── .gitignore ├── Cargo.lock ├── Cargo.toml └── src │ └── main.rs ├── get-libsnark └── src ├── gadget.hpp ├── snark.hpp ├── test.cpp └── test.h /.gitignore: -------------------------------------------------------------------------------- 1 | test 2 | *.o 3 | *.d 4 | depinst 5 | depsrc 6 | 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | OPTFLAGS = -march=native -mtune=native -O2 2 | CXXFLAGS += -g -Wall -Wextra -Wno-unused-parameter -std=c++11 -fPIC -Wno-unused-variable 3 | CXXFLAGS += -I $(DEPINST)/include -I $(DEPINST)/include/libsnark -DUSE_ASM -DCURVE_ALT_BN128 4 | LDFLAGS += -flto 5 | 6 | DEPSRC=depsrc 7 | DEPINST=depinst 8 | 9 | LDLIBS += -L $(DEPINST)/lib -Wl,-rpath $(DEPINST)/lib -L . -lsnark -lgmpxx -lgmp 10 | LDLIBS += -lboost_system 11 | 12 | all: 13 | $(CXX) -o test.o src/test.cpp -c $(CXXFLAGS) 14 | $(CXX) -o test test.o $(CXXFLAGS) $(LDFLAGS) $(LDLIBS) 15 | 16 | clean: 17 | $(RM) test.o test -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This simple SNARK application was made in response to a lightning-dev forum post, https://lists.linuxfoundation.org/pipermail/lightning-dev/2015-November/000309.html where AJ Towns suggested using SNARKs to implement a variant of the lightning protocol. The exact application doesn't matter too much, but in the thread there was an initial attempt at benchmarking, which seemed to suggest ridiculous numbers, like 100+MB for a proof about a single hash. So, this project was made to set the record straight about what performance could be expected. 2 | 3 | This is a SNARK implementation using libsnark for the following: 4 | 5 | ``ZkPoK{ (R1, R2): H1 = sha256(R1) and H2 = sha256(R2) and R1 = R2 ^ X }`` 6 | 7 | Read: given `H1`, `H2`, and `X`, prove you know `R1` and `R2` such that `R1` is the preimage of `H1`, 8 | `R2` is the preimage of `H2`, and `R1` is `R2 xor X`. 9 | 10 | ## performance 11 | 12 | on my computer (Intel(R) Core(TM) i7-3770S CPU @ 3.10GHz): 13 | 14 | * **key generation time**: 11.6551s 15 | * **proof generation time**: 3.0884s 16 | * **verification time**: 0.0262s 17 | * **proof size**: 2294 bits 18 | * **proving key size**: 102284136 bits 19 | * **verifying key size**: 4586 bits 20 | * **R1CS constraints**: 56101 (mostly sha256-related) 21 | 22 | ## howto 23 | 24 | ``./get-libsnark && make && ./test`` 25 | 26 | ## anatomy 27 | 28 | * `src/gadget.hpp` exposes the gadget, which is an abstraction of related constraint 29 | and witness behavior in a circuit. This gadget uses other gadgets, creates its own 30 | constraints, and exposes an interface for building input maps. 31 | 32 | * `src/snark.hpp` exposes a loose wrapper around the constraint system and 33 | key generation used by `test.cpp` to construct proofs and verify them as necessary. 34 | -------------------------------------------------------------------------------- /gen_tests/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /gen_tests/Cargo.lock: -------------------------------------------------------------------------------- 1 | [root] 2 | name = "gen_tests" 3 | version = "0.1.0" 4 | 5 | -------------------------------------------------------------------------------- /gen_tests/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "gen_tests" 3 | version = "0.1.0" 4 | authors = ["Sean Bowe "] 5 | -------------------------------------------------------------------------------- /gen_tests/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(rustc_private)] 2 | 3 | extern crate rustc; 4 | use rustc::util::sha2::{Digest,Sha256}; 5 | use std::u8; 6 | 7 | use self::Test::*; 8 | 9 | enum Test { 10 | Valid, 11 | AndInsteadOfXor 12 | } 13 | 14 | fn main() { 15 | println!("valid: "); 16 | gen(Valid); 17 | println!("using AND instead of XOR: "); 18 | gen(AndInsteadOfXor); 19 | } 20 | 21 | fn gen(test: Test) { 22 | let r2: Vec = { 23 | let mut hash = Sha256::new(); 24 | hash.input("SCIPR".as_ref()); 25 | hash.result_bytes() 26 | }; 27 | let x: Vec = { 28 | let mut hash = Sha256::new(); 29 | hash.input("LAB".as_ref()); 30 | hash.result_bytes() 31 | }; 32 | let r1 = { 33 | let mut v = vec![]; 34 | for (a, b) in r2.iter().zip(x.iter()) { 35 | if let AndInsteadOfXor = test { 36 | v.push(a & b); 37 | } else { 38 | v.push(a ^ b); 39 | } 40 | } 41 | 42 | v 43 | }; 44 | 45 | let h1: Vec = { 46 | let mut hash = Sha256::new(); 47 | hash.input(&r1); 48 | hash.result_bytes() 49 | }; 50 | 51 | let h2: Vec = { 52 | let mut hash = Sha256::new(); 53 | hash.input(&r2); 54 | hash.result_bytes() 55 | }; 56 | 57 | print!("h1_bv = int_list_to_bits("); into_bin(&h1); 58 | print!("h2_bv = int_list_to_bits("); into_bin(&h2); 59 | print!("x_bv = int_list_to_bits("); into_bin(&x); 60 | print!("r1_bv = int_list_to_bits("); into_bin(&r1); 61 | print!("r2_bv = int_list_to_bits("); into_bin(&r2); 62 | } 63 | 64 | fn into_bin(a: &Vec) { 65 | let mut first = true; 66 | print!("{{"); 67 | for a in a.iter() { 68 | print!("{}{}", 69 | {if !first { ", " } else {first = false; ""}}, 70 | a 71 | ); 72 | } 73 | println!("}}, 8);"); 74 | } 75 | -------------------------------------------------------------------------------- /get-libsnark: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # To pass options options to libsnark Makefile, put them in env var LIBSNARK_FLAGS. 3 | # To clone libsnark from an alternate location, set env var LIBSNARK_SRC. For example: 4 | # LIBSNARK_SRC="$HOME/libsnark.git --branch master" ./get-libsnark 5 | # To use curve ALT_BN128 instead of BN128 (which is x64-only), use: 6 | # CURVE=ALT_BN128 ./get-libsnark 7 | 8 | set -e 9 | 10 | LIBSNARK_SRC=${LIBSNARK_SRC:-https://github.com/scipr-lab/libsnark} 11 | 12 | CURVE=${CURVE:-BN128} 13 | 14 | LIBSNARK_FLAGS="$LIBSNARK_FLAGS NO_SUPERCOP=1 NO_GTEST=1 NO_DOCS=1 CURVE=$CURVE" 15 | if [[ `uname -s` == "Darwin" ]]; then 16 | LIBSNARK_FLAGS="$LIBSNARK_FLAGS NO_PROCPS=1" 17 | fi 18 | 19 | set -x 20 | 21 | DEPSRC=./depsrc 22 | DEPINST=./depinst 23 | 24 | mkdir -p $DEPINST 25 | DEPINST=`pwd -P`/$DEPINST # remember absolute path 26 | 27 | mkdir -p $DEPSRC 28 | cd $DEPSRC 29 | 30 | [ ! -d libsnark ] && git clone $LIBSNARK_SRC libsnark 31 | cd libsnark 32 | git pull 33 | if [ "$CURVE" == "BN128" ]; then 34 | # TODO: submit -fPIC patch to ate-pairing 35 | INC_DIR=-fPIC ./prepare-depends.sh 36 | fi 37 | make clean 38 | make lib $LIBSNARK_FLAGS 39 | make install PREFIX=$DEPINST $LIBSNARK_FLAGS 40 | -------------------------------------------------------------------------------- /src/gadget.hpp: -------------------------------------------------------------------------------- 1 | #include "libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp" 2 | #include "algebra/fields/field_utils.hpp" 3 | 4 | const size_t sha256_digest_len = 256; 5 | 6 | /* 7 | computed by: 8 | 9 | unsigned long long bitlen = 256; 10 | 11 | unsigned char padding[32] = {0x80, 0x00, 0x00, 0x00, // 24 bytes of padding 12 | 0x00, 0x00, 0x00, 0x00, 13 | 0x00, 0x00, 0x00, 0x00, 14 | 0x00, 0x00, 0x00, 0x00, 15 | 0x00, 0x00, 0x00, 0x00, 16 | 0x00, 0x00, 0x00, 0x00, 17 | bitlen >> 56, bitlen >> 48, bitlen >> 40, bitlen >> 32, // message length 18 | bitlen >> 24, bitlen >> 16, bitlen >> 8, bitlen 19 | }; 20 | 21 | std::vector padding_bv(256); 22 | 23 | convertBytesToVector(padding, padding_bv); 24 | 25 | printVector(padding_bv); 26 | */ 27 | bool sha256_padding[256] = {1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 28 | 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 29 | 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 30 | 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 31 | 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 32 | 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 33 | 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 34 | 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,1, 0,0,0,0,0,0,0,0}; 35 | 36 | template 37 | class l_gadget : public gadget { 38 | public: 39 | pb_variable_array input_as_field_elements; /* R1CS input */ 40 | pb_variable_array input_as_bits; /* unpacked R1CS input */ 41 | std::shared_ptr > unpack_inputs; /* multipacking gadget */ 42 | 43 | std::shared_ptr> h1_var; /* H(R1) */ 44 | std::shared_ptr> h2_var; /* H(R2) */ 45 | 46 | std::shared_ptr> x_var; /* X */ 47 | std::shared_ptr> r1_var; /* R1 */ 48 | std::shared_ptr> r2_var; /* R2 */ 49 | 50 | std::shared_ptr> h_r1_block; /* 512 bit block that contains r1 + padding */ 51 | std::shared_ptr> h_r1; /* hashing gadget for r1 */ 52 | 53 | std::shared_ptr> h_r2_block; /* 512 bit block that contains r2 + padding */ 54 | std::shared_ptr> h_r2; /* hashing gadget for r2 */ 55 | 56 | pb_variable zero; 57 | pb_variable_array padding_var; /* SHA256 length padding */ 58 | 59 | 60 | l_gadget(protoboard &pb) : gadget(pb, "l_gadget") 61 | { 62 | // Allocate space for the verifier input. 63 | const size_t input_size_in_bits = sha256_digest_len * 3; 64 | { 65 | // We use a "multipacking" technique which allows us to constrain 66 | // the input bits in as few field elements as possible. 67 | const size_t input_size_in_field_elements = div_ceil(input_size_in_bits, FieldT::capacity()); 68 | input_as_field_elements.allocate(pb, input_size_in_field_elements, "input_as_field_elements"); 69 | this->pb.set_input_sizes(input_size_in_field_elements); 70 | } 71 | 72 | zero.allocate(this->pb, FMT(this->annotation_prefix, "zero")); 73 | 74 | // SHA256's length padding 75 | for (size_t i = 0; i < 256; i++) { 76 | if (sha256_padding[i]) 77 | padding_var.emplace_back(ONE); 78 | else 79 | padding_var.emplace_back(zero); 80 | } 81 | 82 | // Verifier (and prover) inputs: 83 | h1_var.reset(new digest_variable(pb, sha256_digest_len, "h1")); 84 | h2_var.reset(new digest_variable(pb, sha256_digest_len, "h2")); 85 | x_var.reset(new digest_variable(pb, sha256_digest_len, "x")); 86 | 87 | input_as_bits.insert(input_as_bits.end(), h1_var->bits.begin(), h1_var->bits.end()); 88 | input_as_bits.insert(input_as_bits.end(), h2_var->bits.begin(), h2_var->bits.end()); 89 | input_as_bits.insert(input_as_bits.end(), x_var->bits.begin(), x_var->bits.end()); 90 | 91 | // Multipacking 92 | assert(input_as_bits.size() == input_size_in_bits); 93 | unpack_inputs.reset(new multipacking_gadget(this->pb, input_as_bits, input_as_field_elements, FieldT::capacity(), FMT(this->annotation_prefix, " unpack_inputs"))); 94 | 95 | // Prover inputs: 96 | r1_var.reset(new digest_variable(pb, sha256_digest_len, "r1")); 97 | r2_var.reset(new digest_variable(pb, sha256_digest_len, "r2")); 98 | 99 | // IV for SHA256 100 | pb_linear_combination_array IV = SHA256_default_IV(pb); 101 | 102 | // Initialize the block gadget for r1's hash 103 | h_r1_block.reset(new block_variable(pb, { 104 | r1_var->bits, 105 | padding_var 106 | }, "h_r1_block")); 107 | 108 | // Initialize the hash gadget for r1's hash 109 | h_r1.reset(new sha256_compression_function_gadget(pb, 110 | IV, 111 | h_r1_block->bits, 112 | *h1_var, 113 | "h_r1")); 114 | 115 | // Initialize the block gadget for r2's hash 116 | h_r2_block.reset(new block_variable(pb, { 117 | r2_var->bits, 118 | padding_var 119 | }, "h_r2_block")); 120 | 121 | // Initialize the hash gadget for r2's hash 122 | h_r2.reset(new sha256_compression_function_gadget(pb, 123 | IV, 124 | h_r2_block->bits, 125 | *h2_var, 126 | "h_r2")); 127 | } 128 | void generate_r1cs_constraints() 129 | { 130 | // Multipacking constraints (for input validation) 131 | unpack_inputs->generate_r1cs_constraints(true); 132 | 133 | // Ensure bitness of the digests. Bitness of the inputs 134 | // is established by `unpack_inputs->generate_r1cs_constraints(true)` 135 | r1_var->generate_r1cs_constraints(); 136 | r2_var->generate_r1cs_constraints(); 137 | 138 | generate_r1cs_equals_const_constraint(this->pb, zero, FieldT::zero(), "zero"); 139 | 140 | for (unsigned int i = 0; i < sha256_digest_len; i++) { 141 | // This is the constraint that R1 = R2 ^ X. 142 | // (2*b)*c = b+c - a 143 | this->pb.add_r1cs_constraint( 144 | r1cs_constraint( 145 | { r2_var->bits[i] * 2 }, // 2*b 146 | { x_var->bits[i] }, // c 147 | { r2_var->bits[i], x_var->bits[i], r1_var->bits[i] * (-1) }), // b+c - a 148 | FMT(this->annotation_prefix, " xor_%zu", i)); 149 | } 150 | 151 | // These are the constraints to ensure the hashes validate. 152 | h_r1->generate_r1cs_constraints(); 153 | h_r2->generate_r1cs_constraints(); 154 | } 155 | void generate_r1cs_witness(const bit_vector &h1, 156 | const bit_vector &h2, 157 | const bit_vector &x, 158 | const bit_vector &r1, 159 | const bit_vector &r2 160 | ) 161 | { 162 | // Fill our digests with our witnessed data 163 | x_var->bits.fill_with_bits(this->pb, x); 164 | r1_var->bits.fill_with_bits(this->pb, r1); 165 | r2_var->bits.fill_with_bits(this->pb, r2); 166 | 167 | // Set the zero pb_variable to zero 168 | this->pb.val(zero) = FieldT::zero(); 169 | 170 | // Generate witnesses as necessary in our other gadgets 171 | h_r1->generate_r1cs_witness(); 172 | h_r2->generate_r1cs_witness(); 173 | unpack_inputs->generate_r1cs_witness_from_bits(); 174 | 175 | h1_var->bits.fill_with_bits(this->pb, h1); 176 | h2_var->bits.fill_with_bits(this->pb, h2); 177 | } 178 | }; 179 | 180 | template 181 | r1cs_primary_input l_input_map(const bit_vector &h1, 182 | const bit_vector &h2, 183 | const bit_vector &x 184 | ) 185 | { 186 | // Construct the multipacked field points which encode 187 | // the verifier's knowledge. This is the "dual" of the 188 | // multipacking gadget logic in the constructor. 189 | assert(h1.size() == sha256_digest_len); 190 | assert(h2.size() == sha256_digest_len); 191 | assert(x.size() == sha256_digest_len); 192 | 193 | bit_vector input_as_bits; 194 | input_as_bits.insert(input_as_bits.end(), h1.begin(), h1.end()); 195 | input_as_bits.insert(input_as_bits.end(), h2.begin(), h2.end()); 196 | input_as_bits.insert(input_as_bits.end(), x.begin(), x.end()); 197 | std::vector input_as_field_elements = pack_bit_vector_into_field_element_vector(input_as_bits); 198 | return input_as_field_elements; 199 | } 200 | -------------------------------------------------------------------------------- /src/snark.hpp: -------------------------------------------------------------------------------- 1 | #include "libsnark/gadgetlib1/gadgets/basic_gadgets.hpp" 2 | #include "libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" 3 | #include "libsnark/common/default_types/r1cs_ppzksnark_pp.hpp" 4 | #include "libsnark/common/utils.hpp" 5 | #include 6 | 7 | using namespace libsnark; 8 | using namespace std; 9 | 10 | #include "gadget.hpp" 11 | 12 | template 13 | r1cs_ppzksnark_keypair generate_keypair() 14 | { 15 | typedef Fr FieldT; 16 | 17 | protoboard pb; 18 | l_gadget g(pb); 19 | g.generate_r1cs_constraints(); 20 | const r1cs_constraint_system constraint_system = pb.get_constraint_system(); 21 | 22 | cout << "Number of R1CS constraints: " << constraint_system.num_constraints() << endl; 23 | 24 | return r1cs_ppzksnark_generator(constraint_system); 25 | } 26 | 27 | template 28 | boost::optional> generate_proof(r1cs_ppzksnark_proving_key proving_key, 29 | const bit_vector &h1, 30 | const bit_vector &h2, 31 | const bit_vector &x, 32 | const bit_vector &r1, 33 | const bit_vector &r2 34 | ) 35 | { 36 | typedef Fr FieldT; 37 | 38 | protoboard pb; 39 | l_gadget g(pb); 40 | g.generate_r1cs_constraints(); 41 | g.generate_r1cs_witness(h1, h2, x, r1, r2); 42 | 43 | if (!pb.is_satisfied()) { 44 | return boost::none; 45 | } 46 | 47 | return r1cs_ppzksnark_prover(proving_key, pb.primary_input(), pb.auxiliary_input()); 48 | } 49 | 50 | template 51 | bool verify_proof(r1cs_ppzksnark_verification_key verification_key, 52 | r1cs_ppzksnark_proof proof, 53 | const bit_vector &h1, 54 | const bit_vector &h2, 55 | const bit_vector &x 56 | ) 57 | { 58 | typedef Fr FieldT; 59 | 60 | const r1cs_primary_input input = l_input_map(h1, h2, x); 61 | 62 | return r1cs_ppzksnark_verifier_strong_IC(verification_key, input, proof); 63 | } -------------------------------------------------------------------------------- /src/test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "snark.hpp" 5 | #include "test.h" 6 | 7 | using namespace libsnark; 8 | using namespace std; 9 | 10 | int main() 11 | { 12 | // Initialize the curve parameters. 13 | default_r1cs_ppzksnark_pp::init_public_params(); 14 | // Generate the verifying/proving keys. (This is trusted setup!) 15 | auto keypair = generate_keypair(); 16 | 17 | // Run test vectors. 18 | assert(run_test(keypair, false, false, false)); 19 | assert(!run_test(keypair, true, false, false)); 20 | assert(!run_test(keypair, false, true, false)); 21 | assert(!run_test(keypair, false, false, true)); 22 | } 23 | 24 | bool run_test(r1cs_ppzksnark_keypair& keypair, 25 | // These are just for changing behavior 26 | // for testing purposes: 27 | bool use_and_instead_of_xor, 28 | bool swap_r1_r2, 29 | bool goofy_verification_inputs 30 | ) { 31 | 32 | // Initialize bit_vectors for all of the variables involved. 33 | std::vector h1_bv(256); 34 | std::vector h2_bv(256); 35 | std::vector x_bv(256); 36 | std::vector r1_bv(256); 37 | std::vector r2_bv(256); 38 | 39 | { 40 | // These are working test vectors. 41 | h1_bv = int_list_to_bits({169, 231, 96, 189, 221, 234, 240, 85, 213, 187, 236, 114, 100, 185, 130, 86, 231, 29, 123, 196, 57, 225, 159, 216, 34, 190, 123, 97, 14, 57, 180, 120}, 8); 42 | h2_bv = int_list_to_bits({253, 199, 66, 55, 24, 155, 80, 121, 138, 60, 36, 201, 186, 221, 164, 65, 194, 53, 192, 159, 252, 7, 194, 24, 200, 217, 57, 55, 45, 204, 71, 9}, 8); 43 | x_bv = int_list_to_bits({122, 98, 227, 172, 61, 124, 6, 226, 115, 70, 192, 164, 29, 38, 29, 199, 205, 180, 109, 59, 126, 216, 144, 115, 183, 112, 152, 41, 35, 218, 1, 76}, 8); 44 | r1_bv = int_list_to_bits({180, 34, 250, 166, 200, 177, 240, 137, 204, 219, 178, 17, 34, 14, 66, 65, 203, 6, 191, 16, 141, 210, 73, 136, 65, 136, 152, 60, 117, 24, 101, 18}, 8); 45 | r2_bv = int_list_to_bits({206, 64, 25, 10, 245, 205, 246, 107, 191, 157, 114, 181, 63, 40, 95, 134, 6, 178, 210, 43, 243, 10, 217, 251, 246, 248, 0, 21, 86, 194, 100, 94}, 8); 46 | } 47 | 48 | if (use_and_instead_of_xor) { 49 | // This uses AND instead of XOR, which should properly test 50 | // the XOR constraint of the circuit. 51 | h1_bv = int_list_to_bits({245, 151, 92, 200, 120, 203, 58, 116, 216, 30, 82, 196, 179, 104, 132, 100, 64, 99, 99, 177, 160, 94, 193, 168, 186, 225, 224, 143, 97, 77, 135, 115}, 8); 52 | h2_bv = int_list_to_bits({253, 199, 66, 55, 24, 155, 80, 121, 138, 60, 36, 201, 186, 221, 164, 65, 194, 53, 192, 159, 252, 7, 194, 24, 200, 217, 57, 55, 45, 204, 71, 9}, 8); 53 | x_bv = int_list_to_bits({122, 98, 227, 172, 61, 124, 6, 226, 115, 70, 192, 164, 29, 38, 29, 199, 205, 180, 109, 59, 126, 216, 144, 115, 183, 112, 152, 41, 35, 218, 1, 76}, 8); 54 | r1_bv = int_list_to_bits({74, 64, 1, 8, 53, 76, 6, 98, 51, 4, 64, 164, 29, 32, 29, 134, 4, 176, 64, 43, 114, 8, 144, 115, 182, 112, 0, 1, 2, 194, 0, 76}, 8); 55 | r2_bv = int_list_to_bits({206, 64, 25, 10, 245, 205, 246, 107, 191, 157, 114, 181, 63, 40, 95, 134, 6, 178, 210, 43, 243, 10, 217, 251, 246, 248, 0, 21, 86, 194, 100, 94}, 8); 56 | } 57 | 58 | if (swap_r1_r2) { 59 | // This swaps r1 and r2 which should test if the hashing 60 | // constraints work properly. 61 | auto tmp = r2_bv; 62 | r2_bv = r1_bv; 63 | r1_bv = tmp; 64 | } 65 | 66 | cout << "Trying to generate proof..." << endl; 67 | auto proof = generate_proof(keypair.pk, h1_bv, h2_bv, x_bv, r1_bv, r2_bv); 68 | cout << "Proof generated!" << endl; 69 | 70 | if (!proof) { 71 | return false; 72 | } else { 73 | if (goofy_verification_inputs) { 74 | // [test] if we generated the proof but try to validate 75 | // with bogus inputs it shouldn't let us 76 | return verify_proof(keypair.vk, *proof, h2_bv, h1_bv, x_bv); 77 | } else { 78 | // verification should not fail if the proof is generated! 79 | assert(verify_proof(keypair.vk, *proof, h1_bv, h2_bv, x_bv)); 80 | return true; 81 | } 82 | } 83 | } -------------------------------------------------------------------------------- /src/test.h: -------------------------------------------------------------------------------- 1 | bool run_test(r1cs_ppzksnark_keypair& keypair, 2 | 3 | // These are just for changing behavior 4 | // for testing purposes: 5 | bool use_and_instead_of_xor, 6 | bool swap_r1_r2, 7 | bool goofy_verification_inputs 8 | ); --------------------------------------------------------------------------------