From 86beff8c7f2b94661833b046e5cf70aed051a956 Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Fri, 4 Dec 2015 19:40:05 -0700 Subject: [PATCH] Initial commit --- .gitignore | 6 ++++ LICENSE | 19 +++++++++++++ Makefile | 17 +++++++++++ README.md | 0 get-libsnark | 39 ++++++++++++++++++++++++++ src/gadget.hpp | 26 +++++++++++++++++ src/gadget.tcc | 55 ++++++++++++++++++++++++++++++++++++ src/snark.hpp | 25 +++++++++++++++++ src/snark.tcc | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/test.cpp | 35 +++++++++++++++++++++++ src/test.h | 3 ++ 11 files changed, 301 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README.md create mode 100755 get-libsnark create mode 100644 src/gadget.hpp create mode 100644 src/gadget.tcc create mode 100644 src/snark.hpp create mode 100644 src/snark.tcc create mode 100644 src/test.cpp create mode 100644 src/test.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bb28849 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +test +*.o +*.d +depinst +depsrc + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..72dc60d --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +The MIT License (MIT) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c862cb4 --- /dev/null +++ b/Makefile @@ -0,0 +1,17 @@ +OPTFLAGS = -march=native -mtune=native -O2 +CXXFLAGS += -g -Wall -Wextra -Wno-unused-parameter -std=c++11 -fPIC -Wno-unused-variable +CXXFLAGS += -I $(DEPINST)/include -I $(DEPINST)/include/libsnark -DUSE_ASM -DCURVE_ALT_BN128 +LDFLAGS += -flto + +DEPSRC=depsrc +DEPINST=depinst + +LDLIBS += -L $(DEPINST)/lib -Wl,-rpath $(DEPINST)/lib -L . -lsnark -lgmpxx -lgmp +LDLIBS += -lboost_system + +all: + $(CXX) -o test.o src/test.cpp -c $(CXXFLAGS) + $(CXX) -o test test.o $(CXXFLAGS) $(LDFLAGS) $(LDLIBS) + +clean: + $(RM) test.o test \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/get-libsnark b/get-libsnark new file mode 100755 index 0000000..5745390 --- /dev/null +++ b/get-libsnark @@ -0,0 +1,39 @@ +#!/bin/bash +# To pass options options to libsnark Makefile, put them in env var LIBSNARK_FLAGS. +# To clone libsnark from an alternate location, set env var LIBSNARK_SRC. For example: +# LIBSNARK_SRC="$HOME/libsnark.git --branch master" ./get-libsnark +# To use curve ALT_BN128 instead of BN128 (which is x64-only), use: +# CURVE=ALT_BN128 ./get-libsnark + +set -e + +LIBSNARK_SRC=${LIBSNARK_SRC:-https://github.com/scipr-lab/libsnark} + +CURVE=${CURVE:-BN128} + +LIBSNARK_FLAGS="$LIBSNARK_FLAGS NO_SUPERCOP=1 NO_GTEST=1 NO_DOCS=1 CURVE=$CURVE" +if [[ `uname -s` == "Darwin" ]]; then + LIBSNARK_FLAGS="$LIBSNARK_FLAGS NO_PROCPS=1" +fi + +set -x + +DEPSRC=./depsrc +DEPINST=./depinst + +mkdir -p $DEPINST +DEPINST=`pwd -P`/$DEPINST # remember absolute path + +mkdir -p $DEPSRC +cd $DEPSRC + +[ ! -d libsnark ] && git clone $LIBSNARK_SRC libsnark +cd libsnark +git pull +if [ "$CURVE" == "BN128" ]; then + # TODO: submit -fPIC patch to ate-pairing + INC_DIR=-fPIC ./prepare-depends.sh +fi +make clean +make lib $LIBSNARK_FLAGS +make install PREFIX=$DEPINST $LIBSNARK_FLAGS diff --git a/src/gadget.hpp b/src/gadget.hpp new file mode 100644 index 0000000..e6250db --- /dev/null +++ b/src/gadget.hpp @@ -0,0 +1,26 @@ +#include "libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp" +#include "algebra/fields/field_utils.hpp" + +using namespace libsnark; + +template +class l_gadget : public gadget { +public: + unsigned int dimension; /* N */ + + pb_variable_array input_as_field_elements; /* R1CS input */ + pb_variable_array input_as_bits; /* unpacked R1CS input */ + std::shared_ptr > unpack_inputs; /* multipacking gadget */ + + std::vector> puzzle_values; + + + l_gadget(protoboard &pb, unsigned int n); + void generate_r1cs_constraints(); + void generate_r1cs_witness(std::vector &puzzle_values); +}; + +template +r1cs_primary_input l_input_map(std::vector &puzzle_values); + +#include "gadget.tcc" diff --git a/src/gadget.tcc b/src/gadget.tcc new file mode 100644 index 0000000..f7a8558 --- /dev/null +++ b/src/gadget.tcc @@ -0,0 +1,55 @@ +template +l_gadget::l_gadget(protoboard &pb, unsigned int n) : + gadget(pb, FMT(annotation_prefix, " l_gadget")) +{ + dimension = n; + + const size_t input_size_in_bits = n * n * 8; + { + const size_t input_size_in_field_elements = div_ceil(input_size_in_bits, FieldT::capacity()); + input_as_field_elements.allocate(pb, input_size_in_field_elements, "input_as_field_elements"); + this->pb.set_input_sizes(input_size_in_field_elements); + } + + puzzle_values.resize(n*n); + + for (unsigned int i = 0; i < (n*n); i++) { + puzzle_values[i].allocate(pb, 8, "puzzle_value[i]"); + input_as_bits.insert(input_as_bits.end(), puzzle_values[i].begin(), puzzle_values[i].end()); + } + + assert(input_as_bits.size() == input_size_in_bits); + unpack_inputs.reset(new multipacking_gadget(this->pb, input_as_bits, input_as_field_elements, FieldT::capacity(), FMT(this->annotation_prefix, " unpack_inputs"))); +} + +template +void l_gadget::generate_r1cs_constraints() +{ + unpack_inputs->generate_r1cs_constraints(true); +} + +template +void l_gadget::generate_r1cs_witness(std::vector &input_puzzle_values) +{ + assert(input_puzzle_values.size() == dimension*dimension); + for (unsigned int i = 0; i < dimension*dimension; i++) { + assert(input_puzzle_values[i].size() == 8); + puzzle_values[i].fill_with_bits(this->pb, input_puzzle_values[i]); + } + + unpack_inputs->generate_r1cs_witness_from_bits(); +} + +template +r1cs_primary_input l_input_map(unsigned int n, std::vector &input_puzzle_values) +{ + assert(input_puzzle_values.size() == n*n); + bit_vector input_as_bits; + + for (unsigned int i = 0; i < n*n; i++) { + assert(input_puzzle_values[i].size() == 8); + input_as_bits.insert(input_as_bits.end(), input_puzzle_values[i].begin(), input_puzzle_values[i].end()); + } + std::vector input_as_field_elements = pack_bit_vector_into_field_element_vector(input_as_bits); + return input_as_field_elements; +} \ No newline at end of file diff --git a/src/snark.hpp b/src/snark.hpp new file mode 100644 index 0000000..7216380 --- /dev/null +++ b/src/snark.hpp @@ -0,0 +1,25 @@ +#include "libsnark/gadgetlib1/gadgets/basic_gadgets.hpp" +#include "libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" +#include "libsnark/common/default_types/r1cs_ppzksnark_pp.hpp" +#include "libsnark/common/utils.hpp" +#include + +using namespace libsnark; + +std::vector> convertPuzzleToBool(std::vector); + +template +r1cs_ppzksnark_keypair generate_keypair(); + +template +boost::optional> generate_proof(r1cs_ppzksnark_proving_key proving_key, + std::vector &puzzle + ); + +template +bool verify_proof(r1cs_ppzksnark_verification_key verification_key, + r1cs_ppzksnark_proof proof, + std::vector &puzzle + ); + +#include "snark.tcc" diff --git a/src/snark.tcc b/src/snark.tcc new file mode 100644 index 0000000..485cc3f --- /dev/null +++ b/src/snark.tcc @@ -0,0 +1,76 @@ +#include "gadget.hpp" + +using namespace std; + +std::vector convertIntToVector(uint8_t val) { + std::vector ret; + + for(unsigned int i = 0; i < sizeof(val) * 8; ++i, val >>= 1) { + ret.push_back(val & 0x01); + } + + reverse(ret.begin(), ret.end()); + return ret; +} + +std::vector> convertPuzzleToBool(std::vector puzzle) { + std::vector> new_puzzle; + + for(vector::iterator it = puzzle.begin(); it != puzzle.end(); ++it) { + new_puzzle.insert(new_puzzle.end(), convertIntToVector(*it)); + } + + return new_puzzle; +} + +template +r1cs_ppzksnark_keypair generate_keypair() +{ + typedef Fr FieldT; + + protoboard pb; + l_gadget g(pb, 9); + g.generate_r1cs_constraints(); + const r1cs_constraint_system constraint_system = pb.get_constraint_system(); + + cout << "Number of R1CS constraints: " << constraint_system.num_constraints() << endl; + + return r1cs_ppzksnark_generator(constraint_system); +} + +template +boost::optional> generate_proof(r1cs_ppzksnark_proving_key proving_key, + vector &puzzle + ) +{ + typedef Fr FieldT; + + protoboard pb; + l_gadget g(pb, 9); + g.generate_r1cs_constraints(); + + auto new_puzzle = convertPuzzleToBool(puzzle); + + g.generate_r1cs_witness(new_puzzle); + + if (!pb.is_satisfied()) { + return boost::none; + } + + return r1cs_ppzksnark_prover(proving_key, pb.primary_input(), pb.auxiliary_input()); +} + +template +bool verify_proof(r1cs_ppzksnark_verification_key verification_key, + r1cs_ppzksnark_proof proof, + vector &puzzle + ) +{ + typedef Fr FieldT; + + auto new_puzzle = convertPuzzleToBool(puzzle); + + const r1cs_primary_input input = l_input_map(9, new_puzzle); + + return r1cs_ppzksnark_verifier_strong_IC(verification_key, input, proof); +} \ No newline at end of file diff --git a/src/test.cpp b/src/test.cpp new file mode 100644 index 0000000..4053117 --- /dev/null +++ b/src/test.cpp @@ -0,0 +1,35 @@ +#include +#include + +#include "snark.hpp" +#include "test.h" + +using namespace libsnark; +using namespace std; + +int main() +{ + // Initialize the curve parameters. + default_r1cs_ppzksnark_pp::init_public_params(); + // Generate the verifying/proving keys. (This is trusted setup!) + auto keypair = generate_keypair(); + + // Run test vectors. + assert(run_test(keypair)); +} + +bool run_test(r1cs_ppzksnark_keypair& keypair + ) { + vector v(81, 0); + + cout << "Trying to generate proof..." << endl; + auto proof = generate_proof(keypair.pk, v); + cout << "Proof generated!" << endl; + + if (!proof) { + return false; + } else { + assert(verify_proof(keypair.vk, *proof, v)); + return true; + } +} diff --git a/src/test.h b/src/test.h new file mode 100644 index 0000000..025345a --- /dev/null +++ b/src/test.h @@ -0,0 +1,3 @@ + +bool run_test(r1cs_ppzksnark_keypair& keypair + );