Duke Leto
4 years ago
28 changed files with 848 additions and 2561 deletions
@ -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 |
|
@ -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 |
|
@ -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) |
|
||||
|
|
@ -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)); |
|
||||
} |
|
@ -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,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
|
|
||||
} |
|
@ -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; |
|
||||
} |
|
@ -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(); |
|
||||
} |
|
||||
}; |
|
@ -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()); |
|
||||
} |
|
||||
}; |
|
@ -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(); |
|
||||
} |
|
||||
}; |
|
@ -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(); |
|
||||
} |
|
||||
}; |
|
@ -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) {} |
|
||||
}; |
|
@ -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() |
|
||||
)); |
|
||||
} |
|
Loading…
Reference in new issue