diff --git a/.gitignore b/.gitignore index 41d2545..a96ef09 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ build/ bin/ +.keys/ *.pyc *.swp *.swo diff --git a/CMakeLists.txt b/CMakeLists.txt index cc306d8..c2462a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,10 @@ -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 3.8) project(ethsnarks) -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/bin) +include(CTest) +enable_testing() set( @@ -38,6 +39,14 @@ set( "Optionally specify the dependency installation directory relative to the source directory (default: inside dependency folder)" ) +set( + DEPENDS_DIR_LIBFQFFT + "${DEPENDS_DIR_LIBSNARK}/depends/libfqfft/" + CACHE + STRING + "Optionally specify the dependency installation directory relative to the source directory (default: inside dependency folder)" +) + set( OPT_FLAGS "" @@ -142,7 +151,7 @@ endif() if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") # Common compilation flags and warning configuration - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wfatal-errors -Wno-unused-variable") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wfatal-errors -Wno-unused-variable") if("${MULTICORE}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp") endif() @@ -195,13 +204,9 @@ else() add_definitions(-DNO_PROCPS) endif() +set(OPENSSL_ROOT_DIR /usr/local/opt/openssl/) find_package(OpenSSL REQUIRED) -include_directories( - ${DEPENDS_DIR}/libsnark - ${DEPENDS_DIR}/libsnark/depends/libff - ${DEPENDS_DIR}/libsnark/depends/libfqfft) - add_library( ff @@ -217,6 +222,14 @@ add_library( ${DEPENDS_DIR_LIBFF}/libff/common/utils.cpp ) +target_include_directories(ff PUBLIC + ${DEPENDS_DIR_LIBSNARK} ${DEPENDS_DIR_LIBFF} ${DEPENDS_DIR_LIBFQFFT}) +target_compile_features(ff PUBLIC cxx_std_11) + +target_include_directories(ff INTERFACE + ${DEPENDS_DIR_LIBSNARK} ${DEPENDS_DIR_LIBFF} ${DEPENDS_DIR_LIBFQFFT}) +target_compile_features(ff INTERFACE cxx_std_11) + target_link_libraries(ff GMP::gmp ${PROCPS_LIBRARIES}) add_subdirectory(src) diff --git a/Makefile b/Makefile index 4ffe6d8..b195878 100644 --- a/Makefile +++ b/Makefile @@ -19,17 +19,19 @@ PIP_ARGS ?= --user PYTHON ?= python3 NAME ?= ethsnarks NPM ?= npm + GANACHE ?= $(ROOT_DIR)/node_modules/.bin/ganache-cli TRUFFLE ?= $(ROOT_DIR)/node_modules/.bin/truffle COVERAGE = $(PYTHON) -mcoverage run --source=$(NAME) -p +PINOCCHIO = build/src/pinocchio/pinocchio PINOCCHIO_TESTS=$(wildcard test/pinocchio/*.circuit) ####################################################################### -all: build/src/libmiximus.$(DLL_EXT) truffle-compile +all: node_modules build/src/verify truffle-compile clean: coverage-clean python-clean rm -rf build @@ -41,12 +43,6 @@ clean: coverage-clean python-clean build: depends/libsnarks/CMakeLists.txt mkdir -p build -bin/miximus_genKeys: build/Makefile - make -C build - -build/src/libmiximus.$(DLL_EXT): build/Makefile - make -C build - cmake-debug: build cd build && cmake -DCMAKE_BUILD_TYPE=Debug .. @@ -57,6 +53,9 @@ release: cmake-release all debug: cmake-debug all +build/src/verify: build/Makefile + make -C build + build/Makefile: build CMakeLists.txt cd build && cmake .. @@ -68,49 +67,23 @@ depends/libsnarks/CMakeLists.txt: .PHONY: test -test: pinocchio-test cxx-tests python-test truffle-test +test: pinocchio-test cxx-tests hashpreimage-tests python-test truffle-test python-test: $(COVERAGE) -m unittest discover test/ -cxx-tests-gadgets: - ./bin/test_field_packing > /dev/null - ./bin/test_hashpreimage - ./bin/test_longsightl - ./bin/test_longsightl_hash_mp - ./bin/test_merkle_tree - ./bin/test_one_of_n - ./bin/test_r1cs_gg_ppzksnark_zok - ./bin/test_shamir_poly - ./bin/test_sha256_full_gadget - ./bin/test_sha256_many > /dev/null - ./bin/test_lookup_1bit - ./bin/test_lookup_2bit - ./bin/test_lookup_3bit - ./bin/test_subadd > /dev/null - ./bin/test_isnonzero - ./bin/test_field2bits - -cxx-tests-jubjub: - ./bin/test_jubjub_add - ./bin/test_jubjub_dbl - ./bin/test_jubjub_mul - ./bin/test_jubjub_mul_fixed - ./bin/test_jubjub_mul_fixed_zcash - ./bin/test_jubjub_point - ./bin/test_jubjub_isoncurve > /dev/null - ./bin/test_jubjub_hash - ./bin/test_jubjub_eddsa - -cxx-tests: zksnark_element/miximus.vk.json cxx-tests-gadgets cxx-tests-jubjub - time ./bin/hashpreimage_cli genkeys zksnark_element/hpi.pk.raw zksnark_element/hpi.vk.json - ls -lah zksnark_element/hpi.pk.raw - time ./bin/hashpreimage_cli prove zksnark_element/hpi.pk.raw 0x9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a089f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08 zksnark_element/hpi.proof.json - time ./bin/hashpreimage_cli verify zksnark_element/hpi.vk.json zksnark_element/hpi.proof.json - time ./bin/test_load_proofkey zksnark_element/hpi.pk.raw - -zksnark_element/miximus.vk.json: - time ./bin/miximus_cli genkeys zksnark_element/miximus.pk.raw zksnark_element/miximus.vk.json +cxx-tests: + make -C build test + +.keys: + mkdir -p $@ + +hashpreimage-tests: .keys + time ./build/src/hashpreimage_cli genkeys .keys/hpi.pk.raw .keys/hpi.vk.json + ls -lah .keys/hpi.pk.raw + time ./build/src/hashpreimage_cli prove .keys/hpi.pk.raw 0x9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a089f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08 .keys/hpi.proof.json + time ./build/src/hashpreimage_cli verify .keys/hpi.vk.json .keys/hpi.proof.json + time ./build/src/test/benchmark/benchmark_load_proofkey .keys/hpi.pk.raw ####################################################################### @@ -122,8 +95,8 @@ pinocchio-test: $(addsuffix .result, $(basename $(PINOCCHIO_TESTS))) pinocchio-clean: rm -f test/pinocchio/*.result -test/pinocchio/%.result: test/pinocchio/%.circuit test/pinocchio/%.test test/pinocchio/%.input ./bin/pinocchio - ./bin/pinocchio $< eval $(basename $<).input > $@ +test/pinocchio/%.result: test/pinocchio/%.circuit test/pinocchio/%.test test/pinocchio/%.input $(PINOCCHIO) + $(PINOCCHIO) $< eval $(basename $<).input > $@ diff -ru $(basename $<).test $@ || rm $@ @@ -182,7 +155,7 @@ ubuntu-dependencies: apt-get install cmake make g++ libgmp-dev libboost-all-dev libprocps-dev python3-pip mac-dependencies: - brew install pkg-config boost cmake gmp openssl || true + brew install python3 pkg-config boost cmake gmp openssl || true ####################################################################### @@ -202,12 +175,8 @@ nvm-install: node_modules: $(NPM) install -$(TRUFFLE): node_modules - -$(GANACHE): node_modules - .PHONY: truffle-test -truffle-test: $(TRUFFLE) zksnark_element/miximus.vk.json +truffle-test: $(TRUFFLE) $(NPM) run test truffle-migrate: $(TRUFFLE) diff --git a/README.md b/README.md index a9c0ecc..37e2ed5 100644 --- a/README.md +++ b/README.md @@ -18,22 +18,11 @@ EthSnarks is participating in the Ethereum Foundation's grants program Wave 4, o ## Examples -### Miximus - -Miximus is a self-service coin mixer and anonymous transfer method for Ethereum, it accepts deposits of 1 ETH, then allows you to withdraw coins by providing a zkSNARK proof that proves you know the spend key for one unspent coin without revealing which one it is. - -For more information, see: - - * [Miximus.sol](contracts/Miximus.sol) - * [miximus.py](ethsnarks/mod/miximus.py) - * [test_miximus.py](test/test_miximus.py) - * [miximus.cpp](src/mod/miximus.cpp) - -The zkSNARK prover is built as a native library which can plug-in to your application, when provided with the correct arguments it returns the zkSNARK proof as JSON. While you may think of zkSNARKs as being slow - the algorithms chosen for Miximus mean proofs can be made in 5 seconds, however we're still studying their security properties. + * [Miximus - a self-service coin mixer and anonymous transfer method for Ethereum](https://github.com/HarryR/ethsnarks-miximus) ## Building -[![Build Status](https://travis-ci.org/HarryR/ethsnarks.svg?branch=master)](https://travis-ci.org/HarryR/ethsnarks) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/137909bd889347728818d0aa5570fa9a)](https://www.codacy.com/project/HarryR/ethsnarks/dashboard?utm_source=github.com&utm_medium=referral&utm_content=HarryR/ethsnarks&utm_campaign=Badge_Grade_Dashboard) [![BCH compliance](https://bettercodehub.com/edge/badge/HarryR/ethsnarks?branch=master)](https://bettercodehub.com/) +[![Build Status](https://travis-ci.org/HarryR/ethsnarks.svg?branch=master)](https://travis-ci.org/HarryR/ethsnarks) [![BCH compliance](https://bettercodehub.com/edge/badge/HarryR/ethsnarks?branch=master)](https://bettercodehub.com/) Type `make` - the first time you run it will retrieve submodules, setup cmake and build everything, for more information about the build process see the [Travis-CI build logs](https://travis-ci.org/HarryR/ethsnarks). diff --git a/ethsnarks/mod/miximus.py b/ethsnarks/mod/miximus.py deleted file mode 100644 index 258e646..0000000 --- a/ethsnarks/mod/miximus.py +++ /dev/null @@ -1,90 +0,0 @@ -__all__ = ('Miximus',) - -import os -import re -import ctypes - -from ..verifier import Proof, VerifyingKey - - -class Miximus(object): - def __init__(self, native_library_path, vk, pk_file=None): - if pk_file: - if not os.path.exists(pk_file): - raise RuntimeError("Proving key file doesnt exist: " + pk_file) - self._pk_file = pk_file - - if not isinstance(vk, VerifyingKey): - if isinstance(vk, dict): - vk = VerifyingKey.from_dict(vk) - elif os.path.exists(vk): - vk = VerifyingKey.from_file(vk) - else: - vk = VerifyingKey.from_json(vk) - if not isinstance(vk, VerifyingKey): - raise TypeError("Invalid vk type") - self._vk = vk - - lib = ctypes.cdll.LoadLibrary(native_library_path) - - lib_tree_depth = lib.miximus_tree_depth - lib_tree_depth.restype = ctypes.c_size_t - self.tree_depth = lib_tree_depth() - assert self.tree_depth > 0 - assert self.tree_depth < 32 - - lib_prove = lib.miximus_prove - lib_prove.argtypes = ([ctypes.c_char_p] * 6) + [(ctypes.c_char_p * self.tree_depth)] - lib_prove.restype = ctypes.c_char_p - self._prove = lib_prove - - lib_verify = lib.miximus_verify - lib_verify.argtypes = [ctypes.c_char_p, ctypes.c_char_p] - lib_verify.restype = ctypes.c_bool - self._verify = lib_verify - - def prove(self, root, nullifier, spend_preimage, exthash, address_bits, path, pk_file=None): - assert isinstance(path, (list, tuple)) - assert len(path) == self.tree_depth - if isinstance(address_bits, (tuple, list)): - address_bits = ''.join([str(_) for _ in address_bits]) - assert re.match(r'^[01]+$', address_bits) - assert len(address_bits) == self.tree_depth - assert isinstance(root, int) - assert isinstance(nullifier, int) - assert isinstance(spend_preimage, int) - assert isinstance(exthash, int) - # TODO: require root, nullifier, spend_preimage and exthash are ints within curve order range - - if pk_file is None: - pk_file = self._pk_file - if pk_file is None: - raise RuntimeError("No proving key file") - - # Public parameters - root = ctypes.c_char_p(str(root).encode('ascii')) - nullifier = ctypes.c_char_p(str(nullifier).encode('ascii')) - exthash = ctypes.c_char_p(str(exthash).encode('ascii')) - - # Private parameters - spend_preimage = ctypes.c_char_p(str(spend_preimage).encode('ascii')) - address_bits = ctypes.c_char_p(address_bits.encode('ascii')) - path = [ctypes.c_char_p(str(_).encode('ascii')) for _ in path] - path_carr = (ctypes.c_char_p * len(path))() - path_carr[:] = path - - pk_file_cstr = ctypes.c_char_p(pk_file.encode('ascii')) - - data = self._prove(pk_file_cstr, root, nullifier, exthash, spend_preimage, address_bits, path_carr) - if data is None: - raise RuntimeError("Could not prove!") - return Proof.from_json(data) - - def verify(self, proof): - if not isinstance(proof, Proof): - raise TypeError("Invalid proof type") - - vk_cstr = ctypes.c_char_p(self._vk.to_json().encode('ascii')) - proof_cstr = ctypes.c_char_p(proof.to_json().encode('ascii')) - - return self._verify( vk_cstr, proof_cstr ) diff --git a/migrations/2_deploy_contracts.js b/migrations/2_deploy_contracts.js deleted file mode 100644 index 3b4812c..0000000 --- a/migrations/2_deploy_contracts.js +++ /dev/null @@ -1,42 +0,0 @@ -const Verifier = artifacts.require('Verifier.sol'); -const TestableMiximus = artifacts.require('TestableMiximus.sol'); - - - -let list_flatten = (l) => { - return [].concat.apply([], l); -}; - - -let vk_to_flat = (vk) => { - return [ - list_flatten([ - vk.alpha[0], vk.alpha[1], - list_flatten(vk.beta), - list_flatten(vk.gamma), - list_flatten(vk.delta), - ]), - list_flatten(vk.gammaABC) - ]; -}; - - -async function doDeploy( deployer, network ) -{ - await deployer.deploy(Verifier); - await deployer.link(Verifier, TestableMiximus); - - var vk = require('../zksnark_element/miximus.vk.json'); - let [vk_flat, vk_flat_IC] = vk_to_flat(vk); - await deployer.deploy(TestableMiximus, - vk_flat, - vk_flat_IC - ); -} - - -module.exports = function (deployer, network) { - deployer.then(async () => { - await doDeploy(deployer, network); - }); -}; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b5fcfa8..078b9d9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,27 +3,12 @@ include_directories(.) add_library(ethsnarks_common STATIC export.cpp import.cpp stubs.cpp utils.cpp) target_link_libraries(ethsnarks_common ff) - -add_library(miximus_objs OBJECT mod/miximus.cpp) - -add_library(miximus_static STATIC $) -target_link_libraries(miximus_static ethsnarks_gadgets) - - -add_library(miximus SHARED $) -target_link_libraries(miximus ethsnarks_gadgets) -set_property(TARGET miximus PROPERTY POSITION_INDEPENDENT_CODE ON) - +target_include_directories(ethsnarks_common PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) add_library(hashpreimage SHARED mod/hashpreimage.cpp) target_link_libraries(hashpreimage ethsnarks_gadgets) set_property(TARGET hashpreimage PROPERTY POSITION_INDEPENDENT_CODE ON) - -add_executable(miximus_cli miximus_cli.cpp) -target_link_libraries(miximus_cli miximus_static) - - add_executable(hashpreimage_cli hashpreimage_cli.cpp) target_link_libraries(hashpreimage_cli ethsnarks_gadgets) diff --git a/src/export.cpp b/src/export.cpp index b046c8e..d189749 100644 --- a/src/export.cpp +++ b/src/export.cpp @@ -1,30 +1,9 @@ -/* - copyright 2018 to the Semaphore Authors - - This file is part of Semaphore. - - Semaphore is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Semaphore is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Semaphore. If not, see . -*/ - #include #include #include #include -#include - #include "ethsnarks.hpp" namespace ethsnarks { @@ -46,18 +25,15 @@ std::string HexStringFromBigint(libff::bigint _x){ } -std::string outputPointG1AffineAsHex(libff::alt_bn128_G1 _p) +std::string outputPointG1AffineAsHex(G1T _p) { - G1T aff = _p; + auto aff = _p; aff.to_affine_coordinates(); - //std::stringstream ss; - //ss << "0x" << aff.X.as_bigint() << "," << aff.Y.as_bigint() << "," << aff.Z.as_bigint(); - return "\"0x" + HexStringFromBigint(aff.X.as_bigint()) + "\", \"0x" + HexStringFromBigint(aff.Y.as_bigint()) + "\""; } -std::string outputPointG2AffineAsHex(libff::alt_bn128_G2 _p) +std::string outputPointG2AffineAsHex(G2T _p) { G2T aff = _p; diff --git a/src/gadgets/CMakeLists.txt b/src/gadgets/CMakeLists.txt index 62550fa..a61f4cb 100644 --- a/src/gadgets/CMakeLists.txt +++ b/src/gadgets/CMakeLists.txt @@ -18,4 +18,5 @@ add_library(ethsnarks_gadgets STATIC isnonzero.cpp field2bits_strict.cpp ) -target_link_libraries(ethsnarks_gadgets ethsnarks_common ${OPENSSL_CRYPTO_LIBRARY}) \ No newline at end of file +target_link_libraries(ethsnarks_gadgets ethsnarks_common OpenSSL::Crypto) +target_compile_features(ethsnarks_gadgets PUBLIC cxx_std_11) \ No newline at end of file diff --git a/src/jubjub/CMakeLists.txt b/src/jubjub/CMakeLists.txt index d02489a..f7b7122 100644 --- a/src/jubjub/CMakeLists.txt +++ b/src/jubjub/CMakeLists.txt @@ -17,4 +17,4 @@ add_library(ethsnarks_jubjub STATIC eddsa.cpp ) -target_link_libraries(ethsnarks_jubjub ethsnarks_gadgets) +target_link_libraries(ethsnarks_jubjub ethsnarks_gadgets) \ No newline at end of file diff --git a/src/miximus_cli.cpp b/src/miximus_cli.cpp deleted file mode 100644 index 114eae7..0000000 --- a/src/miximus_cli.cpp +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2018 HarryR -// License: GPL-3.0+ - -#include -#include // cerr -#include // ofstream - -#include "mod/miximus.cpp" -#include "stubs.hpp" -#include "utils.hpp" // hex_to_bytes - - -using std::cerr; -using std::cout; -using std::endl; -using std::ofstream; - -using ethsnarks::stub_main_genkeys; -using ethsnarks::stub_main_verify; -using ethsnarks::mod_miximus; - - -static int main_prove( int argc, char **argv ) -{ - if( argc < (9 + (int)MIXIMUS_TREE_DEPTH) ) - { - cerr << "Usage: " << argv[0] << " prove " << endl; - cerr << "Args: " << endl; - cerr << "\t Path to proving key" << endl; - cerr << "\t Write proof to this file" << endl; - cerr << "\t Merkle tree root" << endl; - cerr << "\t Nullifier" << endl; - cerr << "\t Hash of external variables" << endl; - cerr << "\t Spend preimage" << endl; - cerr << "\t 0 and 1 bits for tree path" << endl; - cerr << "\t items for merkle tree path" << endl; - return 1; - } - - auto pk_filename = argv[2]; - auto proof_filename = argv[3]; - auto arg_root = argv[4]; - auto arg_nullifier = argv[5]; - auto arg_exthash = argv[6]; - auto arg_preimage = argv[7]; - auto arg_address = argv[8]; - - const char *arg_path[MIXIMUS_TREE_DEPTH]; - for( size_t i = 0; i < MIXIMUS_TREE_DEPTH; i++ ) { - arg_path[i] = argv[9 + i]; - } - - auto json = miximus_prove(pk_filename, arg_root, arg_nullifier, arg_exthash, arg_preimage, arg_address, arg_path); - - ofstream fh; - fh.open(proof_filename, std::ios::binary); - fh << json; - fh.flush(); - fh.close(); - - return 0; -} - - -int main( int argc, char **argv ) -{ - if( argc < 2 ) - { - cerr << "Usage: " << argv[0] << " [...]" << endl; - return 1; - } - - if( 0 == ::strcmp(argv[1], "prove") ) - { - return main_prove(argc, argv); - } - else if( 0 == ::strcmp(argv[1], "genkeys") ) - { - return stub_main_genkeys(argv[0], argc-1, &argv[1]); - } - else if( 0 == ::strcmp(argv[1], "verify") ) - { - return stub_main_verify(argv[0], argc-1, (const char **)&argv[1]); - } - - cerr << "Error: unknown sub-command " << argv[1] << endl; - return 2; -} diff --git a/src/mod/miximus.cpp b/src/mod/miximus.cpp deleted file mode 100644 index 1d62f72..0000000 --- a/src/mod/miximus.cpp +++ /dev/null @@ -1,221 +0,0 @@ -/* - copyright 2018 to the Semaphore Authors - - This file is part of Semaphore. - - Semaphore is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Semaphore is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Semaphore. If not, see . -*/ - -#include "miximus.hpp" -#include "export.hpp" -#include "import.hpp" -#include "stubs.hpp" -#include "utils.hpp" - -#include "gadgets/longsightl.hpp" -#include "gadgets/merkle_tree.cpp" - - -using libsnark::generate_r1cs_equals_const_constraint; -using libff::convert_field_element_to_bit_vector; -using ethsnarks::ppT; -using ethsnarks::FieldT; -using ethsnarks::ProtoboardT; -using ethsnarks::ProvingKeyT; - -const size_t MIXIMUS_TREE_DEPTH = 29; - -namespace ethsnarks { - -/** -* -*/ -class mod_miximus : public GadgetT -{ -public: - typedef LongsightL12p5_MP_gadget HashT; - const size_t tree_depth = MIXIMUS_TREE_DEPTH; - - - // public inputs - const VariableT root_var; - const VariableT nullifier_var; - const VariableT external_hash_var; - - // public constants - const VariableArrayT m_IVs; - - // constant inputs - const VariableT spend_hash_IV; - const VariableT leaf_hash_IV; - - // private inputs - const VariableT spend_preimage_var; - const VariableArrayT address_bits; - const VariableArrayT path_var; - - // logic gadgets - HashT spend_hash; - HashT leaf_hash; - - merkle_path_authenticator m_authenticator; - - - mod_miximus( - ProtoboardT &in_pb, - const std::string &annotation_prefix - ) : - GadgetT(in_pb, annotation_prefix), - - // public inputs - root_var(make_variable(in_pb, FMT(annotation_prefix, ".root_var"))), - nullifier_var(make_variable(in_pb, FMT(annotation_prefix, ".nullifier_var"))), - external_hash_var(make_variable(in_pb, FMT(annotation_prefix, ".external_hash_var"))), - - // Initialisation vector for merkle tree - // Hard-coded constants - // Means that H('a', 'b') on level1 will have a different output than the same values on level2 - m_IVs(merkle_tree_IVs(in_pb)), - - // constant inputs - spend_hash_IV(make_variable(in_pb, FMT(annotation_prefix, ".spend_hash_IV"))), - leaf_hash_IV(make_variable(in_pb, FMT(annotation_prefix, ".leaf_hash_IV"))), - - // private inputs - spend_preimage_var(make_variable(in_pb, FMT(annotation_prefix, ".spend_preimage_var"))), - address_bits(make_var_array(in_pb, tree_depth, FMT(annotation_prefix, ".address_bits")) ), - path_var(make_var_array(in_pb, tree_depth, FMT(annotation_prefix, ".path"))), - - // logic gadgets - spend_hash(in_pb, spend_hash_IV, {spend_preimage_var, nullifier_var}, FMT(annotation_prefix, ".spend_hash")), - leaf_hash(in_pb, leaf_hash_IV, {nullifier_var, spend_hash.result()}, FMT(annotation_prefix, ".leaf_hash")), - m_authenticator(in_pb, tree_depth, address_bits, m_IVs, leaf_hash.result(), root_var, path_var, FMT(annotation_prefix, ".authenticator")) - { - in_pb.set_input_sizes( 3 ); - - // TODO: verify that inputs are expected publics - } - - void generate_r1cs_constraints() - { - spend_hash.generate_r1cs_constraints(); - leaf_hash.generate_r1cs_constraints(); - m_authenticator.generate_r1cs_constraints(); - } - - void generate_r1cs_witness( - FieldT in_root, // merkle tree root - FieldT in_nullifier, // unique linkable tag - FieldT in_exthash, // hash of external parameters - FieldT in_preimage, // spend preimage - libff::bit_vector in_address, - std::vector &in_path - ) { - // public inputs - this->pb.val(root_var) = in_root; - this->pb.val(nullifier_var) = in_nullifier; - this->pb.val(external_hash_var) = in_exthash; - - // private inputs - this->pb.val(spend_preimage_var) = in_preimage; - address_bits.fill_with_bits(this->pb, in_address); - - for( size_t i = 0; i < tree_depth; i++ ) { - this->pb.val(path_var[i]) = in_path[i]; - } - - // gadgets - spend_hash.generate_r1cs_witness(); - leaf_hash.generate_r1cs_witness(); - m_authenticator.generate_r1cs_witness(); - } -}; - -// namespace ethsnarks -} - - -size_t miximus_tree_depth( void ) { - return MIXIMUS_TREE_DEPTH; -} - - -char *miximus_prove( - const char *pk_file, - const char *in_root, - const char *in_nullifier, - const char *in_exthash, - const char *in_spend_preimage, - const char *in_address, - const char **in_path -) { - ppT::init_public_params(); - - FieldT arg_root(in_root); - FieldT arg_nullifier(in_nullifier); - FieldT arg_exthash(in_exthash); - FieldT arg_spend_preimage(in_spend_preimage); - - // Fill address bits with 0s and 1s from str - libff::bit_vector address_bits; - address_bits.resize(MIXIMUS_TREE_DEPTH); - if( strlen(in_address) != MIXIMUS_TREE_DEPTH ) - { - std::cerr << "Address length doesnt match depth" << std::endl; - return nullptr; - } - for( size_t i = 0; i < MIXIMUS_TREE_DEPTH; i++ ) { - if( in_address[i] != '0' and in_address[i] != '1' ) { - std::cerr << "Address bit " << i << " invalid, unknown: " << in_address[i] << std::endl; - return nullptr; - } - address_bits[i] = '0' - in_address[i]; - } - - - // Fill path from field elements from in_path - std::vector arg_path; - arg_path.resize(MIXIMUS_TREE_DEPTH); - for( size_t i = 0; i < MIXIMUS_TREE_DEPTH; i++ ) { - assert( in_path[i] != nullptr ); - arg_path[i] = FieldT(in_path[i]); - } - - ProtoboardT pb; - ethsnarks::mod_miximus mod(pb, "module"); - mod.generate_r1cs_constraints(); - mod.generate_r1cs_witness(arg_root, arg_nullifier, arg_exthash, arg_spend_preimage, address_bits, arg_path); - - if( ! pb.is_satisfied() ) - { - std::cerr << "Not Satisfied!" << std::endl; - return nullptr; - } - - auto json = ethsnarks::stub_prove_from_pb(pb, pk_file); - - return ::strdup(json.c_str()); -} - - -int miximus_genkeys( const char *pk_file, const char *vk_file ) -{ - return ethsnarks::stub_genkeys(pk_file, vk_file); -} - - -bool miximus_verify( const char *vk_json, const char *proof_json ) -{ - return ethsnarks::stub_verify( vk_json, proof_json ); -} diff --git a/src/mod/miximus.hpp b/src/mod/miximus.hpp deleted file mode 100644 index 855ee8e..0000000 --- a/src/mod/miximus.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef MIXIMUS_HPP_ -#define MIXIMUS_HPP_ - -#pragma once - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -const extern size_t MIXIMUS_TREE_DEPTH; - -char *miximus_prove( - const char *pk_file, - const char *in_root, - const char *in_nullifier, - const char *in_exthash, - const char *in_spend_preimage, - const char *in_address, - const char **in_path -); - -int miximus_genkeys( const char *pk_file, const char *vk_file ); - -bool miximus_verify( const char *vk_json, const char *proof_json ); - -size_t miximus_tree_depth( void ); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/pinocchio/CMakeLists.txt b/src/pinocchio/CMakeLists.txt index 0096e61..9aa3d78 100644 --- a/src/pinocchio/CMakeLists.txt +++ b/src/pinocchio/CMakeLists.txt @@ -1,11 +1,11 @@ add_library(ethsnarks_pinocchio STATIC circuit_reader.cpp ) - +target_link_libraries(ethsnarks_pinocchio ethsnarks_common) add_executable(pinocchio main.cpp) -target_link_libraries(pinocchio ethsnarks_common ethsnarks_pinocchio) +target_link_libraries(pinocchio ethsnarks_pinocchio) add_executable(jsnark_test jsnark_test.cpp) -target_link_libraries(jsnark_test ethsnarks_common ethsnarks_pinocchio) +target_link_libraries(jsnark_test ethsnarks_pinocchio) diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 0e3cb9d..ed2613b 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -8,4 +8,5 @@ foreach(test_path ${test_sources}) string(REPLACE ".cpp" "" test_executable ${test_name}) add_executable(${test_executable} ${test_name}) target_link_libraries(${test_executable} ethsnarks_gadgets) + add_test(NAME run_${test_executable} COMMAND ${test_executable}) endforeach() diff --git a/src/test/benchmark/CMakeLists.txt b/src/test/benchmark/CMakeLists.txt index 83e2efe..6b728ca 100644 --- a/src/test/benchmark/CMakeLists.txt +++ b/src/test/benchmark/CMakeLists.txt @@ -1,5 +1,8 @@ -add_executable(benchmark_mpz_mul benchmark_mpz_mul.cpp) -target_link_libraries(benchmark_mpz_mul ff) +file(GLOB test_sources "*.cpp") -add_executable(benchmark_pairing benchmark_pairing.cpp) -target_link_libraries(benchmark_pairing ff) +foreach(test_path ${test_sources}) + get_filename_component(test_name ${test_path} NAME) + string(REPLACE ".cpp" "" test_executable ${test_name}) + add_executable(${test_executable} ${test_name}) + target_link_libraries(${test_executable} ff) +endforeach() diff --git a/src/test/test_load_proofkey.cpp b/src/test/benchmark/benchmark_load_proofkey.cpp similarity index 100% rename from src/test/test_load_proofkey.cpp rename to src/test/benchmark/benchmark_load_proofkey.cpp diff --git a/src/test/jubjub/CMakeLists.txt b/src/test/jubjub/CMakeLists.txt index 02b3bf9..82fbd09 100644 --- a/src/test/jubjub/CMakeLists.txt +++ b/src/test/jubjub/CMakeLists.txt @@ -5,4 +5,5 @@ foreach(test_path ${test_sources}) string(REPLACE ".cpp" "" test_executable ${test_name}) add_executable(${test_executable} ${test_name}) target_link_libraries(${test_executable} ethsnarks_jubjub) + add_test(NAME run_${test_executable} COMMAND ${test_executable}) endforeach() diff --git a/src/test/test_proof_raw2json.cpp b/src/test/test_proof_raw2json.cpp deleted file mode 100644 index a8217b9..0000000 --- a/src/test/test_proof_raw2json.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include "export.hpp" -#include "import.hpp" -#include "utils.hpp" - - -using std::cout; -using std::cerr; -using std::endl; -using std::ifstream; -using std::stringstream; - -using ethsnarks::ppT; -using ethsnarks::ProofT; -using ethsnarks::proof_to_json; -using ethsnarks::proof_from_json; -using ethsnarks::loadFromFile; - - -int main( int argc, char **argv ) -{ - ppT::init_public_params(); - - if( argc < 3 ) { - cerr << "Usage: " << argv[0] << " " << endl; - return 1; - } - - ifstream original_proof_input(argv[1]); - stringstream original_proof_stream; - original_proof_stream << original_proof_input.rdbuf(); - auto original_proof_json = proof_from_json(original_proof_stream); - - // Load raw serialised proof - auto proof = loadFromFile (argv[2]); - - // Dump JSON serialised proof - auto proof_json_serialised = proof_to_json(proof, original_proof_json.first); - - // Load JSON serialised proof - stringstream proof_stream; - proof_stream << proof_json_serialised; - auto proof_json = proof_from_json(proof_stream); - - // Verify serialisation is correct - if( ! (proof_json.second == proof) ) { - cerr << "FAIL\n"; - return 1; - } - - cout << "OK"; - return 0; -} \ No newline at end of file diff --git a/src/test/test_vk_raw2json.cpp b/src/test/test_vk_raw2json.cpp deleted file mode 100644 index eee4da3..0000000 --- a/src/test/test_vk_raw2json.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include "export.hpp" -#include "import.hpp" -#include "utils.hpp" - -using std::cout; -using std::cerr; -using ethsnarks::vk2json_file; -using ethsnarks::ppT; -using ethsnarks::VerificationKeyT; -using ethsnarks::vk_from_json; -using ethsnarks::loadFromFile; - -int main( int argc, char **argv ) -{ - ppT::init_public_params(); - - if( argc < 3 ) { - fprintf(stderr, "Usage: %s \n", argv[0]); - return 1; - } - - // Load raw serialised VK - auto vk = loadFromFile (argv[1]); - - // Dump JSON serialised VK - vk2json_file(vk, argv[2]); - - // Load JSON serialised VK - std::ifstream vk_input(argv[2]); - std::stringstream vk_stream; - vk_stream << vk_input.rdbuf(); - auto vk_json = vk_from_json(vk_stream); - - // Verify serialisation is correct - if( ! (vk_json == vk) ) { - cerr << "FAIL\n"; - return 1; - } - - cout << "OK"; - return 0; -} \ No newline at end of file diff --git a/test/TestMiximus.js b/test/TestMiximus.js deleted file mode 100644 index 514bf78..0000000 --- a/test/TestMiximus.js +++ /dev/null @@ -1,175 +0,0 @@ -const TestableMiximus = artifacts.require("TestableMiximus"); - -const crypto = require("crypto"); - -const fs = require("fs"); -const ffi = require("ffi"); -const ref = require("ref"); -const ArrayType = require("ref-array"); -const BigNumber = require("bignumber.js"); - -var StringArray = ArrayType(ref.types.CString); - -var libmiximus = ffi.Library("build/src/libmiximus", { - // Retrieve depth of tree - "miximus_tree_depth": [ - "size_t", [] - ], - - // Create a proof for the parameters - "miximus_prove": [ - "string", [ - "string", // pk_file - "string", // in_root - "string", // in_nullifier - "string", // in_exthash - "string", // in_spend_preimage - "string", // in_address - StringArray, // in_path - ] - ], - - // Verify a proof - "miximus_verify": [ - "bool", [ - "string", // vk_json - "string", // proof_json - ] - ] -}); - - - -let list_flatten = (l) => { - return [].concat.apply([], l); -}; - - -let vk_to_flat = (vk) => { - return [ - list_flatten([ - vk.alpha[0], vk.alpha[1], - list_flatten(vk.beta), - list_flatten(vk.gamma), - list_flatten(vk.delta), - ]), - list_flatten(vk.gammaABC) - ]; -}; - - -let proof_to_flat = (proof) => { - return list_flatten([ - proof.A, - list_flatten(proof.B), - proof.C - ]); -}; - - -contract("TestableMiximus", () => { - describe("Deposit", () => { - it("deposits then withdraws", async () => { - let obj = await TestableMiximus.deployed(); - - // Parameters for deposit - let spend_preimage = new BigNumber(crypto.randomBytes(30).toString("hex"), 16); - let nullifier = new BigNumber(crypto.randomBytes(30).toString("hex"), 16); - let leaf_hash = await obj.MakeLeafHash.call(spend_preimage, nullifier); - - - // Perform deposit - let new_root_and_offset = await obj.Deposit.call(leaf_hash, {value: 1000000000000000000}); - await obj.Deposit.sendTransaction([leaf_hash], {value: 1000000000000000000}); - - - // TODO: verify amount has been transferred - - - // Build parameters for proving - let tmp = await obj.GetPath.call(new_root_and_offset[1]); - let proof_address = tmp[1].map((_) => _ ? "1" : "0").join(""); - let proof_path = []; - for( var i = 0; i < proof_address.length; i++ ) { - proof_path.push( tmp[0][i].toString(10) ); - } - let proof_root = await obj.GetRoot.call(); - proof_root = new_root_and_offset[0]; - let proof_exthash = await obj.GetExtHash.call(); - - - // Run prover to generate proof - let args = [ - "zksnark_element/miximus.pk.raw", - proof_root.toString(10), - nullifier.toString(10), - proof_exthash.toString(10), - spend_preimage.toString(10), - proof_address, - proof_path - ]; - let proof_json = libmiximus.miximus_prove(...args); - assert.notStrictEqual(proof_json, null); - let proof = JSON.parse(proof_json); - - - // Ensure proof inputs match ours - assert.strictEqual("0x" + proof_root.toString(16), proof.input[0]); - assert.strictEqual("0x" + nullifier.toString(16), proof.input[1]); - assert.strictEqual("0x" + proof_exthash.toString(16), proof.input[2]); - - - // Re-verify proof using native library - // XXX: node-ffi on OSX will not null-terminate strings returned from `readFileSync` ! - let vk_json = fs.readFileSync("zksnark_element/miximus.vk.json"); - let proof_valid_native = libmiximus.miximus_verify(vk_json + '\0', proof_json); - assert.strictEqual(proof_valid_native, true); - let vk = JSON.parse(vk_json); - - - // Verify VK and Proof together - let [vk_flat, vk_flat_IC] = vk_to_flat(vk); - let test_verify_args = [ - vk_flat, // (alpha, beta, gamma, delta) - vk_flat_IC, // gammaABC[] - proof_to_flat(proof), // A B C - [ - proof.input[0], - proof.input[1], - proof.input[2] - ] - ]; - let test_verify_result = await obj.TestVerify(...test_verify_args); - assert.strictEqual(test_verify_result, true); - - - // Verify whether or not our proof would be valid - let proof_valid = await obj.VerifyProof.call( - proof.input[0], - proof.input[1], - proof.input[2], - proof_to_flat(proof)); - assert.strictEqual(proof_valid, true); - - - // Verify nullifier doesn't exist - let is_spent_b4_withdraw = await obj.IsSpent(nullifier.toString(10)); - assert.strictEqual(is_spent_b4_withdraw, false); - - - // Then perform the withdraw - await obj.Withdraw( - proof_root.toString(10), - nullifier.toString(10), - proof_to_flat(proof)); - - - // Verify nullifier exists - let is_spent = await obj.IsSpent(nullifier.toString(10)); - assert.strictEqual(is_spent, true); - - - // TODO: verify balance has been increased - }); - }); -}); diff --git a/test/test_miximus.py b/test/test_miximus.py deleted file mode 100644 index 016e870..0000000 --- a/test/test_miximus.py +++ /dev/null @@ -1,50 +0,0 @@ -import unittest - -from ethsnarks.longsight import random_element, LongsightL12p5_MP -from ethsnarks.utils import native_lib_path -from ethsnarks.mod.miximus import Miximus -from ethsnarks.merkletree import MerkleTree - - -NATIVE_LIB_PATH = native_lib_path('build/src/libmiximus') -VK_PATH = 'zksnark_element/miximus.vk.json' -PK_PATH = 'zksnark_element/miximus.pk.raw' - - -class TestMiximus(unittest.TestCase): - def test_make_proof(self): - n_items = 2<<28 - tree = MerkleTree(n_items) - for n in range(0, 2): - tree.append(random_element()) - - exthash = random_element() - nullifier = random_element() - spend_preimage = random_element() - spend_hash_IV = 0 - spend_hash = LongsightL12p5_MP([spend_preimage, nullifier], spend_hash_IV) - leaf_hash_IV = 0 - leaf_hash = LongsightL12p5_MP([nullifier, spend_hash], leaf_hash_IV) - leaf_idx = tree.append(leaf_hash) - self.assertEqual(leaf_idx, tree.index(leaf_hash)) - - # Verify it exists in true - leaf_proof = tree.proof(leaf_idx) - self.assertTrue(leaf_proof.verify(tree.root)) - - # Generate proof - wrapper = Miximus(NATIVE_LIB_PATH, VK_PATH, PK_PATH) - tree_depth = wrapper.tree_depth - snark_proof = wrapper.prove( - tree.root, - nullifier, - spend_preimage, - exthash, - leaf_proof.address, - leaf_proof.path) - - self.assertTrue(wrapper.verify(snark_proof)) - - -if __name__ == "__main__": - unittest.main() diff --git a/test/test_verify.py b/test/test_verify.py index 194d896..a20a648 100644 --- a/test/test_verify.py +++ b/test/test_verify.py @@ -4,7 +4,7 @@ import random from ethsnarks.verifier import VerifyingKey, Proof -from ethsnarks.mod.miximus import Miximus +from ethsnarks.mod.hashpreimage import HashPreimage from ethsnarks.utils import native_lib_path @@ -24,7 +24,7 @@ def test_verify_native(self): """Verify using fast native library""" vk = VerifyingKey.from_dict(VK_STATIC) proof = Proof.from_dict(PROOF_STATIC) - wrapper = Miximus(native_lib_path('build/src/libmiximus'), vk) + wrapper = HashPreimage(native_lib_path('build/src/libhashpreimage'), vk) self.assertTrue(wrapper.verify(proof)) def test_verify_python(self):