Browse Source

A bunch more libsnark deletions/updates

pull/73/head
Duke Leto 4 years ago
parent
commit
4d965f53eb
  1. 123
      build-aux/m4/ax_openmp.m4
  2. 33
      configure.ac
  3. 44
      depends/packages/libgmp.mk
  4. 4
      depends/packages/packages.mk
  5. 18
      qa/hush/full-test-suite.sh
  6. 12
      src/Makefile.am
  7. 29
      src/Makefile.zcash.include
  8. 10
      src/gtest/main.cpp
  9. 183
      src/gtest/test_circuit.cpp
  10. 61
      src/gtest/test_joinsplit.cpp
  11. 90
      src/gtest/test_merkletree.cpp
  12. 702
      src/gtest/test_proofs.cpp
  13. 1
      src/primitives/transaction.h
  14. 40
      src/zcash/CreateJoinSplit.cpp
  15. 26
      src/zcash/GenerateParams.cpp
  16. 788
      src/zcash/IncrementalMerkleTree.cpp
  17. 13
      src/zcash/IncrementalMerkleTree.hpp
  18. 233
      src/zcash/Proof.cpp
  19. 35
      src/zcash/Proof.hpp
  20. 100
      src/zcash/circuit/commitment.tcc
  21. 349
      src/zcash/circuit/gadget.tcc
  22. 60
      src/zcash/circuit/merkle.tcc
  23. 244
      src/zcash/circuit/note.tcc
  24. 109
      src/zcash/circuit/prfs.tcc
  25. 75
      src/zcash/circuit/utils.tcc
  26. 23
      src/zcbenchmarks.cpp
  27. 2
      src/zcbenchmarks.h
  28. 2
      zcutil/build-win.sh

123
build-aux/m4/ax_openmp.m4

@ -1,123 +0,0 @@
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_openmp.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_OPENMP([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
#
# DESCRIPTION
#
# This macro tries to find out how to compile programs that use OpenMP a
# standard API and set of compiler directives for parallel programming
# (see http://www-unix.mcs/)
#
# On success, it sets the OPENMP_CFLAGS/OPENMP_CXXFLAGS/OPENMP_F77FLAGS
# output variable to the flag (e.g. -omp) used both to compile *and* link
# OpenMP programs in the current language.
#
# NOTE: You are assumed to not only compile your program with these flags,
# but also link it with them as well.
#
# If you want to compile everything with OpenMP, you should set:
#
# CFLAGS="$CFLAGS $OPENMP_CFLAGS"
# #OR# CXXFLAGS="$CXXFLAGS $OPENMP_CXXFLAGS"
# #OR# FFLAGS="$FFLAGS $OPENMP_FFLAGS"
#
# (depending on the selected language).
#
# The user can override the default choice by setting the corresponding
# environment variable (e.g. OPENMP_CFLAGS).
#
# ACTION-IF-FOUND is a list of shell commands to run if an OpenMP flag is
# found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it is
# not found. If ACTION-IF-FOUND is not specified, the default action will
# define HAVE_OPENMP.
#
# LICENSE
#
# Copyright (c) 2008 Steven G. Johnson <stevenj@alum.mit.edu>
# Copyright (c) 2015 John W. Peterson <jwpeterson@gmail.com>
# Copyright (c) 2016 Nick R. Papior <nickpapior@gmail.com>
#
# This program 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.
#
# This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 13
AC_DEFUN([AX_OPENMP], [
AC_PREREQ([2.69]) dnl for _AC_LANG_PREFIX
AC_CACHE_CHECK([for OpenMP flag of _AC_LANG compiler], ax_cv_[]_AC_LANG_ABBREV[]_openmp, [save[]_AC_LANG_PREFIX[]FLAGS=$[]_AC_LANG_PREFIX[]FLAGS
ax_cv_[]_AC_LANG_ABBREV[]_openmp=unknown
# Flags to try: -fopenmp (gcc), -mp (SGI & PGI),
# -qopenmp (icc>=15), -openmp (icc),
# -xopenmp (Sun), -omp (Tru64),
# -qsmp=omp (AIX),
# none
ax_openmp_flags="-fopenmp -openmp -qopenmp -mp -xopenmp -omp -qsmp=omp none"
if test "x$OPENMP_[]_AC_LANG_PREFIX[]FLAGS" != x; then
ax_openmp_flags="$OPENMP_[]_AC_LANG_PREFIX[]FLAGS $ax_openmp_flags"
fi
for ax_openmp_flag in $ax_openmp_flags; do
case $ax_openmp_flag in
none) []_AC_LANG_PREFIX[]FLAGS=$save[]_AC_LANG_PREFIX[] ;;
*) []_AC_LANG_PREFIX[]FLAGS="$save[]_AC_LANG_PREFIX[]FLAGS $ax_openmp_flag" ;;
esac
AC_LINK_IFELSE([AC_LANG_SOURCE([[
@%:@include <omp.h>
static void
parallel_fill(int * data, int n)
{
int i;
@%:@pragma omp parallel for
for (i = 0; i < n; ++i)
data[i] = i;
}
int
main()
{
int arr[100000];
omp_set_num_threads(2);
parallel_fill(arr, 100000);
return 0;
}
]])],[ax_cv_[]_AC_LANG_ABBREV[]_openmp=$ax_openmp_flag; break],[])
done
[]_AC_LANG_PREFIX[]FLAGS=$save[]_AC_LANG_PREFIX[]FLAGS
])
if test "x$ax_cv_[]_AC_LANG_ABBREV[]_openmp" = "xunknown"; then
m4_default([$2],:)
else
if test "x$ax_cv_[]_AC_LANG_ABBREV[]_openmp" != "xnone"; then
OPENMP_[]_AC_LANG_PREFIX[]FLAGS=$ax_cv_[]_AC_LANG_ABBREV[]_openmp
fi
m4_default([$1], [AC_DEFINE(HAVE_OPENMP,1,[Define if OpenMP is enabled])])
fi
])dnl AX_OPENMP

33
configure.ac

@ -700,7 +700,7 @@ if test x$use_pkgconfig = xyes; then
)
else
# BUG: Fix this:
echo 'BUG: configure does not yet check for the following dependencies if pkg-config is not on the system: libcrypto++, libgmp'
echo 'BUG: configure does not yet check for the following dependencies if pkg-config is not on the system: libcrypto++'
AC_CHECK_HEADER([openssl/crypto.h],,AC_MSG_ERROR(libcrypto headers missing))
AC_CHECK_LIB([crypto], [main],CRYPTO_LIBS=-lcrypto, AC_MSG_ERROR(libcrypto missing))
@ -740,22 +740,6 @@ else
fi
fi
# These packages don't provide pkgconfig config files across all
# platforms, so we use older autoconf detection mechanisms:
if test x$TARGET_OS = xdarwin; then
AC_CHECK_HEADER([gmp.h],,AC_MSG_ERROR(libgmp headers missing))
AC_CHECK_LIB([gmp],[[__gmpn_sub_n]],GMP_LIBS=-lgmp, [AC_MSG_ERROR(libgmp missing)])
AC_CHECK_HEADER([gmpxx.h],,AC_MSG_ERROR(libgmpxx headers missing))
AC_CHECK_LIB([gmpxx],[main],GMPXX_LIBS=-lgmpxx, [AC_MSG_ERROR(libgmpxx missing)])
fi
#AC_CHECK_HEADER([gmp.h],,AC_MSG_ERROR(libgmp headers missing))
#AC_CHECK_LIB([gmp],[[__gmpn_sub_n]],GMP_LIBS=-lgmp, [AC_MSG_ERROR(libgmp missing)])
#AC_CHECK_HEADER([gmpxx.h],,AC_MSG_ERROR(libgmpxx headers missing))
#AC_CHECK_LIB([gmpxx],[main],GMPXX_LIBS=-lgmpxx, [AC_MSG_ERROR(libgmpxx missing)])
RUST_LIBS="-lrustzcash"
case $host in
*mingw*)
@ -765,23 +749,12 @@ case $host in
;;
esac
dnl Check for OpenMP support
AX_OPENMP(
[AC_DEFINE(HAVE_OPENMP, 1, [Define if OpenMP is enabled])
AM_CONDITIONAL([HAVE_OPENMP], [true])
CPPFLAGS="$CPPFLAGS -DMULTICORE"
CXXFLAGS="$CXXFLAGS $OPENMP_CXXFLAGS"],
[AC_MSG_WARN([OpenMP not supported, disabling multithreading])
AC_DEFINE(HAVE_OPENMP, 0, [Define if OpenMP is enabled])
AM_CONDITIONAL([HAVE_OPENMP], [false])])
# Additional Zcash flags
# Additional Zcash internals flags
AX_CHECK_COMPILE_FLAG([-fwrapv],[CXXFLAGS="$CXXFLAGS -fwrapv"])
AX_CHECK_COMPILE_FLAG([-fno-strict-aliasing],[CXXFLAGS="$CXXFLAGS -fno-strict-aliasing"])
AX_CHECK_COMPILE_FLAG([-Wno-builtin-declaration-mismatch],[CXXFLAGS="$CXXFLAGS -Wno-builtin-declaration-mismatch"],,[[$CXXFLAG_WERROR]])
LIBZCASH_LIBS="-lgmp -lgmpxx $BOOST_SYSTEM_LIB -lcrypto -lsodium $RUST_LIBS"
LIBZCASH_LIBS="$BOOST_SYSTEM_LIB -lcrypto -lsodium $RUST_LIBS"
AC_MSG_CHECKING([whether to build komodod])
AM_CONDITIONAL([BUILD_BITCOIND], [test x$build_bitcoind = xyes])

44
depends/packages/libgmp.mk

@ -1,44 +0,0 @@
package=libgmp
ifeq ($(host_os),mingw32)
$(package)_download_path=https://github.com/joshuayabut/$(package)/archive
$(package)_file_name=$(package)-$($(package)_git_commit).tar.gz
$(package)_download_file=$($(package)_git_commit).tar.gz
$(package)_sha256_hash=193836c1acc9dc00fe2521205d7bbe1ba13263f6cbef6f02584bf6f8b34b108f
$(package)_git_commit=053c03b1cab347671d936f43ef66b48ab5e380ee
$(package)_dependencies=
$(package)_config_opts=--enable-cxx --disable-shared
else ifeq ($(build_os),darwin)
$(package)_download_path=https://github.com/ca333/$(package)/archive
$(package)_file_name=$(package)-$($(package)_git_commit).tar.gz
$(package)_download_file=$($(package)_git_commit).tar.gz
$(package)_sha256_hash=59b2c2b5d58fdf5943bfde1fa709e9eb53e7e072c9699d28dc1c2cbb3c8cc32c
$(package)_git_commit=aece03c7b6967f91f3efdac8c673f55adff53ab1
$(package)_dependencies=
$(package)_config_opts=--enable-cxx --disable-shared
else
$(package)_version=6.1.1
$(package)_download_path=https://github.com/MyHush/libgmp/releases/download/v6.1.1
$(package)_file_name=gmp-$($(package)_version).tar.bz2
$(package)_sha256_hash=a8109865f2893f1373b0a8ed5ff7429de8db696fc451b1036bd7bdf95bbeffd6
$(package)_dependencies=
$(package)_config_opts=--enable-cxx --disable-shared
endif
define $(package)_config_cmds
$($(package)_autoconf) --host=$(host) --build=$(build)
endef
ifeq ($(build_os),darwin)
define $(package)_build_cmds
$(MAKE)
endef
else
define $(package)_build_cmds
$(MAKE) CPPFLAGS='-fPIC'
endef
endif
define $(package)_stage_cmds
$(MAKE) DESTDIR=$($(package)_staging_dir) install ; echo '=== staging find for $(package):' ; find $($(package)_staging_dir)
endef

4
depends/packages/packages.mk

@ -1,10 +1,10 @@
rust_packages := rust librustzcash
ifeq ($(build_os),darwin)
zcash_packages := libsnark libgmp libsodium utfcpp
zcash_packages := libsnark libsodium utfcpp
else
proton_packages := proton
zcash_packages := libgmp libsodium utfcpp
zcash_packages := libsodium utfcpp
endif
rust_crates := \

18
qa/hush/full-test-suite.sh

@ -64,21 +64,19 @@ def check_security_hardening():
# PIE, RELRO, Canary, and NX are tested by make check-security.
ret &= subprocess.call(['make', '-C', repofile('src'), 'check-security']) == 0
ret &= test_rpath_runpath('src/zcashd')
ret &= test_rpath_runpath('src/zcash-cli')
ret &= test_rpath_runpath('src/zcash-gtest')
ret &= test_rpath_runpath('src/zcash-tx')
ret &= test_rpath_runpath('src/hushd')
ret &= test_rpath_runpath('src/hush-cli')
ret &= test_rpath_runpath('src/hush-gtest')
ret &= test_rpath_runpath('src/hush-tx')
ret &= test_rpath_runpath('src/test/test_bitcoin')
ret &= test_rpath_runpath('src/zcash/GenerateParams')
# NOTE: checksec.sh does not reliably determine whether FORTIFY_SOURCE
# is enabled for the entire binary. See issue #915.
ret &= test_fortify_source('src/zcashd')
ret &= test_fortify_source('src/zcash-cli')
ret &= test_fortify_source('src/zcash-gtest')
ret &= test_fortify_source('src/zcash-tx')
ret &= test_fortify_source('src/hushd')
ret &= test_fortify_source('src/hush-cli')
ret &= test_fortify_source('src/hush-gtest')
ret &= test_fortify_source('src/hush-tx')
ret &= test_fortify_source('src/test/test_bitcoin')
ret &= test_fortify_source('src/zcash/GenerateParams')
return ret

12
src/Makefile.am

@ -633,15 +633,9 @@ libzcash_a_SOURCES = \
zcash/Note.cpp \
zcash/prf.cpp \
zcash/util.cpp \
zcash/zip32.cpp \
zcash/circuit/commitment.tcc \
zcash/circuit/gadget.tcc \
zcash/circuit/merkle.tcc \
zcash/circuit/note.tcc \
zcash/circuit/prfs.tcc \
zcash/circuit/utils.tcc
libzcash_a_CPPFLAGS = -DMULTICORE -fopenmp -fPIC -DBINARY_OUTPUT -DCURVE_ALT_BN128 -DBOOST_SPIRIT_THREADSAFE -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS $(HARDENED_CPPFLAGS) $(HARDENED_CXXFLAGS) $(HARDENED_LDFLAGS) -pipe $(SAN_LDFLAGS) -O1 -g -Wstack-protector $(SAN_CXXFLAGS) -fstack-protector-all -fPIE -fvisibility=hidden -DSTATIC $(BITCOIN_INCLUDES)
zcash/zip32.cpp
libzcash_a_CPPFLAGS = -DMULTICORE -fopenmp -fPIC -DBOOST_SPIRIT_THREADSAFE -DHAVE_BUILD_INFO -D__STDC_FORMAT_MACROS $(HARDENED_CPPFLAGS) $(HARDENED_CXXFLAGS) $(HARDENED_LDFLAGS) -pipe $(SAN_LDFLAGS) -O1 -g -Wstack-protector $(SAN_CXXFLAGS) -fstack-protector-all -fPIE -fvisibility=hidden -DSTATIC $(BITCOIN_INCLUDES)
#libzcash_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
#libzcash_a_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS)

29
src/Makefile.zcash.include

@ -1,29 +0,0 @@
noinst_PROGRAMS += \
zcash/GenerateParams \
zcash/CreateJoinSplit
# tool for generating our public parameters
zcash_GenerateParams_SOURCES = zcash/GenerateParams.cpp
zcash_GenerateParams_CPPFLAGS = $(AM_CPPFLAGS)
zcash_GenerateParams_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
zcash_GenerateParams_LDADD = \
$(BOOST_LIBS) \
$(LIBZCASH) \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_CRYPTO) \
$(LIBZCASH_LIBS)
# tool for profiling the creation of joinsplits
zcash_CreateJoinSplit_SOURCES = zcash/CreateJoinSplit.cpp
zcash_CreateJoinSplit_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
zcash_CreateJoinSplit_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
zcash_CreateJoinSplit_LDADD = \
$(LIBBITCOIN_COMMON) \
$(LIBZCASH) \
$(LIBBITCOIN_UTIL) \
$(LIBBITCOIN_CRYPTO) \
$(BOOST_LIBS) \
$(LIBZCASH_LIBS) \
$(LIBCRYPTOCONDITIONS) \
$(LIBSECP256K1)

10
src/gtest/main.cpp

@ -5,9 +5,6 @@
#include "zcash/JoinSplit.hpp"
#include "util.h"
#include <libsnark/common/default_types/r1cs_ppzksnark_pp.hpp>
#include <libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp>
#include "librustzcash.h"
struct ECCryptoClosure
@ -23,12 +20,7 @@ int main(int argc, char **argv) {
assert(init_and_check_sodium() != -1);
ECC_Start();
libsnark::default_r1cs_ppzksnark_pp::init_public_params();
libsnark::inhibit_profiling_info = true;
libsnark::inhibit_profiling_counters = true;
boost::filesystem::path pk_path = ZC_GetParamsDir() / "sprout-proving.key";
boost::filesystem::path vk_path = ZC_GetParamsDir() / "sprout-verifying.key";
params = ZCJoinSplit::Prepared(vk_path.string(), pk_path.string());
params = ZCJoinSplit::Prepared();
boost::filesystem::path sapling_spend = ZC_GetParamsDir() / "sapling-spend.params";
boost::filesystem::path sapling_output = ZC_GetParamsDir() / "sapling-output.params";

183
src/gtest/test_circuit.cpp

@ -1,183 +0,0 @@
#include <gtest/gtest.h>
#include "uint256.h"
#include "zcash/util.h"
#include <boost/foreach.hpp>
#include <boost/format.hpp>
#include <boost/optional.hpp>
#include <libsnark/common/default_types/r1cs_ppzksnark_pp.hpp>
#include <libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp>
#include <libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp>
#include <libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp>
#include "zcash/IncrementalMerkleTree.hpp"
using namespace libsnark;
using namespace libzcash;
#include "zcash/circuit/utils.tcc"
#include "zcash/circuit/merkle.tcc"
template<typename FieldT>
void test_value_equals(uint64_t i) {
protoboard<FieldT> pb;
pb_variable_array<FieldT> num;
num.allocate(pb, 64, "");
num.fill_with_bits(pb, uint64_to_bool_vector(i));
pb.add_r1cs_constraint(r1cs_constraint<FieldT>(
packed_addition(num),
FieldT::one(),
FieldT::one() * i
), "");
ASSERT_TRUE(pb.is_satisfied());
}
TEST(circuit, values)
{
typedef Fr<default_r1cs_ppzksnark_pp> FieldT;
test_value_equals<FieldT>(0);
test_value_equals<FieldT>(1);
test_value_equals<FieldT>(3);
test_value_equals<FieldT>(5391);
test_value_equals<FieldT>(883128374);
test_value_equals<FieldT>(173419028459);
test_value_equals<FieldT>(2205843009213693953);
}
TEST(circuit, endianness)
{
std::vector<unsigned char> before = {
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63
};
auto result = swap_endianness_u64(before);
std::vector<unsigned char> after = {
56, 57, 58, 59, 60, 61, 62, 63,
48, 49, 50, 51, 52, 53, 54, 55,
40, 41, 42, 43, 44, 45, 46, 47,
32, 33, 34, 35, 36, 37, 38, 39,
24, 25, 26, 27, 28, 29, 30, 31,
16, 17, 18, 19, 20, 21, 22, 23,
8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7
};
EXPECT_EQ(after, result);
std::vector<unsigned char> bad = {0, 1, 2, 3};
ASSERT_THROW(swap_endianness_u64(bad), std::length_error);
}
template<typename FieldT>
bool test_merkle_gadget(
bool enforce_a,
bool enforce_b,
bool write_root_first
)
{
protoboard<FieldT> pb;
digest_variable<FieldT> root(pb, 256, "root");
pb.set_input_sizes(256);
digest_variable<FieldT> commitment1(pb, 256, "commitment1");
digest_variable<FieldT> commitment2(pb, 256, "commitment2");
pb_variable<FieldT> commitment1_read;
commitment1_read.allocate(pb);
pb_variable<FieldT> commitment2_read;
commitment2_read.allocate(pb);
merkle_tree_gadget<FieldT> mgadget1(pb, commitment1, root, commitment1_read);
merkle_tree_gadget<FieldT> mgadget2(pb, commitment2, root, commitment2_read);
commitment1.generate_r1cs_constraints();
commitment2.generate_r1cs_constraints();
root.generate_r1cs_constraints();
mgadget1.generate_r1cs_constraints();
mgadget2.generate_r1cs_constraints();
SproutMerkleTree tree;
uint256 commitment1_data = uint256S("54d626e08c1c802b305dad30b7e54a82f102390cc92c7d4db112048935236e9c");
uint256 commitment2_data = uint256S("59d2cde5e65c1414c32ba54f0fe4bdb3d67618125286e6a191317917c812c6d7");
tree.append(commitment1_data);
auto wit1 = tree.witness();
tree.append(commitment2_data);
wit1.append(commitment2_data);
auto wit2 = tree.witness();
auto expected_root = tree.root();
tree.append(uint256S("3e243c8798678570bb8d42616c23a536af44be15c4eef073490c2a44ae5f32c3"));
auto unexpected_root = tree.root();
tree.append(uint256S("26d9b20c7f1c3d2528bbcd43cd63344b0afd3b6a0a8ebd37ec51cba34907bec7"));
auto badwit1 = tree.witness();
tree.append(uint256S("02c2467c9cd15e0d150f74cd636505ed675b0b71b66a719f6f52fdb49a5937bb"));
auto badwit2 = tree.witness();
// Perform the test
pb.val(commitment1_read) = enforce_a ? FieldT::one() : FieldT::zero();
pb.val(commitment2_read) = enforce_b ? FieldT::one() : FieldT::zero();
commitment1.bits.fill_with_bits(pb, uint256_to_bool_vector(commitment1_data));
commitment2.bits.fill_with_bits(pb, uint256_to_bool_vector(commitment2_data));
if (write_root_first) {
root.bits.fill_with_bits(pb, uint256_to_bool_vector(expected_root));
}
mgadget1.generate_r1cs_witness(wit1.path());
mgadget2.generate_r1cs_witness(wit2.path());
// Overwrite with our expected root
root.bits.fill_with_bits(pb, uint256_to_bool_vector(expected_root));
return pb.is_satisfied();
}
TEST(circuit, merkle_tree_gadget_weirdness)
{
/*
The merkle tree gadget takes a leaf in the merkle tree (the Note commitment),
a merkle tree authentication path, and a root (anchor). It also takes a parameter
called read_success, which is used to determine if the commitment actually needs to
appear in the tree.
If two input notes use the same root (which our protocol does) then if `read_success`
is disabled on the first note but enabled on the second note (i.e., the first note
has value of zero and second note has nonzero value) then there is an edge case in
the witnessing behavior. The first witness will accidentally constrain the root to
equal null (the default value of the anchor) and the second witness will actually
copy the bits, violating the constraint system.
Notice that this edge case is not in the constraint system but in the witnessing
behavior.
*/
typedef Fr<default_r1cs_ppzksnark_pp> FieldT;
// Test the normal case
ASSERT_TRUE(test_merkle_gadget<FieldT>(true, true, false));
ASSERT_TRUE(test_merkle_gadget<FieldT>(true, true, true));
// Test the case where the first commitment is enforced but the second isn't
// Works because the first read is performed before the second one
ASSERT_TRUE(test_merkle_gadget<FieldT>(true, false, false));
ASSERT_TRUE(test_merkle_gadget<FieldT>(true, false, true));
// Test the case where the first commitment isn't enforced but the second is
// Doesn't work because the first multipacker witnesses the existing root (which
// is null)
ASSERT_TRUE(!test_merkle_gadget<FieldT>(false, true, false));
// Test the last again, except this time write the root first.
ASSERT_TRUE(test_merkle_gadget<FieldT>(false, true, true));
}

61
src/gtest/test_joinsplit.cpp

@ -22,10 +22,9 @@ using namespace libzcash;
extern ZCJoinSplit* params;
typedef std::array<JSDescription, 2> SproutProofs;
// Make both the PHGR and Groth proof for a Sprout statement,
// and store the results in JSDescription objects.
SproutProofs makeSproutProofs(
// Make the Groth proof for a Sprout statement,
// and store the result in a JSDescription object.
JSDescription makeSproutProof(
ZCJoinSplit& js,
const std::array<JSInput, 2>& inputs,
const std::array<JSOutput, 2>& outputs,
@ -34,25 +33,17 @@ SproutProofs makeSproutProofs(
uint64_t vpub_new,
const uint256& rt
){
//Making the PHGR proof
JSDescription phgr(false, js, joinSplitPubKey, rt, inputs, outputs, vpub_old, vpub_new);
//Making the Groth proof
JSDescription groth(true, js, joinSplitPubKey, rt, inputs, outputs, vpub_old, vpub_new);
return {phgr, groth};
return JSDescription(js, joinSplitPubKey, rt, inputs, outputs, vpub_old, vpub_new);
}
bool verifySproutProofs(
bool verifySproutProof(
ZCJoinSplit& js,
const SproutProofs& jsdescs,
const JSDescription& jsdesc,
const uint256& joinSplitPubKey
)
{
auto verifier = libzcash::ProofVerifier::Strict();
bool phgrPassed = jsdescs[0].Verify(js, verifier, joinSplitPubKey);
bool grothPassed = jsdescs[1].Verify(js, verifier, joinSplitPubKey);
return phgrPassed && grothPassed;
return jsdesc.Verify(js, verifier, joinSplitPubKey);
}
@ -73,7 +64,7 @@ void test_full_api(ZCJoinSplit* js)
uint64_t vpub_new = 0;
uint256 joinSplitPubKey = random_uint256();
uint256 rt = tree.root();
SproutProofs jsdescs;
JSDescription jsdesc;
{
std::array<JSInput, 2> inputs = {
@ -89,7 +80,7 @@ void test_full_api(ZCJoinSplit* js)
std::array<SproutNote, 2> output_notes;
// Perform the proofs
jsdescs = makeSproutProofs(
jsdesc = makeSproutProof(
*js,
inputs,
outputs,
@ -101,13 +92,11 @@ void test_full_api(ZCJoinSplit* js)
}
// Verify both PHGR and Groth Proof:
ASSERT_TRUE(verifySproutProofs(*js, jsdescs, joinSplitPubKey));
ASSERT_TRUE(verifySproutProof(*js, jsdesc, joinSplitPubKey));
// Run tests using both phgr and groth as basis for field values
for (auto jsdesc : jsdescs)
{
SproutMerkleTree tree;
SproutProofs jsdescs2;
JSDescription jsdesc2;
// Recipient should decrypt
// Now the recipient should spend the money again
auto h_sig = js->h_sig(jsdesc.randomSeed, jsdesc.nullifiers, joinSplitPubKey);
@ -153,7 +142,7 @@ void test_full_api(ZCJoinSplit* js)
// Perform the proofs
jsdescs2 = makeSproutProofs(
jsdesc2 = makeSproutProof(
*js,
inputs,
outputs,
@ -166,8 +155,8 @@ void test_full_api(ZCJoinSplit* js)
}
// Verify both PHGR and Groth Proof:
ASSERT_TRUE(verifySproutProofs(*js, jsdescs2, joinSplitPubKey2));
// Verify Groth Proof:
ASSERT_TRUE(verifySproutProof(*js, jsdesc2, joinSplitPubKey2));
}
}
@ -191,28 +180,8 @@ void invokeAPI(
std::array<SproutNote, 2> output_notes;
// PHGR
SproutProof proof = js->prove(
false,
inputs,
outputs,
output_notes,
ciphertexts,
ephemeralKey,
joinSplitPubKey,
randomSeed,
macs,
nullifiers,
commitments,
vpub_old,
vpub_new,
rt,
false
);
// Groth
proof = js->prove(
true,
SproutProof proof = js->prove(
inputs,
outputs,
output_notes,

90
src/gtest/test_merkletree.cpp

@ -1,14 +1,12 @@
#include <gtest/gtest.h>
#include "test/data/merkle_roots.json.h"
#include "test/data/merkle_roots_empty.json.h"
#include "test/data/merkle_serialization.json.h"
#include "test/data/merkle_witness_serialization.json.h"
#include "test/data/merkle_path.json.h"
#include "test/data/merkle_commitments.json.h"
#include "test/data/merkle_roots_sapling.json.h"
#include "test/data/merkle_roots_empty_sapling.json.h"
#include "test/data/merkle_serialization_sapling.json.h"
#include "test/data/merkle_witness_serialization_sapling.json.h"
#include "test/data/merkle_path_sapling.json.h"
@ -26,17 +24,11 @@
#include "zcash/IncrementalMerkleTree.hpp"
#include "zcash/util.h"
#include <libsnark/common/default_types/r1cs_ppzksnark_pp.hpp>
#include <libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp>
#include <libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp>
#include <libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp>
#include <boost/foreach.hpp>
#include "json_test_vectors.h"
using namespace std;
using namespace libsnark;
template<>
void expect_deser_same(const SproutTestingWitness& expected)
@ -58,8 +50,7 @@ void test_tree(
UniValue root_tests,
UniValue ser_tests,
UniValue witness_ser_tests,
UniValue path_tests,
bool libsnark_test
UniValue path_tests
)
{
size_t witness_ser_i = 0;
@ -115,55 +106,6 @@ void test_tree(
} else {
auto path = wit.path();
expect_test_vector(path_tests[path_i++], path);
if (libsnark_test) {
typedef Fr<default_r1cs_ppzksnark_pp> FieldT;
protoboard<FieldT> pb;
pb_variable_array<FieldT> positions;
digest_variable<FieldT> commitment(pb, 256, "commitment");
digest_variable<FieldT> root(pb, 256, "root");
positions.allocate(pb, INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, "pos");
merkle_authentication_path_variable<FieldT, sha256_two_to_one_hash_gadget<FieldT>> authvars(pb, INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, "auth");
merkle_tree_check_read_gadget<FieldT, sha256_two_to_one_hash_gadget<FieldT>> auth(
pb, INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, positions, commitment, root, authvars, ONE, "path"
);
commitment.generate_r1cs_constraints();
root.generate_r1cs_constraints();
authvars.generate_r1cs_constraints();
auth.generate_r1cs_constraints();
std::vector<bool> commitment_bv;
{
uint256 witnessed_commitment = wit.element();
std::vector<unsigned char> commitment_v(witnessed_commitment.begin(), witnessed_commitment.end());
commitment_bv = convertBytesVectorToVector(commitment_v);
}
size_t path_index = convertVectorToInt(path.index);
commitment.bits.fill_with_bits(pb, bit_vector(commitment_bv));
positions.fill_with_bits_of_uint64(pb, path_index);
authvars.generate_r1cs_witness(path_index, path.authentication_path);
auth.generate_r1cs_witness();
std::vector<bool> root_bv;
{
uint256 witroot = wit.root();
std::vector<unsigned char> root_v(witroot.begin(), witroot.end());
root_bv = convertBytesVectorToVector(root_v);
}
root.bits.fill_with_bits(pb, bit_vector(root_bv));
ASSERT_TRUE(pb.is_satisfied());
root_bv[0] = !root_bv[0];
root.bits.fill_with_bits(pb, bit_vector(root_bv));
ASSERT_TRUE(!pb.is_satisfied());
}
}
// Check witness serialization
@ -200,8 +142,7 @@ TEST(merkletree, vectors) {
root_tests,
ser_tests,
witness_ser_tests,
path_tests,
true
path_tests
);
}
@ -217,18 +158,19 @@ TEST(merkletree, SaplingVectors) {
root_tests,
ser_tests,
witness_ser_tests,
path_tests,
false
path_tests
);
}
TEST(merkletree, emptyroots) {
UniValue empty_roots = read_json(MAKE_STRING(json_tests::merkle_roots_empty));
libzcash::EmptyMerkleRoots<64, libzcash::SHA256Compress> emptyroots;
std::array<libzcash::SHA256Compress, 65> computed;
for (size_t depth = 0; depth <= 64; depth++) {
expect_test_vector(empty_roots[depth], emptyroots.empty_root(depth));
computed.at(0) = libzcash::SHA256Compress::uncommitted();
ASSERT_TRUE(emptyroots.empty_root(0) == computed.at(0));
for (size_t d = 1; d <= 64; d++) {
computed.at(d) = libzcash::SHA256Compress::combine(computed.at(d-1), computed.at(d-1), d-1);
ASSERT_TRUE(emptyroots.empty_root(d) == computed.at(d));
}
// Double check that we're testing (at least) all the empty roots we'll use.
@ -236,12 +178,14 @@ TEST(merkletree, emptyroots) {
}
TEST(merkletree, EmptyrootsSapling) {
UniValue empty_roots = read_json(MAKE_STRING(json_tests::merkle_roots_empty_sapling));
libzcash::EmptyMerkleRoots<62, libzcash::PedersenHash> emptyroots;
std::array<libzcash::PedersenHash, 63> computed;
for (size_t depth = 0; depth <= 62; depth++) {
expect_test_vector(empty_roots[depth], emptyroots.empty_root(depth));
computed.at(0) = libzcash::PedersenHash::uncommitted();
ASSERT_TRUE(emptyroots.empty_root(0) == computed.at(0));
for (size_t d = 1; d <= 62; d++) {
computed.at(d) = libzcash::PedersenHash::combine(computed.at(d-1), computed.at(d-1), d-1);
ASSERT_TRUE(emptyroots.empty_root(d) == computed.at(d));
}
// Double check that we're testing (at least) all the empty roots we'll use.
@ -249,7 +193,7 @@ TEST(merkletree, EmptyrootsSapling) {
}
TEST(merkletree, emptyroot) {
// This literal is the depth-20 empty tree root with the bytes reversed to
// This literal is the depth-29 empty tree root with the bytes reversed to
// account for the fact that uint256S() loads a big-endian representation of
// an integer which converted to little-endian internally.
uint256 expected = uint256S("59d2cde5e65c1414c32ba54f0fe4bdb3d67618125286e6a191317917c812c6d7");
@ -258,7 +202,7 @@ TEST(merkletree, emptyroot) {
}
TEST(merkletree, EmptyrootSapling) {
// This literal is the depth-20 empty tree root with the bytes reversed to
// This literal is the depth-32 empty tree root with the bytes reversed to
// account for the fact that uint256S() loads a big-endian representation of
// an integer which converted to little-endian internally.
uint256 expected = uint256S("3e49b5f954aa9d3545bc6c37744661eea48d7c34e3000d82b7f0010c30f4c2fb");

702
src/gtest/test_proofs.cpp

@ -1,702 +0,0 @@
#include <gtest/gtest.h>
#include "zcash/Proof.hpp"
#include <iostream>
#include <libsnark/common/default_types/r1cs_ppzksnark_pp.hpp>
#include <libsnark/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp>
#include <libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp>
using namespace libzcash;
typedef libsnark::default_r1cs_ppzksnark_pp curve_pp;
typedef libsnark::default_r1cs_ppzksnark_pp::G1_type curve_G1;
typedef libsnark::default_r1cs_ppzksnark_pp::G2_type curve_G2;
typedef libsnark::default_r1cs_ppzksnark_pp::GT_type curve_GT;
typedef libsnark::default_r1cs_ppzksnark_pp::Fp_type curve_Fr;
typedef libsnark::default_r1cs_ppzksnark_pp::Fq_type curve_Fq;
typedef libsnark::default_r1cs_ppzksnark_pp::Fqe_type curve_Fq2;
#include "streams.h"
#include "version.h"
#include "utilstrencodings.h"
TEST(proofs, g1_pairing_at_infinity)
{
for (size_t i = 0; i < 100; i++) {
auto r1 = curve_G1::random_element();
auto r2 = curve_G2::random_element();
ASSERT_TRUE(
curve_pp::reduced_pairing(curve_G1::zero(), r2) ==
curve_GT::one()
);
ASSERT_TRUE(
curve_pp::final_exponentiation(
curve_pp::double_miller_loop(
curve_pp::precompute_G1(curve_G1::zero()),
curve_pp::precompute_G2(r2),
curve_pp::precompute_G1(curve_G1::zero()),
curve_pp::precompute_G2(r2)
)
) ==
curve_GT::one()
);
ASSERT_TRUE(
curve_pp::final_exponentiation(
curve_pp::double_miller_loop(
curve_pp::precompute_G1(r1),
curve_pp::precompute_G2(r2),
curve_pp::precompute_G1(curve_G1::zero()),
curve_pp::precompute_G2(r2)
)
) ==
curve_pp::reduced_pairing(r1, r2)
);
ASSERT_TRUE(
curve_pp::final_exponentiation(
curve_pp::double_miller_loop(
curve_pp::precompute_G1(curve_G1::zero()),
curve_pp::precompute_G2(r2),
curve_pp::precompute_G1(r1),
curve_pp::precompute_G2(r2)
)
) ==
curve_pp::reduced_pairing(r1, r2)
);
}
}
TEST(proofs, g2_subgroup_check)
{
// all G2 elements are order r
ASSERT_TRUE(libsnark::alt_bn128_modulus_r * curve_G2::random_element() == curve_G2::zero());
// but that doesn't mean all elements that satisfy the curve equation are in G2...
curve_G2 p = curve_G2::one();
while (1) {
// This will construct an order r(2q-r) point with high probability
p.X = curve_Fq2::random_element();
try {
p.Y = ((p.X.squared() * p.X) + libsnark::alt_bn128_twist_coeff_b).sqrt();
break;
} catch(...) {}
}
ASSERT_TRUE(p.is_well_formed()); // it's on the curve
ASSERT_TRUE(libsnark::alt_bn128_modulus_r * p != curve_G2::zero()); // but not the order r subgroup..
{
// libsnark unfortunately doesn't check, and the pairing will complete
auto e = curve_Fr("149");
auto a = curve_pp::reduced_pairing(curve_G1::one(), p);
auto b = curve_pp::reduced_pairing(e * curve_G1::one(), p);
// though it will not preserve bilinearity
ASSERT_TRUE((a^e) != b);
}
{
// so, our decompression API should not allow you to decompress G2 elements of that form!
CompressedG2 badp(p);
try {
auto newp = badp.to_libsnark_g2<curve_G2>();
FAIL() << "Expected std::runtime_error";
} catch (std::runtime_error const & err) {
EXPECT_EQ(err.what(), std::string("point is not in G2"));
} catch(...) {
FAIL() << "Expected std::runtime_error";
}
}
// educational purposes: showing that E'(Fp2) is of order r(2q-r),
// by multiplying our random point in E' by (2q-r) = (q + q - r) to
// get an element in G2
{
auto p1 = libsnark::alt_bn128_modulus_q * p;
p1 = p1 + p1;
p1 = p1 - (libsnark::alt_bn128_modulus_r * p);
ASSERT_TRUE(p1.is_well_formed());
ASSERT_TRUE(libsnark::alt_bn128_modulus_r * p1 == curve_G2::zero());
CompressedG2 goodp(p1);
auto newp = goodp.to_libsnark_g2<curve_G2>();
ASSERT_TRUE(newp == p1);
}
}
TEST(proofs, sqrt_zero)
{
ASSERT_TRUE(curve_Fq::zero() == curve_Fq::zero().sqrt());
ASSERT_TRUE(curve_Fq2::zero() == curve_Fq2::zero().sqrt());
}
TEST(proofs, sqrt_fq)
{
// Poor man's PRNG
curve_Fq acc = curve_Fq("348957923485290374852379485") ^ 1000;
size_t quadratic_residues = 0;
size_t quadratic_nonresidues = 0;
for (size_t i = 1; i < 1000; i++) {
try {
acc += curve_Fq("45634563456") ^ i;
curve_Fq x = acc.sqrt();
ASSERT_TRUE((x*x) == acc);
quadratic_residues += 1;
} catch (std::runtime_error &e) {
quadratic_nonresidues += 1;
}
}
// Half of all nonzero elements in Fp are quadratic residues
ASSERT_TRUE(quadratic_residues == 511);
ASSERT_TRUE(quadratic_nonresidues == 488);
for (size_t i = 0; i < 1000; i++) {
curve_Fq x = curve_Fq::random_element();
curve_Fq x2 = x * x;
ASSERT_TRUE((x2.sqrt() == x) || (x2.sqrt() == -x));
}
// Test vectors
ASSERT_TRUE(
curve_Fq("5204065062716160319596273903996315000119019512886596366359652578430118331601")
==
curve_Fq("348579348568").sqrt()
);
ASSERT_THROW(curve_Fq("348579348569").sqrt(), std::runtime_error);
}
TEST(proofs, sqrt_fq2)
{
curve_Fq2 acc = curve_Fq2(
curve_Fq("3456293840592348059238409578239048769348760238476029347885092384059238459834") ^ 1000,
curve_Fq("2394578084760439457823945729347502374590283479582739485723945729384759823745") ^ 1000
);
size_t quadratic_residues = 0;
size_t quadratic_nonresidues = 0;
for (size_t i = 1; i < 1000; i++) {
try {
acc = acc + curve_Fq2(
curve_Fq("5204065062716160319596273903996315000119019512886596366359652578430118331601") ^ i,
curve_Fq("348957923485290374852379485348957923485290374852379485348957923485290374852") ^ i
);
curve_Fq2 x = acc.sqrt();
ASSERT_TRUE((x*x) == acc);
quadratic_residues += 1;
} catch (std::runtime_error &e) {
quadratic_nonresidues += 1;
}
}
// Half of all nonzero elements in Fp^k are quadratic residues as long
// as p != 2
ASSERT_TRUE(quadratic_residues == 505);
ASSERT_TRUE(quadratic_nonresidues == 494);
for (size_t i = 0; i < 1000; i++) {
curve_Fq2 x = curve_Fq2::random_element();
curve_Fq2 x2 = x * x;
ASSERT_TRUE((x2.sqrt() == x) || (x2.sqrt() == -x));
}
// Test vectors
ASSERT_THROW(curve_Fq2(
curve_Fq("2"),
curve_Fq("1")
).sqrt(), std::runtime_error);
ASSERT_THROW(curve_Fq2(
curve_Fq("3345897230485723946872934576923485762803457692345760237495682347502347589473"),
curve_Fq("1234912378405347958234756902345768290345762348957605678245967234857634857676")
).sqrt(), std::runtime_error);
curve_Fq2 x = curve_Fq2(
curve_Fq("12844195307879678418043983815760255909500142247603239203345049921980497041944"),
curve_Fq("7476417578426924565731404322659619974551724117137577781074613937423560117731")
);
curve_Fq2 nx = -x;
curve_Fq2 x2 = curve_Fq2(
curve_Fq("3345897230485723946872934576923485762803457692345760237495682347502347589474"),
curve_Fq("1234912378405347958234756902345768290345762348957605678245967234857634857676")
);
ASSERT_TRUE(x == x2.sqrt());
ASSERT_TRUE(nx == -x2.sqrt());
ASSERT_TRUE(x*x == x2);
ASSERT_TRUE(nx*nx == x2);
}
TEST(proofs, size_is_expected)
{
PHGRProof p;
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << p;
ASSERT_EQ(ss.size(), 296);
}
TEST(proofs, fq_serializes_properly)
{
for (size_t i = 0; i < 1000; i++) {
curve_Fq e = curve_Fq::random_element();
Fq e2(e);
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << e2;
Fq e3;
ss >> e3;
curve_Fq e4 = e3.to_libsnark_fq<curve_Fq>();
ASSERT_TRUE(e == e4);
}
}
TEST(proofs, fq2_serializes_properly)
{
for (size_t i = 0; i < 1000; i++) {
curve_Fq2 e = curve_Fq2::random_element();
Fq2 e2(e);
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << e2;
Fq2 e3;
ss >> e3;
curve_Fq2 e4 = e3.to_libsnark_fq2<curve_Fq2>();
ASSERT_TRUE(e == e4);
}
}
template<typename T>
T deserialize_tv(std::string s)
{
T e;
CDataStream ss(ParseHex(s), SER_NETWORK, PROTOCOL_VERSION);
ss >> e;
return e;
}
curve_Fq deserialize_fq(std::string s)
{
return deserialize_tv<Fq>(s).to_libsnark_fq<curve_Fq>();
}
curve_Fq2 deserialize_fq2(std::string s)
{
return deserialize_tv<Fq2>(s).to_libsnark_fq2<curve_Fq2>();
}
TEST(proofs, fq_valid)
{
curve_Fq e = deserialize_fq("30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46");
ASSERT_TRUE(e == curve_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"));
ASSERT_TRUE(e != curve_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208581"));
curve_Fq e2 = deserialize_fq("30644e72e131a029b75045b68181585d97816a916871ca8d3c208c16d87cfd46");
ASSERT_TRUE(e2 == curve_Fq("21888242871839275222221885816603420866962577604863418715751138068690288573766"));
}
TEST(proofs, fq_invalid)
{
// Should not be able to deserialize the modulus
ASSERT_THROW(
deserialize_fq("30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47"),
std::logic_error
);
// Should not be able to deserialize the modulus plus one
ASSERT_THROW(
deserialize_fq("30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd48"),
std::logic_error
);
// Should not be able to deserialize a ridiculously out of bound int
ASSERT_THROW(
deserialize_fq("ff644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46"),
std::logic_error
);
}
TEST(proofs, fq2_valid)
{
// (q - 1) * q + q
curve_Fq2 e = deserialize_fq2("0925c4b8763cbf9c599a6f7c0348d21cb00b85511637560626edfa5c34c6b38d04689e957a1242c84a50189c6d96cadca602072d09eac1013b5458a2275d69b0");
ASSERT_TRUE(e.c0 == curve_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"));
ASSERT_TRUE(e.c1 == curve_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"));
curve_Fq2 e2 = deserialize_fq2("000000000000000000000000000000000000000000000000010245be1c91e3186bbbe1c430a93fcfc5aada4ab10c3492f70eea97a91c7b29554db55acffa34d2");
ASSERT_TRUE(e2.c0 == curve_Fq("238769481237490823"));
ASSERT_TRUE(e2.c1 == curve_Fq("384579238459723485"));
curve_Fq2 e3 = deserialize_fq2("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
ASSERT_TRUE(e3.c0 == curve_Fq("0"));
ASSERT_TRUE(e3.c1 == curve_Fq("0"));
curve_Fq2 e4 = deserialize_fq2("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001");
ASSERT_TRUE(e4.c0 == curve_Fq("1"));
ASSERT_TRUE(e4.c1 == curve_Fq("0"));
}
TEST(proofs, fq2_invalid)
{
// (q - 1) * q + q is invalid
ASSERT_THROW(
deserialize_fq2("0925c4b8763cbf9c599a6f7c0348d21cb00b85511637560626edfa5c34c6b38d04689e957a1242c84a50189c6d96cadca602072d09eac1013b5458a2275d69b1"),
std::logic_error
);
// q * q + (q - 1) is invalid
ASSERT_THROW(
deserialize_fq2("0925c4b8763cbf9c599a6f7c0348d21cb00b85511637560626edfa5c34c6b38d34cced085b43e2f202a05e52ef18233a3d8371be725c8b8e7774e4b8ffda66f7"),
std::logic_error
);
// Ridiculously out of bounds
ASSERT_THROW(
deserialize_fq2("0fffc4b8763cbf9c599a6f7c0348d21cb00b85511637560626edfa5c34c6b38d04689e957a1242c84a50189c6d96cadca602072d09eac1013b5458a2275d69b0"),
std::logic_error
);
ASSERT_THROW(
deserialize_fq2("ffffffff763cbf9c599a6f7c0348d21cb00b85511637560626edfa5c34c6b38d04689e957a1242c84a50189c6d96cadca602072d09eac1013b5458a2275d69b0"),
std::logic_error
);
}
TEST(proofs, g1_serializes_properly)
{
// Cannot serialize zero
{
ASSERT_THROW({CompressedG1 g = CompressedG1(curve_G1::zero());}, std::domain_error);
}
for (size_t i = 0; i < 1000; i++) {
curve_G1 e = curve_G1::random_element();
CompressedG1 e2(e);
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << e2;
CompressedG1 e3;
ss >> e3;
ASSERT_TRUE(e2 == e3);
curve_G1 e4 = e3.to_libsnark_g1<curve_G1>();
ASSERT_TRUE(e == e4);
}
}
TEST(proofs, g2_serializes_properly)
{
// Cannot serialize zero
{
ASSERT_THROW({CompressedG2 g = CompressedG2(curve_G2::zero());}, std::domain_error);
}
for (size_t i = 0; i < 1000; i++) {
curve_G2 e = curve_G2::random_element();
CompressedG2 e2(e);
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << e2;
CompressedG2 e3;
ss >> e3;
ASSERT_TRUE(e2 == e3);
curve_G2 e4 = e3.to_libsnark_g2<curve_G2>();
ASSERT_TRUE(e == e4);
}
}
TEST(proofs, zksnark_serializes_properly)
{
auto example = libsnark::generate_r1cs_example_with_field_input<curve_Fr>(250, 4);
example.constraint_system.swap_AB_if_beneficial();
auto kp = libsnark::r1cs_ppzksnark_generator<curve_pp>(example.constraint_system);
auto vkprecomp = libsnark::r1cs_ppzksnark_verifier_process_vk(kp.vk);
for (size_t i = 0; i < 20; i++) {
auto badproof = PHGRProof::random_invalid();
auto proof = badproof.to_libsnark_proof<libsnark::r1cs_ppzksnark_proof<curve_pp>>();
auto verifierEnabled = ProofVerifier::Strict();
auto verifierDisabled = ProofVerifier::Disabled();
// This verifier should catch the bad proof
ASSERT_FALSE(verifierEnabled.check(
kp.vk,
vkprecomp,
example.primary_input,
proof
));
// This verifier won't!
ASSERT_TRUE(verifierDisabled.check(
kp.vk,
vkprecomp,
example.primary_input,
proof
));
}
for (size_t i = 0; i < 20; i++) {
auto proof = libsnark::r1cs_ppzksnark_prover<curve_pp>(
kp.pk,
example.primary_input,
example.auxiliary_input,
example.constraint_system
);
{
auto verifierEnabled = ProofVerifier::Strict();
auto verifierDisabled = ProofVerifier::Disabled();
ASSERT_TRUE(verifierEnabled.check(
kp.vk,
vkprecomp,
example.primary_input,
proof
));
ASSERT_TRUE(verifierDisabled.check(
kp.vk,
vkprecomp,
example.primary_input,
proof
));
}
ASSERT_TRUE(libsnark::r1cs_ppzksnark_verifier_strong_IC<curve_pp>(
kp.vk,
example.primary_input,
proof
));
PHGRProof compressed_proof_0(proof);
CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
ss << compressed_proof_0;
PHGRProof compressed_proof_1;
ss >> compressed_proof_1;
ASSERT_TRUE(compressed_proof_0 == compressed_proof_1);
auto newproof = compressed_proof_1.to_libsnark_proof<libsnark::r1cs_ppzksnark_proof<curve_pp>>();
ASSERT_TRUE(proof == newproof);
ASSERT_TRUE(libsnark::r1cs_ppzksnark_verifier_strong_IC<curve_pp>(
kp.vk,
example.primary_input,
newproof
));
}
}
TEST(proofs, g1_deserialization)
{
CompressedG1 g;
curve_G1 expected;
// Valid G1 element.
{
CDataStream ss(ParseHex("0230644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46"), SER_NETWORK, PROTOCOL_VERSION);
ss >> g;
expected.X = curve_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582");
expected.Y = curve_Fq("3969792565221544645472939191694882283483352126195956956354061729942568608776");
expected.Z = curve_Fq::one();
ASSERT_TRUE(g.to_libsnark_g1<curve_G1>() == expected);
}
// Its negation.
{
CDataStream ss(ParseHex("0330644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46"), SER_NETWORK, PROTOCOL_VERSION);
ss >> g;
expected.X = curve_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582");
expected.Y = curve_Fq("3969792565221544645472939191694882283483352126195956956354061729942568608776");
expected.Z = curve_Fq::one();
ASSERT_TRUE(g.to_libsnark_g1<curve_G1>() == -expected);
}
// Invalid leading bytes
{
CDataStream ss(ParseHex("ff30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46"), SER_NETWORK, PROTOCOL_VERSION);
ASSERT_THROW(ss >> g, std::ios_base::failure);
}
// Invalid point
{
CDataStream ss(ParseHex("0208c6d2adffacbc8438f09f321874ea66e2fcc29f8dcfec2caefa21ec8c96a77c"), SER_NETWORK, PROTOCOL_VERSION);
ss >> g;
ASSERT_THROW(g.to_libsnark_g1<curve_G1>(), std::runtime_error);
}
// Point with out of bounds Fq
{
CDataStream ss(ParseHex("02ffc6d2adffacbc8438f09f321874ea66e2fcc29f8dcfec2caefa21ec8c96a77c"), SER_NETWORK, PROTOCOL_VERSION);
ss >> g;
ASSERT_THROW(g.to_libsnark_g1<curve_G1>(), std::logic_error);
}
// Randomly produce valid G1 representations and fail/succeed to
// turn them into G1 points based on whether they are valid.
for (size_t i = 0; i < 5000; i++) {
curve_Fq e = curve_Fq::random_element();
CDataStream ss(ParseHex("02"), SER_NETWORK, PROTOCOL_VERSION);
ss << Fq(e);
CompressedG1 g;
ss >> g;
try {
curve_G1 g_real = g.to_libsnark_g1<curve_G1>();
} catch(...) {
}
}
}
TEST(proofs, g2_deserialization)
{
CompressedG2 g;
curve_G2 expected = curve_G2::random_element();
// Valid G2 point
{
CDataStream ss(ParseHex("0a023aed31b5a9e486366ea9988b05dba469c6206e58361d9c065bbea7d928204a761efc6e4fa08ed227650134b52c7f7dd0463963e8a4bf21f4899fe5da7f984a"), SER_NETWORK, PROTOCOL_VERSION);
ss >> g;
expected.X = curve_Fq2(
curve_Fq("5923585509243758863255447226263146374209884951848029582715967108651637186684"),
curve_Fq("5336385337059958111259504403491065820971993066694750945459110579338490853570")
);
expected.Y = curve_Fq2(
curve_Fq("10374495865873200088116930399159835104695426846400310764827677226300185211748"),
curve_Fq("5256529835065685814318509161957442385362539991735248614869838648137856366932")
);
expected.Z = curve_Fq2::one();
ASSERT_TRUE(g.to_libsnark_g2<curve_G2>() == expected);
}
// Its negation
{
CDataStream ss(ParseHex("0b023aed31b5a9e486366ea9988b05dba469c6206e58361d9c065bbea7d928204a761efc6e4fa08ed227650134b52c7f7dd0463963e8a4bf21f4899fe5da7f984a"), SER_NETWORK, PROTOCOL_VERSION);
ss >> g;
expected.X = curve_Fq2(
curve_Fq("5923585509243758863255447226263146374209884951848029582715967108651637186684"),
curve_Fq("5336385337059958111259504403491065820971993066694750945459110579338490853570")
);
expected.Y = curve_Fq2(
curve_Fq("10374495865873200088116930399159835104695426846400310764827677226300185211748"),
curve_Fq("5256529835065685814318509161957442385362539991735248614869838648137856366932")
);
expected.Z = curve_Fq2::one();
ASSERT_TRUE(g.to_libsnark_g2<curve_G2>() == -expected);
}
// Invalid leading bytes
{
CDataStream ss(ParseHex("ff023aed31b5a9e486366ea9988b05dba469c6206e58361d9c065bbea7d928204a761efc6e4fa08ed227650134b52c7f7dd0463963e8a4bf21f4899fe5da7f984a"), SER_NETWORK, PROTOCOL_VERSION);
ASSERT_THROW(ss >> g, std::ios_base::failure);
}
// Invalid point
{
CDataStream ss(ParseHex("0b023aed31b5a9e486366ea9988b05dba469c6206e58361d9c065bbea7d928204a761efc6e4fa08ed227650134b52c7f7dd0463963e8a4bf21f4899fe5da7f984b"), SER_NETWORK, PROTOCOL_VERSION);
ss >> g;
ASSERT_THROW(g.to_libsnark_g2<curve_G2>(), std::runtime_error);
}
// Point with out of bounds Fq2
{
CDataStream ss(ParseHex("0a0f3aed31b5a9e486366ea9988b05dba469c6206e58361d9c065bbea7d928204a761efc6e4fa08ed227650134b52c7f7dd0463963e8a4bf21f4899fe5da7f984a"), SER_NETWORK, PROTOCOL_VERSION);
ss >> g;
ASSERT_THROW(g.to_libsnark_g2<curve_G2>(), std::logic_error);
}
// Randomly produce valid G2 representations and fail/succeed to
// turn them into G2 points based on whether they are valid.
for (size_t i = 0; i < 5000; i++) {
curve_Fq2 e = curve_Fq2::random_element();
CDataStream ss(ParseHex("0a"), SER_NETWORK, PROTOCOL_VERSION);
ss << Fq2(e);
CompressedG2 g;
ss >> g;
try {
curve_G2 g_real = g.to_libsnark_g2<curve_G2>();
} catch(...) {
}
}
}
#include "json_test_vectors.h"
#include "test/data/g1_compressed.json.h"
TEST(proofs, g1_test_vectors)
{
UniValue v = read_json(std::string(json_tests::g1_compressed, json_tests::g1_compressed + sizeof(json_tests::g1_compressed)));
curve_G1 e = curve_Fr("34958239045823") * curve_G1::one();
for (size_t i = 0; i < 10000; i++) {
e = (curve_Fr("34958239045823") ^ i) * e;
auto expected = CompressedG1(e);
expect_test_vector(v[i], expected);
ASSERT_TRUE(expected.to_libsnark_g1<curve_G1>() == e);
}
}
#include "test/data/g2_compressed.json.h"
TEST(proofs, g2_test_vectors)
{
UniValue v = read_json(std::string(json_tests::g2_compressed, json_tests::g2_compressed + sizeof(json_tests::g2_compressed)));
curve_G2 e = curve_Fr("34958239045823") * curve_G2::one();
for (size_t i = 0; i < 10000; i++) {
e = (curve_Fr("34958239045823") ^ i) * e;
auto expected = CompressedG2(e);
expect_test_vector(v[i], expected);
ASSERT_TRUE(expected.to_libsnark_g2<curve_G2>() == e);
}
}

1
src/primitives/transaction.h

@ -1,5 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin Core developers
// Copyright (c) 2019-2020 The Hush developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

40
src/zcash/CreateJoinSplit.cpp

@ -1,40 +0,0 @@
// Copyright (c) 2016 The Zcash developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "../util.h"
#include "primitives/transaction.h"
#include "zcash/JoinSplit.hpp"
#include "libsnark/common/profiling.hpp"
#include "komodo_defs.h"
char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
uint16_t BITCOIND_RPCPORT = 7771;
uint32_t ASSETCHAINS_CC = 0;
using namespace libzcash;
int main(int argc, char **argv)
{
libsnark::start_profiling();
auto p = ZCJoinSplit::Prepared((ZC_GetParamsDir() / "sprout-verifying.key").string(),
(ZC_GetParamsDir() / "sprout-proving.key").string());
// construct a proof.
for (int i = 0; i < 5; i++) {
uint256 anchor = ZCIncrementalMerkleTree().root();
uint256 pubKeyHash;
JSDescription jsdesc(*p,
pubKeyHash,
anchor,
{JSInput(), JSInput()},
{JSOutput(), JSOutput()},
0,
0);
}
delete p; // not that it matters
}

26
src/zcash/GenerateParams.cpp

@ -1,26 +0,0 @@
#include "zcash/JoinSplit.hpp"
#include <iostream>
#include "crypto/common.h"
int64_t MAX_MONEY = 200000000 * 100000000LL;
int main(int argc, char **argv)
{
if (init_and_check_sodium() == -1) {
return 1;
}
if(argc != 4) {
std::cerr << "Usage: " << argv[0] << " provingKeyFileName verificationKeyFileName r1csFileName" << std::endl;
return 1;
}
std::string pkFile = argv[1];
std::string vkFile = argv[2];
std::string r1csFile = argv[3];
ZCJoinSplit::Generate(r1csFile, vkFile, pkFile);
return 0;
}

788
src/zcash/IncrementalMerkleTree.cpp

@ -35,6 +35,391 @@ PedersenHash PedersenHash::uncommitted() {
return res;
}
static const std::array<PedersenHash, 65> pedersen_empty_roots = {
uint256(std::vector<unsigned char>{
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}),
uint256(std::vector<unsigned char>{
0x81, 0x7d, 0xe3, 0x6a, 0xb2, 0xd5, 0x7f, 0xeb,
0x07, 0x76, 0x34, 0xbc, 0xa7, 0x78, 0x19, 0xc8,
0xe0, 0xbd, 0x29, 0x8c, 0x04, 0xf6, 0xfe, 0xd0,
0xe6, 0xa8, 0x3c, 0xc1, 0x35, 0x6c, 0xa1, 0x55,
}),
uint256(std::vector<unsigned char>{
0xff, 0xe9, 0xfc, 0x03, 0xf1, 0x8b, 0x17, 0x6c,
0x99, 0x88, 0x06, 0x43, 0x9f, 0xf0, 0xbb, 0x8a,
0xd1, 0x93, 0xaf, 0xdb, 0x27, 0xb2, 0xcc, 0xbc,
0x88, 0x85, 0x69, 0x16, 0xdd, 0x80, 0x4e, 0x34,
}),
uint256(std::vector<unsigned char>{
0xd8, 0x28, 0x33, 0x86, 0xef, 0x2e, 0xf0, 0x7e,
0xbd, 0xbb, 0x43, 0x83, 0xc1, 0x2a, 0x73, 0x9a,
0x95, 0x3a, 0x4d, 0x6e, 0x0d, 0x6f, 0xb1, 0x13,
0x9a, 0x40, 0x36, 0xd6, 0x93, 0xbf, 0xbb, 0x6c,
}),
uint256(std::vector<unsigned char>{
0xe1, 0x10, 0xde, 0x65, 0xc9, 0x07, 0xb9, 0xde,
0xa4, 0xae, 0x0b, 0xd8, 0x3a, 0x4b, 0x0a, 0x51,
0xbe, 0xa1, 0x75, 0x64, 0x6a, 0x64, 0xc1, 0x2b,
0x4c, 0x9f, 0x93, 0x1b, 0x2c, 0xb3, 0x1b, 0x49,
}),
uint256(std::vector<unsigned char>{
0x91, 0x2d, 0x82, 0xb2, 0xc2, 0xbc, 0xa2, 0x31,
0xf7, 0x1e, 0xfc, 0xf6, 0x17, 0x37, 0xfb, 0xf0,
0xa0, 0x8b, 0xef, 0xa0, 0x41, 0x62, 0x15, 0xae,
0xef, 0x53, 0xe8, 0xbb, 0x6d, 0x23, 0x39, 0x0a,
}),
uint256(std::vector<unsigned char>{
0x8a, 0xc9, 0xcf, 0x9c, 0x39, 0x1e, 0x3f, 0xd4,
0x28, 0x91, 0xd2, 0x72, 0x38, 0xa8, 0x1a, 0x8a,
0x5c, 0x1d, 0x3a, 0x72, 0xb1, 0xbc, 0xbe, 0xa8,
0xcf, 0x44, 0xa5, 0x8c, 0xe7, 0x38, 0x96, 0x13,
}),
uint256(std::vector<unsigned char>{
0xd6, 0xc6, 0x39, 0xac, 0x24, 0xb4, 0x6b, 0xd1,
0x93, 0x41, 0xc9, 0x1b, 0x13, 0xfd, 0xca, 0xb3,
0x15, 0x81, 0xdd, 0xaf, 0x7f, 0x14, 0x11, 0x33,
0x6a, 0x27, 0x1f, 0x3d, 0x0a, 0xa5, 0x28, 0x13,
}),
uint256(std::vector<unsigned char>{
0x7b, 0x99, 0xab, 0xdc, 0x37, 0x30, 0x99, 0x1c,
0xc9, 0x27, 0x47, 0x27, 0xd7, 0xd8, 0x2d, 0x28,
0xcb, 0x79, 0x4e, 0xdb, 0xc7, 0x03, 0x4b, 0x4f,
0x00, 0x53, 0xff, 0x7c, 0x4b, 0x68, 0x04, 0x44,
}),
uint256(std::vector<unsigned char>{
0x43, 0xff, 0x54, 0x57, 0xf1, 0x3b, 0x92, 0x6b,
0x61, 0xdf, 0x55, 0x2d, 0x4e, 0x40, 0x2e, 0xe6,
0xdc, 0x14, 0x63, 0xf9, 0x9a, 0x53, 0x5f, 0x9a,
0x71, 0x34, 0x39, 0x26, 0x4d, 0x5b, 0x61, 0x6b,
}),
uint256(std::vector<unsigned char>{
0xba, 0x49, 0xb6, 0x59, 0xfb, 0xd0, 0xb7, 0x33,
0x42, 0x11, 0xea, 0x6a, 0x9d, 0x9d, 0xf1, 0x85,
0xc7, 0x57, 0xe7, 0x0a, 0xa8, 0x1d, 0xa5, 0x62,
0xfb, 0x91, 0x2b, 0x84, 0xf4, 0x9b, 0xce, 0x72,
}),
uint256(std::vector<unsigned char>{
0x47, 0x77, 0xc8, 0x77, 0x6a, 0x3b, 0x1e, 0x69,
0xb7, 0x3a, 0x62, 0xfa, 0x70, 0x1f, 0xa4, 0xf7,
0xa6, 0x28, 0x2d, 0x9a, 0xee, 0x2c, 0x7a, 0x6b,
0x82, 0xe7, 0x93, 0x7d, 0x70, 0x81, 0xc2, 0x3c,
}),
uint256(std::vector<unsigned char>{
0xec, 0x67, 0x71, 0x14, 0xc2, 0x72, 0x06, 0xf5,
0xde, 0xbc, 0x1c, 0x1e, 0xd6, 0x6f, 0x95, 0xe2,
0xb1, 0x88, 0x5d, 0xa5, 0xb7, 0xbe, 0x3d, 0x73,
0x6b, 0x1d, 0xe9, 0x85, 0x79, 0x47, 0x30, 0x48,
}),
uint256(std::vector<unsigned char>{
0x1b, 0x77, 0xda, 0xc4, 0xd2, 0x4f, 0xb7, 0x25,
0x8c, 0x3c, 0x52, 0x87, 0x04, 0xc5, 0x94, 0x30,
0xb6, 0x30, 0x71, 0x8b, 0xec, 0x48, 0x64, 0x21,
0x83, 0x70, 0x21, 0xcf, 0x75, 0xda, 0xb6, 0x51,
}),
uint256(std::vector<unsigned char>{
0xbd, 0x74, 0xb2, 0x5a, 0xac, 0xb9, 0x23, 0x78,
0xa8, 0x71, 0xbf, 0x27, 0xd2, 0x25, 0xcf, 0xc2,
0x6b, 0xac, 0xa3, 0x44, 0xa1, 0xea, 0x35, 0xfd,
0xd9, 0x45, 0x10, 0xf3, 0xd1, 0x57, 0x08, 0x2c,
}),
uint256(std::vector<unsigned char>{
0xd6, 0xac, 0xde, 0xdf, 0x95, 0xf6, 0x08, 0xe0,
0x9f, 0xa5, 0x3f, 0xb4, 0x3d, 0xcd, 0x09, 0x90,
0x47, 0x57, 0x26, 0xc5, 0x13, 0x12, 0x10, 0xc9,
0xe5, 0xca, 0xea, 0xb9, 0x7f, 0x0e, 0x64, 0x2f,
}),
uint256(std::vector<unsigned char>{
0x1e, 0xa6, 0x67, 0x5f, 0x95, 0x51, 0xee, 0xb9,
0xdf, 0xaa, 0xa9, 0x24, 0x7b, 0xc9, 0x85, 0x82,
0x70, 0xd3, 0xd3, 0xa4, 0xc5, 0xaf, 0xa7, 0x17,
0x7a, 0x98, 0x4d, 0x5e, 0xd1, 0xbe, 0x24, 0x51,
}),
uint256(std::vector<unsigned char>{
0x6e, 0xdb, 0x16, 0xd0, 0x19, 0x07, 0xb7, 0x59,
0x97, 0x7d, 0x76, 0x50, 0xda, 0xd7, 0xe3, 0xec,
0x04, 0x9a, 0xf1, 0xa3, 0xd8, 0x75, 0x38, 0x0b,
0x69, 0x7c, 0x86, 0x2c, 0x9e, 0xc5, 0xd5, 0x1c,
}),
uint256(std::vector<unsigned char>{
0xcd, 0x1c, 0x8d, 0xbf, 0x6e, 0x3a, 0xcc, 0x7a,
0x80, 0x43, 0x9b, 0xc4, 0x96, 0x2c, 0xf2, 0x5b,
0x9d, 0xce, 0x7c, 0x89, 0x6f, 0x3a, 0x5b, 0xd7,
0x08, 0x03, 0xfc, 0x5a, 0x0e, 0x33, 0xcf, 0x00,
}),
uint256(std::vector<unsigned char>{
0x6a, 0xca, 0x84, 0x48, 0xd8, 0x26, 0x3e, 0x54,
0x7d, 0x5f, 0xf2, 0x95, 0x0e, 0x2e, 0xd3, 0x83,
0x9e, 0x99, 0x8d, 0x31, 0xcb, 0xc6, 0xac, 0x9f,
0xd5, 0x7b, 0xc6, 0x00, 0x2b, 0x15, 0x92, 0x16,
}),
uint256(std::vector<unsigned char>{
0x8d, 0x5f, 0xa4, 0x3e, 0x5a, 0x10, 0xd1, 0x16,
0x05, 0xac, 0x74, 0x30, 0xba, 0x1f, 0x5d, 0x81,
0xfb, 0x1b, 0x68, 0xd2, 0x9a, 0x64, 0x04, 0x05,
0x76, 0x77, 0x49, 0xe8, 0x41, 0x52, 0x76, 0x73,
}),
uint256(std::vector<unsigned char>{
0x08, 0xee, 0xab, 0x0c, 0x13, 0xab, 0xd6, 0x06,
0x9e, 0x63, 0x10, 0x19, 0x7b, 0xf8, 0x0f, 0x9c,
0x1e, 0xa6, 0xde, 0x78, 0xfd, 0x19, 0xcb, 0xae,
0x24, 0xd4, 0xa5, 0x20, 0xe6, 0xcf, 0x30, 0x23,
}),
uint256(std::vector<unsigned char>{
0x07, 0x69, 0x55, 0x7b, 0xc6, 0x82, 0xb1, 0xbf,
0x30, 0x86, 0x46, 0xfd, 0x0b, 0x22, 0xe6, 0x48,
0xe8, 0xb9, 0xe9, 0x8f, 0x57, 0xe2, 0x9f, 0x5a,
0xf4, 0x0f, 0x6e, 0xdb, 0x83, 0x3e, 0x2c, 0x49,
}),
uint256(std::vector<unsigned char>{
0x4c, 0x69, 0x37, 0xd7, 0x8f, 0x42, 0x68, 0x5f,
0x84, 0xb4, 0x3a, 0xd3, 0xb7, 0xb0, 0x0f, 0x81,
0x28, 0x56, 0x62, 0xf8, 0x5c, 0x6a, 0x68, 0xef,
0x11, 0xd6, 0x2a, 0xd1, 0xa3, 0xee, 0x08, 0x50,
}),
uint256(std::vector<unsigned char>{
0xfe, 0xe0, 0xe5, 0x28, 0x02, 0xcb, 0x0c, 0x46,
0xb1, 0xeb, 0x4d, 0x37, 0x6c, 0x62, 0x69, 0x7f,
0x47, 0x59, 0xf6, 0xc8, 0x91, 0x7f, 0xa3, 0x52,
0x57, 0x12, 0x02, 0xfd, 0x77, 0x8f, 0xd7, 0x12,
}),
uint256(std::vector<unsigned char>{
0x16, 0xd6, 0x25, 0x29, 0x68, 0x97, 0x1a, 0x83,
0xda, 0x85, 0x21, 0xd6, 0x53, 0x82, 0xe6, 0x1f,
0x01, 0x76, 0x64, 0x6d, 0x77, 0x1c, 0x91, 0x52,
0x8e, 0x32, 0x76, 0xee, 0x45, 0x38, 0x3e, 0x4a,
}),
uint256(std::vector<unsigned char>{
0xd2, 0xe1, 0x64, 0x2c, 0x9a, 0x46, 0x22, 0x29,
0x28, 0x9e, 0x5b, 0x0e, 0x3b, 0x7f, 0x90, 0x08,
0xe0, 0x30, 0x1c, 0xbb, 0x93, 0x38, 0x5e, 0xe0,
0xe2, 0x1d, 0xa2, 0x54, 0x50, 0x73, 0xcb, 0x58,
}),
uint256(std::vector<unsigned char>{
0xa5, 0x12, 0x2c, 0x08, 0xff, 0x9c, 0x16, 0x1d,
0x9c, 0xa6, 0xfc, 0x46, 0x20, 0x73, 0x39, 0x6c,
0x7d, 0x7d, 0x38, 0xe8, 0xee, 0x48, 0xcd, 0xb3,
0xbe, 0xa7, 0xe2, 0x23, 0x01, 0x34, 0xed, 0x6a,
}),
uint256(std::vector<unsigned char>{
0x28, 0xe7, 0xb8, 0x41, 0xdc, 0xbc, 0x47, 0xcc,
0xeb, 0x69, 0xd7, 0xcb, 0x8d, 0x94, 0x24, 0x5f,
0xb7, 0xcb, 0x2b, 0xa3, 0xa7, 0xa6, 0xbc, 0x18,
0xf1, 0x3f, 0x94, 0x5f, 0x7d, 0xbd, 0x6e, 0x2a,
}),
uint256(std::vector<unsigned char>{
0xe1, 0xf3, 0x4b, 0x03, 0x4d, 0x4a, 0x3c, 0xd2,
0x85, 0x57, 0xe2, 0x90, 0x7e, 0xbf, 0x99, 0x0c,
0x91, 0x8f, 0x64, 0xec, 0xb5, 0x0a, 0x94, 0xf0,
0x1d, 0x6f, 0xda, 0x5c, 0xa5, 0xc7, 0xef, 0x72,
}),
uint256(std::vector<unsigned char>{
0x12, 0x93, 0x5f, 0x14, 0xb6, 0x76, 0x50, 0x9b,
0x81, 0xeb, 0x49, 0xef, 0x25, 0xf3, 0x92, 0x69,
0xed, 0x72, 0x30, 0x92, 0x38, 0xb4, 0xc1, 0x45,
0x80, 0x35, 0x44, 0xb6, 0x46, 0xdc, 0xa6, 0x2d,
}),
uint256(std::vector<unsigned char>{
0xb2, 0xee, 0xd0, 0x31, 0xd4, 0xd6, 0xa4, 0xf0,
0x2a, 0x09, 0x7f, 0x80, 0xb5, 0x4c, 0xc1, 0x54,
0x1d, 0x41, 0x63, 0xc6, 0xb6, 0xf5, 0x97, 0x1f,
0x88, 0xb6, 0xe4, 0x1d, 0x35, 0xc5, 0x38, 0x14,
}),
uint256(std::vector<unsigned char>{
0xfb, 0xc2, 0xf4, 0x30, 0x0c, 0x01, 0xf0, 0xb7,
0x82, 0x0d, 0x00, 0xe3, 0x34, 0x7c, 0x8d, 0xa4,
0xee, 0x61, 0x46, 0x74, 0x37, 0x6c, 0xbc, 0x45,
0x35, 0x9d, 0xaa, 0x54, 0xf9, 0xb5, 0x49, 0x3e,
}),
uint256(std::vector<unsigned char>{
0x25, 0x2e, 0x67, 0x98, 0x64, 0x5f, 0x5b, 0xf1,
0x14, 0xe4, 0xb4, 0xe9, 0x0e, 0x96, 0x18, 0x28,
0x61, 0x48, 0x98, 0x40, 0xd9, 0xb4, 0xcc, 0xc4,
0xc1, 0xfb, 0x5a, 0x46, 0x99, 0x7c, 0xee, 0x14,
}),
uint256(std::vector<unsigned char>{
0x98, 0xb1, 0x90, 0x42, 0xf1, 0xf7, 0xc7, 0xdd,
0x11, 0xec, 0x25, 0xea, 0x66, 0xb6, 0xff, 0x74,
0xe0, 0x8c, 0xe1, 0x1d, 0x44, 0x7e, 0xd6, 0xf1,
0xbf, 0xe8, 0x7e, 0x11, 0x0e, 0x33, 0x1e, 0x11,
}),
uint256(std::vector<unsigned char>{
0xd4, 0x51, 0x30, 0x47, 0x99, 0x57, 0x2b, 0xa9,
0xf4, 0x2c, 0x4d, 0xab, 0x6b, 0x07, 0xc7, 0x03,
0xbd, 0x2c, 0x12, 0x3a, 0xb9, 0xd6, 0x0f, 0x2a,
0x60, 0xf9, 0x95, 0x58, 0x54, 0x91, 0x0b, 0x6a,
}),
uint256(std::vector<unsigned char>{
0x3e, 0xcd, 0x5f, 0x27, 0xac, 0xf0, 0x1b, 0xd3,
0x7a, 0x33, 0xe4, 0x51, 0x78, 0x67, 0xef, 0x76,
0x47, 0x4c, 0xd8, 0x3f, 0xb3, 0x1c, 0x92, 0x08,
0xdc, 0xef, 0x2e, 0xed, 0xce, 0xf3, 0x6c, 0x72,
}),
uint256(std::vector<unsigned char>{
0x26, 0xc3, 0x7d, 0xa6, 0x78, 0x94, 0xa1, 0x3d,
0xf8, 0xaa, 0x48, 0x78, 0xd2, 0x51, 0x4a, 0x42,
0x12, 0x57, 0x3b, 0x73, 0xec, 0xca, 0xab, 0x16,
0xfe, 0x4f, 0xa6, 0x60, 0xe8, 0xfe, 0x27, 0x07,
}),
uint256(std::vector<unsigned char>{
0xb5, 0x45, 0xef, 0x34, 0x48, 0x5e, 0xed, 0x30,
0xd4, 0x2b, 0x2c, 0x29, 0x5a, 0x4a, 0x5b, 0x68,
0x0d, 0xe8, 0xa9, 0xd5, 0xe3, 0x83, 0x45, 0x78,
0x24, 0x62, 0xc0, 0x4f, 0x09, 0xdc, 0x68, 0x51,
}),
uint256(std::vector<unsigned char>{
0x77, 0xfd, 0x20, 0xb3, 0x00, 0x94, 0x67, 0x65,
0xa8, 0x7f, 0x24, 0xbd, 0x04, 0x50, 0x73, 0x72,
0x9c, 0xbd, 0x7b, 0x66, 0xeb, 0x8f, 0xa1, 0x40,
0xb5, 0x83, 0xfa, 0xa9, 0xd1, 0x42, 0x58, 0x01,
}),
uint256(std::vector<unsigned char>{
0xcb, 0xaa, 0x57, 0x6b, 0x17, 0x99, 0xb5, 0x8f,
0xf3, 0xa6, 0xde, 0xcb, 0xba, 0x91, 0x9b, 0x0b,
0x68, 0xd7, 0xc8, 0x93, 0xe4, 0x6f, 0xde, 0x99,
0x87, 0x68, 0xe8, 0x7e, 0x35, 0x0a, 0x07, 0x25,
}),
uint256(std::vector<unsigned char>{
0x45, 0xfe, 0x81, 0xb1, 0x8c, 0xa3, 0x00, 0x74,
0xd0, 0x12, 0x0d, 0x2b, 0x1a, 0x0d, 0x10, 0xb3,
0xa0, 0x50, 0x93, 0x35, 0x12, 0xdb, 0x8e, 0xe3,
0x4e, 0x52, 0x47, 0x3d, 0x4f, 0x08, 0xa2, 0x67,
}),
uint256(std::vector<unsigned char>{
0x0e, 0x60, 0xa1, 0xf0, 0x12, 0x1f, 0x59, 0x1e,
0x55, 0x1d, 0x3e, 0xd1, 0x86, 0x5b, 0x50, 0xa7,
0x5d, 0x7c, 0xcf, 0xf1, 0x28, 0x9d, 0xf7, 0xc4,
0x4d, 0xd4, 0x65, 0xa5, 0x43, 0x17, 0xf5, 0x6a,
}),
uint256(std::vector<unsigned char>{
0xce, 0xdf, 0xb1, 0x84, 0xdd, 0x92, 0xa0, 0xcb,
0xfc, 0x11, 0xe8, 0xbe, 0x69, 0x7b, 0x47, 0x69,
0x88, 0xed, 0x5f, 0x39, 0x36, 0x9a, 0xbd, 0xd9,
0x0c, 0x61, 0x54, 0x49, 0x88, 0x60, 0x1c, 0x0d,
}),
uint256(std::vector<unsigned char>{
0xf3, 0x62, 0x68, 0x66, 0x12, 0x64, 0x9a, 0x31,
0x3b, 0xa4, 0x64, 0x43, 0x7a, 0x0c, 0xad, 0x0e,
0x7e, 0x3d, 0x7e, 0x1b, 0x4b, 0x37, 0x43, 0xf9,
0x0e, 0x05, 0xa2, 0x10, 0x0a, 0x49, 0x5f, 0x42,
}),
uint256(std::vector<unsigned char>{
0x7d, 0xea, 0xe5, 0xf3, 0xbb, 0xde, 0xff, 0xd3,
0xf8, 0x52, 0x71, 0xa0, 0x8b, 0x5e, 0xc3, 0x1f,
0x16, 0xf9, 0x37, 0x96, 0x4a, 0xe7, 0x08, 0xfd,
0xff, 0x7c, 0x13, 0xe5, 0xa4, 0xf3, 0xdf, 0x6b,
}),
uint256(std::vector<unsigned char>{
0x40, 0xcc, 0xf0, 0xfc, 0x1e, 0xab, 0x6d, 0x85,
0x02, 0xbd, 0x93, 0xdc, 0x31, 0x34, 0x2d, 0xfd,
0x57, 0xdf, 0x5b, 0xbb, 0x5d, 0x70, 0xa1, 0xbf,
0x6b, 0x92, 0xef, 0xc6, 0x1e, 0xc9, 0xa2, 0x58,
}),
uint256(std::vector<unsigned char>{
0xd7, 0x80, 0x25, 0x49, 0x1f, 0x1b, 0xca, 0x85,
0x07, 0xf6, 0x4f, 0x25, 0x87, 0x2d, 0xd0, 0x23,
0x88, 0x47, 0x9a, 0x1a, 0x22, 0x51, 0x26, 0xe4,
0x0d, 0x2f, 0xe4, 0x18, 0xb9, 0x8e, 0x0e, 0x2c,
}),
uint256(std::vector<unsigned char>{
0x0d, 0xb7, 0x29, 0x46, 0x85, 0xc8, 0xa0, 0x72,
0x5f, 0x15, 0x84, 0x6e, 0xa5, 0x89, 0x9e, 0xa0,
0xe9, 0x86, 0xc2, 0x70, 0x7b, 0xd7, 0xb4, 0x12,
0x95, 0x44, 0x12, 0xf2, 0x6a, 0xbf, 0x55, 0x0a,
}),
uint256(std::vector<unsigned char>{
0xb7, 0xe2, 0x90, 0xbe, 0x95, 0x55, 0xcf, 0x75,
0x54, 0x86, 0x50, 0xda, 0x6d, 0x47, 0xc8, 0x93,
0xae, 0xf7, 0xf8, 0xc6, 0xdd, 0x27, 0x35, 0x49,
0x94, 0x95, 0xf6, 0x36, 0x59, 0x0d, 0xae, 0x0a,
}),
uint256(std::vector<unsigned char>{
0x2d, 0xd2, 0x53, 0x2a, 0x85, 0x8c, 0x30, 0x01,
0x45, 0xa6, 0x5e, 0x35, 0x1f, 0x91, 0xbe, 0x6a,
0xfe, 0xab, 0x59, 0x7c, 0x41, 0xef, 0x07, 0x3f,
0x50, 0xb6, 0x22, 0xd5, 0x86, 0xff, 0x59, 0x27,
}),
uint256(std::vector<unsigned char>{
0x97, 0x2f, 0x0c, 0x5c, 0x6f, 0x9a, 0xeb, 0x0e,
0x38, 0xbf, 0x83, 0x19, 0xf3, 0xa5, 0xfc, 0xdc,
0x8f, 0xd8, 0x78, 0x2e, 0x41, 0x88, 0x73, 0x0c,
0xd0, 0x82, 0xd9, 0xba, 0xbc, 0x58, 0x98, 0x51,
}),
uint256(std::vector<unsigned char>{
0x00, 0x1e, 0x57, 0x7b, 0x0f, 0x43, 0x90, 0x18,
0x2b, 0x4a, 0xe4, 0x3d, 0x32, 0x9b, 0x3a, 0xa8,
0x83, 0x5d, 0xae, 0x1b, 0xb7, 0x9e, 0x60, 0x4b,
0x7d, 0x2d, 0xa0, 0xe9, 0x0d, 0x06, 0x09, 0x29,
}),
uint256(std::vector<unsigned char>{
0xaa, 0x6e, 0x70, 0xa9, 0x1e, 0xbc, 0x54, 0xee,
0xfc, 0xe5, 0xff, 0xd5, 0xb6, 0x75, 0xda, 0xf3,
0xf1, 0xd9, 0x40, 0xa8, 0x45, 0x1f, 0xcb, 0x01,
0x08, 0x1f, 0xa9, 0xd4, 0xf2, 0x62, 0x43, 0x6f,
}),
uint256(std::vector<unsigned char>{
0xd7, 0x70, 0x38, 0xbf, 0x67, 0xe6, 0x31, 0x75,
0x29, 0x40, 0x23, 0x12, 0x51, 0xd7, 0xfe, 0x85,
0xaf, 0x52, 0xdb, 0xdd, 0x6a, 0xab, 0x37, 0xc7,
0xa5, 0xec, 0x32, 0xb6, 0x5f, 0xe6, 0xde, 0x03,
}),
uint256(std::vector<unsigned char>{
0xd2, 0x27, 0xa1, 0x7a, 0x7e, 0x0c, 0xf9, 0x6d,
0xce, 0xdd, 0x9f, 0xc7, 0xbc, 0xe4, 0x3c, 0x6c,
0x1d, 0x66, 0xba, 0xdd, 0x75, 0x43, 0xa8, 0x87,
0xc8, 0x65, 0x6c, 0x54, 0x7e, 0xcf, 0xb2, 0x4f,
}),
uint256(std::vector<unsigned char>{
0x70, 0xe8, 0xa5, 0x21, 0x95, 0x15, 0x83, 0xe5,
0x3f, 0xc0, 0x58, 0x5c, 0x70, 0x7e, 0xce, 0xda,
0x89, 0xb7, 0xa7, 0xd1, 0xaf, 0x41, 0xd1, 0xa0,
0x15, 0xd7, 0x97, 0xfa, 0x76, 0xc0, 0xf5, 0x69,
}),
uint256(std::vector<unsigned char>{
0xe4, 0x85, 0xa9, 0x68, 0x55, 0xe8, 0x72, 0xfc,
0x50, 0x90, 0x15, 0x0e, 0x2c, 0xd2, 0x4e, 0x10,
0x59, 0x1d, 0x35, 0x16, 0x6e, 0xb0, 0xeb, 0x30,
0xfc, 0xdf, 0xac, 0x93, 0xb0, 0x1d, 0x28, 0x1c,
}),
uint256(std::vector<unsigned char>{
0xe4, 0xa1, 0x9f, 0xeb, 0xdf, 0x2a, 0x86, 0x89,
0x6e, 0x41, 0xf2, 0xce, 0xdc, 0xf2, 0xae, 0x58,
0x46, 0x71, 0x80, 0x2e, 0x6a, 0x46, 0x7e, 0x84,
0x39, 0xca, 0xb5, 0xd6, 0x18, 0x43, 0x41, 0x6b,
}),
uint256(std::vector<unsigned char>{
0xe9, 0x27, 0x83, 0x88, 0x47, 0x80, 0x6a, 0x43,
0xbd, 0x6c, 0x60, 0x88, 0xe3, 0x9f, 0x65, 0xb8,
0xb3, 0xe5, 0x8b, 0x2d, 0xb5, 0xf7, 0xad, 0x56,
0x43, 0xd9, 0x1e, 0x06, 0x59, 0xa2, 0x8a, 0x2a,
}),
uint256(std::vector<unsigned char>{
0x0b, 0xd3, 0xa8, 0x18, 0xe8, 0x3f, 0x9c, 0xd2,
0xff, 0x4f, 0x62, 0x01, 0x1a, 0x51, 0x01, 0x76,
0xac, 0x32, 0xf5, 0x44, 0x8e, 0x6e, 0x15, 0x45,
0x15, 0x04, 0x3c, 0x59, 0x26, 0xd5, 0x1c, 0x6f,
}),
uint256(std::vector<unsigned char>{
0xce, 0x41, 0x34, 0x45, 0xe0, 0x37, 0x90, 0x49,
0x8f, 0xe7, 0x2d, 0x8e, 0x01, 0x91, 0x5e, 0x7f,
0xf1, 0x20, 0xae, 0x35, 0xb3, 0xb5, 0x90, 0xd2,
0x1b, 0x7f, 0x74, 0xde, 0xe1, 0x83, 0x0f, 0x0d,
}),
uint256(std::vector<unsigned char>{
0x60, 0x0e, 0x6f, 0x93, 0xe7, 0x3d, 0x7a, 0xbd,
0x4e, 0xe0, 0xa6, 0x5c, 0xb1, 0xb1, 0x9a, 0xa3,
0xec, 0xc5, 0x25, 0x68, 0x9d, 0xbf, 0x17, 0x77,
0x96, 0x58, 0x74, 0x1b, 0x95, 0xc1, 0x5a, 0x55,
}),
};
PedersenHash PedersenHash::EmptyRoot(size_t depth) {
return pedersen_empty_roots.at(depth);
}
SHA256Compress SHA256Compress::combine(
const SHA256Compress& a,
const SHA256Compress& b,
@ -51,6 +436,409 @@ SHA256Compress SHA256Compress::combine(
return res;
}
static const std::array<SHA256Compress, 66> sha256_empty_roots = {
uint256(std::vector<unsigned char>{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}),
uint256(std::vector<unsigned char>{
0xda, 0x56, 0x98, 0xbe, 0x17, 0xb9, 0xb4, 0x69,
0x62, 0x33, 0x57, 0x99, 0x77, 0x9f, 0xbe, 0xca,
0x8c, 0xe5, 0xd4, 0x91, 0xc0, 0xd2, 0x62, 0x43,
0xba, 0xfe, 0xf9, 0xea, 0x18, 0x37, 0xa9, 0xd8,
}),
uint256(std::vector<unsigned char>{
0xdc, 0x76, 0x6f, 0xab, 0x49, 0x2c, 0xcf, 0x3d,
0x1e, 0x49, 0xd4, 0xf3, 0x74, 0xb5, 0x23, 0x5f,
0xa5, 0x65, 0x06, 0xaa, 0xc2, 0x22, 0x4d, 0x39,
0xf9, 0x43, 0xfc, 0xd4, 0x92, 0x02, 0x97, 0x4c,
}),
uint256(std::vector<unsigned char>{
0x3f, 0x0a, 0x40, 0x61, 0x81, 0x10, 0x59, 0x68,
0xfd, 0xae, 0xe3, 0x06, 0x79, 0xe3, 0x27, 0x3c,
0x66, 0xb7, 0x2b, 0xf9, 0xa7, 0xf5, 0xde, 0xbb,
0xf3, 0xb5, 0xa0, 0xa2, 0x6e, 0x35, 0x9f, 0x92,
}),
uint256(std::vector<unsigned char>{
0x26, 0xb0, 0x05, 0x26, 0x94, 0xfc, 0x42, 0xfd,
0xff, 0x93, 0xe6, 0xfb, 0x5a, 0x71, 0xd3, 0x8c,
0x3d, 0xd7, 0xdc, 0x5b, 0x6a, 0xd7, 0x10, 0xeb,
0x04, 0x8c, 0x66, 0x02, 0x33, 0x13, 0x7f, 0xab,
}),
uint256(std::vector<unsigned char>{
0x01, 0x09, 0xec, 0xc0, 0x72, 0x26, 0x59, 0xff,
0x83, 0x45, 0x0b, 0x8f, 0x7b, 0x88, 0x46, 0xe6,
0x7b, 0x28, 0x59, 0xf3, 0x3c, 0x30, 0xd9, 0xb7,
0xac, 0xd5, 0xbf, 0x39, 0xca, 0xe5, 0x4e, 0x31,
}),
uint256(std::vector<unsigned char>{
0x3f, 0x90, 0x9b, 0x8c, 0xe3, 0xd7, 0xff, 0xd8,
0xa5, 0xb3, 0x09, 0x08, 0xf6, 0x05, 0xa0, 0x3b,
0x0d, 0xb8, 0x51, 0x69, 0x55, 0x8d, 0xdc, 0x1d,
0xa7, 0xbb, 0xbc, 0xc9, 0xb0, 0x9f, 0xd3, 0x25,
}),
uint256(std::vector<unsigned char>{
0x40, 0x46, 0x0f, 0xa6, 0xbc, 0x69, 0x2a, 0x06,
0xf4, 0x75, 0x21, 0xa6, 0x72, 0x5a, 0x54, 0x7c,
0x02, 0x8a, 0x6a, 0x24, 0x0d, 0x84, 0x09, 0xf1,
0x65, 0xe6, 0x3c, 0xb5, 0x4d, 0xa2, 0xd2, 0x3f,
}),
uint256(std::vector<unsigned char>{
0x8c, 0x08, 0x56, 0x74, 0x24, 0x9b, 0x43, 0xda,
0x1b, 0x9a, 0x31, 0xa0, 0xe8, 0x20, 0xe8, 0x1e,
0x75, 0xf3, 0x42, 0x80, 0x7b, 0x03, 0xb6, 0xb9,
0xe6, 0x49, 0x83, 0x21, 0x7b, 0xc2, 0xb3, 0x8e,
}),
uint256(std::vector<unsigned char>{
0xa0, 0x83, 0x45, 0x0c, 0x1b, 0xa2, 0xa3, 0xa7,
0xbe, 0x76, 0xfa, 0xd9, 0xd1, 0x3b, 0xc3, 0x7b,
0xe4, 0xbf, 0x83, 0xbd, 0x3e, 0x59, 0xfc, 0x37,
0x5a, 0x36, 0xba, 0x62, 0xdc, 0x62, 0x02, 0x98,
}),
uint256(std::vector<unsigned char>{
0x1d, 0xdd, 0xda, 0xbc, 0x2c, 0xaa, 0x2d, 0xe9,
0xef, 0xf9, 0xe1, 0x8c, 0x8c, 0x5a, 0x39, 0x40,
0x6d, 0x79, 0x36, 0xe8, 0x89, 0xbc, 0x16, 0xcf,
0xab, 0xb1, 0x44, 0xf5, 0xc0, 0x02, 0x26, 0x82,
}),
uint256(std::vector<unsigned char>{
0xc2, 0x2d, 0x8f, 0x0b, 0x5e, 0x40, 0x56, 0xe5,
0xf3, 0x18, 0xba, 0x22, 0x09, 0x1c, 0xc0, 0x7d,
0xb5, 0x69, 0x4f, 0xbe, 0xb5, 0xe8, 0x7e, 0xf0,
0xd7, 0xe2, 0xc5, 0x7c, 0xa3, 0x52, 0x35, 0x9e,
}),
uint256(std::vector<unsigned char>{
0x89, 0xa4, 0x34, 0xae, 0x1f, 0xeb, 0xd7, 0x68,
0x7e, 0xce, 0xea, 0x21, 0xd0, 0x7f, 0x20, 0xa2,
0x51, 0x24, 0x49, 0xd0, 0x8c, 0xe2, 0xee, 0xe5,
0x58, 0x71, 0xcd, 0xb9, 0xd4, 0x6c, 0x12, 0x33,
}),
uint256(std::vector<unsigned char>{
0x73, 0x33, 0xdb, 0xff, 0xbd, 0x11, 0xf0, 0x92,
0x47, 0xa2, 0xb3, 0x3a, 0x01, 0x3e, 0xc4, 0xc4,
0x34, 0x20, 0x29, 0xd8, 0x51, 0xe2, 0x2b, 0xa4,
0x85, 0xd4, 0x46, 0x18, 0x51, 0x37, 0x0c, 0x15,
}),
uint256(std::vector<unsigned char>{
0x5d, 0xad, 0x84, 0x4a, 0xb9, 0x46, 0x6b, 0x70,
0xf7, 0x45, 0x13, 0x71, 0x95, 0xca, 0x22, 0x1b,
0x48, 0xf3, 0x46, 0xab, 0xd1, 0x45, 0xfb, 0x5e,
0xfc, 0x23, 0xa8, 0xb4, 0xba, 0x50, 0x80, 0x22,
}),
uint256(std::vector<unsigned char>{
0x50, 0x7e, 0x0d, 0xae, 0x81, 0xcb, 0xfb, 0xe4,
0x57, 0xfd, 0x37, 0x0e, 0xf1, 0xca, 0x42, 0x01,
0xc2, 0xb6, 0x40, 0x10, 0x83, 0xdd, 0xab, 0x44,
0x0e, 0x4a, 0x03, 0x8d, 0xc1, 0xe3, 0x58, 0xc4,
}),
uint256(std::vector<unsigned char>{
0xbd, 0xcd, 0xb3, 0x29, 0x31, 0x88, 0xc9, 0x80,
0x7d, 0x80, 0x82, 0x67, 0x01, 0x86, 0x84, 0xcf,
0xec, 0xe0, 0x7a, 0xc3, 0x5a, 0x42, 0xc0, 0x0f,
0x2c, 0x79, 0xb4, 0x00, 0x38, 0x25, 0x30, 0x5d,
}),
uint256(std::vector<unsigned char>{
0xba, 0xb5, 0x80, 0x09, 0x72, 0xa1, 0x6c, 0x2c,
0x22, 0x53, 0x0c, 0x66, 0x06, 0x6d, 0x0a, 0x58,
0x67, 0xe9, 0x87, 0xbe, 0xd2, 0x1a, 0x6d, 0x5a,
0x45, 0x0b, 0x68, 0x3c, 0xf1, 0xcf, 0xd7, 0x09,
}),
uint256(std::vector<unsigned char>{
0x11, 0xaa, 0x0b, 0x4a, 0xd2, 0x9b, 0x13, 0xb0,
0x57, 0xa3, 0x16, 0x19, 0xd6, 0x50, 0x0d, 0x63,
0x6c, 0xd7, 0x35, 0xcd, 0xd0, 0x7d, 0x81, 0x1e,
0xa2, 0x65, 0xec, 0x4b, 0xcb, 0xbb, 0xd0, 0x58,
}),
uint256(std::vector<unsigned char>{
0x51, 0x45, 0xb1, 0xb0, 0x55, 0xc2, 0xdf, 0x02,
0xb9, 0x56, 0x75, 0xe3, 0x79, 0x7b, 0x91, 0xde,
0x1b, 0x84, 0x6d, 0x25, 0x00, 0x3c, 0x0a, 0x80,
0x3d, 0x08, 0x90, 0x07, 0x28, 0xf2, 0xcd, 0x6a,
}),
uint256(std::vector<unsigned char>{
0x03, 0x23, 0xf2, 0x85, 0x0b, 0xf3, 0x44, 0x4f,
0x4b, 0x4c, 0x5c, 0x09, 0xa6, 0x05, 0x7e, 0xc7,
0x16, 0x91, 0x90, 0xf4, 0x5a, 0xcb, 0x9e, 0x46,
0x98, 0x4a, 0xb3, 0xdf, 0xce, 0xc4, 0xf0, 0x6a,
}),
uint256(std::vector<unsigned char>{
0x67, 0x15, 0x46, 0xe2, 0x6b, 0x1d, 0xa1, 0xaf,
0x75, 0x45, 0x31, 0xe2, 0x6d, 0x8a, 0x6a, 0x51,
0x07, 0x3a, 0x57, 0xdd, 0xd7, 0x2d, 0xc4, 0x72,
0xef, 0xb4, 0x3f, 0xcb, 0x25, 0x7c, 0xff, 0xff,
}),
uint256(std::vector<unsigned char>{
0xbb, 0x23, 0xa9, 0xbb, 0xa5, 0x6d, 0xe5, 0x7c,
0xb2, 0x84, 0xb0, 0xd2, 0xb0, 0x1c, 0x64, 0x2c,
0xf7, 0x9c, 0x9a, 0x55, 0x63, 0xf0, 0x06, 0x7a,
0x21, 0x29, 0x24, 0x12, 0x14, 0x5b, 0xd7, 0x8a,
}),
uint256(std::vector<unsigned char>{
0xf3, 0x0c, 0xc8, 0x36, 0xb9, 0xf7, 0x1b, 0x4e,
0x7e, 0xe3, 0xc7, 0x2b, 0x1f, 0xd2, 0x53, 0x26,
0x8a, 0xf9, 0xa2, 0x7e, 0x9d, 0x72, 0x91, 0xa2,
0x3d, 0x02, 0x82, 0x1b, 0x21, 0xdd, 0xfd, 0x16,
}),
uint256(std::vector<unsigned char>{
0x58, 0xa2, 0x75, 0x3d, 0xad, 0xe1, 0x03, 0xce,
0xcb, 0xcd, 0xa5, 0x0b, 0x5e, 0xbf, 0xce, 0x31,
0xe1, 0x2d, 0x41, 0xd5, 0x84, 0x1d, 0xcc, 0x95,
0x62, 0x0f, 0x7b, 0x3d, 0x50, 0xa1, 0xb9, 0xa1,
}),
uint256(std::vector<unsigned char>{
0x92, 0x5e, 0x6d, 0x47, 0x4a, 0x5d, 0x8d, 0x30,
0x04, 0xf2, 0x9d, 0xa0, 0xdd, 0x78, 0xd3, 0x0a,
0xe3, 0x82, 0x4c, 0xe7, 0x9d, 0xfe, 0x49, 0x34,
0xbb, 0x29, 0xec, 0x3a, 0xfa, 0xf3, 0xd5, 0x21,
}),
uint256(std::vector<unsigned char>{
0x08, 0xf2, 0x79, 0x61, 0x86, 0x16, 0xbc, 0xdd,
0x4e, 0xad, 0xc9, 0xc7, 0xa9, 0x06, 0x26, 0x91,
0xa5, 0x9b, 0x43, 0xb0, 0x7e, 0x2c, 0x1e, 0x23,
0x7f, 0x17, 0xbd, 0x18, 0x9c, 0xd6, 0xa8, 0xfe,
}),
uint256(std::vector<unsigned char>{
0xc9, 0x2b, 0x32, 0xdb, 0x42, 0xf4, 0x2e, 0x2b,
0xf0, 0xa5, 0x9d, 0xf9, 0x05, 0x5b, 0xe5, 0xc6,
0x69, 0xd3, 0x24, 0x2d, 0xf4, 0x53, 0x57, 0x65,
0x9b, 0x75, 0xae, 0x2c, 0x27, 0xa7, 0x6f, 0x50,
}),
uint256(std::vector<unsigned char>{
0xc0, 0xdb, 0x2a, 0x74, 0x99, 0x8c, 0x50, 0xeb,
0x7b, 0xa6, 0x53, 0x4f, 0x6d, 0x41, 0x0e, 0xfc,
0x27, 0xc4, 0xbb, 0x88, 0xac, 0xb0, 0x22, 0x2c,
0x79, 0x06, 0xea, 0x28, 0xa3, 0x27, 0xb5, 0x11,
}),
uint256(std::vector<unsigned char>{
0xd7, 0xc6, 0x12, 0xc8, 0x17, 0x79, 0x31, 0x91,
0xa1, 0xe6, 0x86, 0x52, 0x12, 0x18, 0x76, 0xd6,
0xb3, 0xbd, 0xe4, 0x0f, 0x4f, 0xa5, 0x2b, 0xc3,
0x14, 0x14, 0x5c, 0xe6, 0xe5, 0xcd, 0xd2, 0x59,
}),
uint256(std::vector<unsigned char>{
0xb2, 0x23, 0x70, 0x10, 0x6c, 0x67, 0xa1, 0x72,
0x09, 0xf6, 0x13, 0x0b, 0xc0, 0x9f, 0x73, 0x5d,
0x83, 0xaa, 0x2c, 0x04, 0xfc, 0x4f, 0xe7, 0x2e,
0xa5, 0xd8, 0x0b, 0x21, 0x67, 0x23, 0xe7, 0xce,
}),
uint256(std::vector<unsigned char>{
0x9f, 0x67, 0xd5, 0xf6, 0x64, 0x66, 0x4c, 0x90,
0x19, 0x40, 0xee, 0xe3, 0xd0, 0x2d, 0xd5, 0xb3,
0xe4, 0xb9, 0x2e, 0x7b, 0x42, 0x82, 0x0c, 0x42,
0xfc, 0x51, 0x59, 0xe9, 0x1b, 0x41, 0x17, 0x2a,
}),
uint256(std::vector<unsigned char>{
0xac, 0x58, 0xcd, 0x13, 0x88, 0xfe, 0xc2, 0x90,
0xd3, 0x98, 0xf1, 0x94, 0x4b, 0x56, 0x44, 0x49,
0xa6, 0x3c, 0x81, 0x58, 0x80, 0x56, 0x6b, 0xd1,
0xd1, 0x89, 0xf7, 0x83, 0x9e, 0x3b, 0x0c, 0x8c,
}),
uint256(std::vector<unsigned char>{
0x56, 0x98, 0xea, 0xe7, 0xc8, 0x51, 0x5e, 0xd0,
0x5a, 0x70, 0x33, 0x9b, 0xdf, 0x7c, 0x10, 0x28,
0xe7, 0xac, 0xca, 0x13, 0xa4, 0xfa, 0x97, 0xd9,
0x53, 0x8f, 0x01, 0xac, 0x8d, 0x88, 0x9a, 0xe3,
}),
uint256(std::vector<unsigned char>{
0x2d, 0x49, 0x95, 0x77, 0x0a, 0x76, 0xfb, 0x93,
0x31, 0x4c, 0xa7, 0x4b, 0x35, 0x24, 0xea, 0x1d,
0xb5, 0x68, 0x8a, 0xd0, 0xa7, 0x61, 0x83, 0xea,
0x17, 0x20, 0x4a, 0x8f, 0x02, 0x4a, 0x9f, 0x3b,
}),
uint256(std::vector<unsigned char>{
0x5e, 0x89, 0x92, 0xc1, 0xb0, 0x72, 0xc1, 0x6e,
0x9e, 0x28, 0xa8, 0x53, 0x58, 0xfb, 0x5f, 0xb6,
0x90, 0x1a, 0x81, 0x58, 0x77, 0x66, 0xda, 0xdb,
0x7a, 0xa0, 0xb9, 0x73, 0xde, 0xd2, 0xf2, 0x64,
}),
uint256(std::vector<unsigned char>{
0xe9, 0x5d, 0xb7, 0x1e, 0x1f, 0x72, 0x91, 0xba,
0x54, 0x99, 0x46, 0x1b, 0xc7, 0x15, 0x20, 0x3e,
0x29, 0xb8, 0x4b, 0xfa, 0x42, 0x83, 0xe3, 0xbb,
0x7f, 0x47, 0x0a, 0x15, 0xd0, 0xe1, 0x58, 0x4e,
}),
uint256(std::vector<unsigned char>{
0x41, 0xf0, 0x78, 0xbd, 0x18, 0x24, 0xc8, 0xa4,
0xb7, 0x19, 0x64, 0xf3, 0x94, 0xaa, 0x59, 0x50,
0x84, 0xd8, 0xeb, 0x17, 0xb9, 0x7a, 0x36, 0x30,
0x43, 0x3a, 0xf7, 0x0d, 0x10, 0xe0, 0xef, 0xf6,
}),
uint256(std::vector<unsigned char>{
0xa1, 0x91, 0x3f, 0xe6, 0xb2, 0x01, 0x32, 0x31,
0x2f, 0x8c, 0x1f, 0x00, 0xdd, 0xd6, 0x3c, 0xec,
0x7a, 0x03, 0xf5, 0xf1, 0xd7, 0xd8, 0x34, 0x92,
0xfa, 0x28, 0x4c, 0x0b, 0x5d, 0x63, 0x20, 0xb0,
}),
uint256(std::vector<unsigned char>{
0xba, 0x94, 0x40, 0xc4, 0xdb, 0xfc, 0xf5, 0x5c,
0xeb, 0x60, 0x5a, 0x5b, 0x89, 0x90, 0xfc, 0x11,
0xf8, 0xef, 0x22, 0x87, 0x0d, 0x8d, 0x12, 0xe1,
0x30, 0xf9, 0x86, 0x49, 0x1e, 0xae, 0x84, 0xb3,
}),
uint256(std::vector<unsigned char>{
0x49, 0xdb, 0x2d, 0x5e, 0x22, 0xb8, 0x01, 0x5c,
0xae, 0x48, 0x10, 0xd7, 0x5e, 0x54, 0x01, 0x4c,
0x54, 0x69, 0x86, 0x27, 0x38, 0xe1, 0x61, 0xec,
0x96, 0xec, 0x20, 0x21, 0x87, 0x18, 0x82, 0x8a,
}),
uint256(std::vector<unsigned char>{
0xd4, 0x85, 0x1f, 0xb8, 0x43, 0x1e, 0xdf, 0xbb,
0x8b, 0x1e, 0x85, 0xad, 0xa6, 0x89, 0x59, 0x67,
0xc2, 0xda, 0xc8, 0x7d, 0xf3, 0x44, 0x99, 0x2a,
0x05, 0xfa, 0xf1, 0xec, 0xf8, 0x36, 0xee, 0xc9,
}),
uint256(std::vector<unsigned char>{
0xe4, 0xab, 0x9f, 0x44, 0x70, 0xf0, 0x0c, 0xd1,
0x96, 0xd4, 0x7c, 0x75, 0xc8, 0x2e, 0x7a, 0xda,
0xf0, 0x6f, 0xe1, 0x7e, 0x04, 0x2e, 0x39, 0x53,
0xd9, 0x3b, 0xb5, 0xd5, 0x6d, 0x8c, 0xd8, 0xfb,
}),
uint256(std::vector<unsigned char>{
0x7e, 0x43, 0x20, 0x43, 0x48, 0x49, 0xec, 0xb3,
0x57, 0xf1, 0xaf, 0xaa, 0xba, 0x21, 0xa5, 0x44,
0x00, 0xef, 0x2d, 0x11, 0xcf, 0xf8, 0x3b, 0x93,
0x7d, 0x87, 0xfd, 0xaf, 0xa4, 0x9f, 0x81, 0x99,
}),
uint256(std::vector<unsigned char>{
0x02, 0x0a, 0xdc, 0x98, 0xd9, 0x6c, 0xfb, 0xbc,
0xca, 0x15, 0xfc, 0x3a, 0xa0, 0x37, 0x60, 0xed,
0x28, 0x66, 0x86, 0xc3, 0x5b, 0x5d, 0x92, 0xc7,
0xcb, 0x64, 0xa9, 0x99, 0xb3, 0x94, 0xa8, 0x54,
}),
uint256(std::vector<unsigned char>{
0x3a, 0x26, 0xb2, 0x9f, 0xe1, 0xac, 0xfd, 0xd6,
0xc6, 0xa1, 0x51, 0xbc, 0xc3, 0xdb, 0xcb, 0x95,
0xa1, 0x0e, 0xbe, 0x2f, 0x05, 0x53, 0xf8, 0x07,
0x79, 0x56, 0x9b, 0x67, 0xb7, 0x24, 0x4e, 0x77,
}),
uint256(std::vector<unsigned char>{
0xec, 0x2d, 0x09, 0x86, 0xe6, 0xa0, 0xdd, 0xf4,
0x38, 0x97, 0xb2, 0xd4, 0xf2, 0x3b, 0xb0, 0x34,
0xf5, 0x38, 0xff, 0xe0, 0x08, 0x27, 0xf3, 0x10,
0xdc, 0x49, 0x63, 0xf3, 0x26, 0x7f, 0x0b, 0xfb,
}),
uint256(std::vector<unsigned char>{
0xd4, 0x80, 0x73, 0xf8, 0x81, 0x9f, 0x81, 0xf0,
0x35, 0x8e, 0x3f, 0xc3, 0x5a, 0x04, 0x7c, 0xc7,
0x40, 0x82, 0xae, 0x1c, 0xb7, 0xee, 0x22, 0xfb,
0x60, 0x9c, 0x01, 0x64, 0x93, 0x42, 0xd0, 0xe6,
}),
uint256(std::vector<unsigned char>{
0xad, 0x80, 0x37, 0x60, 0x17, 0x93, 0xf1, 0x72,
0x44, 0x1e, 0xcb, 0x00, 0xdc, 0x13, 0x8d, 0x9f,
0xc5, 0x95, 0x71, 0x25, 0xec, 0xc3, 0x82, 0xec,
0x65, 0xe3, 0x6f, 0x81, 0x7d, 0xc7, 0x99, 0xfb,
}),
uint256(std::vector<unsigned char>{
0xca, 0x50, 0x0a, 0x54, 0x41, 0xf3, 0x6f, 0x4d,
0xf6, 0x73, 0xd6, 0xb8, 0xed, 0x07, 0x5d, 0x36,
0xda, 0xe2, 0xc7, 0xe6, 0x48, 0x14, 0x28, 0xc7,
0x0a, 0x5a, 0x76, 0xb7, 0xa9, 0xbe, 0xbc, 0xe8,
}),
uint256(std::vector<unsigned char>{
0x42, 0x2b, 0x6d, 0xdd, 0x47, 0x32, 0x31, 0xdc,
0x4d, 0x56, 0xfe, 0x91, 0x34, 0x44, 0xcc, 0xd5,
0x6f, 0x7c, 0x61, 0xf7, 0x47, 0xba, 0x57, 0xca,
0x94, 0x6d, 0x5f, 0xef, 0x72, 0xd8, 0x40, 0xa0,
}),
uint256(std::vector<unsigned char>{
0xab, 0x41, 0xf4, 0xec, 0xb7, 0xd7, 0x08, 0x96,
0x15, 0x80, 0x0e, 0x19, 0xfc, 0xc5, 0x3b, 0x83,
0x79, 0xed, 0x05, 0xee, 0x35, 0xc8, 0x25, 0x67,
0x09, 0x55, 0x83, 0xfd, 0x90, 0xff, 0x30, 0x35,
}),
uint256(std::vector<unsigned char>{
0xbb, 0xf7, 0x61, 0x82, 0x48, 0x35, 0x4c, 0xeb,
0x1b, 0xc1, 0xfc, 0x9d, 0xbc, 0x42, 0xc4, 0x26,
0xa4, 0xe2, 0xc1, 0xe0, 0xd4, 0x43, 0xc5, 0x68,
0x3a, 0x92, 0x56, 0xc6, 0x2e, 0xcd, 0xc2, 0x6f,
}),
uint256(std::vector<unsigned char>{
0xe5, 0x0a, 0xe7, 0x14, 0x79, 0xfc, 0x8e, 0xc5,
0x69, 0x19, 0x2a, 0x13, 0x07, 0x2e, 0x01, 0x1a,
0xfc, 0x24, 0x9f, 0x47, 0x1a, 0xf0, 0x95, 0x00,
0xea, 0x39, 0xf7, 0x5d, 0x0a, 0xf8, 0x56, 0xbf,
}),
uint256(std::vector<unsigned char>{
0xe7, 0x4c, 0x0b, 0x92, 0x20, 0x14, 0x7d, 0xb2,
0xd5, 0x0a, 0x3b, 0x58, 0xd4, 0x13, 0x77, 0x5d,
0x16, 0xc9, 0x84, 0x69, 0x0b, 0xe7, 0xd9, 0x0f,
0x0b, 0xc4, 0x3d, 0x99, 0xdb, 0xa1, 0xb6, 0x89,
}),
uint256(std::vector<unsigned char>{
0x29, 0x32, 0x4a, 0x0a, 0x48, 0xd1, 0x16, 0x57,
0xa5, 0x1b, 0xa0, 0x8b, 0x00, 0x48, 0x79, 0xbf,
0xcf, 0xc6, 0x6a, 0x1a, 0xcb, 0x7c, 0xe3, 0x6d,
0xfe, 0x47, 0x8d, 0x26, 0x55, 0x48, 0x4b, 0x48,
}),
uint256(std::vector<unsigned char>{
0x88, 0x95, 0x2e, 0x3d, 0x0a, 0xc0, 0x6c, 0xb1,
0x6b, 0x66, 0x52, 0x01, 0x12, 0x22, 0x49, 0x65,
0x9a, 0x22, 0x32, 0x5e, 0x01, 0xc8, 0x70, 0xf4,
0x9e, 0x29, 0xda, 0x6b, 0x17, 0x57, 0xe0, 0x82,
}),
uint256(std::vector<unsigned char>{
0xcd, 0xf8, 0x79, 0xf2, 0x43, 0x5b, 0x95, 0xaf,
0x04, 0x2a, 0x3b, 0xf7, 0xb8, 0x50, 0xf7, 0x81,
0x92, 0x46, 0xc8, 0x05, 0x28, 0x58, 0x03, 0xd6,
0x7f, 0xfb, 0xf4, 0xf2, 0x95, 0xbe, 0xd0, 0x04,
}),
uint256(std::vector<unsigned char>{
0xe0, 0x05, 0xe3, 0x24, 0x20, 0x0b, 0x4f, 0x42,
0x8c, 0x62, 0xbc, 0x33, 0x31, 0xe6, 0x95, 0xc3,
0x73, 0x60, 0x7c, 0xd0, 0xfa, 0xa9, 0x79, 0x03,
0x41, 0xfa, 0x3b, 0xa1, 0xed, 0x22, 0x8b, 0xc5,
}),
uint256(std::vector<unsigned char>{
0x35, 0x44, 0x47, 0x72, 0x7a, 0xa9, 0xa5, 0x3d,
0xd8, 0x34, 0x5b, 0x6b, 0x6c, 0x69, 0x34, 0x43,
0xe5, 0x6e, 0xf4, 0xae, 0xba, 0x13, 0xc4, 0x10,
0x17, 0x9f, 0xc8, 0x58, 0x9e, 0x77, 0x33, 0xd5,
}),
uint256(std::vector<unsigned char>{
0xda, 0x52, 0xdd, 0xa9, 0x1f, 0x28, 0x29, 0xc1,
0x5c, 0x0e, 0x58, 0xd2, 0x9a, 0x95, 0x36, 0x0b,
0x86, 0xab, 0x30, 0xcf, 0x0c, 0xac, 0x81, 0x01,
0x83, 0x2a, 0x29, 0xf3, 0x8c, 0x31, 0x85, 0xf1,
}),
uint256(std::vector<unsigned char>{
0xc7, 0xda, 0x78, 0x14, 0xe2, 0x28, 0xe1, 0x14,
0x44, 0x11, 0xd7, 0x8b, 0x53, 0x60, 0x92, 0xfe,
0x92, 0x0b, 0xcd, 0xfc, 0xc3, 0x6c, 0xf1, 0x9d,
0x12, 0x59, 0x04, 0x7b, 0x26, 0x7d, 0x58, 0xb5,
}),
uint256(std::vector<unsigned char>{
0xab, 0xa1, 0xf6, 0x8b, 0x6c, 0x2b, 0x4d, 0xb6,
0xcc, 0x06, 0xa7, 0x34, 0x0e, 0x12, 0x31, 0x3c,
0x4b, 0x4a, 0x4e, 0xa6, 0xde, 0xb1, 0x7d, 0xeb,
0x3e, 0x1e, 0x66, 0xcd, 0x8e, 0xac, 0xf3, 0x2b,
}),
uint256(std::vector<unsigned char>{
0xc1, 0x60, 0xae, 0x4f, 0x64, 0xab, 0x76, 0x4d,
0x86, 0x4a, 0x52, 0xad, 0x5e, 0x33, 0x12, 0x6c,
0x4b, 0x5c, 0xe1, 0x05, 0xa4, 0x7d, 0xee, 0xdd,
0x75, 0xbc, 0x70, 0x19, 0x9a, 0x52, 0x47, 0xef,
}),
uint256(std::vector<unsigned char>{
0xea, 0xdf, 0x23, 0xfc, 0x99, 0xd5, 0x14, 0xdd,
0x8e, 0xa2, 0x04, 0xd2, 0x23, 0xe9, 0x8d, 0xa9,
0x88, 0x83, 0x1f, 0x9b, 0x5d, 0x19, 0x40, 0x27,
0x4c, 0xa5, 0x20, 0xb7, 0xfb, 0x17, 0x3d, 0x8a,
}),
uint256(std::vector<unsigned char>{
0x5b, 0x8e, 0x14, 0xfa, 0xca, 0xc8, 0xa7, 0xc7,
0xa3, 0xbf, 0xee, 0x8b, 0xae, 0x71, 0xf2, 0xf7,
0x79, 0x3d, 0x3a, 0xd5, 0xfe, 0x33, 0x83, 0xf9,
0x3a, 0xb6, 0x06, 0x1f, 0x2a, 0x11, 0xbb, 0x02
}),
};
SHA256Compress SHA256Compress::EmptyRoot(size_t depth) {
return sha256_empty_roots.at(depth);
}
template <size_t Depth, typename Hash>
class PathFiller {
private:

13
src/zcash/IncrementalMerkleTree.hpp

@ -57,14 +57,9 @@ public:
template<size_t Depth, typename Hash>
class EmptyMerkleRoots {
public:
EmptyMerkleRoots() {
empty_roots.at(0) = Hash::uncommitted();
for (size_t d = 1; d <= Depth; d++) {
empty_roots.at(d) = Hash::combine(empty_roots.at(d-1), empty_roots.at(d-1), d-1);
}
}
Hash empty_root(size_t depth) {
return empty_roots.at(depth);
EmptyMerkleRoots() { }
Hash empty_root(size_t depth) const {
return Hash::EmptyRoot(depth);
}
template <size_t D, typename H>
friend bool operator==(const EmptyMerkleRoots<D, H>& a,
@ -227,6 +222,7 @@ public:
static SHA256Compress uncommitted() {
return SHA256Compress();
}
static SHA256Compress EmptyRoot(size_t);
};
class PedersenHash : public uint256 {
@ -241,6 +237,7 @@ public:
);
static PedersenHash uncommitted();
static PedersenHash EmptyRoot(size_t);
};
template<size_t Depth, typename Hash>

233
src/zcash/Proof.cpp

@ -3,249 +3,16 @@
#include "crypto/common.h"
#include <boost/static_assert.hpp>
#include <libsnark/common/default_types/r1cs_ppzksnark_pp.hpp>
#include <libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp>
#include <mutex>
using namespace libsnark;
typedef alt_bn128_pp curve_pp;
typedef alt_bn128_pp::G1_type curve_G1;
typedef alt_bn128_pp::G2_type curve_G2;
typedef alt_bn128_pp::GT_type curve_GT;
typedef alt_bn128_pp::Fp_type curve_Fr;
typedef alt_bn128_pp::Fq_type curve_Fq;
typedef alt_bn128_pp::Fqe_type curve_Fq2;
BOOST_STATIC_ASSERT(sizeof(mp_limb_t) == 8);
namespace libzcash {
// FE2IP as defined in the protocol spec and IEEE Std 1363a-2004.
bigint<8> fq2_to_bigint(const curve_Fq2 &e)
{
auto modq = curve_Fq::field_char();
auto c0 = e.c0.as_bigint();
auto c1 = e.c1.as_bigint();
bigint<8> temp = c1 * modq;
temp += c0;
return temp;
}
// Writes a bigint in big endian
template<mp_size_t LIMBS>
void write_bigint(base_blob<8 * LIMBS * sizeof(mp_limb_t)> &blob, const bigint<LIMBS> &val)
{
auto ptr = blob.begin();
for (ssize_t i = LIMBS-1; i >= 0; i--, ptr += 8) {
WriteBE64(ptr, val.data[i]);
}
}
// Reads a bigint from big endian
template<mp_size_t LIMBS>
bigint<LIMBS> read_bigint(const base_blob<8 * LIMBS * sizeof(mp_limb_t)> &blob)
{
bigint<LIMBS> ret;
auto ptr = blob.begin();
for (ssize_t i = LIMBS-1; i >= 0; i--, ptr += 8) {
ret.data[i] = ReadBE64(ptr);
}
return ret;
}
template<>
Fq::Fq(curve_Fq element) : data()
{
write_bigint<4>(data, element.as_bigint());
}
template<>
curve_Fq Fq::to_libsnark_fq() const
{
auto element_bigint = read_bigint<4>(data);
// Check that the integer is smaller than the modulus
auto modq = curve_Fq::field_char();
element_bigint.limit(modq, "element is not in Fq");
return curve_Fq(element_bigint);
}
template<>
Fq2::Fq2(curve_Fq2 element) : data()
{
write_bigint<8>(data, fq2_to_bigint(element));
}
template<>
curve_Fq2 Fq2::to_libsnark_fq2() const
{
bigint<4> modq = curve_Fq::field_char();
bigint<8> combined = read_bigint<8>(data);
bigint<5> res;
bigint<4> c0;
bigint<8>::div_qr(res, c0, combined, modq);
bigint<4> c1 = res.shorten(modq, "element is not in Fq2");
return curve_Fq2(curve_Fq(c0), curve_Fq(c1));
}
template<>
CompressedG1::CompressedG1(curve_G1 point)
{
if (point.is_zero()) {
throw std::domain_error("curve point is zero");
}
point.to_affine_coordinates();
x = Fq(point.X);
y_lsb = point.Y.as_bigint().data[0] & 1;
}
template<>
curve_G1 CompressedG1::to_libsnark_g1() const
{
curve_Fq x_coordinate = x.to_libsnark_fq<curve_Fq>();
// y = +/- sqrt(x^3 + b)
auto y_coordinate = ((x_coordinate.squared() * x_coordinate) + alt_bn128_coeff_b).sqrt();
if ((y_coordinate.as_bigint().data[0] & 1) != y_lsb) {
y_coordinate = -y_coordinate;
}
curve_G1 r = curve_G1::one();
r.X = x_coordinate;
r.Y = y_coordinate;
r.Z = curve_Fq::one();
assert(r.is_well_formed());
return r;
}
template<>
CompressedG2::CompressedG2(curve_G2 point)
{
if (point.is_zero()) {
throw std::domain_error("curve point is zero");
}
point.to_affine_coordinates();
x = Fq2(point.X);
y_gt = fq2_to_bigint(point.Y) > fq2_to_bigint(-(point.Y));
}
template<>
curve_G2 CompressedG2::to_libsnark_g2() const
{
auto x_coordinate = x.to_libsnark_fq2<curve_Fq2>();
// y = +/- sqrt(x^3 + b)
auto y_coordinate = ((x_coordinate.squared() * x_coordinate) + alt_bn128_twist_coeff_b).sqrt();
auto y_coordinate_neg = -y_coordinate;
if ((fq2_to_bigint(y_coordinate) > fq2_to_bigint(y_coordinate_neg)) != y_gt) {
y_coordinate = y_coordinate_neg;
}
curve_G2 r = curve_G2::one();
r.X = x_coordinate;
r.Y = y_coordinate;
r.Z = curve_Fq2::one();
assert(r.is_well_formed());
if (alt_bn128_modulus_r * r != curve_G2::zero()) {
throw std::runtime_error("point is not in G2");
}
return r;
}
template<>
PHGRProof::PHGRProof(const r1cs_ppzksnark_proof<curve_pp> &proof)
{
g_A = CompressedG1(proof.g_A.g);
g_A_prime = CompressedG1(proof.g_A.h);
g_B = CompressedG2(proof.g_B.g);
g_B_prime = CompressedG1(proof.g_B.h);
g_C = CompressedG1(proof.g_C.g);
g_C_prime = CompressedG1(proof.g_C.h);
g_K = CompressedG1(proof.g_K);
g_H = CompressedG1(proof.g_H);
}
template<>
r1cs_ppzksnark_proof<curve_pp> PHGRProof::to_libsnark_proof() const
{
r1cs_ppzksnark_proof<curve_pp> proof;
proof.g_A.g = g_A.to_libsnark_g1<curve_G1>();
proof.g_A.h = g_A_prime.to_libsnark_g1<curve_G1>();
proof.g_B.g = g_B.to_libsnark_g2<curve_G2>();
proof.g_B.h = g_B_prime.to_libsnark_g1<curve_G1>();
proof.g_C.g = g_C.to_libsnark_g1<curve_G1>();
proof.g_C.h = g_C_prime.to_libsnark_g1<curve_G1>();
proof.g_K = g_K.to_libsnark_g1<curve_G1>();
proof.g_H = g_H.to_libsnark_g1<curve_G1>();
return proof;
}
PHGRProof PHGRProof::random_invalid()
{
PHGRProof p;
p.g_A = curve_G1::random_element();
p.g_A_prime = curve_G1::random_element();
p.g_B = curve_G2::random_element();
p.g_B_prime = curve_G1::random_element();
p.g_C = curve_G1::random_element();
p.g_C_prime = curve_G1::random_element();
p.g_K = curve_G1::random_element();
p.g_H = curve_G1::random_element();
return p;
}
static std::once_flag init_public_params_once_flag;
void initialize_curve_params()
{
std::call_once (init_public_params_once_flag, curve_pp::init_public_params);
}
ProofVerifier ProofVerifier::Strict() {
initialize_curve_params();
return ProofVerifier(true);
}
ProofVerifier ProofVerifier::Disabled() {
initialize_curve_params();
return ProofVerifier(false);
}
template<>
bool ProofVerifier::check(
const r1cs_ppzksnark_verification_key<curve_pp>& vk,
const r1cs_ppzksnark_processed_verification_key<curve_pp>& pvk,
const r1cs_primary_input<curve_Fr>& primary_input,
const r1cs_ppzksnark_proof<curve_pp>& proof
)
{
if (perform_verification) {
return r1cs_ppzksnark_online_verifier_strong_IC<curve_pp>(pvk, primary_input, proof);
} else {
return true;
}
}
}

35
src/zcash/Proof.hpp

@ -16,12 +16,6 @@ private:
public:
Fq() : data() { }
template<typename libsnark_Fq>
Fq(libsnark_Fq element);
template<typename libsnark_Fq>
libsnark_Fq to_libsnark_fq() const;
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
@ -49,12 +43,6 @@ private:
public:
Fq2() : data() { }
template<typename libsnark_Fq2>
Fq2(libsnark_Fq2 element);
template<typename libsnark_Fq2>
libsnark_Fq2 to_libsnark_fq2() const;
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
@ -84,12 +72,6 @@ private:
public:
CompressedG1() : y_lsb(false), x() { }
template<typename libsnark_G1>
CompressedG1(libsnark_G1 point);
template<typename libsnark_G1>
libsnark_G1 to_libsnark_g1() const;
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
@ -134,12 +116,6 @@ private:
public:
CompressedG2() : y_gt(false), x() { }
template<typename libsnark_G2>
CompressedG2(libsnark_G2 point);
template<typename libsnark_G2>
libsnark_G2 to_libsnark_g2() const;
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
@ -190,17 +166,6 @@ private:
public:
PHGRProof() : g_A(), g_A_prime(), g_B(), g_B_prime(), g_C(), g_C_prime(), g_K(), g_H() { }
// Produces a compressed proof using a libsnark zkSNARK proof
template<typename libsnark_proof>
PHGRProof(const libsnark_proof& proof);
// Produces a libsnark zkSNARK proof out of this proof,
// or throws an exception if it is invalid.
template<typename libsnark_proof>
libsnark_proof to_libsnark_proof() const;
static PHGRProof random_invalid();
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>

100
src/zcash/circuit/commitment.tcc

@ -1,100 +0,0 @@
template<typename FieldT>
class note_commitment_gadget : gadget<FieldT> {
private:
std::shared_ptr<block_variable<FieldT>> block1;
std::shared_ptr<block_variable<FieldT>> block2;
std::shared_ptr<sha256_compression_function_gadget<FieldT>> hasher1;
std::shared_ptr<digest_variable<FieldT>> intermediate_hash;
std::shared_ptr<sha256_compression_function_gadget<FieldT>> hasher2;
public:
note_commitment_gadget(
protoboard<FieldT> &pb,
pb_variable<FieldT>& ZERO,
pb_variable_array<FieldT>& a_pk,
pb_variable_array<FieldT>& v,
pb_variable_array<FieldT>& rho,
pb_variable_array<FieldT>& r,
std::shared_ptr<digest_variable<FieldT>> result
) : gadget<FieldT>(pb) {
pb_variable_array<FieldT> leading_byte =
from_bits({1, 0, 1, 1, 0, 0, 0, 0}, ZERO);
pb_variable_array<FieldT> first_of_rho(rho.begin(), rho.begin()+184);
pb_variable_array<FieldT> last_of_rho(rho.begin()+184, rho.end());
intermediate_hash.reset(new digest_variable<FieldT>(pb, 256, ""));
// final padding
pb_variable_array<FieldT> length_padding =
from_bits({
// padding
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,
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,
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,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
// length of message (840 bits)
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,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,
0,0,0,0,0,0,1,1,
0,1,0,0,1,0,0,0
}, ZERO);
block1.reset(new block_variable<FieldT>(pb, {
leading_byte,
a_pk,
v,
first_of_rho
}, ""));
block2.reset(new block_variable<FieldT>(pb, {
last_of_rho,
r,
length_padding
}, ""));
pb_linear_combination_array<FieldT> IV = SHA256_default_IV(pb);
hasher1.reset(new sha256_compression_function_gadget<FieldT>(
pb,
IV,
block1->bits,
*intermediate_hash,
""));
pb_linear_combination_array<FieldT> IV2(intermediate_hash->bits);
hasher2.reset(new sha256_compression_function_gadget<FieldT>(
pb,
IV2,
block2->bits,
*result,
""));
}
void generate_r1cs_constraints() {
hasher1->generate_r1cs_constraints();
hasher2->generate_r1cs_constraints();
}
void generate_r1cs_witness() {
hasher1->generate_r1cs_witness();
hasher2->generate_r1cs_witness();
}
};

349
src/zcash/circuit/gadget.tcc

@ -1,349 +0,0 @@
#include "zcash/circuit/utils.tcc"
#include "zcash/circuit/prfs.tcc"
#include "zcash/circuit/commitment.tcc"
#include "zcash/circuit/merkle.tcc"
#include "zcash/circuit/note.tcc"
template<typename FieldT, size_t NumInputs, size_t NumOutputs>
class joinsplit_gadget : gadget<FieldT> {
private:
// Verifier inputs
pb_variable_array<FieldT> zk_packed_inputs;
pb_variable_array<FieldT> zk_unpacked_inputs;
std::shared_ptr<multipacking_gadget<FieldT>> unpacker;
std::shared_ptr<digest_variable<FieldT>> zk_merkle_root;
std::shared_ptr<digest_variable<FieldT>> zk_h_sig;
std::array<std::shared_ptr<digest_variable<FieldT>>, NumInputs> zk_input_nullifiers;
std::array<std::shared_ptr<digest_variable<FieldT>>, NumInputs> zk_input_macs;
std::array<std::shared_ptr<digest_variable<FieldT>>, NumOutputs> zk_output_commitments;
pb_variable_array<FieldT> zk_vpub_old;
pb_variable_array<FieldT> zk_vpub_new;
// Aux inputs
pb_variable<FieldT> ZERO;
std::shared_ptr<digest_variable<FieldT>> zk_phi;
pb_variable_array<FieldT> zk_total_uint64;
// Input note gadgets
std::array<std::shared_ptr<input_note_gadget<FieldT>>, NumInputs> zk_input_notes;
std::array<std::shared_ptr<PRF_pk_gadget<FieldT>>, NumInputs> zk_mac_authentication;
// Output note gadgets
std::array<std::shared_ptr<output_note_gadget<FieldT>>, NumOutputs> zk_output_notes;
public:
// PRF_pk only has a 1-bit domain separation "nonce"
// for different macs.
BOOST_STATIC_ASSERT(NumInputs <= 2);
// PRF_rho only has a 1-bit domain separation "nonce"
// for different output `rho`.
BOOST_STATIC_ASSERT(NumOutputs <= 2);
joinsplit_gadget(protoboard<FieldT> &pb) : gadget<FieldT>(pb) {
// Verification
{
// The verification inputs are all bit-strings of various
// lengths (256-bit digests and 64-bit integers) and so we
// pack them into as few field elements as possible. (The
// more verification inputs you have, the more expensive
// verification is.)
zk_packed_inputs.allocate(pb, verifying_field_element_size());
pb.set_input_sizes(verifying_field_element_size());
alloc_uint256(zk_unpacked_inputs, zk_merkle_root);
alloc_uint256(zk_unpacked_inputs, zk_h_sig);
for (size_t i = 0; i < NumInputs; i++) {
alloc_uint256(zk_unpacked_inputs, zk_input_nullifiers[i]);
alloc_uint256(zk_unpacked_inputs, zk_input_macs[i]);
}
for (size_t i = 0; i < NumOutputs; i++) {
alloc_uint256(zk_unpacked_inputs, zk_output_commitments[i]);
}
alloc_uint64(zk_unpacked_inputs, zk_vpub_old);
alloc_uint64(zk_unpacked_inputs, zk_vpub_new);
assert(zk_unpacked_inputs.size() == verifying_input_bit_size());
// This gadget will ensure that all of the inputs we provide are
// boolean constrained.
unpacker.reset(new multipacking_gadget<FieldT>(
pb,
zk_unpacked_inputs,
zk_packed_inputs,
FieldT::capacity(),
"unpacker"
));
}
// We need a constant "zero" variable in some contexts. In theory
// it should never be necessary, but libsnark does not synthesize
// optimal circuits.
//
// The first variable of our constraint system is constrained
// to be one automatically for us, and is known as `ONE`.
ZERO.allocate(pb);
zk_phi.reset(new digest_variable<FieldT>(pb, 252, ""));
zk_total_uint64.allocate(pb, 64);
for (size_t i = 0; i < NumInputs; i++) {
// Input note gadget for commitments, macs, nullifiers,
// and spend authority.
zk_input_notes[i].reset(new input_note_gadget<FieldT>(
pb,
ZERO,
zk_input_nullifiers[i],
*zk_merkle_root
));
// The input keys authenticate h_sig to prevent
// malleability.
zk_mac_authentication[i].reset(new PRF_pk_gadget<FieldT>(
pb,
ZERO,
zk_input_notes[i]->a_sk->bits,
zk_h_sig->bits,
i ? true : false,
zk_input_macs[i]
));
}
for (size_t i = 0; i < NumOutputs; i++) {
zk_output_notes[i].reset(new output_note_gadget<FieldT>(
pb,
ZERO,
zk_phi->bits,
zk_h_sig->bits,
i ? true : false,
zk_output_commitments[i]
));
}
}
void generate_r1cs_constraints() {
// The true passed here ensures all the inputs
// are boolean constrained.
unpacker->generate_r1cs_constraints(true);
// Constrain `ZERO`
generate_r1cs_equals_const_constraint<FieldT>(this->pb, ZERO, FieldT::zero(), "ZERO");
// Constrain bitness of phi
zk_phi->generate_r1cs_constraints();
for (size_t i = 0; i < NumInputs; i++) {
// Constrain the JoinSplit input constraints.
zk_input_notes[i]->generate_r1cs_constraints();
// Authenticate h_sig with a_sk
zk_mac_authentication[i]->generate_r1cs_constraints();
}
for (size_t i = 0; i < NumOutputs; i++) {
// Constrain the JoinSplit output constraints.
zk_output_notes[i]->generate_r1cs_constraints();
}
// Value balance
{
linear_combination<FieldT> left_side = packed_addition(zk_vpub_old);
for (size_t i = 0; i < NumInputs; i++) {
left_side = left_side + packed_addition(zk_input_notes[i]->value);
}
linear_combination<FieldT> right_side = packed_addition(zk_vpub_new);
for (size_t i = 0; i < NumOutputs; i++) {
right_side = right_side + packed_addition(zk_output_notes[i]->value);
}
// Ensure that both sides are equal
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(
1,
left_side,
right_side
));
// #854: Ensure that left_side is a 64-bit integer.
for (size_t i = 0; i < 64; i++) {
generate_boolean_r1cs_constraint<FieldT>(
this->pb,
zk_total_uint64[i],
""
);
}
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(
1,
left_side,
packed_addition(zk_total_uint64)
));
}
}
void generate_r1cs_witness(
const uint252& phi,
const uint256& rt,
const uint256& h_sig,
const std::array<JSInput, NumInputs>& inputs,
const std::array<SproutNote, NumOutputs>& outputs,
uint64_t vpub_old,
uint64_t vpub_new
) {
// Witness `zero`
this->pb.val(ZERO) = FieldT::zero();
// Witness rt. This is not a sanity check.
//
// This ensures the read gadget constrains
// the intended root in the event that
// both inputs are zero-valued.
zk_merkle_root->bits.fill_with_bits(
this->pb,
uint256_to_bool_vector(rt)
);
// Witness public balance values
zk_vpub_old.fill_with_bits(
this->pb,
uint64_to_bool_vector(vpub_old)
);
zk_vpub_new.fill_with_bits(
this->pb,
uint64_to_bool_vector(vpub_new)
);
{
// Witness total_uint64 bits
uint64_t left_side_acc = vpub_old;
for (size_t i = 0; i < NumInputs; i++) {
left_side_acc += inputs[i].note.value();
}
zk_total_uint64.fill_with_bits(
this->pb,
uint64_to_bool_vector(left_side_acc)
);
}
// Witness phi
zk_phi->bits.fill_with_bits(
this->pb,
uint252_to_bool_vector(phi)
);
// Witness h_sig
zk_h_sig->bits.fill_with_bits(
this->pb,
uint256_to_bool_vector(h_sig)
);
for (size_t i = 0; i < NumInputs; i++) {
// Witness the input information.
auto merkle_path = inputs[i].witness.path();
zk_input_notes[i]->generate_r1cs_witness(
merkle_path,
inputs[i].key,
inputs[i].note
);
// Witness macs
zk_mac_authentication[i]->generate_r1cs_witness();
}
for (size_t i = 0; i < NumOutputs; i++) {
// Witness the output information.
zk_output_notes[i]->generate_r1cs_witness(outputs[i]);
}
// [SANITY CHECK] Ensure that the intended root
// was witnessed by the inputs, even if the read
// gadget overwrote it. This allows the prover to
// fail instead of the verifier, in the event that
// the roots of the inputs do not match the
// treestate provided to the proving API.
zk_merkle_root->bits.fill_with_bits(
this->pb,
uint256_to_bool_vector(rt)
);
// This happens last, because only by now are all the
// verifier inputs resolved.
unpacker->generate_r1cs_witness_from_bits();
}
static r1cs_primary_input<FieldT> witness_map(
const uint256& rt,
const uint256& h_sig,
const std::array<uint256, NumInputs>& macs,
const std::array<uint256, NumInputs>& nullifiers,
const std::array<uint256, NumOutputs>& commitments,
uint64_t vpub_old,
uint64_t vpub_new
) {
std::vector<bool> verify_inputs;
insert_uint256(verify_inputs, rt);
insert_uint256(verify_inputs, h_sig);
for (size_t i = 0; i < NumInputs; i++) {
insert_uint256(verify_inputs, nullifiers[i]);
insert_uint256(verify_inputs, macs[i]);
}
for (size_t i = 0; i < NumOutputs; i++) {
insert_uint256(verify_inputs, commitments[i]);
}
insert_uint64(verify_inputs, vpub_old);
insert_uint64(verify_inputs, vpub_new);
assert(verify_inputs.size() == verifying_input_bit_size());
auto verify_field_elements = pack_bit_vector_into_field_element_vector<FieldT>(verify_inputs);
assert(verify_field_elements.size() == verifying_field_element_size());
return verify_field_elements;
}
static size_t verifying_input_bit_size() {
size_t acc = 0;
acc += 256; // the merkle root (anchor)
acc += 256; // h_sig
for (size_t i = 0; i < NumInputs; i++) {
acc += 256; // nullifier
acc += 256; // mac
}
for (size_t i = 0; i < NumOutputs; i++) {
acc += 256; // new commitment
}
acc += 64; // vpub_old
acc += 64; // vpub_new
return acc;
}
static size_t verifying_field_element_size() {
return div_ceil(verifying_input_bit_size(), FieldT::capacity());
}
void alloc_uint256(
pb_variable_array<FieldT>& packed_into,
std::shared_ptr<digest_variable<FieldT>>& var
) {
var.reset(new digest_variable<FieldT>(this->pb, 256, ""));
packed_into.insert(packed_into.end(), var->bits.begin(), var->bits.end());
}
void alloc_uint64(
pb_variable_array<FieldT>& packed_into,
pb_variable_array<FieldT>& integer
) {
integer.allocate(this->pb, 64, "");
packed_into.insert(packed_into.end(), integer.begin(), integer.end());
}
};

60
src/zcash/circuit/merkle.tcc

@ -1,60 +0,0 @@
template<typename FieldT>
class merkle_tree_gadget : gadget<FieldT> {
private:
typedef sha256_two_to_one_hash_gadget<FieldT> sha256_gadget;
pb_variable_array<FieldT> positions;
std::shared_ptr<merkle_authentication_path_variable<FieldT, sha256_gadget>> authvars;
std::shared_ptr<merkle_tree_check_read_gadget<FieldT, sha256_gadget>> auth;
public:
merkle_tree_gadget(
protoboard<FieldT>& pb,
digest_variable<FieldT> leaf,
digest_variable<FieldT> root,
pb_variable<FieldT>& enforce
) : gadget<FieldT>(pb) {
positions.allocate(pb, INCREMENTAL_MERKLE_TREE_DEPTH);
authvars.reset(new merkle_authentication_path_variable<FieldT, sha256_gadget>(
pb, INCREMENTAL_MERKLE_TREE_DEPTH, "auth"
));
auth.reset(new merkle_tree_check_read_gadget<FieldT, sha256_gadget>(
pb,
INCREMENTAL_MERKLE_TREE_DEPTH,
positions,
leaf,
root,
*authvars,
enforce,
""
));
}
void generate_r1cs_constraints() {
for (size_t i = 0; i < INCREMENTAL_MERKLE_TREE_DEPTH; i++) {
// TODO: This might not be necessary, and doesn't
// appear to be done in libsnark's tests, but there
// is no documentation, so let's do it anyway to
// be safe.
generate_boolean_r1cs_constraint<FieldT>(
this->pb,
positions[i],
"boolean_positions"
);
}
authvars->generate_r1cs_constraints();
auth->generate_r1cs_constraints();
}
void generate_r1cs_witness(const MerklePath& path) {
// TODO: Change libsnark so that it doesn't require this goofy
// number thing in its API.
size_t path_index = convertVectorToInt(path.index);
positions.fill_with_bits_of_uint64(this->pb, path_index);
authvars->generate_r1cs_witness(path_index, path.authentication_path);
auth->generate_r1cs_witness();
}
};

244
src/zcash/circuit/note.tcc

@ -1,244 +0,0 @@
template<typename FieldT>
class note_gadget : public gadget<FieldT> {
public:
pb_variable_array<FieldT> value;
std::shared_ptr<digest_variable<FieldT>> r;
note_gadget(protoboard<FieldT> &pb) : gadget<FieldT>(pb) {
value.allocate(pb, 64);
r.reset(new digest_variable<FieldT>(pb, 256, ""));
}
void generate_r1cs_constraints() {
for (size_t i = 0; i < 64; i++) {
generate_boolean_r1cs_constraint<FieldT>(
this->pb,
value[i],
"boolean_value"
);
}
r->generate_r1cs_constraints();
}
void generate_r1cs_witness(const SproutNote& note) {
r->bits.fill_with_bits(this->pb, uint256_to_bool_vector(note.r));
value.fill_with_bits(this->pb, uint64_to_bool_vector(note.value()));
}
};
template<typename FieldT>
class input_note_gadget : public note_gadget<FieldT> {
private:
std::shared_ptr<digest_variable<FieldT>> a_pk;
std::shared_ptr<digest_variable<FieldT>> rho;
std::shared_ptr<digest_variable<FieldT>> commitment;
std::shared_ptr<note_commitment_gadget<FieldT>> commit_to_inputs;
pb_variable<FieldT> value_enforce;
std::shared_ptr<merkle_tree_gadget<FieldT>> witness_input;
std::shared_ptr<PRF_addr_a_pk_gadget<FieldT>> spend_authority;
std::shared_ptr<PRF_nf_gadget<FieldT>> expose_nullifiers;
public:
std::shared_ptr<digest_variable<FieldT>> a_sk;
input_note_gadget(
protoboard<FieldT>& pb,
pb_variable<FieldT>& ZERO,
std::shared_ptr<digest_variable<FieldT>> nullifier,
digest_variable<FieldT> rt
) : note_gadget<FieldT>(pb) {
a_sk.reset(new digest_variable<FieldT>(pb, 252, ""));
a_pk.reset(new digest_variable<FieldT>(pb, 256, ""));
rho.reset(new digest_variable<FieldT>(pb, 256, ""));
commitment.reset(new digest_variable<FieldT>(pb, 256, ""));
spend_authority.reset(new PRF_addr_a_pk_gadget<FieldT>(
pb,
ZERO,
a_sk->bits,
a_pk
));
expose_nullifiers.reset(new PRF_nf_gadget<FieldT>(
pb,
ZERO,
a_sk->bits,
rho->bits,
nullifier
));
commit_to_inputs.reset(new note_commitment_gadget<FieldT>(
pb,
ZERO,
a_pk->bits,
this->value,
rho->bits,
this->r->bits,
commitment
));
value_enforce.allocate(pb);
witness_input.reset(new merkle_tree_gadget<FieldT>(
pb,
*commitment,
rt,
value_enforce
));
}
void generate_r1cs_constraints() {
note_gadget<FieldT>::generate_r1cs_constraints();
a_sk->generate_r1cs_constraints();
rho->generate_r1cs_constraints();
spend_authority->generate_r1cs_constraints();
expose_nullifiers->generate_r1cs_constraints();
commit_to_inputs->generate_r1cs_constraints();
// value * (1 - enforce) = 0
// Given `enforce` is boolean constrained:
// If `value` is zero, `enforce` _can_ be zero.
// If `value` is nonzero, `enforce` _must_ be one.
generate_boolean_r1cs_constraint<FieldT>(this->pb, value_enforce,"");
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(
packed_addition(this->value),
(1 - value_enforce),
0
), "");
witness_input->generate_r1cs_constraints();
}
void generate_r1cs_witness(
const MerklePath& path,
const SproutSpendingKey& key,
const SproutNote& note
) {
note_gadget<FieldT>::generate_r1cs_witness(note);
// Witness a_sk for the input
a_sk->bits.fill_with_bits(
this->pb,
uint252_to_bool_vector(key)
);
// Witness a_pk for a_sk with PRF_addr
spend_authority->generate_r1cs_witness();
// [SANITY CHECK] Witness a_pk with note information
a_pk->bits.fill_with_bits(
this->pb,
uint256_to_bool_vector(note.a_pk)
);
// Witness rho for the input note
rho->bits.fill_with_bits(
this->pb,
uint256_to_bool_vector(note.rho)
);
// Witness the nullifier for the input note
expose_nullifiers->generate_r1cs_witness();
// Witness the commitment of the input note
commit_to_inputs->generate_r1cs_witness();
// [SANITY CHECK] Ensure the commitment is
// valid.
commitment->bits.fill_with_bits(
this->pb,
uint256_to_bool_vector(note.cm())
);
// Set enforce flag for nonzero input value
this->pb.val(value_enforce) = (note.value() != 0) ? FieldT::one() : FieldT::zero();
// Witness merkle tree authentication path
witness_input->generate_r1cs_witness(path);
}
};
template<typename FieldT>
class output_note_gadget : public note_gadget<FieldT> {
private:
std::shared_ptr<digest_variable<FieldT>> rho;
std::shared_ptr<digest_variable<FieldT>> a_pk;
std::shared_ptr<PRF_rho_gadget<FieldT>> prevent_faerie_gold;
std::shared_ptr<note_commitment_gadget<FieldT>> commit_to_outputs;
public:
output_note_gadget(
protoboard<FieldT>& pb,
pb_variable<FieldT>& ZERO,
pb_variable_array<FieldT>& phi,
pb_variable_array<FieldT>& h_sig,
bool nonce,
std::shared_ptr<digest_variable<FieldT>> commitment
) : note_gadget<FieldT>(pb) {
rho.reset(new digest_variable<FieldT>(pb, 256, ""));
a_pk.reset(new digest_variable<FieldT>(pb, 256, ""));
// Do not allow the caller to choose the same "rho"
// for any two valid notes in a given view of the
// blockchain. See protocol specification for more
// details.
prevent_faerie_gold.reset(new PRF_rho_gadget<FieldT>(
pb,
ZERO,
phi,
h_sig,
nonce,
rho
));
// Commit to the output notes publicly without
// disclosing them.
commit_to_outputs.reset(new note_commitment_gadget<FieldT>(
pb,
ZERO,
a_pk->bits,
this->value,
rho->bits,
this->r->bits,
commitment
));
}
void generate_r1cs_constraints() {
note_gadget<FieldT>::generate_r1cs_constraints();
a_pk->generate_r1cs_constraints();
prevent_faerie_gold->generate_r1cs_constraints();
commit_to_outputs->generate_r1cs_constraints();
}
void generate_r1cs_witness(const SproutNote& note) {
note_gadget<FieldT>::generate_r1cs_witness(note);
prevent_faerie_gold->generate_r1cs_witness();
// [SANITY CHECK] Witness rho ourselves with the
// note information.
rho->bits.fill_with_bits(
this->pb,
uint256_to_bool_vector(note.rho)
);
a_pk->bits.fill_with_bits(
this->pb,
uint256_to_bool_vector(note.a_pk)
);
commit_to_outputs->generate_r1cs_witness();
}
};

109
src/zcash/circuit/prfs.tcc

@ -1,109 +0,0 @@
template<typename FieldT>
class PRF_gadget : gadget<FieldT> {
private:
std::shared_ptr<block_variable<FieldT>> block;
std::shared_ptr<sha256_compression_function_gadget<FieldT>> hasher;
std::shared_ptr<digest_variable<FieldT>> result;
public:
PRF_gadget(
protoboard<FieldT>& pb,
pb_variable<FieldT>& ZERO,
bool a,
bool b,
bool c,
bool d,
pb_variable_array<FieldT> x,
pb_variable_array<FieldT> y,
std::shared_ptr<digest_variable<FieldT>> result
) : gadget<FieldT>(pb), result(result) {
pb_linear_combination_array<FieldT> IV = SHA256_default_IV(pb);
pb_variable_array<FieldT> discriminants;
discriminants.emplace_back(a ? ONE : ZERO);
discriminants.emplace_back(b ? ONE : ZERO);
discriminants.emplace_back(c ? ONE : ZERO);
discriminants.emplace_back(d ? ONE : ZERO);
block.reset(new block_variable<FieldT>(pb, {
discriminants,
x,
y
}, "PRF_block"));
hasher.reset(new sha256_compression_function_gadget<FieldT>(
pb,
IV,
block->bits,
*result,
"PRF_hasher"));
}
void generate_r1cs_constraints() {
hasher->generate_r1cs_constraints();
}
void generate_r1cs_witness() {
hasher->generate_r1cs_witness();
}
};
template<typename FieldT>
pb_variable_array<FieldT> gen256zeroes(pb_variable<FieldT>& ZERO) {
pb_variable_array<FieldT> ret;
while (ret.size() < 256) {
ret.emplace_back(ZERO);
}
return ret;
}
template<typename FieldT>
class PRF_addr_a_pk_gadget : public PRF_gadget<FieldT> {
public:
PRF_addr_a_pk_gadget(
protoboard<FieldT>& pb,
pb_variable<FieldT>& ZERO,
pb_variable_array<FieldT>& a_sk,
std::shared_ptr<digest_variable<FieldT>> result
) : PRF_gadget<FieldT>(pb, ZERO, 1, 1, 0, 0, a_sk, gen256zeroes(ZERO), result) {}
};
template<typename FieldT>
class PRF_nf_gadget : public PRF_gadget<FieldT> {
public:
PRF_nf_gadget(
protoboard<FieldT>& pb,
pb_variable<FieldT>& ZERO,
pb_variable_array<FieldT>& a_sk,
pb_variable_array<FieldT>& rho,
std::shared_ptr<digest_variable<FieldT>> result
) : PRF_gadget<FieldT>(pb, ZERO, 1, 1, 1, 0, a_sk, rho, result) {}
};
template<typename FieldT>
class PRF_pk_gadget : public PRF_gadget<FieldT> {
public:
PRF_pk_gadget(
protoboard<FieldT>& pb,
pb_variable<FieldT>& ZERO,
pb_variable_array<FieldT>& a_sk,
pb_variable_array<FieldT>& h_sig,
bool nonce,
std::shared_ptr<digest_variable<FieldT>> result
) : PRF_gadget<FieldT>(pb, ZERO, 0, nonce, 0, 0, a_sk, h_sig, result) {}
};
template<typename FieldT>
class PRF_rho_gadget : public PRF_gadget<FieldT> {
public:
PRF_rho_gadget(
protoboard<FieldT>& pb,
pb_variable<FieldT>& ZERO,
pb_variable_array<FieldT>& phi,
pb_variable_array<FieldT>& h_sig,
bool nonce,
std::shared_ptr<digest_variable<FieldT>> result
) : PRF_gadget<FieldT>(pb, ZERO, 0, nonce, 1, 0, phi, h_sig, result) {}
};

75
src/zcash/circuit/utils.tcc

@ -1,75 +0,0 @@
#include "uint252.h"
template<typename FieldT>
pb_variable_array<FieldT> from_bits(std::vector<bool> bits, pb_variable<FieldT>& ZERO) {
pb_variable_array<FieldT> acc;
BOOST_FOREACH(bool bit, bits) {
acc.emplace_back(bit ? ONE : ZERO);
}
return acc;
}
std::vector<bool> trailing252(std::vector<bool> input) {
if (input.size() != 256) {
throw std::length_error("trailing252 input invalid length");
}
return std::vector<bool>(input.begin() + 4, input.end());
}
template<typename T>
std::vector<bool> to_bool_vector(T input) {
std::vector<unsigned char> input_v(input.begin(), input.end());
return convertBytesVectorToVector(input_v);
}
std::vector<bool> uint256_to_bool_vector(uint256 input) {
return to_bool_vector(input);
}
std::vector<bool> uint252_to_bool_vector(uint252 input) {
return trailing252(to_bool_vector(input));
}
std::vector<bool> uint64_to_bool_vector(uint64_t input) {
auto num_bv = convertIntToVectorLE(input);
return convertBytesVectorToVector(num_bv);
}
void insert_uint256(std::vector<bool>& into, uint256 from) {
std::vector<bool> blob = uint256_to_bool_vector(from);
into.insert(into.end(), blob.begin(), blob.end());
}
void insert_uint64(std::vector<bool>& into, uint64_t from) {
std::vector<bool> num = uint64_to_bool_vector(from);
into.insert(into.end(), num.begin(), num.end());
}
template<typename T>
T swap_endianness_u64(T v) {
if (v.size() != 64) {
throw std::length_error("invalid bit length for 64-bit unsigned integer");
}
for (size_t i = 0; i < 4; i++) {
for (size_t j = 0; j < 8; j++) {
std::swap(v[i*8 + j], v[((7-i)*8)+j]);
}
}
return v;
}
template<typename FieldT>
linear_combination<FieldT> packed_addition(pb_variable_array<FieldT> input) {
auto input_swapped = swap_endianness_u64(input);
return pb_packing_sum<FieldT>(pb_variable_array<FieldT>(
input_swapped.rbegin(), input_swapped.rend()
));
}

23
src/zcbenchmarks.cpp

@ -1,3 +1,5 @@
// Copyright (c) 2019-2020 The Hush developers
#include <cstdio>
#include <future>
#include <map>
@ -91,24 +93,6 @@ double benchmark_sleep()
return timer_stop(tv_start);
}
double benchmark_parameter_loading()
{
// FIXME: this is duplicated with the actual loading code
boost::filesystem::path pk_path = ZC_GetParamsDir() / "sprout-proving.key";
boost::filesystem::path vk_path = ZC_GetParamsDir() / "sprout-verifying.key";
struct timeval tv_start;
timer_start(tv_start);
auto newParams = ZCJoinSplit::Prepared(vk_path.string(), pk_path.string());
double ret = timer_stop(tv_start);
delete newParams;
return ret;
}
double benchmark_create_joinsplit()
{
uint256 joinSplitPubKey;
@ -118,8 +102,7 @@ double benchmark_create_joinsplit()
struct timeval tv_start;
timer_start(tv_start);
JSDescription jsdesc(true,
*pzcashParams,
JSDescription jsdesc(*pzcashParams,
joinSplitPubKey,
anchor,
{JSInput(), JSInput()},

2
src/zcbenchmarks.h

@ -1,3 +1,4 @@
// Copyright (c) 2019-2020 The Hush developers
#ifndef BENCHMARKS_H
#define BENCHMARKS_H
@ -5,7 +6,6 @@
#include <stdlib.h>
extern double benchmark_sleep();
extern double benchmark_parameter_loading();
extern double benchmark_create_joinsplit();
extern std::vector<double> benchmark_create_joinsplit_threaded(int nThreads);
extern double benchmark_solve_equihash();

2
zcutil/build-win.sh

@ -18,7 +18,7 @@ echo $PWD
cd $WD
./autogen.sh
CONFIG_SITE=$PWD/depends/x86_64-w64-mingw32/share/config.site CXXFLAGS="-DPTW32_STATIC_LIB -DCURL_STATICLIB -DCURVE_ALT_BN128 -fopenmp -pthread" ./configure --prefix="${PREFIX}" --host=x86_64-w64-mingw32 --enable-static --disable-shared
CONFIG_SITE=$PWD/depends/x86_64-w64-mingw32/share/config.site CXXFLAGS="-DPTW32_STATIC_LIB -DCURL_STATICLIB -fopenmp -pthread" ./configure --prefix="${PREFIX}" --host=x86_64-w64-mingw32 --enable-static --disable-shared
sed -i 's/-lboost_system-mt /-lboost_system-mt-s /' configure
cd src/
CC="${CC} -g " CXX="${CXX} -g " make V=1 komodod.exe komodo-cli.exe komodo-tx.exe

Loading…
Cancel
Save