diff --git a/.gitignore b/.gitignore index 408d59085..ae3cff264 100644 --- a/.gitignore +++ b/.gitignore @@ -156,7 +156,9 @@ src/Makefile.in doc/man/Makefile.in Makefile.in src/libcc.so +src/libcc.dll src/cc/customcc.so +src/cc/customcc.dll src/HUSH3_7776 REGTEST_7776 src/cc/librogue.so diff --git a/DEVELOPING.md b/DEVELOPING.md index 15942011d..c64fb5f4f 100644 --- a/DEVELOPING.md +++ b/DEVELOPING.md @@ -25,14 +25,8 @@ sometimes introduce weird bugs or make compiling really annoying. Switching branches and doing partial compiles in Komodo/Hush source code can introduce weird bugs, which are fixed by running `build.sh` again. -When in doubt, if you run into a compile error, especially if it mentions -`OCTET_STRING`, run `build.sh` again. Running `make clean` before switching -branches can often prevent those problems. - -``` -cryptoconditions/src/asn/SimpleSha256Condition.h:14:10: fatal error: OCTET_STRING.h: No such file or directory -``` - +Additionally, it's a good idea to run `make clean` before you switch +between branches. ## Partial compiles @@ -60,3 +54,7 @@ After successfully compiling Hush, you can generate a debian package of these bi This command will not work on Mac OS X. Currently you cannot generate a Debian package from operating systems other than Linux. + +## Updates to this document + +If you think something else should be in this guide, please send your suggestions! diff --git a/INSTALL.md b/INSTALL.md index c47c6ddfe..bb667b7be 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -39,7 +39,7 @@ sudo apt-get install build-essential pkg-config libc6-dev m4 g++-multilib \ git clone https://github.com/MyHush/hush3.git cd hush3 # Build -./zcutil/build.sh -j$(nproc) +./build.sh -j$(nproc) ``` ## Run a HUSH Node @@ -63,10 +63,8 @@ Downloading Git source repo, building and running Hush: # pull git clone https://github.com/MyHush/hush3.git cd hush -# fetch key -./zcutil/fetch-params.sh # Build -./zcutil/build-win.sh -j$(nproc) +./build-win.sh -j$(nproc) # Run a HUSH node ./src/hushd ``` diff --git a/README.md b/README.md index 1ec5dd7b1..95c8999fe 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# HUSH 3 +# HUSH ## What is HUSH? diff --git a/build-aux/m4/ax_openmp.m4 b/build-aux/m4/ax_openmp.m4 deleted file mode 100644 index 866e1d664..000000000 --- a/build-aux/m4/ax_openmp.m4 +++ /dev/null @@ -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 -# Copyright (c) 2015 John W. Peterson -# Copyright (c) 2016 Nick R. Papior -# -# 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 . -# -# 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 - -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 diff --git a/build.sh b/build.sh new file mode 100755 index 000000000..2ae8514c3 --- /dev/null +++ b/build.sh @@ -0,0 +1,5 @@ +#!/bin/bash +# Copyright (c) 2019-2020 The Hush developers + +set -eu -o pipefail +./zcutil/build.sh $@ diff --git a/configure.ac b/configure.ac index b57e0969f..4ff3855b8 100644 --- a/configure.ac +++ b/configure.ac @@ -1,8 +1,8 @@ dnl require autoconf 2.60 (AS_ECHO/AS_ECHO_N) AC_PREREQ([2.60]) define(_CLIENT_VERSION_MAJOR, 3) -define(_CLIENT_VERSION_MINOR, 3) -define(_CLIENT_VERSION_REVISION, 1) +define(_CLIENT_VERSION_MINOR, 4) +define(_CLIENT_VERSION_REVISION, 0) define(_CLIENT_VERSION_BUILD, 50) define(_ZC_BUILD_VAL, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, m4_incr(_CLIENT_VERSION_BUILD), m4_eval(_CLIENT_VERSION_BUILD < 50), 1, m4_eval(_CLIENT_VERSION_BUILD - 24), m4_eval(_CLIENT_VERSION_BUILD == 50), 1, , m4_eval(_CLIENT_VERSION_BUILD - 50))) define(_CLIENT_VERSION_SUFFIX, m4_if(m4_eval(_CLIENT_VERSION_BUILD < 25), 1, _CLIENT_VERSION_REVISION-beta$1, m4_eval(_CLIENT_VERSION_BUILD < 50), 1, _CLIENT_VERSION_REVISION-rc$1, m4_eval(_CLIENT_VERSION_BUILD == 50), 1, _CLIENT_VERSION_REVISION, _CLIENT_VERSION_REVISION-$1))) @@ -96,12 +96,6 @@ AC_ARG_ENABLE([mining], [enable_mining=$enableval], [enable_mining=yes]) -AC_ARG_ENABLE([proton], - [AS_HELP_STRING([--disable-proton], - [disable Proton (AMQP messaging)])], - [use_proton=$enableval], - [use_proton=yes]) - AC_ARG_ENABLE(tests, AS_HELP_STRING([--enable-tests],[compile tests (default is yes)]), [use_tests=$enableval], @@ -507,15 +501,24 @@ if test x$use_hardening != xno; then HARDENED_CPPFLAGS="$HARDENED_CPPFLAGS -D_FORTIFY_SOURCE=2" ],[AC_MSG_ERROR(Cannot enable -D_FORTIFY_SOURCE=2)]) - #AX_CHECK_LINK_FLAG([[-Wl,-z,relro]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-z,relro"],[AC_MSG_ERROR(Cannot enable RELRO)]) - #AX_CHECK_LINK_FLAG([[-Wl,-z,now]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-z,now"],[AC_MSG_ERROR(Cannot enable BIND_NOW)]) + if test x$BUILD_OS = xdarwin || test x$TARGET_OS = xwindows; then + # Xcode's ld (at least ld64-302.3) doesn't support -z + # mingw-w64's ld (at least mingw-w64 4.0.4-2) also appears to not support -z + AX_CHECK_LINK_FLAG([[-Wl,-z,relro]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-z,relro"],[AC_MSG_WARN(Cannot enable RELRO)]) + AX_CHECK_LINK_FLAG([[-Wl,-z,now]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-z,now"],[AC_MSG_WARN(Cannot enable BIND_NOW)]) + else + AX_CHECK_LINK_FLAG([[-Wl,-z,relro]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-z,relro"],[AC_MSG_ERROR(Cannot enable RELRO)]) + AX_CHECK_LINK_FLAG([[-Wl,-z,now]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-z,now"],[AC_MSG_ERROR(Cannot enable BIND_NOW)]) + fi if test x$TARGET_OS != xwindows; then # All windows code is PIC, forcing it on just adds useless compile warnings - AX_CHECK_LINK_FLAG([[-Wl,-z,relro]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-z,relro"],[AC_MSG_ERROR(Cannot enable RELRO)]) - AX_CHECK_LINK_FLAG([[-Wl,-z,now]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-z,now"],[AC_MSG_ERROR(Cannot enable BIND_NOW)]) - AX_CHECK_COMPILE_FLAG([-fPIE],[HARDENED_CXXFLAGS="$HARDENED_CXXFLAGS -fPIE"],[AC_MSG_ERROR(Cannot enable -fPIE)]) - AX_CHECK_LINK_FLAG([[-pie]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -pie"],[AC_MSG_ERROR(Cannot enable -pie)]) + AX_CHECK_COMPILE_FLAG([-fPIE],[PIE_FLAGS="-fPIE"],[AC_MSG_ERROR(Cannot enable -fPIE)]) + if test x$BUILD_OS = xdarwin; then + AX_CHECK_LINK_FLAG([[-Wl,-pie]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,-pie"],[AC_MSG_ERROR(Cannot enable -Wl,-pie)]) + else + AX_CHECK_LINK_FLAG([[-pie]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -pie"],[AC_MSG_ERROR(Cannot enable -pie)]) + fi else # These are only available on Windows. AX_CHECK_LINK_FLAG([[-Wl,--dynamicbase]], [HARDENED_LDFLAGS="$HARDENED_LDFLAGS -Wl,--dynamicbase"],[AC_MSG_ERROR(Cannot enable --dynamicbase)]) @@ -596,23 +599,6 @@ if test x$enable_wallet != xno; then BITCOIN_FIND_BDB62 fi -dnl Check Qpid Proton headers and library exist -if test x$use_proton = xyes; then - AC_CHECK_HEADERS([proton/connection.hpp], - [], - [AC_MSG_WARN([Proton headers not found, disabling Proton support]) - use_proton=no]) - AC_CHECK_LIB([qpid-proton-cpp], [main], - [PROTON_LIBS="-lqpid-proton-cpp -lqpid-proton"], - [AC_MSG_WARN([Proton libraries not found, disabling Proton support]) - use_proton=no]) -fi -if test x$use_proton = xyes; then - AC_DEFINE(ENABLE_PROTON, 1, [Define to 1 to enable Proton functions]) -else - AC_DEFINE(ENABLE_PROTON, 0, [Define to 1 to enable Proton functions]) -fi - if test x$build_bitcoin_utils$build_bitcoind$use_tests = xnonono; then use_boost=no else @@ -700,7 +686,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++, gmp' 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)) @@ -716,6 +702,22 @@ 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)]) + if test "x$use_zmq" = "xyes"; then AC_CHECK_HEADER([zmq.h], [AC_DEFINE([ENABLE_ZMQ],[1],[Define to 1 to enable ZMQ functions])], @@ -742,40 +744,11 @@ 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)]) - -# libsnark header layout is broken unless cpp's -I is passed with the -# libsnark directory, so for now we use this hideous workaround: -echo 'Hunting for libsnark include directory...' -[LIBSNARK_INCDIR="$(echo "$CPPFLAGS" | sed 's,^.*-I\([^ ]*/include\).*$,\1/libsnark,')"] -if test -d "$LIBSNARK_INCDIR"; then - echo "Found libsnark include directory: $LIBSNARK_INCDIR" -else -#AC_MSG_ERROR(libsnark include directory not found) -echo "libsnark include directory not found ($LIBSNARK_INCDIR)" -fi - -CPPFLAGS="-I$LIBSNARK_INCDIR $CPPFLAGS" - -# Now check for libsnark compilability using traditional autoconf tests: -if test x$TARGET_OS = xdarwin; then -AC_CHECK_HEADER([libsnark/gadgetlib1/gadget.hpp],,AC_MSG_ERROR(libsnark headers missing)) -AC_CHECK_LIB([snark],[main],LIBSNARK_LIBS=-lsnark, [AC_MSG_ERROR(libsnark missing)], [-lgmpxx]) -fi -#AC_CHECK_HEADER([libsnark/gadgetlib1/gadget.hpp],,AC_MSG_ERROR(libsnark headers missing)) -#AC_CHECK_LIB([snark],[main],LIBSNARK_LIBS=-lsnark, [AC_MSG_ERROR(libsnark missing)], [-lgmpxx]) RUST_LIBS="-lrustzcash" case $host in @@ -786,25 +759,7 @@ 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])]) - -# Gitian uses a config.site that sets depends_prefix, and then sets --prefix=/ -# build.sh just uses --prefix -if test x$depends_prefix != x; then - LIBSNARK_DEPINST="$depends_prefix" -else - LIBSNARK_DEPINST="$prefix" -fi - -# 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]]) @@ -871,8 +826,6 @@ fi AM_CONDITIONAL([ENABLE_ZMQ], [test "x$use_zmq" = "xyes"]) -AM_CONDITIONAL([ENABLE_PROTON], [test "x$use_proton" = "xyes"]) - AC_MSG_CHECKING([whether to build test_bitcoin]) if test x$use_tests = xyes; then AC_MSG_RESULT([yes]) @@ -944,9 +897,7 @@ AC_SUBST(EVENT_PTHREADS_LIBS) AC_SUBST(ZMQ_LIBS) AC_SUBST(GMP_LIBS) AC_SUBST(GMPXX_LIBS) -AC_SUBST(LIBSNARK_DEPINST) AC_SUBST(LIBZCASH_LIBS) -AC_SUBST(PROTON_LIBS) AC_CONFIG_FILES([Makefile src/Makefile doc/man/Makefile src/test/buildenv.py]) AC_CONFIG_FILES([qa/pull-tester/run-bitcoind-for-test.sh],[chmod +x qa/pull-tester/run-bitcoind-for-test.sh]) AC_CONFIG_FILES([qa/pull-tester/tests-config.sh],[chmod +x qa/pull-tester/tests-config.sh]) @@ -975,7 +926,7 @@ unset PKG_CONFIG_LIBDIR PKG_CONFIG_LIBDIR="$PKGCONFIG_LIBDIR_TEMP" ac_configure_args="${ac_configure_args} --disable-shared --with-pic --with-bignum=no --enable-module-recovery" -AC_CONFIG_SUBDIRS([src/secp256k1 src/snark src/univalue src/cryptoconditions]) +AC_CONFIG_SUBDIRS([src/secp256k1 src/univalue src/cryptoconditions]) AC_OUTPUT @@ -993,7 +944,6 @@ esac echo echo "Options used to compile and link:" echo " with wallet = $enable_wallet" -echo " with proton = $use_proton" echo " with zmq = $use_zmq" echo " with test = $use_tests" echo " debug enabled = $enable_debug" diff --git a/contrib/amqp/amqp_sub.py b/contrib/amqp/amqp_sub.py deleted file mode 100644 index bc51e8428..000000000 --- a/contrib/amqp/amqp_sub.py +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env python2 -# Copyright (c) 2017 The Zcash developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -# Requirements: -# pip install python-qpid-proton - -import binascii -from proton.handlers import MessagingHandler -from proton.reactor import Container - -port = 5672 - -class Server(MessagingHandler): - def __init__(self, url): - super(Server, self).__init__() - self.url = url - self.senders = {} - - def on_start(self, event): - print "Listening on:", self.url - self.container = event.container - self.acceptor = event.container.listen(self.url) - - def on_message(self, event): - m = event.message - topic = m.subject - body = m.body - sequence = str( m.properties['x-opt-sequence-number'] ) - if topic == "hashablock": - print '- HASH BLOCK ('+sequence+') -' - print binascii.hexlify(body) - elif topic == "hashtx": - print '- HASH TX ('+sequence+') -' - print binascii.hexlify(body) - elif topic == "rawblock": - print '- RAW BLOCK HEADER ('+sequence+') -' - print binascii.hexlify(body[:80]) - elif topic == "rawtx": - print '- RAW TX ('+sequence+') -' - print binascii.hexlify(body) - -try: - Container(Server("127.0.0.1:%i" % port)).run() -except KeyboardInterrupt: - pass - diff --git a/contrib/block_time.pl b/contrib/block_time.pl index dff43ea4e..17da3c461 100755 --- a/contrib/block_time.pl +++ b/contrib/block_time.pl @@ -1,5 +1,5 @@ #!/usr/bin/perl -# Copyright 2019 The Hush developers +# Copyright 2019-2020 The Hush developers # Released under the GPLv3 use warnings; use strict; @@ -9,6 +9,11 @@ my $block = shift || die "Usage: $0 123"; my $hush = "./src/hush-cli"; my $blockcount = qx{$hush getblockcount}; +unless ($blockcount = int($blockcount)) { + print "Invalid response from hush-cli\n"; + exit 1; +} + if ($block <= $blockcount) { die "That block has already happened!"; } else { diff --git a/contrib/checkpoints.pl b/contrib/checkpoints.pl index 99a84f2c2..93ea1041c 100755 --- a/contrib/checkpoints.pl +++ b/contrib/checkpoints.pl @@ -1,5 +1,5 @@ #!/usr/bin/perl -# Copyright 2019 The Hush developers +# Copyright 2019-2020 The Hush developers # Released under the GPLv3 use warnings; use strict; @@ -12,6 +12,10 @@ my $gethash = "$hush getblockhash"; my $stride = shift || 1000; my $count = 0; my $blocks = qx{$hush getblockcount}; +if($?) { + print "ERROR, exiting...\n"; + exit 1; +} my $prev = $blocks - $perday; my $last = 0; my $now = time(); diff --git a/contrib/debian/copyright b/contrib/debian/copyright index 3c93ce7a9..2f51f4a4c 100644 --- a/contrib/debian/copyright +++ b/contrib/debian/copyright @@ -16,10 +16,6 @@ Files: depends/sources/libsodium-*.tar.gz Copyright: 2013-2016 Frank Denis License: ISC -Files: depends/sources/libsnark-*.tar.gz -Copyright: 2012-2016 SCIPR Lab and contributors; 2016 The Zcash developers -License: Expat - Files: depends/sources/gmp-*.tar.bz2 Copyright: 1991, 1996, 1999, 2000, 2007 Free Software Foundation, Inc. License: LGPL @@ -56,10 +52,6 @@ Files: depends/sources/google*.tar.gz Copyright: 2008 Google Inc. License: BSD-3clause-Google -Files: depends/sources/qpid-proton-*.tar.gz -Copyright: 2012-2017 The Apache Software Foundation -License: Apache-Qpid-Proton-with-BSD-Subcomponents - Files: src/secp256k1/build-aux/m4/ax_jni_include_dir.m4 Copyright: 2008 Don Anderson License: GNU-All-permissive-License @@ -1105,222 +1097,6 @@ Comment: You should have received a copy of the GNU General Public License along with this program. If not, see . -License: Apache-Qpid-Proton-with-BSD-Subcomponents - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - . - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - . - 1. Definitions. - . - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - . - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - . - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - . - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - . - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - . - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - . - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - . - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - . - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - . - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - . - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - . - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - . - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - . - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - . - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - . - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - . - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - . - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - . - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - . - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - . - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - . - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - . - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - . - END OF TERMS AND CONDITIONS - . - APPENDIX: How to apply the Apache License to your work. - . - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - . - Copyright [yyyy] [name of copyright owner] - . - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - . - http://www.apache.org/licenses/LICENSE-2.0 - . - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - . - . - PROTON SUBCOMPONENTS: - . - Proton includes freegetopt with a separate BSD license. Your use - of the source code for freegetopt is subject to the terms and - conditions of its license in examples/include/pncompat/internal/LICENSE. - . - The setup scripts for the python bindings include files derived by - PyZMQ and are licensed with a separate Modified BSD license. Use of - the source code in these setup files are subject to the terms and - conditions in the license: - proton-c/bindings/python/setuputils/PYZMQ_LICENSE.BSD. - License: GNU-All-permissive-License Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice diff --git a/contrib/gitian-descriptors/gitian-linux.yml b/contrib/gitian-descriptors/gitian-linux.yml index c619cf270..317bd8694 100644 --- a/contrib/gitian-descriptors/gitian-linux.yml +++ b/contrib/gitian-descriptors/gitian-linux.yml @@ -85,7 +85,7 @@ script: | BASEPREFIX=`pwd`/depends # Build dependencies for each host for i in $HOSTS; do - NO_PROTON="x" make ${MAKEOPTS} -C ${BASEPREFIX} HOST="${i}" + make ${MAKEOPTS} -C ${BASEPREFIX} HOST="${i}" done # Faketime for binaries diff --git a/depends/.gitignore b/depends/.gitignore index 1f163897b..3cb4b9ac1 100644 --- a/depends/.gitignore +++ b/depends/.gitignore @@ -7,3 +7,4 @@ x86_64* i686* mips* arm* +aarch64* diff --git a/depends/Makefile b/depends/Makefile index 636577d13..82acde0ac 100644 --- a/depends/Makefile +++ b/depends/Makefile @@ -74,9 +74,8 @@ include builders/default.mk include packages/packages.mk wallet_packages_$(NO_WALLET) = $(wallet_packages) -proton_packages_$(NO_PROTON) = $(proton_packages) -packages += $($(host_arch)_$(host_os)_packages) $($(host_os)_packages) $(rust_packages) $(proton_packages_) $(wallet_packages_) +packages += $($(host_arch)_$(host_os)_packages) $($(host_os)_packages) $(rust_packages) $(wallet_packages_) native_packages += $($(host_arch)_$(host_os)_native_packages) $($(host_os)_native_packages) all_packages = $(packages) $(native_packages) @@ -112,6 +111,7 @@ $(host_prefix)/share/config.site : config.site.in $(host_prefix)/.stamp_$(final_ -e 's|@CXXFLAGS@|$(strip $(host_CXXFLAGS) $(host_$(release_type)_CXXFLAGS))|' \ -e 's|@CPPFLAGS@|$(strip $(host_CPPFLAGS) $(host_$(release_type)_CPPFLAGS))|' \ -e 's|@LDFLAGS@|$(strip $(host_LDFLAGS) $(host_$(release_type)_LDFLAGS))|' \ + -e 's|@rust_target@|$(call rust_target,rust,$(canonical_host),$(host_os))|' \ -e 's|@no_wallet@|$(NO_WALLET)|' \ -e 's|@debug@|$(DEBUG)|' \ $< > $@ diff --git a/depends/config.site.in b/depends/config.site.in index 8cdbcd2e4..dbcb7a6e4 100644 --- a/depends/config.site.in +++ b/depends/config.site.in @@ -13,6 +13,9 @@ if test -z $enable_wallet && test -n "@no_wallet@"; then enable_wallet=no fi +RUST_TARGET="@rust_target@" +RUST_VENDORED_SOURCES="$depends_prefix/vendored-sources" + if test x@host_os@ = xdarwin; then BREW=no PORT=no diff --git a/depends/funcs.mk b/depends/funcs.mk index 3d89de8a7..35ca5abcf 100644 --- a/depends/funcs.mk +++ b/depends/funcs.mk @@ -40,7 +40,7 @@ endef define vendor_crate_source mkdir -p $($(1)_staging_prefix_dir)/$(CRATE_REGISTRY) && \ -cp -r $($(1)_extract_dir) $($(1)_staging_prefix_dir)/$(CRATE_REGISTRY)/$($(1)_crate_name) && \ +cp -r $($(1)_extract_dir) $($(1)_staging_prefix_dir)/$(CRATE_REGISTRY)/$($(1)_crate_versioned_name) && \ cd $($(1)_staging_prefix_dir)/$(CRATE_REGISTRY)/$($(1)_crate_versioned_name) && \ rm -r `basename $($(1)_patch_dir)` .stamp_* .$($(1)_file_name).hash endef @@ -59,8 +59,8 @@ $(eval $(1)_build_id:=$(shell echo -n "$($(1)_build_id_long)" | $(build_SHA256SU final_build_id_long+=$($(package)_build_id_long) #override platform specific files and hashes -$(eval $(1)_file_name=$(if $($(1)_file_name_$(host_os)),$($(1)_file_name_$(host_os)),$($(1)_file_name))) -$(eval $(1)_sha256_hash=$(if $($(1)_sha256_hash_$(host_os)),$($(1)_sha256_hash_$(host_os)),$($(1)_sha256_hash))) +$(eval $(1)_file_name=$(if $($(1)_exact_file_name),$($(1)_exact_file_name),$(if $($(1)_file_name_$(host_os)),$($(1)_file_name_$(host_os)),$($(1)_file_name)))) +$(eval $(1)_sha256_hash=$(if $($(1)_exact_sha256_hash),$($(1)_exact_sha256_hash),$(if $($(1)_sha256_hash_$(host_os)),$($(1)_sha256_hash_$(host_os)),$($(1)_sha256_hash)))) #compute package-specific paths $(1)_build_subdir?=. @@ -91,8 +91,9 @@ $(1)_download_path_fixed=$(subst :,\:,$$($(1)_download_path)) #default commands +# The default behavior for tar will try to set ownership when running as uid 0 and may not succeed, --no-same-owner disables this behavior $(1)_fetch_cmds ?= $(call fetch_file,$(1),$(subst \:,:,$$($(1)_download_path_fixed)),$$($(1)_download_file),$($(1)_file_name),$($(1)_sha256_hash)) -$(1)_extract_cmds ?= mkdir -p $$($(1)_extract_dir) && echo "$$($(1)_sha256_hash) $$($(1)_source)" > $$($(1)_extract_dir)/.$$($(1)_file_name).hash && $(build_SHA256SUM) -c $$($(1)_extract_dir)/.$$($(1)_file_name).hash && tar --strip-components=1 -xf $$($(1)_source) +$(1)_extract_cmds ?= mkdir -p $$($(1)_extract_dir) && echo "$$($(1)_sha256_hash) $$($(1)_source)" > $$($(1)_extract_dir)/.$$($(1)_file_name).hash && $(build_SHA256SUM) -c $$($(1)_extract_dir)/.$$($(1)_file_name).hash && tar --no-same-owner --strip-components=1 -xf $$($(1)_source) $(1)_preprocess_cmds ?= $(1)_build_cmds ?= $(1)_config_cmds ?= @@ -193,7 +194,7 @@ $($(1)_preprocessed): | $($(1)_dependencies) $($(1)_extracted) $(AT)touch $$@ $($(1)_configured): | $($(1)_preprocessed) $(AT)echo Configuring $(1)... - $(AT)rm -rf $(host_prefix); mkdir -p $(host_prefix)/lib; cd $(host_prefix); $(foreach package,$($(1)_all_dependencies), tar xf $($(package)_cached); ) + $(AT)rm -rf $(host_prefix); mkdir -p $(host_prefix)/lib; cd $(host_prefix); $(foreach package,$($(1)_all_dependencies), tar --no-same-owner -xf $($(package)_cached); ) $(AT)mkdir -p $$(@D) $(AT)+cd $$(@D); $($(1)_config_env) $(call $(1)_config_cmds, $(1)) $(AT)touch $$@ diff --git a/depends/packages/bdb.mk b/depends/packages/bdb.mk index 404d94c51..c8f677490 100644 --- a/depends/packages/bdb.mk +++ b/depends/packages/bdb.mk @@ -9,6 +9,11 @@ define $(package)_set_vars $(package)_config_opts=--disable-shared --enable-cxx --disable-replication $(package)_config_opts_mingw32=--enable-mingw $(package)_config_opts_linux=--with-pic +$(package)_config_opts_freebsd=--with-pic +ifneq ($(build_os),darwin) +$(package)_config_opts_darwin=--disable-atomicsupport +endif +$(package)_config_opts_aarch64=--disable-atomicsupport $(package)_cxxflags=-std=c++11 endef diff --git a/depends/packages/boost.mk b/depends/packages/boost.mk index 800c424c5..3112ca7be 100644 --- a/depends/packages/boost.mk +++ b/depends/packages/boost.mk @@ -1,8 +1,8 @@ package=boost -$(package)_version=1_66_0 -$(package)_download_path=https://dl.bintray.com/boostorg/release/1.66.0/source -$(package)_sha256_hash=5721818253e6a0989583192f96782c4a98eb6204965316df9f5ad75819225ca9 +$(package)_version=1_72_0 +$(package)_download_path=https://github.com/MyHush/boost/releases/download/v1.72.0/ +$(package)_sha256_hash=59c9b274bc451cf91a9ba1dd2c7fdcaf5d60b1b3aa83f2c9fa143417cc660722 $(package)_file_name=$(package)_$($(package)_version).tar.bz2 define $(package)_set_vars diff --git a/depends/packages/libcurl.mk b/depends/packages/libcurl.mk index 159817139..91ff1c0f1 100644 --- a/depends/packages/libcurl.mk +++ b/depends/packages/libcurl.mk @@ -1,10 +1,10 @@ package=libcurl -$(package)_version=7.64.1 +$(package)_version=7.67.0 $(package)_dependencies=openssl $(package)_download_path=https://curl.haxx.se/download $(package)_file_name=curl-$($(package)_version).tar.gz -$(package)_sha256_hash=432d3f466644b9416bc5b649d344116a753aeaa520c8beaf024a90cba9d3d35d -$(package)_config_opts_linux=--disable-shared --enable-static --prefix=$(host_prefix) --host=x86_64-unknown-linux-gnu +$(package)_sha256_hash=52af3361cf806330b88b4fe6f483b6844209d47ae196ac46da4de59bb361ab02 +$(package)_config_opts_linux=--disable-shared --enable-static --prefix=$(host_prefix) --host=$(host) $(package)_config_opts_mingw32=--enable-mingw --disable-shared --enable-static --prefix=$(host_prefix) --host=x86_64-w64-mingw32 $(package)_config_opts_darwin=--disable-shared --enable-static --prefix=$(host_prefix) $(package)_cflags_darwin=-mmacosx-version-min=10.9 diff --git a/depends/packages/librustzcash.mk b/depends/packages/librustzcash.mk index 8612ac05a..fe6ef8a58 100644 --- a/depends/packages/librustzcash.mk +++ b/depends/packages/librustzcash.mk @@ -8,15 +8,29 @@ $(package)_git_commit=06da3b9ac8f278e5d4ae13088cf0a4c03d2c13f5 $(package)_dependencies=rust $(rust_crates) $(package)_patches=cargo.config 0001-Start-using-cargo-clippy-for-CI.patch remove-dev-dependencies.diff no-groth16.patch +$(package)_rust_target=$(if $(rust_rust_target_$(canonical_host)),$(rust_rust_target_$(canonical_host)),$(canonical_host)) + ifeq ($(host_os),mingw32) $(package)_library_file=target/x86_64-pc-windows-gnu/release/rustzcash.lib +else ifneq ($(canonical_host),$(build)) +ifeq ($(host_os),darwin) +$(package)_library_file=target/x86_64-apple-darwin/release/librustzcash.a +else +$(package)_library_file=target/$($(package)_rust_target)/release/librustzcash.a +endif else $(package)_library_file=target/release/librustzcash.a endif define $(package)_set_vars $(package)_build_opts=--frozen --release -$(package)_build_opts_mingw32=--target=x86_64-pc-windows-gnu +ifneq ($(canonical_host),$(build)) +ifeq ($(host_os),darwin) +$(package)_build_opts+=--target=x86_64-apple-darwin +else +$(package)_build_opts+=--target=$($(package)_rust_target) +endif +endif endef define $(package)_preprocess_cmds @@ -27,7 +41,7 @@ define $(package)_preprocess_cmds endef define $(package)_build_cmds - cargo build --package librustzcash $($(package)_build_opts) + $(host_prefix)/native/bin/cargo build --package librustzcash $($(package)_build_opts) endef define $(package)_stage_cmds diff --git a/depends/packages/native_ccache.mk b/depends/packages/native_ccache.mk index b63c18b90..64fee77ba 100644 --- a/depends/packages/native_ccache.mk +++ b/depends/packages/native_ccache.mk @@ -1,8 +1,8 @@ package=native_ccache -$(package)_version=3.3.1 -$(package)_download_path=https://www.samba.org/ftp/ccache -$(package)_file_name=ccache-$($(package)_version).tar.bz2 -$(package)_sha256_hash=cb6e4bafbb19ba0a2ec43386b123a5f92a20e1e3384c071d5d13e0cb3c84bf73 +$(package)_version=3.7.9 +$(package)_download_path=https://github.com/ccache/ccache/releases/download/v$($(package)_version) +$(package)_file_name=ccache-$($(package)_version).tar.gz +$(package)_sha256_hash=92838e2133c9e704fdab9ee2608dad86c99021278b9ac47d065aa8ff2ea8ce36 define $(package)_set_vars $(package)_config_opts= diff --git a/depends/packages/openssl.mk b/depends/packages/openssl.mk index c5ac5bb32..276e887a7 100644 --- a/depends/packages/openssl.mk +++ b/depends/packages/openssl.mk @@ -1,6 +1,6 @@ package=openssl $(package)_version=1.1.1a -$(package)_download_path=https://www.openssl.org/source +$(package)_download_path=https://www.openssl.org/source/old/1.1.1 $(package)_file_name=$(package)-$($(package)_version).tar.gz $(package)_sha256_hash=fc20130f8b7cbd2fb918b2f14e2f429e109c31ddd0fb38fc5d71d9ffed3f9f41 $(package)_patches=ssl_fix.patch diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk index 1c1a50668..9c76166af 100644 --- a/depends/packages/packages.mk +++ b/depends/packages/packages.mk @@ -1,12 +1,4 @@ -rust_packages := rust librustzcash - -ifeq ($(build_os),darwin) - zcash_packages := libsnark libgmp libsodium utfcpp -else - proton_packages := proton - zcash_packages := libgmp libsodium utfcpp -endif - +zcash_packages := libgmp libsodium utfcpp rust_crates := \ crate_aes \ crate_aesni \ diff --git a/depends/packages/proton.mk b/depends/packages/proton.mk deleted file mode 100644 index 39428f54b..000000000 --- a/depends/packages/proton.mk +++ /dev/null @@ -1,23 +0,0 @@ -package=proton -$(package)_version=0.17.0 -$(package)_download_path=https://archive.apache.org/dist/qpid/proton/$($(package)_version) -$(package)_file_name=qpid-proton-$($(package)_version).tar.gz -$(package)_sha256_hash=6ffd26d3d0e495bfdb5d9fefc5349954e6105ea18cc4bb191161d27742c5a01a -$(package)_patches=minimal-build.patch - -define $(package)_preprocess_cmds - patch -p1 < $($(package)_patch_dir)/minimal-build.patch && \ - mkdir -p build/proton-c/src -endef - -define $(package)_config_cmds - cd build; cmake .. -DCMAKE_CXX_STANDARD=11 -DCMAKE_INSTALL_PREFIX=/ -DSYSINSTALL_BINDINGS=ON -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DBUILD_PYTHON=OFF -DBUILD_PHP=OFF -DBUILD_JAVA=OFF -DBUILD_PERL=OFF -DBUILD_RUBY=OFF -DBUILD_JAVASCRIPT=OFF -DBUILD_GO=OFF -endef - -define $(package)_build_cmds - cd build; $(MAKE) VERBOSE=1 -endef - -define $(package)_stage_cmds - cd build; $(MAKE) VERBOSE=1 DESTDIR=$($(package)_staging_prefix_dir) install -endef diff --git a/depends/packages/rust.mk b/depends/packages/rust.mk index 9cfb95054..6fbdda037 100644 --- a/depends/packages/rust.mk +++ b/depends/packages/rust.mk @@ -1,7 +1,6 @@ package=rust $(package)_version=1.32.0 $(package)_download_path=https://static.rust-lang.org/dist - $(package)_file_name_linux=rust-$($(package)_version)-x86_64-unknown-linux-gnu.tar.gz $(package)_sha256_hash_linux=e024698320d76b74daf0e6e71be3681a1e7923122e3ebd03673fcac3ecc23810 $(package)_file_name_darwin=rust-$($(package)_version)-x86_64-apple-darwin.tar.gz @@ -9,20 +8,26 @@ $(package)_sha256_hash_darwin=f0dfba507192f9b5c330b5984ba71d57d434475f3d62bd44a3 $(package)_file_name_mingw32=rust-$($(package)_version)-x86_64-pc-windows-gnu.tar.gz $(package)_sha256_hash_mingw32=358e1435347c67dbf33aa9cad6fe501a833d6633ed5d5aa1863d5dffa0349be9 -ifeq ($(build_os),darwin) -$(package)_file_name=$($(package)_file_name_darwin) -$(package)_sha256_hash=$($(package)_sha256_hash_darwin) -else ifeq ($(host_os),mingw32) -$(package)_file_name=$($(package)_file_name_mingw32) -$(package)_sha256_hash=$($(package)_sha256_hash_mingw32) -else -$(package)_file_name=$($(package)_file_name_linux) -$(package)_sha256_hash=$($(package)_sha256_hash_linux) -endif +# Mapping from GCC canonical hosts to Rust targets +# If a mapping is not present, we assume they are identical, unless $host_os is +# "darwin", in which case we assume x86_64-apple-darwin. +$(package)_rust_target_x86_64-w64-mingw32=x86_64-pc-windows-gnu -ifeq ($(host_os),mingw32) +# Mapping from Rust targets to SHA-256 hashes +$(package)_rust_std_sha256_hash_aarch64-unknown-linux-gnu=346efe3aef2aff7b71a611bf7661bcec5f9bc4025a599c2866ec5fd330247cb9 +$(package)_rust_std_sha256_hash_x86_64-apple-darwin=b736d035a97f830585360e54e3f8877b68c942211cf0a75e805f34bfb36103a6 +$(package)_rust_std_sha256_hash_x86_64-pc-windows-gnu=cad5f1454d591c13eeb3657f1c9dbfeb30e648f59680bd0765b94c63e7afc49e + +define rust_target +$(if $($(1)_rust_target_$(2)),$($(1)_rust_target_$(2)),$(if $(findstring darwin,$(3)),x86_64-apple-darwin,$(2))) +endef + +ifneq ($(canonical_host),$(build)) +$(package)_rust_target=$(call rust_target,$(package),$(canonical_host),$(host_os)) +$(package)_exact_file_name=rust-std-$($(package)_version)-$($(package)_rust_target).tar.gz +$(package)_exact_sha256_hash=$($(package)_rust_std_sha256_hash_$($(package)_rust_target)) $(package)_build_subdir=buildos -$(package)_extra_sources = $($(package)_file_name_$(build_os)) +$(package)_extra_sources=$($(package)_file_name_$(build_os)) define $(package)_fetch_cmds $(call fetch_file,$(package),$($(package)_download_path),$($(package)_download_file),$($(package)_file_name),$($(package)_sha256_hash)) && \ @@ -34,19 +39,19 @@ define $(package)_extract_cmds echo "$($(package)_sha256_hash) $($(package)_source)" > $($(package)_extract_dir)/.$($(package)_file_name).hash && \ echo "$($(package)_sha256_hash_$(build_os)) $($(package)_source_dir)/$($(package)_file_name_$(build_os))" >> $($(package)_extract_dir)/.$($(package)_file_name).hash && \ $(build_SHA256SUM) -c $($(package)_extract_dir)/.$($(package)_file_name).hash && \ - mkdir mingw32 && \ - tar --strip-components=1 -xf $($(package)_source) -C mingw32 && \ + mkdir $(canonical_host) && \ + tar --strip-components=1 -xf $($(package)_source) -C $(canonical_host) && \ mkdir buildos && \ tar --strip-components=1 -xf $($(package)_source_dir)/$($(package)_file_name_$(build_os)) -C buildos endef define $(package)_stage_cmds - ./install.sh --destdir=$($(package)_staging_dir) --prefix=$(host_prefix)/native --disable-ldconfig && \ - cp -r ../mingw32/rust-std-x86_64-pc-windows-gnu/lib/rustlib/x86_64-pc-windows-gnu $($(package)_staging_dir)$(host_prefix)/native/lib/rustlib + bash ./install.sh --destdir=$($(package)_staging_dir) --prefix=$(host_prefix)/native --disable-ldconfig && \ + ../$(canonical_host)/install.sh --destdir=$($(package)_staging_dir) --prefix=$(host_prefix)/native --disable-ldconfig endef else define $(package)_stage_cmds - ./install.sh --destdir=$($(package)_staging_dir) --prefix=$(host_prefix)/native --disable-ldconfig + bash ./install.sh --destdir=$($(package)_staging_dir) --prefix=$(host_prefix)/native --disable-ldconfig endef endif diff --git a/depends/patches/proton/minimal-build.patch b/depends/patches/proton/minimal-build.patch deleted file mode 100644 index 90588929f..000000000 --- a/depends/patches/proton/minimal-build.patch +++ /dev/null @@ -1,288 +0,0 @@ -From 03f5fc0826115edbfca468261b70c0daf627f488 Mon Sep 17 00:00:00 2001 -From: Simon -Date: Thu, 27 Apr 2017 17:15:59 -0700 -Subject: [PATCH] Enable C++11, build static library and cpp bindings with minimal dependencies. - ---- - CMakeLists.txt | 13 +++++++------ - examples/cpp/CMakeLists.txt | 1 + - proton-c/CMakeLists.txt | 32 +++++++++++++++---------------- - proton-c/bindings/CMakeLists.txt | 6 +++--- - proton-c/bindings/cpp/CMakeLists.txt | 24 +++++++++++------------ - proton-c/bindings/cpp/docs/CMakeLists.txt | 2 +- - proton-c/docs/api/CMakeLists.txt | 2 +- - 7 files changed, 41 insertions(+), 39 deletions(-) - -diff --git a/CMakeLists.txt b/CMakeLists.txt -index b538ffd..4a5e787 100644 ---- a/CMakeLists.txt -+++ b/CMakeLists.txt -@@ -18,14 +18,15 @@ - # - cmake_minimum_required (VERSION 2.8.7) - -+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") - project (Proton C) - - # Enable C++ now for examples and bindings subdirectories, but make it optional. - enable_language(CXX OPTIONAL) - - # Enable testing --enable_testing() --include (CTest) -+#enable_testing() -+#include (CTest) - - # Pull in local cmake modules - set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/tools/cmake/Modules/") -@@ -141,7 +142,7 @@ set (BINDINGS_DIR ${LIB_INSTALL_DIR}/proton/bindings) - - set (SYSINSTALL_BINDINGS OFF CACHE BOOL "If SYSINSTALL_BINDINGS is OFF then proton bindings will be installed underneath ${BINDINGS_DIR} and each user will need to modify their interpreter configuration to load the appropriate binding. If SYSINSTALL_BINDINGS is ON, then each language interpreter will be queried for the appropriate directory and proton bindings will be installed and available system wide with no additional per user configuration.") - --set (BINDING_LANGS PERL PHP PYTHON RUBY) -+#set (BINDING_LANGS PERL PHP PYTHON RUBY) - - foreach (LANG ${BINDING_LANGS}) - set (SYSINSTALL_${LANG} OFF CACHE BOOL "Install ${LANG} bindings into interpreter specified location.") -@@ -156,10 +157,10 @@ set (PROTON_SHARE ${SHARE_INSTALL_DIR}/proton-${PN_VERSION}) - # End of variables used during install - - # Check for valgrind here so tests under proton-c/ and examples/ can use it. --find_program(VALGRIND_EXE valgrind DOC "Location of the valgrind program") -+#find_program(VALGRIND_EXE valgrind DOC "Location of the valgrind program") - mark_as_advanced (VALGRIND_EXE) - --option(ENABLE_VALGRIND "Use valgrind to detect run-time problems" ON) -+#option(ENABLE_VALGRIND "Use valgrind to detect run-time problems" ON) - if (ENABLE_VALGRIND) - if (NOT VALGRIND_EXE) - message(STATUS "Can't locate the valgrind command; no run-time error detection") -@@ -171,7 +172,7 @@ if (ENABLE_VALGRIND) - endif (ENABLE_VALGRIND) - - add_subdirectory(proton-c) --add_subdirectory(examples) -+#add_subdirectory(examples) - - install (FILES LICENSE README.md - DESTINATION ${PROTON_SHARE}) -diff --git a/examples/cpp/CMakeLists.txt b/examples/cpp/CMakeLists.txt -index 304d899..f4877b4 100644 ---- a/examples/cpp/CMakeLists.txt -+++ b/examples/cpp/CMakeLists.txt -@@ -17,6 +17,7 @@ - # under the License. - # - -+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") - find_package(ProtonCpp REQUIRED) - - include_directories(${ProtonCpp_INCLUDE_DIRS}) -diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt -index 8edb661..dc7b99c 100644 ---- a/proton-c/CMakeLists.txt -+++ b/proton-c/CMakeLists.txt -@@ -22,24 +22,24 @@ include(CheckSymbolExists) - - include(soversion.cmake) - --add_custom_target(docs) --add_custom_target(doc DEPENDS docs) -+#add_custom_target(docs) -+#add_custom_target(doc DEPENDS docs) - - # Set the default SSL/TLS implementation --find_package(OpenSSL) -+#find_package(OpenSSL) - find_package(PythonInterp REQUIRED) --find_package(SWIG) -+#find_package(SWIG) - # FindSwig.cmake "forgets" make its outputs advanced like a good citizen - mark_as_advanced(SWIG_DIR SWIG_EXECUTABLE SWIG_VERSION) - - # See if Cyrus SASL is available --find_library(CYRUS_SASL_LIBRARY sasl2) --find_path(CYRUS_SASL_INCLUDE_DIR sasl/sasl.h PATH_SUFFIXES include) --find_package_handle_standard_args(CyrusSASL DEFAULT_MSG CYRUS_SASL_LIBRARY CYRUS_SASL_INCLUDE_DIR) -+#find_library(CYRUS_SASL_LIBRARY sasl2) -+#find_path(CYRUS_SASL_INCLUDE_DIR sasl/sasl.h PATH_SUFFIXES include) -+#find_package_handle_standard_args(CyrusSASL DEFAULT_MSG CYRUS_SASL_LIBRARY CYRUS_SASL_INCLUDE_DIR) - mark_as_advanced(CYRUS_SASL_LIBRARY CYRUS_SASL_INCLUDE_DIR) - - # Find saslpasswd2 executable to generate test config --find_program(SASLPASSWD_EXE saslpasswd2 DOC "Program used to make SASL user db for testing") -+#find_program(SASLPASSWD_EXE saslpasswd2 DOC "Program used to make SASL user db for testing") - mark_as_advanced(SASLPASSWD_EXE) - - if(WIN32 AND NOT CYGWIN) -@@ -315,8 +315,8 @@ pn_absolute_install_dir(EXEC_PREFIX "." ${CMAKE_INSTALL_PREFIX}) - pn_absolute_install_dir(LIBDIR ${LIB_INSTALL_DIR} ${CMAKE_INSTALL_PREFIX}) - pn_absolute_install_dir(INCLUDEDIR ${INCLUDE_INSTALL_DIR} ${CMAKE_INSTALL_PREFIX}) - --add_subdirectory(docs/api) --add_subdirectory(../tests/tools/apps/c ../tests/tools/apps/c) -+#add_subdirectory(docs/api) -+#add_subdirectory(../tests/tools/apps/c ../tests/tools/apps/c) - - # for full source distribution: - set (qpid-proton-platform-all -@@ -507,7 +507,7 @@ if (BUILD_WITH_CXX) - endif (BUILD_WITH_CXX) - - add_library ( -- qpid-proton-core SHARED -+ qpid-proton-core STATIC - ${qpid-proton-core} - ${qpid-proton-layers} - ${qpid-proton-platform} -@@ -527,7 +527,7 @@ set_target_properties ( - ) - - add_library( -- qpid-proton SHARED -+ qpid-proton STATIC - # Proton Core - ${qpid-proton-core} - ${qpid-proton-layers} -@@ -629,7 +629,7 @@ install (FILES - - # c tests: - --add_subdirectory(src/tests) -+#add_subdirectory(src/tests) - - if (CMAKE_SYSTEM_NAME STREQUAL Windows) - # No change needed for windows already use correct separator -@@ -712,7 +712,7 @@ if (BUILD_PYTHON) - - endif (BUILD_PYTHON) - --find_program(RUBY_EXE "ruby") -+#find_program(RUBY_EXE "ruby") - if (RUBY_EXE AND BUILD_RUBY) - set (rb_root "${pn_test_root}/ruby") - set (rb_src "${CMAKE_CURRENT_SOURCE_DIR}/bindings/ruby") -@@ -751,8 +751,8 @@ if (RUBY_EXE AND BUILD_RUBY) - else (DEFAULT_RUBY_TESTING) - message(STATUS "Skipping Ruby tests: missing dependencies") - endif (DEFAULT_RUBY_TESTING) --else (RUBY_EXE) -- message (STATUS "Cannot find ruby, skipping ruby tests") -+#else (RUBY_EXE) -+# message (STATUS "Cannot find ruby, skipping ruby tests") - endif() - - mark_as_advanced (RUBY_EXE RSPEC_EXE) -diff --git a/proton-c/bindings/CMakeLists.txt b/proton-c/bindings/CMakeLists.txt -index 6b88384..d1a50a5 100644 ---- a/proton-c/bindings/CMakeLists.txt -+++ b/proton-c/bindings/CMakeLists.txt -@@ -19,14 +19,14 @@ - - # Add bindings that do not require swig here - the directory name must be the same as the binding name - # See below for swig bindings --set(BINDINGS javascript cpp go) -+set(BINDINGS cpp) - - # Prerequisites for javascript. - # - # It uses a C/C++ to JavaScript cross-compiler called emscripten (https://github.com/kripken/emscripten). Emscripten takes C/C++ - # and compiles it into a highly optimisable subset of JavaScript called asm.js (http://asmjs.org/) that can be - # aggressively optimised and run at near-native speed (usually between 1.5 to 10 times slower than native C/C++). --find_package(Emscripten) -+#find_package(Emscripten) - if (EMSCRIPTEN_FOUND) - set (DEFAULT_JAVASCRIPT ON) - endif (EMSCRIPTEN_FOUND) -@@ -37,7 +37,7 @@ if (CMAKE_CXX_COMPILER) - endif (CMAKE_CXX_COMPILER) - - # Prerequisites for Go --find_program(GO_EXE go) -+#find_program(GO_EXE go) - mark_as_advanced(GO_EXE) - if (GO_EXE) - if(WIN32) -diff --git a/proton-c/bindings/cpp/CMakeLists.txt b/proton-c/bindings/cpp/CMakeLists.txt -index 0cc4024..796fe29 100644 ---- a/proton-c/bindings/cpp/CMakeLists.txt -+++ b/proton-c/bindings/cpp/CMakeLists.txt -@@ -16,7 +16,7 @@ - # specific language governing permissions and limitations - # under the License. - # -- -+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") - include(cpp.cmake) # Compiler checks - - include_directories( -@@ -89,7 +89,7 @@ set_source_files_properties ( - COMPILE_FLAGS "${LTO}" - ) - --add_library(qpid-proton-cpp SHARED ${qpid-proton-cpp-source}) -+add_library(qpid-proton-cpp STATIC ${qpid-proton-cpp-source}) - - target_link_libraries (qpid-proton-cpp ${PLATFORM_LIBS} qpid-proton) - -@@ -120,8 +120,8 @@ endif (MSVC) - - install (DIRECTORY "include/proton" DESTINATION ${INCLUDE_INSTALL_DIR} FILES_MATCHING PATTERN "*.hpp") - --add_subdirectory(docs) --add_subdirectory(${CMAKE_SOURCE_DIR}/tests/tools/apps/cpp ${CMAKE_BINARY_DIR}/tests/tools/apps/cpp) -+#add_subdirectory(docs) -+#add_subdirectory(${CMAKE_SOURCE_DIR}/tests/tools/apps/cpp ${CMAKE_BINARY_DIR}/tests/tools/apps/cpp) - - # Pkg config file - configure_file( -@@ -171,12 +171,12 @@ macro(add_cpp_test test) - endif () - endmacro(add_cpp_test) - --add_cpp_test(codec_test) -+#add_cpp_test(codec_test) - #add_cpp_test(engine_test) --add_cpp_test(thread_safe_test) --add_cpp_test(interop_test ${CMAKE_SOURCE_DIR}/tests) --add_cpp_test(message_test) --add_cpp_test(scalar_test) --add_cpp_test(value_test) --add_cpp_test(container_test) --add_cpp_test(url_test) -+#add_cpp_test(thread_safe_test) -+#add_cpp_test(interop_test ${CMAKE_SOURCE_DIR}/tests) -+#add_cpp_test(message_test) -+#add_cpp_test(scalar_test) -+#add_cpp_test(value_test) -+#add_cpp_test(container_test) -+#add_cpp_test(url_test) -diff --git a/proton-c/bindings/cpp/docs/CMakeLists.txt b/proton-c/bindings/cpp/docs/CMakeLists.txt -index d512d15..8576867 100644 ---- a/proton-c/bindings/cpp/docs/CMakeLists.txt -+++ b/proton-c/bindings/cpp/docs/CMakeLists.txt -@@ -17,7 +17,7 @@ - # under the License. - # - --find_package(Doxygen) -+#find_package(Doxygen) - - if (DOXYGEN_FOUND) - configure_file ( -diff --git a/proton-c/docs/api/CMakeLists.txt b/proton-c/docs/api/CMakeLists.txt -index 7756e48..71ebb93 100644 ---- a/proton-c/docs/api/CMakeLists.txt -+++ b/proton-c/docs/api/CMakeLists.txt -@@ -17,7 +17,7 @@ - # under the License. - # - --find_package(Doxygen) -+#find_package(Doxygen) - if (DOXYGEN_FOUND) - configure_file (${CMAKE_CURRENT_SOURCE_DIR}/user.doxygen.in - ${CMAKE_CURRENT_BINARY_DIR}/user.doxygen) --- -2.7.4 - diff --git a/doc/amqp.md b/doc/amqp.md deleted file mode 100644 index 431fa55b1..000000000 --- a/doc/amqp.md +++ /dev/null @@ -1,123 +0,0 @@ -# Block and Transaction Broadcasting With AMQP 1.0 (Experimental Feature) - -[AMQP](https://www.amqp.org/) is an enterprise-level message queuing -protocol for the reliable passing of real-time data and business -transactions between applications. AMQP supports both broker and -brokerless messaging. AMQP 1.0 is an open standard and has been -ratified as ISO/IEC 19464. - -The Hush daemon can be configured to act as a trusted "border -router", implementing the Hush P2P protocol and relay, making -consensus decisions, maintaining the local blockchain database, -broadcasting locally generated transactions into the network, and -providing a queryable RPC interface to interact on a polled basis for -requesting blockchain related data. However, there exists only a -limited service to notify external software of events like the arrival -of new blocks or transactions. - -The AMQP facility implements a notification interface through a set -of specific notifiers. Currently there are notifiers that publish -blocks and transactions. This read-only facility requires only the -connection of a corresponding AMQP subscriber port in receiving -software. - -Currently the facility is not authenticated nor is there any two-way -protocol involvement. Therefore, subscribers should validate the -received data since it may be out of date, incomplete or even invalid. - -Because AMQP is message oriented, subscribers receive transactions -and blocks all-at-once and do not need to implement any sort of -buffering or reassembly. - -## Prerequisites - -The AMQP feature in Hush requires [Qpid Proton](https://qpid.apache.org/proton/) -version 0.17 or newer, which you will need to install if you are not -using the depends system. Typically, it is packaged by distributions as -something like *libqpid-proton*. The C++ wrapper for AMQP *is* required. - -In order to run the example Python client scripts in contrib/ one must -also install *python-qpid-proton*, though this is not necessary for -daemon operation. - -## Enabling - -By default, the AMQP feature is automatically compiled in if the -necessary prerequisites are found. To disable, use --disable-proton -during the *configure* step of building zcashd: - - $ ./configure --disable-proton (other options) - -To actually enable operation, one must set the appropriate options on -the commandline or in the configuration file. - -## Usage - -AMQP support is currently an experimental feature, so you must pass -the option: - - -experimentalfeatures - -Currently, the following notifications are supported: - - -amqppubhashtx=address - -amqppubhashblock=address - -amqppubrawblock=address - -amqppubrawtx=address - -The address must be a valid AMQP address, where the same address can be -used in more than notification. Note that SSL and SASL addresses are -not currently supported. - -Launch zcashd like this: - - $ zcashd -amqppubhashtx=amqp://127.0.0.1:5672 - -Or this: - - $ zcashd -amqppubhashtx=amqp://127.0.0.1:5672 \ - -amqppubrawtx=amqp://127.0.0.1:5672 \ - -amqppubrawblock=amqp://127.0.0.1:5672 \ - -amqppubhashblock=amqp://127.0.0.1:5672 \ - -debug=amqp - -The debug category `amqp` enables AMQP-related logging. - -Each notification has a topic and body, where the header corresponds -to the notification type. For instance, for the notification `-amqpubhashtx` -the topic is `hashtx` (no null terminator) and the body is the hexadecimal -transaction hash (32 bytes). This transaction hash and the block hash -found in `hashblock` are in RPC byte order. - -These options can also be provided in zcash.conf. - -Please see `contrib/amqp/amqp_sub.py` for a working example of an -AMQP server listening for messages. - -## Remarks - -From the perspective of zcashd, the local end of an AMQP link is write-only. - -No information is broadcast that wasn't already received from the public -P2P network. - -No authentication or authorization is done on peers that zcashd connects -to; it is assumed that the AMQP link is exposed only to trusted entities, -using other means such as firewalling. - -TLS support may be added once OpenSSL has been removed from the Hush -project and alternative TLS implementations have been evaluated. - -SASL support may be added in a future update for secure communication. - -Note that when the block chain tip changes, a reorganisation may occur -and just the tip will be notified. It is up to the subscriber to -retrieve the chain from the last known block to the new tip. - -At present, zcashd does not try to resend a notification if there was -a problem confirming receipt. Support for delivery guarantees such as -*at-least-once* and *exactly-once* will be added in in a future update. - -Currently, zcashd appends an up-counting sequence number to each notification -which allows listeners to detect lost notifications. - diff --git a/doc/man/hush-cli.1 b/doc/man/hush-cli.1 index a1be67812..5d87d8205 100644 --- a/doc/man/hush-cli.1 +++ b/doc/man/hush-cli.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.10. -.TH HUSH-CLI "1" "January 2020" "hush-cli v3.3.1" "User Commands" +.TH HUSH-CLI "1" "June 2020" "hush-cli v3.4.0" "User Commands" .SH NAME -hush-cli \- manual page for hush-cli v3.3.1 +hush-cli \- manual page for hush-cli v3.4.0 .SH DESCRIPTION -Komodo RPC client version v3.3.1\-d4ac8162f +Komodo RPC client version v3.4.0\-2fbcca416\-dirty .PP In order to ensure you are adequately protecting your privacy when using Hush, please see . @@ -71,7 +71,7 @@ Timeout in seconds during HTTP requests, or 0 for no timeout. (default: Read extra arguments from standard input, one per line until EOF/Ctrl\-D (recommended for sensitive information such as passphrases) .SH COPYRIGHT -Hush Daemon version v3.3.1-d4ac8162f +Hush Daemon version v3.4.0-2fbcca416-dirty In order to ensure you are adequately protecting your privacy when using Hush, please see . diff --git a/doc/man/hush-tx.1 b/doc/man/hush-tx.1 index b707fd059..a6d3be7ef 100644 --- a/doc/man/hush-tx.1 +++ b/doc/man/hush-tx.1 @@ -1,9 +1,9 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.10. -.TH HUSH-TX "1" "January 2020" "hush-tx v3.3.1" "User Commands" +.TH HUSH-TX "1" "June 2020" "hush-tx v3.4.0" "User Commands" .SH NAME -hush-tx \- manual page for hush-tx v3.3.1 +hush-tx \- manual page for hush-tx v3.4.0 .SH DESCRIPTION -Hush komodo\-tx utility version v3.3.1\-d4ac8162f +Hush komodo\-tx utility version v3.4.0\-2fbcca416\-dirty .SS "Usage:" .TP komodo\-tx [options] [commands] @@ -84,7 +84,7 @@ set=NAME:JSON\-STRING .IP Set register NAME to given JSON\-STRING .SH COPYRIGHT -Hush Daemon version v3.3.1-d4ac8162f +Hush Daemon version v3.4.0-2fbcca416-dirty In order to ensure you are adequately protecting your privacy when using Hush, please see . diff --git a/doc/man/hushd.1 b/doc/man/hushd.1 index 0c47538ea..6e57386b7 100644 --- a/doc/man/hushd.1 +++ b/doc/man/hushd.1 @@ -1,10 +1,10 @@ .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.10. -.TH HUSHD "1" "January 2020" "hushd v3.3.1" "User Commands" +.TH HUSHD "1" "June 2020" "hushd v3.4.0" "User Commands" .SH NAME -hushd \- manual page for hushd v3.3.1 +hushd \- manual page for hushd v3.4.0 .SH DESCRIPTION Found binary: ./komodod -Hush Daemon version v3.3.1\-d4ac8162f +Hush Daemon version v3.4.0\-2fbcca416\-dirty .PP In order to ensure you are adequately protecting your privacy when using Hush, please see . @@ -87,6 +87,11 @@ leave that many cores free, default: 0) .IP Specify pid file (default: komodod.pid) .HP +\fB\-txexpirynotify=\fR +.IP +Execute command when transaction expires (%s in cmd is replaced by +transaction id) +.HP \fB\-prune=\fR .IP Reduce storage requirements by pruning (deleting) old blocks. This mode @@ -265,6 +270,41 @@ Do not load the wallet and disable wallet RPC calls .IP Set key pool size to (default: 100) .HP +\fB\-consolidation\fR +.IP +Enable auto Sapling note consolidation (default: false) +.HP +\fB\-consolidatesaplingaddress=\fR +.IP +Specify Sapling Address to Consolidate. (default: all) +.HP +\fB\-consolidationtxfee\fR +.IP +Fee amount in Puposhis used send consolidation transactions. (default +10000) +.HP +\fB\-deletetx\fR +.IP +Enable Old Transaction Deletion +.HP +\fB\-deleteinterval\fR +.IP +Delete transaction every blocks during inital block download +(default: 1000) +.HP +\fB\-keeptxnum\fR +.IP +Keep the last transactions (default: 200) +.HP +\fB\-keeptxfornblocks\fR +.IP +Keep transactions for at least blocks (default: 10000) +.HP +\fB\-opretmintxfee=\fR +.IP +Minimum fee (in KMD/kB) to allow for OP_RETURN transactions (default: +400000) +.HP \fB\-paytxfee=\fR .IP Fee (in KMD/kB) to add to transactions you send (default: 0.00) @@ -358,7 +398,7 @@ Debugging/Testing options: Output debugging information (default: 0, supplying is optional). If is not supplied or if = 1, output all debugging information. can be: addrman, alert, bench, -coindb, db, estimatefee, http, libevent, lock, mempool, net, +coindb, db, deletetx, estimatefee, http, libevent, lock, mempool, net, partitioncheck, pow, proxy, prune, rand, reindex, rpc, selectcoins, tor, zmq, zrpc, zrpcunsafe (implies zrpc). .HP @@ -599,7 +639,7 @@ Starting supply, default is 0 .IP Enforce transaction\-rate limit, default 0 .SH COPYRIGHT -Hush Daemon version v3.3.1-d4ac8162f +Hush Daemon version v3.4.0-2fbcca416-dirty In order to ensure you are adequately protecting your privacy when using Hush, please see . diff --git a/doc/payment-disclosure.md b/doc/payment-disclosure.md deleted file mode 100644 index 02b4167da..000000000 --- a/doc/payment-disclosure.md +++ /dev/null @@ -1,107 +0,0 @@ -# Payment Disclosure (Experimental Feature) - -**Summary** - -Use RPC calls `z_getpaymentdisclosure` and `z_validatepaymentdisclosure` to reveal details of a shielded payment. - -**Who should read this document** - -Frequent users of shielded transactions, payment processors, exchanges, block explorer - -### Experimental Feature - -This is an experimental feature. Enable it by launching `zcashd` with flags: - - zcashd -experimentalfeatures -paymentdisclosure -debug=paymentdisclosure -txindex=1 - -These flags can also be set as options in `zcash.conf`. - -All nodes that generate or validate payment disclosures must run with `txindex=1` enabled. - -### Background - -Payment Disclosure is an implementation of the work-in-progress Payment Disclosure ZIP [1]. - -The ZIP describes a method of proving that a payment was sent to a shielded address. In the typical case, this means enabling a sender to present a proof that they transferred funds to a recipient's shielded address. - -[1] https://github.com/zcash/zips/pull/119 - -### Example Use Case - -Alice the customer sends 10 HUSH to Bob the merchant at the shielded address shown on their website. However, Bob is not sure if he received the funds. - -Alice's node is running with payment disclosure enabled, so Alice generates a payment disclosure and provides it to Bob, who verifies the payment was made. - -If Bob is a bad merchant, Alice can present the payment disclosure to a third party to validate that payment was indeed made. - -### Solution - -A payment disclosure can be generated for any output of a JoinSplit using the RPC call: - - z_getpaymentdisclosure txid js_index output_index (message) - -An optional message can be supplied. This could be used for a refund address or some other reference, as currently it is not common practice to (ahead of time) include a refund address in the memo field when making a payment. - -To validate a payment disclosure, the following RPC call can be used: - - z_validatepaymentdisclosure hexdata - -### Example - -Generate a payment disclosure for the first joinsplit, second output (index starts from zero): - - hush-cli z_getpaymentdisclosure 79189528d611e811a1c7bb0358dd31343033d14b4c1e998d7c4799c40f8b652b 0 1 "Hello" - -This returns a payment disclosure in the form of a hex string: - - 706462ff000a3722aafa8190cdf9710bfad6da2af6d3a74262c1fc96ad47df814b0cd5641c2b658b0fc499477c8d991e4c4bd133303431dd5803bbc7a111e811d6289518790000000000000000017e861adb829d8cb1cbcf6330b8c2e25fb0d08041a67a857815a136f0227f8a5342bce5b3c0d894e2983000eb594702d3c1580817d0374e15078528e56bb6f80c0548656c6c6f59a7085395c9e706d82afe3157c54ad4ae5bf144fcc774a8d9c921c58471402019c156ec5641e2173c4fb6467df5f28530dc4636fa71f4d0e48fc5c560fac500 - -To validate the payment disclosure: - - hush-cli z_validatepaymentdisclosure HEXDATA - -This returns data related to the payment and the payment disclosure: - - { - "txid": "79189528d611e811a1c7bb0358dd31343033d14b4c1e998d7c4799c40f8b652b", - "jsIndex": 0, - "outputIndex": 1, - "version": 0, - "onetimePrivKey": "1c64d50c4b81df47ad96fcc16242a7d3f62adad6fa0b71f9cd9081faaa22370a", - "message": "Hello", - "joinSplitPubKey": "d1c465d16166b602992479acfac18e87dc18065f6cefde6a002e70bc371b9faf", - "signatureVerified": true, - "paymentAddress": "ztaZJXy8iX8nrk2ytXKDBoTWqPkhQcj6E2ifARnD3wfkFwsxXs5SoX7NGmrjkzSiSKn8VtLHTJae48vX5NakvmDhtGNY5eb", - "memo": "f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "value": 12.49900000, - "commitmentMatch": true, - "valid": true - } - -The `signatureVerified` field confirms that the payment disclosure was generated and signed with the joinSplitPrivKey, which should only be known by the node generating and sending the transaction 7918...652b in question. - -### Where is the data stored? - -For all nodes, payment disclosure does not touch `wallet.dat` in any way. - -For nodes that only validate payment disclosures, no data is stored locally. - -For nodes that generate payment disclosures, a LevelDB database is created in the node's datadir. For most users, this would be in the folder: - - $HOME/.zcash/paymentdisclosure - -If you decide you don't want to use payment disclosure, it is safe to shut down your node and delete the database folder. - -### Security Properties - -Please consult the work-in-progress ZIP for details about the protocol, security properties and caveats. - -### Reminder - -Feedback is most welcome! - -This is an experimental feature so there are no guarantees that the protocol, database format, RPC interface etc. will remain the same in the future. - -### Notes - -Currently there is no user friendly way to help senders identify which joinsplit output index maps to a given payment they made. It is possible to construct this from `debug.log`. Ideas and feedback are most welcome on how to improve the user experience. diff --git a/doc/security-warnings.md b/doc/security-warnings.md index eba7141fc..66797444b 100644 --- a/doc/security-warnings.md +++ b/doc/security-warnings.md @@ -1,13 +1,20 @@ Security Warnings ==================== -Security Audit +Security Audits -------------- -Hush has been subjected to a formal third-party security review. For security +Hush has not been subjected to a formal third-party security review! But the +Zcash source code has. For security announcements, audit results and other general security information, see https://z.cash/support/security.html +Hush does our best to integrate fixes and recommendations from Zcash audits +to our own code, such as audits on ZecWallet that apply to SilentDragon. +Hush also reports many new bugs and issues to upstream Zcash and many other +Zcash Protocol coins. + + x86-64 Linux Only ----------------------- @@ -64,7 +71,7 @@ be able to: each note ciphertext on the blockchain. You should ensure no other users have the ability to execute code (even -unprivileged) on the hardware your `zcashd` process runs on until these +unprivileged) on the hardware your `hushd` process runs on until these vulnerabilities are fully analyzed and fixed. REST Interface @@ -77,9 +84,9 @@ security review. RPC Interface --------------- -Users should choose a strong RPC password. If no RPC username and password are set, zcashd will not start and will print an error message with a suggestion for a strong random password. If the client knows the RPC password, they have at least full access to the node. In addition, certain RPC commands can be misused to overwrite files and/or take over the account that is running zcashd. (In the future we may restrict these commands, but full node access – including the ability to spend from and export keys held by the wallet – would still be possible unless wallet methods are disabled.) +Users should choose a strong RPC password. If no RPC username and password are set, hush will not start and will print an error message with a suggestion for a strong random password. If the client knows the RPC password, they have at least full access to the node. In addition, certain RPC commands can be misused to overwrite files and/or take over the account that is running hushd. (In the future we may restrict these commands, but full node access – including the ability to spend from and export keys held by the wallet – would still be possible unless wallet methods are disabled.) -Users should also refrain from changing the default setting that only allows RPC connections from localhost. Allowing connections from remote hosts would enable a MITM to execute arbitrary RPC commands, which could lead to compromise of the account running zcashd and loss of funds. For multi-user services that use one or more zcashd instances on the backend, the parameters passed in by users should be controlled to prevent confused-deputy attacks which could spend from any keys held by that zcashd. +Users should also refrain from changing the default setting that only allows RPC connections from localhost. Allowing connections from remote hosts would enable a MITM to execute arbitrary RPC commands, which could lead to compromise of the account running hushd and loss of funds. For multi-user services that use one or more hushd instances on the backend, the parameters passed in by users should be controlled to prevent confused-deputy attacks which could spend from any keys held by that zcashd. Block Chain Reorganization: Major Differences ------------------------------------------------- @@ -100,11 +107,9 @@ Private spending keys for z addresses are never logged. Potentially-Missing Required Modifications ------------------------------------------ -In addition to potential mistakes in code we added to Bitcoin Core, and -potential mistakes in our modifications to Bitcoin Core, it is also possible -that there were potential changes we were supposed to make to Bitcoin Core but -didn't, either because we didn't even consider making those changes, or we ran -out of time. We have brainstormed and documented a variety of such possibilities -in [issue #826](https://github.com/zcash/zcash/issues/826), and believe that we -have changed or done everything that was necessary for the 1.0.0 launch. Users -may want to review this list themselves. +In addition to potential mistakes in code we added to Bitcoin Core, Zcash +and Komodo and +potential mistakes in our modifications to Bitcoin Core, Zcash and Komodo, it is also possible +that there were potential changes we were supposed to make to Bitcoin Core, Zcash and Komodo but +didn't, either because we didn't even consider making those changes or have not found out about +them. Submitting Github issues is highly appreciated! diff --git a/qa/hush/full-test-suite.sh b/qa/hush/full-test-suite.sh index 0a19b32c8..5c048ff9d 100755 --- a/qa/hush/full-test-suite.sh +++ b/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 diff --git a/qa/hush/full_test_suite.py b/qa/hush/full_test_suite.py index 0e8605cc3..deee55881 100755 --- a/qa/hush/full_test_suite.py +++ b/qa/hush/full_test_suite.py @@ -1,6 +1,8 @@ #!/usr/bin/env python2 +# Copyright (c) 2019-2020 Hush developers +# Released under the GPLv3 # -# Execute all of the automated tests related to Zcash. +# Execute all of the automated tests related to Hush # import argparse @@ -32,7 +34,7 @@ RE_FORTIFY_USED = re.compile('Binary compiled with FORTIFY_SOURCE support.*Yes') def test_rpath_runpath(filename): output = subprocess.check_output( - [repofile('qa/zcash/checksec.sh'), '--file', repofile(filename)] + [repofile('qa/hush/checksec.sh'), '--file', repofile(filename)] ) if RE_RPATH_RUNPATH.search(output): print('PASS: %s has no RPATH or RUNPATH.' % filename) @@ -44,7 +46,7 @@ def test_rpath_runpath(filename): def test_fortify_source(filename): proc = subprocess.Popen( - [repofile('qa/zcash/checksec.sh'), '--fortify-file', repofile(filename)], + [repofile('qa/hush/checksec.sh'), '--fortify-file', repofile(filename)], stdout=subprocess.PIPE, ) line1 = proc.stdout.readline() @@ -64,24 +66,24 @@ def check_security_hardening(): ret &= subprocess.call(['make', '-C', repofile('src'), 'check-security']) == 0 # The remaining checks are only for ELF binaries - # Assume that if zcashd is an ELF binary, they all are - with open(repofile('src/zcashd'), 'rb') as f: + # Assume that if hushd is an ELF binary, they all are + with open(repofile('src/hushd'), 'rb') as f: magic = f.read(4) if not magic.startswith(b'\x7fELF'): return ret - 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') # 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') return ret @@ -138,19 +140,17 @@ STAGES = [ 'no-dot-so', 'util-test', 'secp256k1', - 'libsnark', 'univalue', 'rpc', ] STAGE_COMMANDS = { 'btest': [repofile('src/test/test_bitcoin'), '-p'], - 'gtest': [repofile('src/zcash-gtest')], + 'gtest': [repofile('src/komodo-gtest')], 'sec-hard': check_security_hardening, 'no-dot-so': ensure_no_dot_so_in_depends, 'util-test': util_test, 'secp256k1': ['make', '-C', repofile('src/secp256k1'), 'check'], - 'libsnark': ['make', '-C', repofile('src'), 'libsnark-tests'], 'univalue': ['make', '-C', repofile('src/univalue'), 'check'], 'rpc': [repofile('qa/pull-tester/rpc-tests.sh')], } diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh index a23f2908d..4af883ea3 100755 --- a/qa/pull-tester/rpc-tests.sh +++ b/qa/pull-tester/rpc-tests.sh @@ -17,14 +17,12 @@ testScripts=( 'dpow.py' 'dpowconfs.py' 'ac_private.py' - 'paymentdisclosure.py' 'prioritisetransaction.py' 'wallet_treestate.py' 'wallet_anchorfork.py' 'wallet_changeindicator.py' 'wallet_import_export.py' 'wallet_protectcoinbase.py' - 'wallet_shieldcoinbase_sprout.py' 'wallet_shieldcoinbase_sapling.py' 'wallet_listreceived.py' 'wallet_mergetoaddress.py' @@ -65,14 +63,11 @@ testScripts=( 'decodescript.py' 'blockchain.py' 'disablewallet.py' - 'zcjoinsplit.py' - 'zcjoinsplitdoublespend.py' 'ivk_import_export.py' 'zkey_import_export.py' 'getblocktemplate.py' 'bip65-cltv-p2p.py' 'bipdersig-p2p.py' - 'p2p_nu_peer_management.py' 'rewind_index.py' 'p2p_txexpiry_dos.py' 'p2p_node_bloom.py' @@ -101,10 +96,6 @@ if [ "x$ENABLE_ZMQ" = "x1" ]; then testScripts+=('zmq_test.py') fi -if [ "x$ENABLE_PROTON" = "x1" ]; then - testScripts+=('proton_test.py') -fi - extArg="-extended" passOn=${@#$extArg} diff --git a/qa/rpc-tests/mempool_resurrect_test.py b/qa/rpc-tests/mempool_resurrect_test.py index 1cbbd2cd5..faa97d461 100755 --- a/qa/rpc-tests/mempool_resurrect_test.py +++ b/qa/rpc-tests/mempool_resurrect_test.py @@ -54,6 +54,7 @@ class MempoolCoinbaseTest(BitcoinTestFramework): spends2_id = [ self.nodes[0].sendrawtransaction(tx) for tx in spends2_raw ] blocks.extend(self.nodes[0].generate(1)) + self.sync_all() # mempool should be empty, all txns confirmed assert_equal(set(self.nodes[0].getrawmempool()), set()) @@ -74,6 +75,8 @@ class MempoolCoinbaseTest(BitcoinTestFramework): # Generate another block, they should all get mined self.nodes[0].generate(1) + self.sync_all() + # mempool should be empty, all txns confirmed assert_equal(set(self.nodes[0].getrawmempool()), set()) for txid in spends1_id+spends2_id: diff --git a/qa/rpc-tests/p2p_nu_peer_management.py b/qa/rpc-tests/p2p_nu_peer_management.py deleted file mode 100755 index 6cedf66bb..000000000 --- a/qa/rpc-tests/p2p_nu_peer_management.py +++ /dev/null @@ -1,192 +0,0 @@ -#!/usr/bin/env python2 -# Copyright (c) 2018 The Zcash developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -from test_framework.mininode import ( - NodeConn, - NodeConnCB, - NetworkThread, - msg_ping, - SPROUT_PROTO_VERSION, - OVERWINTER_PROTO_VERSION, - SAPLING_PROTO_VERSION, -) -from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import initialize_chain_clean, start_nodes, \ - p2p_port, assert_equal - -import time - -# -# In this test we connect Sprout, Overwinter, and Sapling mininodes to a Zcashd -# node which will activate Overwinter at block 10 and Sapling at block 15. -# -# We test: -# 1. the mininodes stay connected to Zcash with Sprout consensus rules -# 2. when Overwinter activates, the Sprout mininodes are dropped -# 3. new Overwinter and Sapling nodes can connect to Zcash -# 4. new Sprout nodes cannot connect to Zcash -# 5. when Sapling activates, the Overwinter mininodes are dropped -# 6. new Sapling nodes can connect to Zcash -# 7. new Sprout and Overwinter nodes cannot connect to Zcash -# -# This test *does not* verify that prior to each activation, the Zcashd -# node will prefer connections with NU-aware nodes, with an eviction process -# that prioritizes non-NU-aware connections. -# - - -class TestManager(NodeConnCB): - def __init__(self): - NodeConnCB.__init__(self) - self.create_callback_map() - - def on_close(self, conn): - pass - - def on_reject(self, conn, message): - conn.rejectMessage = message - - -class NUPeerManagementTest(BitcoinTestFramework): - - def setup_chain(self): - print "Initializing test directory "+self.options.tmpdir - initialize_chain_clean(self.options.tmpdir, 1) - - def setup_network(self): - self.nodes = start_nodes(1, self.options.tmpdir, extra_args=[[ - '-nuparams=5ba81b19:10', # Overwinter - '-nuparams=76b809bb:15', # Sapling - '-debug', - '-whitelist=127.0.0.1', - ]]) - - def run_test(self): - test = TestManager() - - # Launch Sprout, Overwinter, and Sapling mininodes - nodes = [] - for x in xrange(10): - nodes.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], - test, "regtest", SPROUT_PROTO_VERSION)) - nodes.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], - test, "regtest", OVERWINTER_PROTO_VERSION)) - nodes.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], - test, "regtest", SAPLING_PROTO_VERSION)) - - # Start up network handling in another thread - NetworkThread().start() - - # Sprout consensus rules apply at block height 9 - self.nodes[0].generate(9) - assert_equal(9, self.nodes[0].getblockcount()) - - # Verify mininodes are still connected to zcashd node - peerinfo = self.nodes[0].getpeerinfo() - versions = [x["version"] for x in peerinfo] - assert_equal(10, versions.count(SPROUT_PROTO_VERSION)) - assert_equal(10, versions.count(OVERWINTER_PROTO_VERSION)) - assert_equal(10, versions.count(SAPLING_PROTO_VERSION)) - - # Overwinter consensus rules activate at block height 10 - self.nodes[0].generate(1) - assert_equal(10, self.nodes[0].getblockcount()) - print('Overwinter active') - - # Mininodes send ping message to zcashd node. - pingCounter = 1 - for node in nodes: - node.send_message(msg_ping(pingCounter)) - pingCounter = pingCounter + 1 - - time.sleep(3) - - # Verify Sprout mininodes have been dropped, while Overwinter and - # Sapling mininodes are still connected. - peerinfo = self.nodes[0].getpeerinfo() - versions = [x["version"] for x in peerinfo] - assert_equal(0, versions.count(SPROUT_PROTO_VERSION)) - assert_equal(10, versions.count(OVERWINTER_PROTO_VERSION)) - assert_equal(10, versions.count(SAPLING_PROTO_VERSION)) - - # Extend the Overwinter chain with another block. - self.nodes[0].generate(1) - - # Connect a new Overwinter mininode to the zcashd node, which is accepted. - nodes.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", OVERWINTER_PROTO_VERSION)) - time.sleep(3) - assert_equal(21, len(self.nodes[0].getpeerinfo())) - - # Connect a new Sapling mininode to the zcashd node, which is accepted. - nodes.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", SAPLING_PROTO_VERSION)) - time.sleep(3) - assert_equal(22, len(self.nodes[0].getpeerinfo())) - - # Try to connect a new Sprout mininode to the zcashd node, which is rejected. - sprout = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", SPROUT_PROTO_VERSION) - nodes.append(sprout) - time.sleep(3) - assert("Version must be 170003 or greater" in str(sprout.rejectMessage)) - - # Verify that only Overwinter and Sapling mininodes are connected. - peerinfo = self.nodes[0].getpeerinfo() - versions = [x["version"] for x in peerinfo] - assert_equal(0, versions.count(SPROUT_PROTO_VERSION)) - assert_equal(11, versions.count(OVERWINTER_PROTO_VERSION)) - assert_equal(11, versions.count(SAPLING_PROTO_VERSION)) - - # Sapling consensus rules activate at block height 15 - self.nodes[0].generate(4) - assert_equal(15, self.nodes[0].getblockcount()) - print('Sapling active') - - # Mininodes send ping message to zcashd node. - pingCounter = 1 - for node in nodes: - node.send_message(msg_ping(pingCounter)) - pingCounter = pingCounter + 1 - - time.sleep(3) - - # Verify Sprout and Overwinter mininodes have been dropped, while - # Sapling mininodes are still connected. - peerinfo = self.nodes[0].getpeerinfo() - versions = [x["version"] for x in peerinfo] - assert_equal(0, versions.count(SPROUT_PROTO_VERSION)) - assert_equal(0, versions.count(OVERWINTER_PROTO_VERSION)) - assert_equal(11, versions.count(SAPLING_PROTO_VERSION)) - - # Extend the Sapling chain with another block. - self.nodes[0].generate(1) - - # Connect a new Sapling mininode to the zcashd node, which is accepted. - nodes.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", SAPLING_PROTO_VERSION)) - time.sleep(3) - assert_equal(12, len(self.nodes[0].getpeerinfo())) - - # Try to connect a new Sprout mininode to the zcashd node, which is rejected. - sprout = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", SPROUT_PROTO_VERSION) - nodes.append(sprout) - time.sleep(3) - assert("Version must be 170006 or greater" in str(sprout.rejectMessage)) - - # Try to connect a new Overwinter mininode to the zcashd node, which is rejected. - sprout = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test, "regtest", OVERWINTER_PROTO_VERSION) - nodes.append(sprout) - time.sleep(3) - assert("Version must be 170006 or greater" in str(sprout.rejectMessage)) - - # Verify that only Sapling mininodes are connected. - peerinfo = self.nodes[0].getpeerinfo() - versions = [x["version"] for x in peerinfo] - assert_equal(0, versions.count(SPROUT_PROTO_VERSION)) - assert_equal(0, versions.count(OVERWINTER_PROTO_VERSION)) - assert_equal(12, versions.count(SAPLING_PROTO_VERSION)) - - for node in nodes: - node.disconnect_node() - -if __name__ == '__main__': - NUPeerManagementTest().main() diff --git a/qa/rpc-tests/paymentdisclosure.py b/qa/rpc-tests/paymentdisclosure.py deleted file mode 100755 index 48d4712a9..000000000 --- a/qa/rpc-tests/paymentdisclosure.py +++ /dev/null @@ -1,215 +0,0 @@ -#!/usr/bin/env python2 -# Copyright (c) 2017 The Zcash developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -from test_framework.test_framework import BitcoinTestFramework -from test_framework.authproxy import JSONRPCException -from test_framework.util import assert_equal, initialize_chain_clean, \ - start_node, connect_nodes_bi, wait_and_assert_operationid_status - -from decimal import Decimal - -class PaymentDisclosureTest (BitcoinTestFramework): - - def setup_chain(self): - print("Initializing test directory "+self.options.tmpdir) - initialize_chain_clean(self.options.tmpdir, 4) - - def setup_network(self, split=False): - args = ['-debug=zrpcunsafe,paymentdisclosure', '-experimentalfeatures', '-paymentdisclosure', '-txindex=1'] - self.nodes = [] - self.nodes.append(start_node(0, self.options.tmpdir, args)) - self.nodes.append(start_node(1, self.options.tmpdir, args)) - # node 2 does not enable payment disclosure - args2 = ['-debug=zrpcunsafe', '-experimentalfeatures', '-txindex=1'] - self.nodes.append(start_node(2, self.options.tmpdir, args2)) - connect_nodes_bi(self.nodes,0,1) - connect_nodes_bi(self.nodes,1,2) - connect_nodes_bi(self.nodes,0,2) - self.is_network_split=False - self.sync_all() - - def run_test (self): - print "Mining blocks..." - - self.nodes[0].generate(4) - walletinfo = self.nodes[0].getwalletinfo() - assert_equal(walletinfo['immature_balance'], 40) - assert_equal(walletinfo['balance'], 0) - self.sync_all() - self.nodes[2].generate(3) - self.sync_all() - self.nodes[1].generate(101) - self.sync_all() - assert_equal(self.nodes[0].getbalance(), 40) - assert_equal(self.nodes[1].getbalance(), 10) - assert_equal(self.nodes[2].getbalance(), 30) - - mytaddr = self.nodes[0].getnewaddress() - myzaddr = self.nodes[0].z_getnewaddress() - - # Check that Node 2 has payment disclosure disabled. - try: - self.nodes[2].z_getpaymentdisclosure("invalidtxid", 0, 0) - assert(False) - except JSONRPCException as e: - errorString = e.error['message'] - assert("payment disclosure is disabled" in errorString) - - # Check that Node 0 returns an error for an unknown txid - try: - self.nodes[0].z_getpaymentdisclosure("invalidtxid", 0, 0) - assert(False) - except JSONRPCException as e: - errorString = e.error['message'] - assert("No information available about transaction" in errorString) - - # Shield coinbase utxos from node 0 of value 40, standard fee of 0.00010000 - recipients = [{"address":myzaddr, "amount":Decimal('40.0')-Decimal('0.0001')}] - myopid = self.nodes[0].z_sendmany(mytaddr, recipients) - txid = wait_and_assert_operationid_status(self.nodes[0], myopid) - - # Check the tx has joinsplits - assert( len(self.nodes[0].getrawtransaction("" + txid, 1)["vjoinsplit"]) > 0 ) - - # Sync mempools - self.sync_all() - - # Confirm that you can't create a payment disclosure for an unconfirmed tx - try: - self.nodes[0].z_getpaymentdisclosure(txid, 0, 0) - assert(False) - except JSONRPCException as e: - errorString = e.error['message'] - assert("Transaction has not been confirmed yet" in errorString) - - try: - self.nodes[1].z_getpaymentdisclosure(txid, 0, 0) - assert(False) - except JSONRPCException as e: - errorString = e.error['message'] - assert("Transaction has not been confirmed yet" in errorString) - - # Mine tx - self.nodes[0].generate(1) - self.sync_all() - - # Confirm that Node 1 cannot create a payment disclosure for a transaction which does not impact its wallet - try: - self.nodes[1].z_getpaymentdisclosure(txid, 0, 0) - assert(False) - except JSONRPCException as e: - errorString = e.error['message'] - assert("Transaction does not belong to the wallet" in errorString) - - # Check that an invalid joinsplit index is rejected - try: - self.nodes[0].z_getpaymentdisclosure(txid, 1, 0) - assert(False) - except JSONRPCException as e: - errorString = e.error['message'] - assert("Invalid js_index" in errorString) - - try: - self.nodes[0].z_getpaymentdisclosure(txid, -1, 0) - assert(False) - except JSONRPCException as e: - errorString = e.error['message'] - assert("Invalid js_index" in errorString) - - # Check that an invalid output index is rejected - try: - self.nodes[0].z_getpaymentdisclosure(txid, 0, 2) - assert(False) - except JSONRPCException as e: - errorString = e.error['message'] - assert("Invalid output_index" in errorString) - - try: - self.nodes[0].z_getpaymentdisclosure(txid, 0, -1) - assert(False) - except JSONRPCException as e: - errorString = e.error['message'] - assert("Invalid output_index" in errorString) - - # Ask Node 0 to create and validate a payment disclosure for output 0 - message = "Here is proof of my payment!" - pd = self.nodes[0].z_getpaymentdisclosure(txid, 0, 0, message) - result = self.nodes[0].z_validatepaymentdisclosure(pd) - assert(result["valid"]) - output_value_sum = Decimal(result["value"]) - - # Ask Node 1 to confirm the payment disclosure is valid - result = self.nodes[1].z_validatepaymentdisclosure(pd) - assert(result["valid"]) - assert_equal(result["message"], message) - assert_equal(result["value"], output_value_sum) - - # Confirm that payment disclosure begins with prefix zpd: - assert(pd.startswith("zpd:")) - - # Confirm that payment disclosure without prefix zpd: fails validation - try: - self.nodes[1].z_validatepaymentdisclosure(pd[4:]) - assert(False) - except JSONRPCException as e: - errorString = e.error['message'] - assert("payment disclosure prefix not found" in errorString) - - # Check that total value of output index 0 and index 1 should equal shielding amount of 40 less standard fee. - pd = self.nodes[0].z_getpaymentdisclosure(txid, 0, 1) - result = self.nodes[0].z_validatepaymentdisclosure(pd) - output_value_sum += Decimal(result["value"]) - assert_equal(output_value_sum, Decimal('39.99990000')) - - # Create a z->z transaction, sending shielded funds from node 0 to node 1 - node1zaddr = self.nodes[1].z_getnewaddress() - recipients = [{"address":node1zaddr, "amount":Decimal('1')}] - myopid = self.nodes[0].z_sendmany(myzaddr, recipients) - txid = wait_and_assert_operationid_status(self.nodes[0], myopid) - self.sync_all() - self.nodes[0].generate(1) - self.sync_all() - - # Confirm that Node 0 can create a valid payment disclosure - pd = self.nodes[0].z_getpaymentdisclosure(txid, 0, 0, "a message of your choice") - result = self.nodes[0].z_validatepaymentdisclosure(pd) - assert(result["valid"]) - - # Confirm that Node 1, even as recipient of shielded funds, cannot create a payment disclosure - # as the transaction was created by Node 0 and Node 1's payment disclosure database does not - # contain the necessary data to do so, where the data would only have been available on Node 0 - # when executing z_shieldcoinbase. - try: - self.nodes[1].z_getpaymentdisclosure(txid, 0, 0) - assert(False) - except JSONRPCException as e: - errorString = e.error['message'] - assert("Could not find payment disclosure info for the given joinsplit output" in errorString) - - # Payment disclosures cannot be created for transparent transactions. - txid = self.nodes[2].sendtoaddress(mytaddr, 1.0) - self.sync_all() - - # No matter the type of transaction, if it has not been confirmed, it is ignored. - try: - self.nodes[0].z_getpaymentdisclosure(txid, 0, 0) - assert(False) - except JSONRPCException as e: - errorString = e.error['message'] - assert("Transaction has not been confirmed yet" in errorString) - - self.nodes[0].generate(1) - self.sync_all() - - # Confirm that a payment disclosure can only be generated for a shielded transaction. - try: - self.nodes[0].z_getpaymentdisclosure(txid, 0, 0) - assert(False) - except JSONRPCException as e: - errorString = e.error['message'] - assert("Transaction is not a shielded transaction" in errorString) - -if __name__ == '__main__': - PaymentDisclosureTest().main() diff --git a/qa/rpc-tests/proton_test.py b/qa/rpc-tests/proton_test.py deleted file mode 100755 index d9fb27bd3..000000000 --- a/qa/rpc-tests/proton_test.py +++ /dev/null @@ -1,117 +0,0 @@ -#!/usr/bin/env python2 -# Copyright (c) 2017 The Zcash developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -# -# Test Proton interface (provides AMQP 1.0 messaging support). -# -# Requirements: -# Python library for Qpid Proton: -# https://pypi.python.org/pypi/python-qpid-proton -# To install: -# pip install python-qpid-proton -# - -from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, bytes_to_hex_str, \ - start_nodes - -from proton.handlers import MessagingHandler -from proton.reactor import Container - -import threading - - -class Server(MessagingHandler): - - def __init__(self, url, limit): - super(Server, self).__init__() - self.url = url - self.counter = limit - self.blockhashes = [] - self.txids = [] - self.blockseq = -1 - self.txidseq = -1 - - def on_start(self, event): - print "Proton listening on:", self.url - self.container = event.container - self.acceptor = event.container.listen(self.url) - - def on_message(self, event): - m = event.message - hash = bytes_to_hex_str(m.body) - sequence = m.properties['x-opt-sequence-number'] - if m.subject == "hashtx": - self.txids.append(hash) - - # Test that sequence id is incrementing - assert(sequence == 1 + self.txidseq) - self.txidseq = sequence - elif m.subject == "hashblock": - self.blockhashes.append(hash) - - # Test that sequence id is incrementing - assert(sequence == 1 + self.blockseq) - self.blockseq = sequence - - self.counter = self.counter - 1 - if self.counter == 0: - self.container.stop() - - -class ProtonTest (BitcoinTestFramework): - - port = 25672 - numblocks = 10 # must be even, as two nodes generate equal number - assert(numblocks % 2 == 0) - - def setup_nodes(self): - - # Launch proton server in background thread - # It terminates after receiving numblocks * 2 messages (one for coinbase, one for block) - self.server = Server("127.0.0.1:%i" % self.port, self.numblocks * 2) - self.container = Container(self.server) - self.t1 = threading.Thread(target=self.container.run) - self.t1.start() - - return start_nodes(4, self.options.tmpdir, extra_args=[ - ['-experimentalfeatures', '-debug=amqp', '-amqppubhashtx=amqp://127.0.0.1:'+str(self.port), - '-amqppubhashblock=amqp://127.0.0.1:'+str(self.port)], - [], - [], - [] - ]) - - def run_test(self): - self.sync_all() - baseheight = self.nodes[0].getblockcount() # 200 blocks already mined - - # generate some blocks - self.nodes[0].generate(self.numblocks/2) - self.sync_all() - self.nodes[1].generate(self.numblocks/2) - self.sync_all() - - # wait for server to finish - self.t1.join() - - # sequence numbers have already been checked in the server's message handler - - # sanity check that we have the right number of block hashes and coinbase txids - assert_equal(len(self.server.blockhashes), self.numblocks) - assert_equal(len(self.server.txids), self.numblocks) - - # verify that each block has the correct coinbase txid - for i in xrange(0, self.numblocks): - height = baseheight + i + 1 - blockhash = self.nodes[0].getblockhash(height) - assert_equal(blockhash, self.server.blockhashes[i]) - resp = self.nodes[0].getblock(blockhash) - coinbase = resp["tx"][0] - assert_equal(coinbase, self.server.txids[i]) - - -if __name__ == '__main__': - ProtonTest().main() diff --git a/qa/rpc-tests/regtest_signrawtransaction.py b/qa/rpc-tests/regtest_signrawtransaction.py index 2e0273677..78ec1fbc8 100755 --- a/qa/rpc-tests/regtest_signrawtransaction.py +++ b/qa/rpc-tests/regtest_signrawtransaction.py @@ -1,4 +1,5 @@ #!/usr/bin/env python2 +# Copyright (c) 2019-2020 The Hush developers # Copyright (c) 2018 The Zcash developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -18,7 +19,7 @@ class RegtestSignrawtransactionTest (BitcoinTestFramework): self.nodes[0].generate(1) self.sync_all() taddr = self.nodes[1].getnewaddress() - zaddr1 = self.nodes[1].z_getnewaddress('sprout') + zaddr1 = self.nodes[1].z_getnewaddress('sapling') self.nodes[0].sendtoaddress(taddr, 2.0) self.nodes[0].generate(1) diff --git a/qa/rpc-tests/test_framework/util.py b/qa/rpc-tests/test_framework/util.py index b41c4b451..78c66089a 100644 --- a/qa/rpc-tests/test_framework/util.py +++ b/qa/rpc-tests/test_framework/util.py @@ -60,6 +60,14 @@ def sync_blocks(rpc_connections, wait=1): break time.sleep(wait) + # Now that the block counts are in sync, wait for the internal + # notifications to finish + while True: + notified = [ x.getblockchaininfo()['fullyNotified'] for x in rpc_connections ] + if notified == [ True ] * len(notified): + break + time.sleep(wait) + def sync_mempools(rpc_connections, wait=1): """ Wait until everybody has the same transactions in their memory diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py index 5d221a28c..0268dd292 100755 --- a/qa/rpc-tests/wallet.py +++ b/qa/rpc-tests/wallet.py @@ -31,6 +31,7 @@ class WalletTest (BitcoinTestFramework): print "Mining blocks..." self.nodes[0].generate(4) + self.sync_all() walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 40) diff --git a/qa/rpc-tests/wallet_1941.py b/qa/rpc-tests/wallet_1941.py index d70b514fc..6f90f33bd 100755 --- a/qa/rpc-tests/wallet_1941.py +++ b/qa/rpc-tests/wallet_1941.py @@ -45,6 +45,7 @@ class Wallet1941RegressionTest (BitcoinTestFramework): self.nodes[0].setmocktime(starttime) self.nodes[0].generate(101) + self.sync_all() mytaddr = self.nodes[0].getnewaddress() # where coins were mined myzaddr = self.nodes[0].z_getnewaddress() @@ -63,6 +64,7 @@ class Wallet1941RegressionTest (BitcoinTestFramework): self.nodes[0].generate(1) self.nodes[0].setmocktime(starttime + 9000) self.nodes[0].generate(1) + self.sync_all() # Confirm the balance on node 0. resp = self.nodes[0].z_getbalance(myzaddr) diff --git a/qa/rpc-tests/wallet_anchorfork.py b/qa/rpc-tests/wallet_anchorfork.py index 0e2d19385..1cb16e152 100755 --- a/qa/rpc-tests/wallet_anchorfork.py +++ b/qa/rpc-tests/wallet_anchorfork.py @@ -27,6 +27,7 @@ class WalletAnchorForkTest (BitcoinTestFramework): def run_test (self): print "Mining blocks..." self.nodes[0].generate(4) + self.sync_all() walletinfo = self.nodes[0].getwalletinfo() assert_equal(walletinfo['immature_balance'], 40) diff --git a/qa/rpc-tests/wallet_listnotes.py b/qa/rpc-tests/wallet_listnotes.py index 5cd89c661..90fbcced1 100755 --- a/qa/rpc-tests/wallet_listnotes.py +++ b/qa/rpc-tests/wallet_listnotes.py @@ -1,4 +1,5 @@ #!/usr/bin/env python2 +# Copyright (c) 2019-2020 The Hush developers # Copyright (c) 2018 The Zcash developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -20,89 +21,9 @@ class WalletListNotes(BitcoinTestFramework): def run_test(self): # Current height = 200 -> Sprout assert_equal(200, self.nodes[0].getblockcount()) - sproutzaddr = self.nodes[0].z_getnewaddress('sprout') # test that we can create a sapling zaddr before sapling activates saplingzaddr = self.nodes[0].z_getnewaddress('sapling') - - # we've got lots of coinbase (taddr) but no shielded funds yet - assert_equal(0, Decimal(self.nodes[0].z_gettotalbalance()['private'])) - - # Set current height to 201 -> Sprout - self.nodes[0].generate(1) - self.sync_all() - assert_equal(201, self.nodes[0].getblockcount()) - - mining_addr = self.nodes[0].listunspent()[0]['address'] - - # Shield coinbase funds (must be a multiple of 10, no change allowed pre-sapling) - receive_amount_10 = Decimal('10.0') - Decimal('0.0001') - recipients = [{"address":sproutzaddr, "amount":receive_amount_10}] - myopid = self.nodes[0].z_sendmany(mining_addr, recipients) - txid_1 = wait_and_assert_operationid_status(self.nodes[0], myopid) - self.sync_all() - - # No funds (with (default) one or more confirmations) in sproutzaddr yet - assert_equal(0, len(self.nodes[0].z_listunspent())) - assert_equal(0, len(self.nodes[0].z_listunspent(1))) - - # no private balance because no confirmations yet - assert_equal(0, Decimal(self.nodes[0].z_gettotalbalance()['private'])) - - # list private unspent, this time allowing 0 confirmations - unspent_cb = self.nodes[0].z_listunspent(0) - assert_equal(1, len(unspent_cb)) - assert_equal(False, unspent_cb[0]['change']) - assert_equal(txid_1, unspent_cb[0]['txid']) - assert_equal(True, unspent_cb[0]['spendable']) - assert_equal(sproutzaddr, unspent_cb[0]['address']) - assert_equal(receive_amount_10, unspent_cb[0]['amount']) - - # list unspent, filtering by address, should produce same result - unspent_cb_filter = self.nodes[0].z_listunspent(0, 9999, False, [sproutzaddr]) - assert_equal(unspent_cb, unspent_cb_filter) - - # Generate a block to confirm shield coinbase tx - self.nodes[0].generate(1) - self.sync_all() - - # Current height = 202 -> Overwinter. Default address type remains Sprout - assert_equal(202, self.nodes[0].getblockcount()) - - # Send 1.0 (actually 0.9999) from sproutzaddr to a new zaddr - sproutzaddr2 = self.nodes[0].z_getnewaddress() - receive_amount_1 = Decimal('1.0') - Decimal('0.0001') - change_amount_9 = receive_amount_10 - Decimal('1.0') - assert_equal('sprout', self.nodes[0].z_validateaddress(sproutzaddr2)['type']) - recipients = [{"address": sproutzaddr2, "amount":receive_amount_1}] - myopid = self.nodes[0].z_sendmany(sproutzaddr, recipients) - txid_2 = wait_and_assert_operationid_status(self.nodes[0], myopid) - self.sync_all() - - # list unspent, allowing 0conf txs - unspent_tx = self.nodes[0].z_listunspent(0) - assert_equal(len(unspent_tx), 2) - # sort low-to-high by amount (order of returned entries is not guaranteed) - unspent_tx = sorted(unspent_tx, key=lambda k: k['amount']) - assert_equal(False, unspent_tx[0]['change']) - assert_equal(txid_2, unspent_tx[0]['txid']) - assert_equal(True, unspent_tx[0]['spendable']) - assert_equal(sproutzaddr2, unspent_tx[0]['address']) - assert_equal(receive_amount_1, unspent_tx[0]['amount']) - - assert_equal(True, unspent_tx[1]['change']) - assert_equal(txid_2, unspent_tx[1]['txid']) - assert_equal(True, unspent_tx[1]['spendable']) - assert_equal(sproutzaddr, unspent_tx[1]['address']) - assert_equal(change_amount_9, unspent_tx[1]['amount']) - - unspent_tx_filter = self.nodes[0].z_listunspent(0, 9999, False, [sproutzaddr2]) - assert_equal(1, len(unspent_tx_filter)) - assert_equal(unspent_tx[0], unspent_tx_filter[0]) - - unspent_tx_filter = self.nodes[0].z_listunspent(0, 9999, False, [sproutzaddr]) - assert_equal(1, len(unspent_tx_filter)) - assert_equal(unspent_tx[1], unspent_tx_filter[0]) # Set current height to 204 -> Sapling self.nodes[0].generate(2) diff --git a/qa/rpc-tests/wallet_shieldcoinbase.py b/qa/rpc-tests/wallet_shieldcoinbase.py index d8366c81d..f325b29ca 100755 --- a/qa/rpc-tests/wallet_shieldcoinbase.py +++ b/qa/rpc-tests/wallet_shieldcoinbase.py @@ -44,6 +44,7 @@ class WalletShieldCoinbaseTest (BitcoinTestFramework): print "Mining blocks..." self.nodes[0].generate(1) + self.sync_all() do_not_shield_taddr = self.nodes[0].getnewaddress() self.nodes[0].generate(4) diff --git a/qa/rpc-tests/zcjoinsplit.py b/qa/rpc-tests/zcjoinsplit.py deleted file mode 100755 index 7e5aba6e3..000000000 --- a/qa/rpc-tests/zcjoinsplit.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python2 - -# -# Test joinsplit semantics -# - -from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, start_node, \ - gather_inputs - - -class JoinSplitTest(BitcoinTestFramework): - def setup_network(self): - self.nodes = [] - self.is_network_split = False - self.nodes.append(start_node(0, self.options.tmpdir)) - - def run_test(self): - zckeypair = self.nodes[0].zcrawkeygen() - zcsecretkey = zckeypair["zcsecretkey"] - zcaddress = zckeypair["zcaddress"] - - (total_in, inputs) = gather_inputs(self.nodes[0], 40) - protect_tx = self.nodes[0].createrawtransaction(inputs, {}) - joinsplit_result = self.nodes[0].zcrawjoinsplit(protect_tx, {}, {zcaddress:39.99}, 39.99, 0) - - receive_result = self.nodes[0].zcrawreceive(zcsecretkey, joinsplit_result["encryptednote1"]) - assert_equal(receive_result["exists"], False) - - protect_tx = self.nodes[0].signrawtransaction(joinsplit_result["rawtxn"]) - self.nodes[0].sendrawtransaction(protect_tx["hex"]) - self.nodes[0].generate(1) - - receive_result = self.nodes[0].zcrawreceive(zcsecretkey, joinsplit_result["encryptednote1"]) - assert_equal(receive_result["exists"], True) - - # The pure joinsplit we create should be mined in the next block - # despite other transactions being in the mempool. - addrtest = self.nodes[0].getnewaddress() - for xx in range(0,10): - self.nodes[0].generate(1) - for x in range(0,50): - self.nodes[0].sendtoaddress(addrtest, 0.01); - - joinsplit_tx = self.nodes[0].createrawtransaction([], {}) - joinsplit_result = self.nodes[0].zcrawjoinsplit(joinsplit_tx, {receive_result["note"] : zcsecretkey}, {zcaddress: 39.98}, 0, 0.01) - - self.nodes[0].sendrawtransaction(joinsplit_result["rawtxn"]) - self.nodes[0].generate(1) - - print "Done!" - receive_result = self.nodes[0].zcrawreceive(zcsecretkey, joinsplit_result["encryptednote1"]) - assert_equal(receive_result["exists"], True) - -if __name__ == '__main__': - JoinSplitTest().main() diff --git a/qa/rpc-tests/zcjoinsplitdoublespend.py b/qa/rpc-tests/zcjoinsplitdoublespend.py deleted file mode 100755 index b56e7475a..000000000 --- a/qa/rpc-tests/zcjoinsplitdoublespend.py +++ /dev/null @@ -1,182 +0,0 @@ -#!/usr/bin/env python2 - -# -# Tests a joinsplit double-spend and a subsequent reorg. -# - -from test_framework.test_framework import BitcoinTestFramework -from test_framework.authproxy import JSONRPCException -from test_framework.util import assert_equal, connect_nodes, \ - gather_inputs, sync_blocks - -import time - -class JoinSplitTest(BitcoinTestFramework): - def setup_network(self): - # Start with split network: - return super(JoinSplitTest, self).setup_network(True) - - def txid_in_mempool(self, node, txid): - exception_triggered = False - - try: - node.getrawtransaction(txid) - except JSONRPCException: - exception_triggered = True - - return not exception_triggered - - def cannot_joinsplit(self, node, txn): - exception_triggered = False - - try: - node.sendrawtransaction(txn) - except JSONRPCException: - exception_triggered = True - - return exception_triggered - - def expect_cannot_joinsplit(self, node, txn): - assert_equal(self.cannot_joinsplit(node, txn), True) - - def run_test(self): - # All nodes should start with 250 HUSH: - starting_balance = 250 - for i in range(4): - assert_equal(self.nodes[i].getbalance(), starting_balance) - self.nodes[i].getnewaddress("") # bug workaround, coins generated assigned to first getnewaddress! - - # Generate zcaddress keypairs - zckeypair = self.nodes[0].zcrawkeygen() - zcsecretkey = zckeypair["zcsecretkey"] - zcaddress = zckeypair["zcaddress"] - - pool = [0, 1, 2, 3] - for i in range(4): - (total_in, inputs) = gather_inputs(self.nodes[i], 40) - pool[i] = self.nodes[i].createrawtransaction(inputs, {}) - pool[i] = self.nodes[i].zcrawjoinsplit(pool[i], {}, {zcaddress:39.99}, 39.99, 0) - signed = self.nodes[i].signrawtransaction(pool[i]["rawtxn"]) - - # send the tx to both halves of the network - self.nodes[0].sendrawtransaction(signed["hex"]) - self.nodes[0].generate(1) - self.nodes[2].sendrawtransaction(signed["hex"]) - self.nodes[2].generate(1) - pool[i] = pool[i]["encryptednote1"] - - sync_blocks(self.nodes[0:2]) - sync_blocks(self.nodes[2:4]) - - # Confirm that the protects have taken place - for i in range(4): - enc_note = pool[i] - receive_result = self.nodes[0].zcrawreceive(zcsecretkey, enc_note) - assert_equal(receive_result["exists"], True) - pool[i] = receive_result["note"] - - # Extra confirmations - receive_result = self.nodes[1].zcrawreceive(zcsecretkey, enc_note) - assert_equal(receive_result["exists"], True) - - receive_result = self.nodes[2].zcrawreceive(zcsecretkey, enc_note) - assert_equal(receive_result["exists"], True) - - receive_result = self.nodes[3].zcrawreceive(zcsecretkey, enc_note) - assert_equal(receive_result["exists"], True) - - blank_tx = self.nodes[0].createrawtransaction([], {}) - # Create joinsplit {A, B}->{*} - joinsplit_AB = self.nodes[0].zcrawjoinsplit(blank_tx, - {pool[0] : zcsecretkey, pool[1] : zcsecretkey}, - {zcaddress:(39.99*2)-0.01}, - 0, 0.01) - - # Create joinsplit {B, C}->{*} - joinsplit_BC = self.nodes[0].zcrawjoinsplit(blank_tx, - {pool[1] : zcsecretkey, pool[2] : zcsecretkey}, - {zcaddress:(39.99*2)-0.01}, - 0, 0.01) - - # Create joinsplit {C, D}->{*} - joinsplit_CD = self.nodes[0].zcrawjoinsplit(blank_tx, - {pool[2] : zcsecretkey, pool[3] : zcsecretkey}, - {zcaddress:(39.99*2)-0.01}, - 0, 0.01) - - # Create joinsplit {A, D}->{*} - joinsplit_AD = self.nodes[0].zcrawjoinsplit(blank_tx, - {pool[0] : zcsecretkey, pool[3] : zcsecretkey}, - {zcaddress:(39.99*2)-0.01}, - 0, 0.01) - - # (a) Node 0 will spend joinsplit AB, then attempt to - # double-spend it with BC. It should fail before and - # after Node 0 mines blocks. - # - # (b) Then, Node 2 will spend BC, and mine 5 blocks. - # Node 1 connects, and AB will be reorg'd from the chain. - # Any attempts to spend AB or CD should fail for - # both nodes. - # - # (c) Then, Node 0 will spend AD, which should work - # because the previous spend for A (AB) is considered - # invalid due to the reorg. - - # (a) - - AB_txid = self.nodes[0].sendrawtransaction(joinsplit_AB["rawtxn"]) - - self.expect_cannot_joinsplit(self.nodes[0], joinsplit_BC["rawtxn"]) - - # Wait until node[1] receives AB before we attempt to double-spend - # with BC. - print "Waiting for AB_txid...\n" - while True: - if self.txid_in_mempool(self.nodes[1], AB_txid): - break - time.sleep(0.2) - print "Done!\n" - - self.expect_cannot_joinsplit(self.nodes[1], joinsplit_BC["rawtxn"]) - - # Generate a block - self.nodes[0].generate(1) - sync_blocks(self.nodes[0:2]) - - self.expect_cannot_joinsplit(self.nodes[0], joinsplit_BC["rawtxn"]) - self.expect_cannot_joinsplit(self.nodes[1], joinsplit_BC["rawtxn"]) - - # (b) - self.nodes[2].sendrawtransaction(joinsplit_BC["rawtxn"]) - self.nodes[2].generate(5) - - # Connect the two nodes - - connect_nodes(self.nodes[1], 2) - sync_blocks(self.nodes) - - # AB and CD should all be impossible to spend for each node. - self.expect_cannot_joinsplit(self.nodes[0], joinsplit_AB["rawtxn"]) - self.expect_cannot_joinsplit(self.nodes[0], joinsplit_CD["rawtxn"]) - - self.expect_cannot_joinsplit(self.nodes[1], joinsplit_AB["rawtxn"]) - self.expect_cannot_joinsplit(self.nodes[1], joinsplit_CD["rawtxn"]) - - self.expect_cannot_joinsplit(self.nodes[2], joinsplit_AB["rawtxn"]) - self.expect_cannot_joinsplit(self.nodes[2], joinsplit_CD["rawtxn"]) - - self.expect_cannot_joinsplit(self.nodes[3], joinsplit_AB["rawtxn"]) - self.expect_cannot_joinsplit(self.nodes[3], joinsplit_CD["rawtxn"]) - - # (c) - # AD should be possible to send due to the reorg that - # tossed out AB. - - self.nodes[0].sendrawtransaction(joinsplit_AD["rawtxn"]) - self.nodes[0].generate(1) - - sync_blocks(self.nodes) - -if __name__ == '__main__': - JoinSplitTest().main() diff --git a/qa/rpc-tests/zmq_test.py b/qa/rpc-tests/zmq_test.py index d70e73114..dcb899861 100755 --- a/qa/rpc-tests/zmq_test.py +++ b/qa/rpc-tests/zmq_test.py @@ -37,15 +37,6 @@ class ZMQTest(BitcoinTestFramework): self.sync_all() print "listen..." - msg = self.zmqSubSocket.recv_multipart() - topic = msg[0] - assert_equal(topic, b"hashtx") - body = msg[1] - nseq = msg[2] - [nseq] # hush pyflakes - msgSequence = struct.unpack('nTime || pinfo->nTime < addr.nTime - nUpdateInterval - nTimePenalty)) pinfo->nTime = std::max((int64_t)0, addr.nTime - nTimePenalty); diff --git a/src/addrman.h b/src/addrman.h index 0390b4e9b..b23ab5aa3 100644 --- a/src/addrman.h +++ b/src/addrman.h @@ -1,6 +1,7 @@ // Copyright (c) 2012 Pieter Wuille +// 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. +// file COPYING or https://www.opensource.org/licenses/mit-license.php /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * @@ -112,10 +113,10 @@ public: int GetBucketPosition(const uint256 &nKey, bool fNew, int nBucket) const; //! Determine whether the statistics about this entry are bad enough so that it can just be deleted - bool IsTerrible(int64_t nNow = GetAdjustedTime()) const; + bool IsTerrible(int64_t nNow = GetTime()) const; //! Calculate the relative chance this entry should be given when selecting nodes to connect to - double GetChance(int64_t nNow = GetAdjustedTime()) const; + double GetChance(int64_t nNow = GetTime()) const; }; @@ -530,7 +531,7 @@ public: } //! Mark an entry as accessible. - void Good(const CService &addr, int64_t nTime = GetAdjustedTime()) + void Good(const CService &addr, int64_t nTime = GetTime()) { { LOCK(cs); @@ -541,7 +542,7 @@ public: } //! Mark an entry as connection attempted to. - void Attempt(const CService &addr, int64_t nTime = GetAdjustedTime()) + void Attempt(const CService &addr, int64_t nTime = GetTime()) { { LOCK(cs); @@ -580,7 +581,7 @@ public: } //! Mark an entry as currently-connected-to. - void Connected(const CService &addr, int64_t nTime = GetAdjustedTime()) + void Connected(const CService &addr, int64_t nTime = GetTime()) { { LOCK(cs); diff --git a/src/alert.cpp b/src/alert.cpp index 99f6472e9..db70cd620 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -1,7 +1,8 @@ // Copyright (c) 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. +// file COPYING or https://www.opensource.org/licenses/mit-license.php /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * @@ -117,7 +118,7 @@ uint256 CAlert::GetHash() const bool CAlert::IsInEffect() const { - return (GetAdjustedTime() < nExpiration); + return (GetTime() < nExpiration); } bool CAlert::Cancels(const CAlert& alert) const @@ -152,7 +153,7 @@ bool CAlert::RelayTo(CNode* pnode) const { if (AppliesTo(pnode->nVersion, pnode->strSubVer) || AppliesToMe() || - GetAdjustedTime() < nRelayUntil) + GetTime() < nRelayUntil) { pnode->PushMessage("alert", *this); return true; diff --git a/src/amount.h b/src/amount.h index be1c39a6e..c5f49593c 100644 --- a/src/amount.h +++ b/src/amount.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. diff --git a/src/amqp/amqpabstractnotifier.cpp b/src/amqp/amqpabstractnotifier.cpp deleted file mode 100644 index 57686ef1d..000000000 --- a/src/amqp/amqpabstractnotifier.cpp +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2017 The Zcash developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "amqpabstractnotifier.h" -#include "util.h" - - -AMQPAbstractNotifier::~AMQPAbstractNotifier() -{ -} - -bool AMQPAbstractNotifier::NotifyBlock(const CBlockIndex * /*CBlockIndex*/) -{ - return true; -} - -bool AMQPAbstractNotifier::NotifyTransaction(const CTransaction &/*transaction*/) -{ - return true; -} diff --git a/src/amqp/amqpabstractnotifier.h b/src/amqp/amqpabstractnotifier.h deleted file mode 100644 index c993a2b3e..000000000 --- a/src/amqp/amqpabstractnotifier.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2017 The Zcash developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef ZCASH_AMQP_AMQPABSTRACTNOTIFIER_H -#define ZCASH_AMQP_AMQPABSTRACTNOTIFIER_H - -#include "amqpconfig.h" - -class CBlockIndex; -class AMQPAbstractNotifier; - -typedef AMQPAbstractNotifier* (*AMQPNotifierFactory)(); - -class AMQPAbstractNotifier -{ -public: - AMQPAbstractNotifier() { } - virtual ~AMQPAbstractNotifier(); - - template - static AMQPAbstractNotifier* Create() - { - return new T(); - } - - std::string GetType() const { return type; } - void SetType(const std::string &t) { type = t; } - std::string GetAddress() const { return address; } - void SetAddress(const std::string &a) { address = a; } - - virtual bool Initialize() = 0; - virtual void Shutdown() = 0; - - virtual bool NotifyBlock(const CBlockIndex *pindex); - virtual bool NotifyTransaction(const CTransaction &transaction); - -protected: - std::string type; - std::string address; -}; - -#endif // ZCASH_AMQP_AMQPABSTRACTNOTIFIER_H diff --git a/src/amqp/amqpconfig.h b/src/amqp/amqpconfig.h deleted file mode 100644 index dcc5f7709..000000000 --- a/src/amqp/amqpconfig.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2017 The Zcash developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef ZCASH_AMQP_AMQPCONFIG_H -#define ZCASH_AMQP_AMQPCONFIG_H - -#if defined(HAVE_CONFIG_H) -#include "config/bitcoin-config.h" -#endif - -#include -#include - -#if ENABLE_PROTON -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif - -#include "primitives/block.h" -#include "primitives/transaction.h" - -#endif // ZCASH_AMQP_AMQPCONFIG_H diff --git a/src/amqp/amqpnotificationinterface.cpp b/src/amqp/amqpnotificationinterface.cpp deleted file mode 100644 index 66f5398ca..000000000 --- a/src/amqp/amqpnotificationinterface.cpp +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (c) 2017 The Zcash developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "amqpnotificationinterface.h" -#include "amqppublishnotifier.h" - -#include "version.h" -#include "main.h" -#include "streams.h" -#include "util.h" - -// AMQP 1.0 Support -// -// The boost::signals2 signals and slot system is thread safe, so CValidationInterface listeners -// can be invoked from any thread. -// -// Currently signals are fired from main.cpp so the callbacks should be invoked on the same thread. -// It should be safe to share objects responsible for sending, as they should not be run concurrently -// across different threads. -// -// Developers should be mindful of where notifications are fired to avoid potential race conditions. -// For example, different signals targeting the same address could be fired from different threads -// in different parts of the system around the same time. -// -// Like the ZMQ notification interface, if a notifier fails to send a message, the notifier is shut down. -// - -AMQPNotificationInterface::AMQPNotificationInterface() -{ -} - -AMQPNotificationInterface::~AMQPNotificationInterface() -{ - Shutdown(); - - for (std::list::iterator i = notifiers.begin(); i != notifiers.end(); ++i) { - delete *i; - } -} - -AMQPNotificationInterface* AMQPNotificationInterface::CreateWithArguments(const std::map &args) -{ - AMQPNotificationInterface* notificationInterface = nullptr; - std::map factories; - std::list notifiers; - - factories["pubhashblock"] = AMQPAbstractNotifier::Create; - factories["pubhashtx"] = AMQPAbstractNotifier::Create; - factories["pubrawblock"] = AMQPAbstractNotifier::Create; - factories["pubrawtx"] = AMQPAbstractNotifier::Create; - - for (std::map::const_iterator i=factories.begin(); i!=factories.end(); ++i) { - std::map::const_iterator j = args.find("-amqp" + i->first); - if (j!=args.end()) { - AMQPNotifierFactory factory = i->second; - std::string address = j->second; - AMQPAbstractNotifier *notifier = factory(); - notifier->SetType(i->first); - notifier->SetAddress(address); - notifiers.push_back(notifier); - } - } - - if (!notifiers.empty()) { - notificationInterface = new AMQPNotificationInterface(); - notificationInterface->notifiers = notifiers; - - if (!notificationInterface->Initialize()) { - delete notificationInterface; - notificationInterface = nullptr; - } - } - - return notificationInterface; -} - -// Called at startup to conditionally set up -bool AMQPNotificationInterface::Initialize() -{ - LogPrint("amqp", "amqp: Initialize notification interface\n"); - - std::list::iterator i = notifiers.begin(); - for (; i != notifiers.end(); ++i) { - AMQPAbstractNotifier *notifier = *i; - if (notifier->Initialize()) { - LogPrint("amqp", "amqp: Notifier %s ready (address = %s)\n", notifier->GetType(), notifier->GetAddress()); - } else { - LogPrint("amqp", "amqp: Notifier %s failed (address = %s)\n", notifier->GetType(), notifier->GetAddress()); - break; - } - } - - if (i != notifiers.end()) { - return false; - } - - return true; -} - -// Called during shutdown sequence -void AMQPNotificationInterface::Shutdown() -{ - LogPrint("amqp", "amqp: Shutdown notification interface\n"); - - for (std::list::iterator i = notifiers.begin(); i != notifiers.end(); ++i) { - AMQPAbstractNotifier *notifier = *i; - notifier->Shutdown(); - } -} - -void AMQPNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindex) -{ - for (std::list::iterator i = notifiers.begin(); i != notifiers.end(); ) { - AMQPAbstractNotifier *notifier = *i; - if (notifier->NotifyBlock(pindex)) { - i++; - } else { - notifier->Shutdown(); - i = notifiers.erase(i); - } - } -} - -void AMQPNotificationInterface::SyncTransaction(const CTransaction &tx, const CBlock *pblock) -{ - for (std::list::iterator i = notifiers.begin(); i != notifiers.end(); ) { - AMQPAbstractNotifier *notifier = *i; - if (notifier->NotifyTransaction(tx)) { - i++; - } else { - notifier->Shutdown(); - i = notifiers.erase(i); - } - } -} diff --git a/src/amqp/amqpnotificationinterface.h b/src/amqp/amqpnotificationinterface.h deleted file mode 100644 index 0c07ce235..000000000 --- a/src/amqp/amqpnotificationinterface.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2017 The Zcash developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef ZCASH_AMQP_AMQPNOTIFICATIONINTERFACE_H -#define ZCASH_AMQP_AMQPNOTIFICATIONINTERFACE_H - -#include "validationinterface.h" -#include -#include - -class CBlockIndex; -class AMQPAbstractNotifier; - -class AMQPNotificationInterface : public CValidationInterface -{ -public: - virtual ~AMQPNotificationInterface(); - - static AMQPNotificationInterface* CreateWithArguments(const std::map &args); - -protected: - bool Initialize(); - void Shutdown(); - - // CValidationInterface - void SyncTransaction(const CTransaction &tx, const CBlock *pblock); - void UpdatedBlockTip(const CBlockIndex *pindex); - -private: - AMQPNotificationInterface(); - - std::list notifiers; -}; - -#endif // ZCASH_AMQP_AMQPNOTIFICATIONINTERFACE_H diff --git a/src/amqp/amqppublishnotifier.cpp b/src/amqp/amqppublishnotifier.cpp deleted file mode 100644 index 589eb151f..000000000 --- a/src/amqp/amqppublishnotifier.cpp +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright (c) 2017 The Zcash developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "amqppublishnotifier.h" -#include "main.h" -#include "util.h" - -#include "amqpsender.h" - -#include -#include - -static std::multimap mapPublishNotifiers; - -static const char *MSG_HASHBLOCK = "hashblock"; -static const char *MSG_HASHTX = "hashtx"; -static const char *MSG_RAWBLOCK = "rawblock"; -static const char *MSG_RAWTX = "rawtx"; - -// Invoke this method from a new thread to run the proton container event loop. -void AMQPAbstractPublishNotifier::SpawnProtonContainer() -{ - try { - proton::default_container(*handler_).run(); - } - catch (const proton::error_condition &e) { - LogPrint("amqp", "amqp: container error: %s\n", e.what()); - } - catch (const std::runtime_error &e) { - LogPrint("amqp", "amqp: runtime error: %s\n", e.what()); - } - catch (const std::exception &e) { - LogPrint("amqp", "amqp: exception: %s\n", e.what()); - } - catch (...) { - LogPrint("amqp", "amqp: unknown error\n"); - } - handler_->terminate(); -} - -bool AMQPAbstractPublishNotifier::Initialize() -{ - std::multimap::iterator i = mapPublishNotifiers.find(address); - - if (i == mapPublishNotifiers.end()) { - try { - handler_ = std::make_shared(address); - thread_ = std::make_shared(&AMQPAbstractPublishNotifier::SpawnProtonContainer, this); - } - catch (std::exception &e) { - LogPrint("amqp", "amqp: initialization error: %s\n", e.what()); - return false; - } - mapPublishNotifiers.insert(std::make_pair(address, this)); - } else { - // copy the shared ptrs to the message handler and the thread where the proton container is running - handler_ = i->second->handler_; - thread_ = i->second->thread_; - mapPublishNotifiers.insert(std::make_pair(address, this)); - } - - return true; -} - - -void AMQPAbstractPublishNotifier::Shutdown() -{ - LogPrint("amqp", "amqp: Shutdown notifier %s at %s\n", GetType(), GetAddress()); - - int count = mapPublishNotifiers.count(address); - - // remove this notifier from the list of publishers using this address - typedef std::multimap::iterator iterator; - std::pair iterpair = mapPublishNotifiers.equal_range(address); - - for (iterator it = iterpair.first; it != iterpair.second; ++it) { - if (it->second == this) { - mapPublishNotifiers.erase(it); - break; - } - } - - // terminate the connection if this is the last publisher using this address - if (count == 1) { - handler_->terminate(); - if (thread_.get() != nullptr) { - if (thread_->joinable()) { - thread_->join(); - } - } - } -} - - -bool AMQPAbstractPublishNotifier::SendMessage(const char *command, const void* data, size_t size) -{ - try { - proton::binary content; - const char *p = (const char *)data; - content.assign(p, p + size); - - proton::message message(content); - message.subject(std::string(command)); - proton::message::property_map & props = message.properties(); - props.put("x-opt-sequence-number", sequence_); - handler_->publish(message); - - } catch (proton::error_condition &e) { - LogPrint("amqp", "amqp: error : %s\n", e.what()); - return false; - } - catch (const std::runtime_error &e) { - LogPrint("amqp", "amqp: runtime error: %s\n", e.what()); - return false; - } - catch (const std::exception &e) { - LogPrint("amqp", "amqp: exception: %s\n", e.what()); - return false; - } - catch (...) { - LogPrint("amqp", "amqp: unknown error\n"); - return false; - } - - sequence_++; - - return true; -} - -bool AMQPPublishHashBlockNotifier::NotifyBlock(const CBlockIndex *pindex) -{ - uint256 hash = pindex->GetBlockHash(); - LogPrint("amqp", "amqp: Publish hashblock %s\n", hash.GetHex()); - char data[32]; - for (unsigned int i = 0; i < 32; i++) - data[31 - i] = hash.begin()[i]; - return SendMessage(MSG_HASHBLOCK, data, 32); -} - -bool AMQPPublishHashTransactionNotifier::NotifyTransaction(const CTransaction &transaction) -{ - uint256 hash = transaction.GetHash(); - LogPrint("amqp", "amqp: Publish hashtx %s\n", hash.GetHex()); - char data[32]; - for (unsigned int i = 0; i < 32; i++) - data[31 - i] = hash.begin()[i]; - return SendMessage(MSG_HASHTX, data, 32); -} - -bool AMQPPublishRawBlockNotifier::NotifyBlock(const CBlockIndex *pindex) -{ - LogPrint("amqp", "amqp: Publish rawblock %s\n", pindex->GetBlockHash().GetHex()); - - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - { - LOCK(cs_main); - CBlock block; - if(!ReadBlockFromDisk(block, pindex)) { - LogPrint("amqp", "amqp: Can't read block from disk"); - return false; - } - - ss << block; - } - - return SendMessage(MSG_RAWBLOCK, &(*ss.begin()), ss.size()); -} - -bool AMQPPublishRawTransactionNotifier::NotifyTransaction(const CTransaction &transaction) -{ - uint256 hash = transaction.GetHash(); - LogPrint("amqp", "amqp: Publish rawtx %s\n", hash.GetHex()); - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << transaction; - return SendMessage(MSG_RAWTX, &(*ss.begin()), ss.size()); -} diff --git a/src/amqp/amqppublishnotifier.h b/src/amqp/amqppublishnotifier.h deleted file mode 100644 index 08b3aba08..000000000 --- a/src/amqp/amqppublishnotifier.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 2017 The Zcash developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef ZCASH_AMQP_AMQPPUBLISHNOTIFIER_H -#define ZCASH_AMQP_AMQPPUBLISHNOTIFIER_H - -#include "amqpabstractnotifier.h" -#include "amqpconfig.h" -#include "amqpsender.h" - -#include -#include - -class CBlockIndex; - -class AMQPAbstractPublishNotifier : public AMQPAbstractNotifier -{ -private: - uint64_t sequence_; // memory only, per notifier instance: upcounting message sequence number - - std::shared_ptr thread_; // proton container thread, may be shared between notifiers - std::shared_ptr handler_; // proton container message handler, may be shared between notifiers - -public: - bool SendMessage(const char *command, const void* data, size_t size); - bool Initialize(); - void Shutdown(); - void SpawnProtonContainer(); -}; - -class AMQPPublishHashBlockNotifier : public AMQPAbstractPublishNotifier -{ -public: - bool NotifyBlock(const CBlockIndex *pindex); -}; - -class AMQPPublishHashTransactionNotifier : public AMQPAbstractPublishNotifier -{ -public: - bool NotifyTransaction(const CTransaction &transaction); -}; - -class AMQPPublishRawBlockNotifier : public AMQPAbstractPublishNotifier -{ -public: - bool NotifyBlock(const CBlockIndex *pindex); -}; - -class AMQPPublishRawTransactionNotifier : public AMQPAbstractPublishNotifier -{ -public: - bool NotifyTransaction(const CTransaction &transaction); -}; - -#endif // ZCASH_AMQP_AMQPPUBLISHNOTIFIER_H diff --git a/src/amqp/amqpsender.h b/src/amqp/amqpsender.h deleted file mode 100644 index 7fa85d89c..000000000 --- a/src/amqp/amqpsender.h +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) 2017 The Zcash developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef ZCASH_AMQP_AMQPSENDER_H -#define ZCASH_AMQP_AMQPSENDER_H - -#include "amqpconfig.h" - -#include -#include -#include -#include - -class AMQPSender : public proton::messaging_handler { - private: - std::deque messages_; - proton::url url_; - proton::connection conn_; - proton::sender sender_; - std::mutex lock_; - std::atomic terminated_ = {false}; - - public: - - AMQPSender(const std::string& url) : url_(url) {} - - // Callback to initialize the container when run() is invoked - void on_container_start(proton::container& c) override { - proton::duration t(10000); // milliseconds - proton::connection_options opts = proton::connection_options().idle_timeout(t); - conn_ = c.connect(url_, opts); - sender_ = conn_.open_sender(url_.path()); - } - - // Remote end signals when the local end can send (i.e. has credit) - void on_sendable(proton::sender &s) override { - dispatch(); - } - - // Publish message by adding to queue and trying to dispatch it - void publish(const proton::message &m) { - add_message(m); - dispatch(); - } - - // Add message to queue - void add_message(const proton::message &m) { - std::lock_guard guard(lock_); - messages_.push_back(m); - } - - // Send messages in queue - void dispatch() { - std::lock_guard guard(lock_); - - if (isTerminated()) { - throw std::runtime_error("amqp connection was terminated"); - } - - if (!conn_.active()) { - throw std::runtime_error("amqp connection is not active"); - } - - while (messages_.size() > 0) { - if (sender_.credit()) { - const proton::message& m = messages_.front(); - sender_.send(m); - messages_.pop_front(); - } else { - break; - } - } - } - - // Close connection to remote end. Container event-loop, by default, will auto-stop. - void terminate() { - std::lock_guard guard(lock_); - conn_.close(); - terminated_.store(true); - } - - bool isTerminated() const { - return terminated_.load(); - } - - void on_transport_error(proton::transport &t) override { - t.connection().close(); - throw t.error(); - } - - void on_connection_error(proton::connection &c) override { - c.close(); - throw c.error(); - } - - void on_session_error(proton::session &s) override { - s.connection().close(); - throw s.error(); - } - - void on_receiver_error(proton::receiver &r) override { - r.connection().close(); - throw r.error(); - } - - void on_sender_error(proton::sender &s) override { - s.connection().close(); - throw s.error(); - } - -}; - - -#endif //ZCASH_AMQP_AMQPSENDER_H diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp index e9c0dd056..d7a5c0afe 100644 --- a/src/arith_uint256.cpp +++ b/src/arith_uint256.cpp @@ -193,9 +193,10 @@ unsigned int base_uint::bits() const { for (int pos = WIDTH - 1; pos >= 0; pos--) { if (pn[pos]) { - for (int bits = 31; bits > 0; bits--) { - if (pn[pos] & 1 << bits) + for (size_t bits = 31; bits > 0; bits--) { + if (pn[pos] & (1U << bits)) { return 32 * pos + bits + 1; + } } return 32 * pos + 1; } diff --git a/src/cc/Makefile_custom b/src/cc/Makefile_custom old mode 100755 new mode 100644 index 79219ec96..3989eefa3 --- a/src/cc/Makefile_custom +++ b/src/cc/Makefile_custom @@ -2,6 +2,7 @@ SHELL = /bin/sh CC = gcc CC_DARWIN = g++-8 CC_WIN = x86_64-w64-mingw32-gcc-posix +CC_AARCH64 = aarch64-linux-gnu-g++ CFLAGS_DARWIN = -DBUILD_CUSTOMCC -std=c++11 -arch x86_64 -I../secp256k1/include -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -Wl,-undefined -Wl,dynamic_lookup -Wno-write-strings -shared -dynamiclib CFLAGS = -Wno-write-strings -DBUILD_CUSTOMCC -std=c++11 -I../secp256k1/include -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared CFLAGS_WIN = -Wno-write-strings -DBUILD_CUSTOMCC -std=c++11 -I../secp256k1/include -I../../depends/x86_64-w64-mingw32/include -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared @@ -28,6 +29,10 @@ else ifeq ($(HOST),x86_64-w64-mingw32) $(CC_WIN) $(CFLAGS_WIN) $(DEBUGFLAGS) -o $(TARGET_WIN) -c $(SOURCES) cp $(TARGET_WIN) ../libcc.dll #else ifeq ($(WIN_HOST),True) - todo: pass ENV var from build.sh if WIN host +else ifeq ($(HOST),aarch64-linux-gnu) + $(info LINUX ARM 64bit ) + $(CC_AARCH64) $(CFLAGS) $(DEBUGFLAGS) -o $(TARGET) -c $(SOURCES) + cp $(TARGET) ../libcc.so else $(info LINUX) $(CC) $(CFLAGS) $(DEBUGFLAGS) -o $(TARGET) -c $(SOURCES) diff --git a/src/cc/cclib.cpp b/src/cc/cclib.cpp index 364953148..67440f3da 100644 --- a/src/cc/cclib.cpp +++ b/src/cc/cclib.cpp @@ -1,3 +1,4 @@ +// Copyright © 2019-2020 The Hush Developers /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * * * diff --git a/src/cc/dapps/Makefile b/src/cc/dapps/Makefile index 6e7874788..1fea27084 100644 --- a/src/cc/dapps/Makefile +++ b/src/cc/dapps/Makefile @@ -1,6 +1,10 @@ +# Copyright 2020 The Hush Developers # just type make to compile all dapps all: zmigrate oraclefeed +subatomic: + $(CC) subatomic.c -o subatomic -lm + zmigrate: $(CC) zmigrate.c -o zmigrate -lm @@ -9,3 +13,4 @@ oraclefeed: clean: rm zmigrate oraclefeed + diff --git a/src/cc/dapps/dappinc.h b/src/cc/dapps/dappinc.h new file mode 100644 index 000000000..3c71dfdec --- /dev/null +++ b/src/cc/dapps/dappinc.h @@ -0,0 +1,1599 @@ +/****************************************************************************** + * Copyright © 2014-2020 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +#include +#include +#include +#include +#include "cJSON.c" + +bits256 zeroid; + +int32_t unstringbits(char *buf,uint64_t bits) +{ + int32_t i; + for (i=0; i<8; i++,bits>>=8) + if ( (buf[i]= (char)(bits & 0xff)) == 0 ) + break; + buf[i] = 0; + return(i); +} + +uint64_t stringbits(char *str) +{ + uint64_t bits = 0; + if ( str == 0 ) + return(0); + int32_t i,n = (int32_t)strlen(str); + if ( n > 8 ) + n = 8; + for (i=n-1; i>=0; i--) + bits = (bits << 8) | (str[i] & 0xff); + //printf("(%s) -> %llx %llu\n",str,(long long)bits,(long long)bits); + return(bits); +} + +char hexbyte(int32_t c) +{ + c &= 0xf; + if ( c < 10 ) + return('0'+c); + else if ( c < 16 ) + return('a'+c-10); + else return(0); +} + +int32_t _unhex(char c) +{ + if ( c >= '0' && c <= '9' ) + return(c - '0'); + else if ( c >= 'a' && c <= 'f' ) + return(c - 'a' + 10); + else if ( c >= 'A' && c <= 'F' ) + return(c - 'A' + 10); + return(-1); +} + +int32_t is_hexstr(char *str,int32_t n) +{ + int32_t i; + if ( str == 0 || str[0] == 0 ) + return(0); + for (i=0; str[i]!=0; i++) + { + if ( n > 0 && i >= n ) + break; + if ( _unhex(str[i]) < 0 ) + break; + } + if ( n == 0 ) + return(i); + return(i == n); +} + +int32_t unhex(char c) +{ + int32_t hex; + if ( (hex= _unhex(c)) < 0 ) + { + //printf("unhex: illegal hexchar.(%c)\n",c); + } + return(hex); +} + +unsigned char _decode_hex(char *hex) { return((unhex(hex[0])<<4) | unhex(hex[1])); } + +int32_t decode_hex(unsigned char *bytes,int32_t n,char *hex) +{ + int32_t adjust,i = 0; + //printf("decode.(%s)\n",hex); + if ( is_hexstr(hex,n) <= 0 ) + { + memset(bytes,0,n); + return(n); + } + if ( hex[n-1] == '\n' || hex[n-1] == '\r' ) + hex[--n] = 0; + if ( hex[n-1] == '\n' || hex[n-1] == '\r' ) + hex[--n] = 0; + if ( n == 0 || (hex[n*2+1] == 0 && hex[n*2] != 0) ) + { + if ( n > 0 ) + { + bytes[0] = unhex(hex[0]); + printf("decode_hex n.%d hex[0] (%c) -> %d hex.(%s) [n*2+1: %d] [n*2: %d %c] len.%ld\n",n,hex[0],bytes[0],hex,hex[n*2+1],hex[n*2],hex[n*2],(long)strlen(hex)); + } + bytes++; + hex++; + adjust = 1; + } else adjust = 0; + if ( n > 0 ) + { + for (i=0; i>4) & 0xf); + hexbytes[i*2 + 1] = hexbyte(message[i] & 0xf); + //printf("i.%d (%02x) [%c%c]\n",i,message[i],hexbytes[i*2],hexbytes[i*2+1]); + } + hexbytes[len*2] = 0; + //printf("len.%ld\n",len*2+1); + return((int32_t)len*2+1); +} + +long _stripwhite(char *buf,int accept) +{ + int32_t i,j,c; + if ( buf == 0 || buf[0] == 0 ) + return(0); + for (i=j=0; buf[i]!=0; i++) + { + buf[j] = c = buf[i]; + if ( c == accept || (c != ' ' && c != '\n' && c != '\r' && c != '\t' && c != '\b') ) + j++; + } + buf[j] = 0; + return(j); +} + +char *clonestr(char *str) +{ + char *clone; + if ( str == 0 || str[0]==0) + { + printf("warning cloning nullstr.%p\n",str); + //#ifdef __APPLE__ + // while ( 1 ) sleep(1); + //#endif + str = (char *)""; + } + clone = (char *)malloc(strlen(str)+16); + strcpy(clone,str); + return(clone); +} + +int32_t safecopy(char *dest,char *src,long len) +{ + int32_t i = -1; + if ( src != 0 && dest != 0 && src != dest ) + { + if ( dest != 0 ) + memset(dest,0,len); + for (i=0; i0; i--) + str[i] = str[i-1]; + str[0] = '/'; + str[n+1] = 0; + }*/ +#endif + return(str); +#endif +} + +void *loadfile(char *fname,uint8_t **bufp,long *lenp,long *allocsizep) +{ + FILE *fp; + long filesize,buflen = *allocsizep; + uint8_t *buf = *bufp; + *lenp = 0; + if ( (fp= fopen(portable_path(fname),"rb")) != 0 ) + { + fseek(fp,0,SEEK_END); + filesize = ftell(fp); + if ( filesize == 0 ) + { + fclose(fp); + *lenp = 0; + //printf("loadfile null size.(%s)\n",fname); + return(0); + } + if ( filesize > buflen ) + { + *allocsizep = filesize; + *bufp = buf = (uint8_t *)realloc(buf,(long)*allocsizep+64); + } + rewind(fp); + if ( buf == 0 ) + printf("Null buf ???\n"); + else + { + if ( fread(buf,1,(long)filesize,fp) != (unsigned long)filesize ) + printf("error reading filesize.%ld\n",(long)filesize); + buf[filesize] = 0; + } + fclose(fp); + *lenp = filesize; + //printf("loaded.(%s)\n",buf); + } //else printf("OS_loadfile couldnt load.(%s)\n",fname); + return(buf); +} + +void *filestr(long *allocsizep,char *_fname) +{ + long filesize = 0; char *fname,*buf = 0; void *retptr; + *allocsizep = 0; + fname = malloc(strlen(_fname)+1); + strcpy(fname,_fname); + retptr = loadfile(fname,(uint8_t **)&buf,&filesize,allocsizep); + free(fname); + return(retptr); +} + +char *send_curl(char *url,char *fname) +{ + long fsize; char curlstr[1024]; + sprintf(curlstr,"curl --url \"%s\" > %s",url,fname); + system(curlstr); + return(filestr(&fsize,fname)); +} + +cJSON *get_urljson(char *url,char *fname) +{ + char *jsonstr; cJSON *json = 0; + if ( (jsonstr= send_curl(url,fname)) != 0 ) + { + //printf("(%s) -> (%s)\n",url,jsonstr); + json = cJSON_Parse(jsonstr); + free(jsonstr); + } + return(json); +} + +////////////////////////////////////////////// +// start of dapp +////////////////////////////////////////////// +int md_unlink(char *file) +{ +#ifdef _WIN32 + _chmod(file, 0600); + return( _unlink(file) ); +#else + return(unlink(file)); +#endif +} + +char *REFCOIN_CLI,DPOW_pubkeystr[67],DPOW_secpkeystr[67],DPOW_handle[67],DPOW_recvaddr[64],DPOW_recvZaddr[128]; + +cJSON *get_komodocli(char *refcoin,char **retstrp,char *acname,char *method,char *arg0,char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6) +{ + long fsize; cJSON *retjson = 0; char cmdstr[32768],*jsonstr,fname[32768]; + sprintf(fname,"/tmp/notarizer_%s_%d",method,(rand() >> 17) % 10000); + //if ( (acname == 0 || acname[0] == 0) && strcmp(refcoin,"KMD") != 0 ) + // acname = refcoin; + if ( acname[0] != 0 ) + { + if ( refcoin[0] != 0 && strcmp(refcoin,"KMD") != 0 && strcmp(refcoin,acname) != 0 ) + printf("unexpected: refcoin.(%s) acname.(%s)\n",refcoin,acname); + sprintf(cmdstr,"komodo-cli -ac_name=%s %s %s %s %s %s %s %s %s > %s\n",acname,method,arg0,arg1,arg2,arg3,arg4,arg5,arg6,fname); + } + else if ( strcmp(refcoin,"KMD") == 0 ) + sprintf(cmdstr,"komodo-cli %s %s %s %s %s %s %s %s > %s\n",method,arg0,arg1,arg2,arg3,arg4,arg5,arg6,fname); + else if ( REFCOIN_CLI != 0 && REFCOIN_CLI[0] != 0 ) + { + sprintf(cmdstr,"%s %s %s %s %s %s %s %s %s > %s\n",REFCOIN_CLI,method,arg0,arg1,arg2,arg3,arg4,arg5,arg6,fname); + //printf("ref.(%s) REFCOIN_CLI (%s)\n",refcoin,cmdstr); + } +//fprintf(stderr,"system(%s)\n",cmdstr); + system(cmdstr); + *retstrp = 0; + if ( (jsonstr= filestr(&fsize,fname)) != 0 ) + { + jsonstr[strlen(jsonstr)-1]='\0'; + //fprintf(stderr,"%s -> jsonstr.(%s)\n",cmdstr,jsonstr); + if ( (jsonstr[0] != '{' && jsonstr[0] != '[') || (retjson= cJSON_Parse(jsonstr)) == 0 ) + *retstrp = jsonstr; + else free(jsonstr); + md_unlink(fname); + } //else fprintf(stderr,"system(%s) -> NULL\n",cmdstr); + return(retjson); +} + +cJSON *subatomic_cli(char *clistr,char **retstrp,char *method,char *arg0,char *arg1,char *arg2,char *arg3,char *arg4,char *arg5,char *arg6) +{ + long fsize; cJSON *retjson = 0; char cmdstr[32768],*jsonstr,fname[32768]; + sprintf(fname,"/tmp/subatomic_%s_%d",method,(rand() >> 17) % 10000); + sprintf(cmdstr,"%s %s %s %s %s %s %s %s %s > %s\n",clistr,method,arg0,arg1,arg2,arg3,arg4,arg5,arg6,fname); +//fprintf(stderr,"system(%s)\n",cmdstr); + system(cmdstr); + *retstrp = 0; + if ( (jsonstr= filestr(&fsize,fname)) != 0 ) + { + jsonstr[strlen(jsonstr)-1]='\0'; + //fprintf(stderr,"%s -> jsonstr.(%s)\n",cmdstr,jsonstr); + if ( (jsonstr[0] != '{' && jsonstr[0] != '[') || (retjson= cJSON_Parse(jsonstr)) == 0 ) + *retstrp = jsonstr; + else free(jsonstr); + md_unlink(fname); + } //else fprintf(stderr,"system(%s) -> NULL\n",cmdstr); + return(retjson); +} + +bits256 komodobroadcast(char *refcoin,char *acname,cJSON *hexjson) +{ + char *hexstr,*retstr,str[65]; cJSON *retjson; bits256 txid; + memset(txid.bytes,0,sizeof(txid)); + if ( (hexstr= jstr(hexjson,"hex")) != 0 ) + { + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"sendrawtransaction",hexstr,"","","","","","")) != 0 ) + { + //fprintf(stderr,"broadcast.(%s)\n",jprint(retjson,0)); + free_json(retjson); + } + else if ( retstr != 0 ) + { + if ( strlen(retstr) >= 64 ) + { + retstr[64] = 0; + decode_hex(txid.bytes,32,retstr); + } + fprintf(stderr,"broadcast %s txid.(%s)\n",strlen(acname)>0?acname:refcoin,bits256_str(str,txid)); + free(retstr); + } + } + return(txid); +} + +bits256 sendtoaddress(char *refcoin,char *acname,char *destaddr,int64_t satoshis,char *oprethexstr) +{ + char numstr[32],*retstr,str[65]; cJSON *retjson; bits256 txid; + memset(txid.bytes,0,sizeof(txid)); + sprintf(numstr,"%.8f",(double)satoshis/SATOSHIDEN); + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"sendtoaddress",destaddr,numstr,"false","","",oprethexstr,"")) != 0 ) + { + fprintf(stderr,"unexpected sendrawtransaction json.(%s)\n",jprint(retjson,0)); + free_json(retjson); + } + else if ( retstr != 0 ) + { + if ( strlen(retstr) >= 64 ) + { + retstr[64] = 0; + decode_hex(txid.bytes,32,retstr); + } + fprintf(stderr,"sendtoaddress %s %.8f txid.(%s)\n",destaddr,(double)satoshis/SATOSHIDEN,bits256_str(str,txid)); + free(retstr); + } + return(txid); +} + +bits256 tokentransfer(char *refcoin,char *acname,char *tokenid,char *destpub,int64_t units) +{ + char numstr[32],*retstr,str[65]; cJSON *retjson; bits256 txid; + memset(txid.bytes,0,sizeof(txid)); + sprintf(numstr,"%llu",(long long)units); + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"tokentransfer",tokenid,destpub,numstr,"","","","")) != 0 ) + { + txid = komodobroadcast(refcoin,acname,retjson); + fprintf(stderr,"tokentransfer returned (%s)\n",jprint(retjson,0)); + free_json(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"tokentransfer.(%s) error.(%s)\n",acname,retstr); + free(retstr); + } + return(txid); +} + +char *get_tokenaddress(char *refcoin,char *acname,char *tokenaddr) +{ + char *retstr,*str; cJSON *retjson; + tokenaddr[0] = 0; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"tokenaddress","","","","","","","")) != 0 ) + { + if ( (str= jstr(retjson,"myCCAddress(Tokens)")) != 0 ) + { + strcpy(tokenaddr,str); + fprintf(stderr,"tokenaddress returned (%s)\n",tokenaddr); + free_json(retjson); + return(tokenaddr); + } + free_json(retjson); + } + else if ( retstr != 0 ) + { + //fprintf(stderr,"tokentransfer.(%s) error.(%s)\n",acname,retstr); + free(retstr); + } + return(0); +} + +int64_t get_tokenbalance(char *refcoin,char *acname,char *tokenid) +{ + cJSON *retjson; char *retstr,cmpstr[64]; int64_t amount=0; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"tokenbalance",tokenid,"","","","","","")) != 0 ) + { + amount = j64bits(retjson,"balance"); + fprintf(stderr,"tokenbalance %llu\n",(long long)amount); + free_json(retjson); + } + else if ( retstr != 0 ) + { + //printf("retstr %s -> %.8f\n",retstr,dstr(amount)); + free(retstr); + } + return (amount); +} + +cJSON *get_decodescript(char *refcoin,char *acname,char *script) +{ + cJSON *retjson; char *retstr; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"decodescript",script,"","","","","","")) != 0 ) + { + return(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"get_decodescript.(%s) error.(%s)\n",acname,retstr); + free(retstr); + } + return(0); +} + +char *get_createmultisig2(char *refcoin,char *acname,char *msigaddr,char *redeemscript,char *pubkeyA,char *pubkeyB) +{ + //char para 2 '["02c3af47b51a506b08b4ededb156cb4c3f9db9e0ac7ad27b8623c08a056fdcc220", "038e61fbface549a850862f12ed99b7cbeef5c2bd2d8f1daddb34809416f0259e1"]' + cJSON *retjson; char *retstr,*str,params[256]; int32_t height=0; + msigaddr[0] = 0; + redeemscript[0] = 0; + sprintf(params,"'[\"%s\", \"%s\"]'",pubkeyA,pubkeyB); + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"createmultisig","2",params,"","","","","")) != 0 ) + { + if ( (str= jstr(retjson,"address")) != 0 ) + strcpy(msigaddr,str); + if ( (str= jstr(retjson,"redeemScript")) != 0 ) + strcpy(redeemscript,str); + free_json(retjson); + if ( msigaddr[0] != 0 && redeemscript[0] != 0 ) + return(msigaddr); + else return(0); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"%s get_createmultisig2.(%s) error.(%s)\n",refcoin,acname,retstr); + free(retstr); + } + return(0); +} + +int32_t get_coinheight(char *refcoin,char *acname,bits256 *blockhashp) +{ + cJSON *retjson; char *retstr; int32_t height=0; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getblockchaininfo","","","","","","","")) != 0 ) + { + height = jint(retjson,"blocks"); + *blockhashp = jbits256(retjson,"bestblockhash"); + free_json(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"%s get_coinheight.(%s) error.(%s)\n",refcoin,acname,retstr); + free(retstr); + } + return(height); +} + +bits256 get_coinblockhash(char *refcoin,char *acname,int32_t height) +{ + cJSON *retjson; char *retstr,heightstr[32]; bits256 hash; + memset(hash.bytes,0,sizeof(hash)); + sprintf(heightstr,"%d",height); + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getblockhash",heightstr,"","","","","","")) != 0 ) + { + fprintf(stderr,"unexpected blockhash json.(%s)\n",jprint(retjson,0)); + free_json(retjson); + } + else if ( retstr != 0 ) + { + if ( strlen(retstr) >= 64 ) + { + retstr[64] = 0; + decode_hex(hash.bytes,32,retstr); + } + free(retstr); + } + return(hash); +} + +bits256 get_coinmerkleroot(char *refcoin,char *acname,bits256 blockhash,uint32_t *blocktimep) +{ + cJSON *retjson; char *retstr,str[65]; bits256 merkleroot; + memset(merkleroot.bytes,0,sizeof(merkleroot)); + *blocktimep = 0; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getblockheader",bits256_str(str,blockhash),"","","","","","")) != 0 ) + { + merkleroot = jbits256(retjson,"merkleroot"); + *blocktimep = juint(retjson,"time"); + //fprintf(stderr,"got merkleroot.(%s)\n",bits256_str(str,merkleroot)); + free_json(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"%s %s get_coinmerkleroot error.(%s)\n",refcoin,acname,retstr); + free(retstr); + } + return(merkleroot); +} + +uint32_t get_heighttime(char *refcoin,char *acname,int32_t height) +{ + bits256 blockhash; uint32_t blocktime; + blockhash = get_coinblockhash(refcoin,acname,height); + get_coinmerkleroot(refcoin,acname,blockhash,&blocktime); + return(blocktime); +} + +int32_t get_coinheader(char *refcoin,char *acname,bits256 *blockhashp,bits256 *merklerootp,int32_t prevheight) +{ + int32_t height = 0; char str[65]; bits256 bhash; uint32_t blocktime; + if ( prevheight == 0 ) + height = get_coinheight(refcoin,acname,&bhash) - 20; + else height = prevheight + 1; + if ( height > 0 ) + { + *blockhashp = get_coinblockhash(refcoin,acname,height); + if ( bits256_nonz(*blockhashp) != 0 ) + { + *merklerootp = get_coinmerkleroot(refcoin,acname,*blockhashp,&blocktime); + if ( bits256_nonz(*merklerootp) != 0 ) + return(height); + } + } + memset(blockhashp,0,sizeof(*blockhashp)); + memset(merklerootp,0,sizeof(*merklerootp)); + return(0); +} + +cJSON *get_rawmempool(char *refcoin,char *acname) +{ + cJSON *retjson; char *retstr; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getrawmempool","","","","","","","")) != 0 ) + { + //printf("mempool.(%s)\n",jprint(retjson,0)); + return(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"get_rawmempool.(%s) error.(%s)\n",acname,retstr); + free(retstr); + } + return(0); +} + +cJSON *get_addressutxos(char *refcoin,char *acname,char *coinaddr) +{ + cJSON *retjson; char *retstr,jsonbuf[256]; + if ( refcoin[0] != 0 && strcmp(refcoin,"KMD") != 0 ) + printf("warning: assumes %s has addressindex enabled\n",refcoin); + sprintf(jsonbuf,"{\\\"addresses\\\":[\\\"%s\\\"]}",coinaddr); + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getaddressutxos",jsonbuf,"","","","","","")) != 0 ) + { + //printf("addressutxos.(%s)\n",jprint(retjson,0)); + return(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"get_addressutxos.(%s) error.(%s)\n",acname,retstr); + free(retstr); + } + return(0); +} + +cJSON *get_rawtransaction(char *refcoin,char *acname,bits256 txid) +{ + cJSON *retjson; char *retstr,str[65]; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getrawtransaction",bits256_str(str,txid),"1","","","","","")) != 0 ) + { + return(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"get_rawtransaction.(%s) %s error.(%s)\n",refcoin,acname,retstr); + free(retstr); + } + return(0); +} + +cJSON *get_z_viewtransaction(char *refcoin,char *acname,bits256 txid) +{ + cJSON *retjson; char *retstr,str[65]; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"z_viewtransaction",bits256_str(str,txid),"","","","","","")) != 0 ) + { + return(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"get_z_viewtransaction.(%s) %s error.(%s)\n",refcoin,acname,retstr); + free(retstr); + } + return(0); +} + +cJSON *get_listunspent(char *refcoin,char *acname) +{ + cJSON *retjson; char *retstr,str[65]; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"listunspent","","","","","","","")) != 0 ) + { + return(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"get_listunspent.(%s) %s error.(%s)\n",refcoin,acname,retstr); + free(retstr); + } + return(0); +} + +cJSON *get_getinfo(char *refcoin,char *acname) +{ + cJSON *retjson; char *retstr,str[65]; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getinfo","","","","","","","")) != 0 ) + { + return(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"get_getinfo.(%s) %s error.(%s)\n",refcoin,acname,retstr); + free(retstr); + } + return(0); +} + +cJSON *z_listunspent(char *refcoin,char *acname) +{ + cJSON *retjson; char *retstr,str[65]; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"z_listunspent","","","","","","","")) != 0 ) + { + return(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"z_listunspent.(%s) %s error.(%s)\n",refcoin,acname,retstr); + free(retstr); + } + return(0); +} + +cJSON *z_listoperationids(char *refcoin,char *acname) +{ + cJSON *retjson; char *retstr,str[65]; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"z_listoperationids","","","","","","","")) != 0 ) + { + return(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"z_listoperationids.(%s) %s error.(%s)\n",refcoin,acname,retstr); + free(retstr); + } + return(0); +} + +cJSON *z_getoperationstatus(char *refcoin,char *acname,char *opid) +{ + cJSON *retjson; char *retstr,str[65],params[512]; + sprintf(params,"'[\"%s\"]'",opid); + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"z_getoperationstatus",params,"","","","","","")) != 0 ) + { + //printf("got status (%s)\n",jprint(retjson,0)); + return(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"z_getoperationstatus.(%s) %s error.(%s)\n",refcoin,acname,retstr); + free(retstr); + } + return(0); +} + +cJSON *z_getoperationresult(char *refcoin,char *acname,char *opid) +{ + cJSON *retjson; char *retstr,str[65],params[512]; + sprintf(params,"'[\"%s\"]'",opid); + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"z_getoperationresult",params,"","","","","","")) != 0 ) + { + return(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"z_getoperationresult.(%s) %s error.(%s)\n",refcoin,acname,retstr); + free(retstr); + } + return(0); +} + +int32_t validateaddress(char *refcoin,char *acname,char *depositaddr, char* compare) +{ + cJSON *retjson; char *retstr; int32_t res=0; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"validateaddress",depositaddr,"","","","","","")) != 0 ) + { + if (is_cJSON_True(jobj(retjson,compare)) != 0 ) res=1; + free_json(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"validateaddress.(%s) %s error.(%s)\n",refcoin,acname,retstr); + free(retstr); + } + return (res); +} + +int32_t z_validateaddress(char *refcoin,char *acname,char *depositaddr, char *compare) +{ + cJSON *retjson; char *retstr; int32_t res=0; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"z_validateaddress",depositaddr,"","","","","","")) != 0 ) + { + if (is_cJSON_True(jobj(retjson,compare)) != 0 ) + res=1; + free_json(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"z_validateaddress.(%s) %s error.(%s)\n",refcoin,acname,retstr); + free(retstr); + } + return (res); +} + +int64_t get_getbalance(char *refcoin,char *acname) +{ + cJSON *retjson; char *retstr,cmpstr[64]; int64_t amount=0; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getbalance","","","","","","","")) != 0 ) + { + fprintf(stderr,"get_getbalance.(%s) %s returned json!\n",refcoin,acname); + free_json(retjson); + } + else if ( retstr != 0 ) + { + amount = atof(retstr) * SATOSHIDEN; + sprintf(cmpstr,"%.8f",dstr(amount)); + if ( strcmp(retstr,cmpstr) != 0 ) + amount++; + //printf("retstr %s -> %.8f\n",retstr,dstr(amount)); + free(retstr); + } + return (amount); +} + +int64_t z_getbalance(char *refcoin,char *acname,char *coinaddr) +{ + cJSON *retjson; char *retstr,cmpstr[64]; int64_t amount=0; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"z_getbalance",coinaddr,"","","","","","")) != 0 ) + { + fprintf(stderr,"z_getbalance.(%s) %s returned json!\n",refcoin,acname); + free_json(retjson); + } + else if ( retstr != 0 ) + { + amount = atof(retstr) * SATOSHIDEN; + sprintf(cmpstr,"%.8f",dstr(amount)); + if ( strcmp(retstr,cmpstr) != 0 ) + amount++; + //printf("retstr %s -> %.8f\n",retstr,dstr(amount)); + free(retstr); + } + return (amount); +} + +int32_t z_exportkey(char *privkey,char *refcoin,char *acname,char *zaddr) +{ + cJSON *retjson; char *retstr,cmpstr[64]; int64_t amount=0; + privkey[0] = 0; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"z_exportkey",zaddr,"","","","","","")) != 0 ) + { + fprintf(stderr,"z_exportkey.(%s) %s returned json!\n",refcoin,acname); + free_json(retjson); + return(-1); + } + else if ( retstr != 0 ) + { + //printf("retstr %s -> %.8f\n",retstr,dstr(amount)); + strcpy(privkey,retstr); + free(retstr); + return(0); + } + return(-1); +} + +int32_t getnewaddress(char *coinaddr,char *refcoin,char *acname) +{ + cJSON *retjson; char *retstr; int64_t amount=0; int32_t retval = -1; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getnewaddress","","","","","","","")) != 0 ) + { + fprintf(stderr,"getnewaddress.(%s) %s returned json!\n",refcoin,acname); + free_json(retjson); + } + else if ( retstr != 0 ) + { + strcpy(coinaddr,retstr); + free(retstr); + retval = 0; + } + return(retval); +} + +int32_t z_getnewaddress(char *coinaddr,char *refcoin,char *acname,char *typestr) +{ + cJSON *retjson; char *retstr; int64_t amount=0; int32_t retval = -1; + if ( (retjson= get_komodocli(refcoin,&retstr,acname,"z_getnewaddress",typestr,"","","","","","")) != 0 ) + { + fprintf(stderr,"z_getnewaddress.(%s) %s returned json!\n",refcoin,acname); + free_json(retjson); + } + else if ( retstr != 0 ) + { + strcpy(coinaddr,retstr); + free(retstr); + retval = 0; + } + return(retval); +} + +int64_t find_onetime_amount(char *coinstr,char *coinaddr) +{ + cJSON *array,*item; int32_t i,n; char *addr; int64_t amount = 0; + coinaddr[0] = 0; + if ( (array= get_listunspent(coinstr,"")) != 0 ) + { + //printf("got listunspent.(%s)\n",jprint(array,0)); + if ( (n= cJSON_GetArraySize(array)) > 0 ) + { + for (i=0; i 0 ) + { + for (i=0; i %s\n",coinstr,acname,srcaddr,params); + if ( (retjson= get_komodocli(coinstr,&retstr,acname,"z_sendmany",addr,params,"","","","","")) != 0 ) + { + printf("unexpected json z_sendmany.(%s)\n",jprint(retjson,0)); + free_json(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"z_sendmany.(%s) -> opid.(%s)\n",coinstr,retstr); + strcpy(opidstr,retstr); + free(retstr); + retval = 0; + } + return(retval); +} + +int32_t z_mergetoaddress(char *opidstr,char *coinstr,char *acname,char *destaddr) +{ + cJSON *retjson; char *retstr,addr[128],*opstr; int32_t retval = -1; + sprintf(addr,"[\\\"ANY_SPROUT\\\"]"); + if ( (retjson= get_komodocli(coinstr,&retstr,acname,"z_mergetoaddress",addr,destaddr,"","","","","")) != 0 ) + { + if ( (opstr= jstr(retjson,"opid")) != 0 ) + strcpy(opidstr,opstr); + retval = jint(retjson,"remainingNotes"); + fprintf(stderr,"%s\n",jprint(retjson,0)); + free_json(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"z_mergetoaddress.(%s) -> opid.(%s)\n",coinstr,retstr); + strcpy(opidstr,retstr); + free(retstr); + } + return(retval); +} + +int32_t empty_mempool(char *coinstr,char *acname) +{ + cJSON *array; int32_t n; + if ( (array= get_rawmempool(coinstr,acname)) != 0 ) + { + if ( (n= cJSON_GetArraySize(array)) > 0 ) + return(0); + free_json(array); + return(1); + } + return(-1); +} + +cJSON *getinputarray(int64_t *totalp,cJSON *unspents,int64_t required) +{ + cJSON *vin,*item,*vins = cJSON_CreateArray(); int32_t i,n,v; int64_t satoshis; bits256 txid; + *totalp = 0; + if ( (n= cJSON_GetArraySize(unspents)) > 0 ) + { + for (i=0; i= required ) + break; + } + } + } + return(vins); +} + +int32_t tx_has_voutaddress(char *refcoin,char *acname,bits256 txid,char *coinaddr) +{ + cJSON *txobj,*vouts,*vout,*vins,*vin,*sobj,*addresses; char *addr,str[65]; int32_t i,j,n,numarray,retval = 0, hasvout=0; + if ( (txobj= get_rawtransaction(refcoin,acname,txid)) != 0 ) + { + if ( (vouts= jarray(&numarray,txobj,"vout")) != 0 ) + { + for (i=0; i 0 ) + { + for (i=0; i 0 ) + { + for (j=0; j 0 && strcmp(vinaddr,cmpaddr) == 0 ) + return(0); + printf("mismatched vinaddr.(%s) vs %s\n",vinaddr,cmpaddr); + } + } + return(-1); +} + +int32_t txid_in_vins(char *refcoin,bits256 txid,bits256 cmptxid) +{ + cJSON *txjson,*vins,*vin; int32_t numvins,v,vinvout; bits256 vintxid; char str[65]; + if ( (txjson= get_rawtransaction(refcoin,"",txid)) != 0 ) + { + if ( (vins= jarray(&numvins,txjson,"vin")) != 0 ) + { + for (v=0; v n.%d retval.%d\n",tagA,tagB,pubkeystr,n,retval); + } + free_json(retjson); + } + return(retval); +} + +int32_t dpow_hasmessage(char *payload,char *tagA,char *tagB,char *pubkeystr) +{ + cJSON *retjson,*item,*array; char *retstr,*pstr; int32_t i,n,retval = 0; + if ( (retjson= get_komodocli((char *)"",&retstr,DEXP2P_CHAIN,"DEX_list","0","0",tagA,tagB,pubkeystr,"","")) != 0 ) + { + if ( (array= jarray(&n,retjson,"matches")) != 0 ) + { + for (i=0; i 0 ) + { + ptrs = calloc(n,sizeof(*ptrs)); + for (i=0; ishorthash = juint(item,"id"); + ptrs[m]->jsonstr = ptr; + strcpy(ptrs[m]->senderpub,senderpub); + m++; + } + } + } + *nump = m; + } + free_json(retjson); + } + return(ptrs); +} + + diff --git a/src/cc/dapps/subatomic.c b/src/cc/dapps/subatomic.c new file mode 100644 index 000000000..2f6ebf824 --- /dev/null +++ b/src/cc/dapps/subatomic.c @@ -0,0 +1,1429 @@ +/****************************************************************************** + * Copyright © 2014-2020 The SuperNET Developers. * + * * + * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * + * the top-level directory of this distribution for the individual copyright * + * holder information and the developer policies on copyright and licensing. * + * * + * Unless otherwise agreed in a custom licensing agreement, no part of the * + * SuperNET software, including this file may be copied, modified, propagated * + * or distributed except according to the terms contained in the LICENSE file * + * * + * Removal or modification of this copyright notice is prohibited. * + * * + ******************************************************************************/ + +// build subatomic and put in path: git pull; gcc cc/dapps/subatomic.c -lm -o subatomic; cp subatomic /usr/bin +// alice sends relcoin and gets basecoin + +#define DEXP2P_CHAIN ((char *)"DEX") +#define DEXP2P_PUBKEYS ((char *)"subatomic") +#include "dappinc.h" + +// for OTC mode, the following 4 functions are the only ones that should be needed to support a new "coin" +//int64_t subatomic_getbalance(char *coin); +//bits256 subatomic_coinpayment(int32_t OTCmode,char *coin,char *destaddr,uint64_t paytoshis,char *memostr); +//cJSON *subatomic_txidwait(char *coin,bits256 txid,char *hexstr,int32_t numseconds); +//int64_t subatomic_verifypayment(char *coin,cJSON *rawtx,uint64_t destsatoshis,char *destaddr); + +// TODO: +// address conversion +// new inventory types: +// anonsend + +// bob nodes: +// mutex for bob instances +// "deposits" messages and approved bobs +// volume caps per coin and non-notarized exposure + +// later: +// sharded storage + +#define SUBATOMIC_OTCDEFAULT 1 +#define SUBATOMIC_TIMEOUT 60 +#define SUBATOMIC_LOCKTIME 3600 +#define SUBATOMIC_TXFEE 10000 + +#define SUBATOMIC_PRIORITY 5 + +#define SUBATOMIC_OPENREQUEST 1 +#define SUBATOMIC_APPROVED 2 +#define SUBATOMIC_OPENED 3 +#define SUBATOMIC_PAYMENT 4 +#define SUBATOMIC_PAIDINFULL 5 +#define SUBATOMIC_CLOSED 6 + +cJSON *SUBATOMIC_json; +int32_t SUBATOMIC_retval = -1; + +struct abinfo +{ + char pubkey[67],recvaddr[64],recvZaddr[128],secp[67]; +}; + +struct coininfo +{ + uint64_t satoshis,txfee,maxamount; + char istoken,iszaddr,isfile,isexternal,tokenid[65],coin[16],name[16],cli[256],acname[16],coinstr[16]; +}; + +struct msginfo +{ + UT_hash_handle hh; + bits256 bobpayment,alicepayment; + double price; + uint64_t gotpayment; + uint32_t origid,openrequestid,approvalid,openedid,paymentids[100],paidid,closedid,locktime; + int32_t bobflag,status,OTCmode; + char payload[128],approval[128],senderpub[67],msigaddr[64],redeemscript[256]; + struct coininfo base,rel; + struct abinfo alice,bob; +} *Messages; + +uint64_t subatomic_txfee(char *coin) +{ + return(SUBATOMIC_TXFEE); +} + +char *subatomic_checkname(char *tmpstr,struct msginfo *mp,int32_t baserel,char *coin) +{ + int32_t i,n; cJSON *external,*item; char *coinstr,*clistr; struct coininfo *ptr; + ptr = (baserel == 0) ? &mp->base : &mp->rel; + if ( coin[0] == 0 ) + return(coin); + if ( (external= jarray(&n,SUBATOMIC_json,"externalcoins")) != 0 && n > 0 ) + { + for (i=0; icli) ) + { + ptr->isexternal = 1; + strcpy(ptr->cli,clistr); + //fprintf(stderr,"found external coin %s %s\n",coin,clistr); + } + } + } + if ( coin[0] == '#' ) + { + strcpy(ptr->coinstr,coin); + strcpy(ptr->acname,""); + ptr->isfile = 1; + return(coin); + } + else if ( coin[0] != 'z' ) + { + for (i=1; coin[i]!=0; i++) + if ( coin[i] == '.' ) + { + dpow_tokenregister(ptr->tokenid,0,coin,0); + if ( ptr->tokenid[0] != 0 ) + { + strcpy(tmpstr,coin); + tmpstr[i] = 0; + //fprintf(stderr,"found a tokenmap %s -> %s %s\n",coin,tmpstr,ptr->tokenid); + ptr->istoken = 1; + strcpy(ptr->acname,coin); + strcpy(ptr->coinstr,""); + return(tmpstr); + } + } + if ( ptr->isexternal == 0 ) + { + if ( strcmp(coin,"KMD") != 0 ) + { + strcpy(ptr->acname,coin); + strcpy(ptr->coinstr,""); + } + else + { + strcpy(ptr->coinstr,coin); + strcpy(ptr->acname,""); + } + } + else + { + strcpy(ptr->coinstr,coin); + strcpy(ptr->acname,""); + } + return(coin); + } + else + { + for (i=1; coin[i]!=0; i++) + if ( isupper(coin[i]) == 0 ) + return(coin); + if ( strcmp(coin+1,"KMD") != 0 ) + ptr->iszaddr = 1; + return(coin+1); + } +} + +int32_t subatomic_zonly(struct coininfo *coin) +{ + if ( strcmp(coin->coin,"PIRATE") == 0 ) + return(1); + else return(coin->iszaddr); +} + +// //////////////////////////////// the four key functions needed to support a new item for subatomics + +int64_t _subatomic_getbalance(struct coininfo *coin) +{ + cJSON *retjson; char *retstr,cmpstr[64]; int64_t amount=0; + if ( (retjson= subatomic_cli(coin->cli,&retstr,"getbalance","","","","","","","")) != 0 ) + { + fprintf(stderr,"_subatomic_getbalance.(%s) %s returned json!\n",coin->coinstr,coin->cli); + free_json(retjson); + } + else if ( retstr != 0 ) + { + amount = atof(retstr) * SATOSHIDEN; + sprintf(cmpstr,"%.8f",dstr(amount)); + if ( strcmp(retstr,cmpstr) != 0 ) + amount++; + //printf("retstr %s -> %.8f\n",retstr,dstr(amount)); + free(retstr); + } + return (amount); +} + +bits256 _subatomic_sendtoaddress(struct coininfo *coin,char *destaddr,int64_t satoshis) +{ + char numstr[32],*retstr,str[65]; cJSON *retjson; bits256 txid; + memset(txid.bytes,0,sizeof(txid)); + sprintf(numstr,"%.8f",(double)satoshis/SATOSHIDEN); + if ( (retjson= subatomic_cli(coin->cli,&retstr,"sendtoaddress",destaddr,numstr,"false","","","","")) != 0 ) + { + fprintf(stderr,"unexpected _subatomic_sendtoaddress json.(%s)\n",jprint(retjson,0)); + free_json(retjson); + } + else if ( retstr != 0 ) + { + if ( strlen(retstr) >= 64 ) + { + retstr[64] = 0; + decode_hex(txid.bytes,32,retstr); + } + fprintf(stderr,"_subatomic_sendtoaddress %s %.8f txid.(%s)\n",destaddr,(double)satoshis/SATOSHIDEN,bits256_str(str,txid)); + free(retstr); + } + return(txid); +} + +cJSON *_subatomic_rawtransaction(struct coininfo *coin,bits256 txid) +{ + cJSON *retjson; char *retstr,str[65]; + if ( (retjson= subatomic_cli(coin->cli,&retstr,"getrawtransaction",bits256_str(str,txid),"1","","","","","")) != 0 ) + { + return(retjson); + } + else if ( retstr != 0 ) + { + fprintf(stderr,"_subatomic_rawtransaction.(%s) %s error.(%s)\n",coin->coin,coin->name,retstr); + free(retstr); + } + return(0); +} + +int64_t subatomic_getbalance(struct coininfo *coin) +{ + char *coinstr,*acname=""; FILE *fp; int64_t retval = 0; + if ( strcmp(coin->coin,"KMD") != 0 ) + { + acname = coin->coin; + coinstr = ""; + } else coinstr = coin->coin; + if ( coin->isfile != 0 ) + { + if ( (fp= fopen(coin->name+1,"rb")) != 0 ) // if alice, add bob pubkey to fname + { + fclose(fp); + retval = SATOSHIDEN; + } + return(retval); + } + else if ( subatomic_zonly(coin) != 0 ) + return(z_getbalance(coinstr,acname,DPOW_recvZaddr)); + else + { + if ( coin->istoken != 0 ) + { + if ( get_getbalance(coinstr,acname) < SUBATOMIC_TXFEE ) + { + fprintf(stderr,"not enough balance to send token\n"); + return(0); + } + //fprintf(stderr,"token balance %s\n",coin->tokenid); + return(get_tokenbalance(coinstr,acname,coin->tokenid) * SATOSHIDEN); + } + else if ( coin->isexternal == 0 ) + return(get_getbalance(coinstr,acname)); + else return(_subatomic_getbalance(coin)); + } +} + +bits256 subatomic_coinpayment(uint32_t origid,int32_t OTCmode,struct coininfo *coin,char *destaddr,uint64_t paytoshis,char *memostr,char *destpub,char *senderpub) +{ + bits256 txid; char opidstr[128],opretstr[32],str[65],*status,*coinstr,*acname=""; cJSON *retjson,*retjson2,*item,*res; int32_t i,pending=0; + memset(&txid,0,sizeof(txid)); + if ( OTCmode == 0 ) + { + fprintf(stderr,"micropayment channels are not supported yet\n"); + return(txid); + } + if ( coin->isfile != 0 ) + { + fprintf(stderr,"start broadcast of (%s)\n",coin->coin+1); + if ( (retjson= dpow_publish(SUBATOMIC_PRIORITY,coin->coin+1)) != 0 ) // spawn thread + { + sprintf(opretstr,"%08x",juint(retjson,"id")); + sprintf(opidstr,"%u",origid); + if ( (retjson2= dpow_broadcast(SUBATOMIC_PRIORITY,opretstr,"inbox",opidstr,senderpub,"","")) != 0 ) + free_json(retjson2); + fprintf(stderr,"broadcast file.(%s) and send id.%u to alice (%s)\n",coin->coin+1,juint(retjson,"id"),jprint(retjson,0)); + txid = jbits256(retjson,"filehash"); + free_json(retjson); + } + fprintf(stderr,"end broadcast of (%s) to %s\n",coin->coin+1,senderpub); + return(txid); + } + else if ( subatomic_zonly(coin) != 0 ) + { + if ( memostr[0] == 0 ) + memostr = "beef"; + z_sendmany(opidstr,"",coin->coin,DPOW_recvZaddr,destaddr,paytoshis,memostr); + for (i=0; icoin,opidstr)) != 0 ) + { + item = jitem(retjson,0); + if ( (status= jstr(item,"status")) != 0 ) + { + if ( strcmp(status,"executing") == 0 ) + pending++; + else + { + res = jobj(item,"result"); + txid = jbits256(res,"txid"); + //fprintf(stderr,"got Ztx txid.%s\n",bits256_str(str,txid)); + free_json(retjson); + break; + } + /*else if ( clearresults != 0 ) + { + if ( (result= z_getoperationresult(coinstr,"",jstri(array,i))) != 0 ) + { + free_json(result); + } + }*/ + } + free_json(retjson); + } + sleep(1); + } + if ( i == 60 ) + printf("%u timed out waiting for opid to finish\n",origid); + } + else + { + if ( strcmp(coin->coin,"KMD") != 0 ) + { + acname = coin->coin; + coinstr = ""; + } else coinstr = coin->coin; + if ( coin->istoken != 0 ) + txid = tokentransfer(coinstr,acname,coin->tokenid,destpub,paytoshis/SATOSHIDEN); + else if ( coin->isexternal == 0 ) + { + sprintf(opretstr,"%08x",origid); + txid = sendtoaddress(coinstr,acname,destaddr,paytoshis,opretstr); + } else txid = _subatomic_sendtoaddress(coin,destaddr,paytoshis); + printf("%u got txid.%s\n",origid,bits256_str(str,txid)); + } + return(txid); +} + +cJSON *subatomic_txidwait(struct coininfo *coin,bits256 txid,char *hexstr,int32_t numseconds,char *senderpub) +{ + int32_t i,zflag; char *coinstr,str[65],*acname=""; cJSON *rawtx; bits256 z; bits256 filehash; + memset(&z,0,sizeof(z)); + if ( memcmp(&z,&txid,sizeof(txid)) == 0 ) + return(0); + if ( hexstr != 0 && hexstr[0] != 0 ) // probably not worth doing and zaddr is a problem to decode + { + // compare against txid + // if matches, sendrawtransaction if OTC mode, decoode and return if channels mode + } + zflag = (subatomic_zonly(coin) != 0); + if ( strcmp(coin->coin,"KMD") != 0 ) + { + acname = coin->coin; + coinstr = ""; + } else coinstr = coin->coin; + for (i=0; iisfile != 0 ) + { + if ( (rawtx= dpow_subscribe(SUBATOMIC_PRIORITY,coin->coin+1,senderpub)) != 0 ) + { + filehash = jbits256(rawtx,"filehash"); + if ( memcmp(&filehash,&txid,sizeof(filehash)) != 0 ) + { + fprintf(stderr,"waiting (%s) (%s)\n",coin->coin+1,jprint(rawtx,0)); + free_json(rawtx); + rawtx = 0; + } else return(rawtx); + } + } + else if ( zflag != 0 ) + rawtx = get_z_viewtransaction(coinstr,acname,txid); + else if ( coin->isexternal == 0 ) + rawtx = get_rawtransaction(coinstr,acname,txid); + else rawtx = _subatomic_rawtransaction(coin,txid); + if ( rawtx != 0 ) + return(rawtx); + sleep(1); + } + printf("%s/%s timeout waiting for %s\n",coin->name,coin->coin,bits256_str(str,txid)); + return(0); +} + +int64_t subatomic_verifypayment(struct coininfo *coin,cJSON *rawtx,uint64_t destsatoshis,char *destaddr,bits256 txid) +{ + int32_t i,n,m,valid=0; bits256 tokenid,filehash,checkhash; cJSON *array,*item,*sobj,*a; char *addr,*acname,*coinstr,tokenaddr[64],*hex; uint8_t hexbuf[512],pub33[33]; uint64_t netval,recvsatoshis = 0; + if ( coin->isfile != 0 ) + { + filehash = jbits256(rawtx,"filehash"); + checkhash = jbits256(rawtx,"checkhash"); + if ( memcmp(&txid,&filehash,sizeof(txid)) == 0 && memcmp(&txid,&checkhash,sizeof(txid)) == 0 ) + { + fprintf(stderr,"verified file is matching the filehash (%s)\n",jprint(rawtx,0)); + return(SATOSHIDEN); + } else return(0); + } + else if ( subatomic_zonly(coin) != 0 ) + { + if ( (array= jarray(&n,rawtx,"outputs")) != 0 && n > 0 ) + { + for (i=0; iistoken != 0 ) + { + if ( (array= jarray(&n,rawtx,"vout")) != 0 && n > 0 ) + { + item = jitem(array,0); + if ( (sobj= jobj(item,"scriptPubKey")) != 0 && (a= jarray(&m,sobj,"addresses")) != 0 && m == 1 ) + { + if ( strcmp(coin->coin,"KMD") != 0 ) + { + acname = coin->coin; + coinstr = ""; + } else coinstr = coin->coin; + if ( get_tokenaddress(coinstr,acname,tokenaddr) != 0 ) + { + //fprintf(stderr,"tokenaddr.%s\n",tokenaddr); + if ( (addr= jstri(a,0)) != 0 && strcmp(addr,tokenaddr) == 0 ) + recvsatoshis += SATOSHIDEN * (uint64_t)(jdouble(item,"value")*SATOSHIDEN + 0.000000004999); + else fprintf(stderr,"miscompare (%s) vs %s\n",jprint(sobj,0),addr); + } + } + item = jitem(array,n-1); + if ( (sobj= jobj(item,"scriptPubKey")) != 0 && (hex= jstr(sobj,"hex")) != 0 && (m= is_hexstr(hex,0)) > 1 && m/2 < sizeof(hexbuf) ) + { + m >>= 1; + decode_hex(hexbuf,m,hex); + decode_hex(tokenid.bytes,32,coin->tokenid); + decode_hex(pub33,33,DPOW_secpkeystr); + // opret 69len EVAL_TOKENS 't' tokenid 1 33 pub33 + if ( hexbuf[0] == 0x6a && hexbuf[1] == 0x45 && hexbuf[2] == 0xf2 && hexbuf[3] == 't' && memcmp(&hexbuf[4],&tokenid,sizeof(tokenid)) == 0 && hexbuf[4+32] == 1 && hexbuf[4+32+1] == 33 && memcmp(&hexbuf[4+32+2],pub33,33) == 0 ) + { + valid = 1; + //fprintf(stderr,"validated it is a token transfer!\n"); + } else fprintf(stderr,"need to validate tokentransfer.(%s) %s %d\n",hex,DPOW_secpkeystr,memcmp(&hexbuf[4+32+2],pub33,33) == 0); + //6a 45 f2 74 2b1feef719ecb526b07416dd432bce603ac6dc8bfe794cddf105cb52f6aae3cd 01 21 02b27de3ee5335518b06f69f4fbabb029cfc737613b100996841d5532b324a5a61 + + } + recvsatoshis *= valid; + } + } + else + { + if ( (array= jarray(&n,rawtx,"vout")) != 0 && n > 0 ) + { + for (i=0; iorigid = origid; + HASH_ADD(hh,Messages,origid,sizeof(origid),mp); + return(mp); +} + +int32_t subatomic_status(struct msginfo *mp,int32_t status) +{ + static FILE *fp; + if ( fp == 0 ) + { + int32_t i,oid,s,n,num,count; struct msginfo *m; long fsize; + if ( (fp= fopen("SUBATOMIC.DB","rb+")) == 0 ) + { + if ( (fp= fopen("SUBATOMIC.DB","wb")) == 0 ) + { + fprintf(stderr,"cant create SUBATOMIC.DB\n"); + exit(-1); + } + } + else + { + fseek(fp,0,SEEK_END); + fsize = ftell(fp); + if ( (fsize % (sizeof(uint32_t)*2)) != 0 ) + { + fprintf(stderr,"SUBATOMIC.DB illegal filesize.%ld\n",fsize); + exit(-1); + } + n = (int32_t)(fsize / (sizeof(uint32_t)*2)); + rewind(fp); + for (i=num=count=0; i SUBATOMIC_CLOSED ) + { + fprintf(stderr,"SUBATOMIC.DB corrupted at filepos.%ld: illegal status.%d\n",ftell(fp),s); + exit(-1); + } + //fprintf(stderr,"%u <- %d\n",oid,s); + if ( (m= subatomic_find(oid)) == 0 ) + { + m = subatomic_add(oid); + count++; + } + if ( s > m->status ) + { + m->status = s; + num++; + } + } + fprintf(stderr,"initialized %d messages, updated %d out of total.%d\n",count,num,n); + } + } + if ( mp->status >= status ) + return(-1); + if ( fwrite(&mp->origid,1,sizeof(mp->origid),fp) != sizeof(mp->origid) || fwrite(&status,1,sizeof(status),fp) != sizeof(status) ) + fprintf(stderr,"error updating SUBATOMIC.DB, risk of double spends\n"); + fflush(fp); + mp->status = status; + return(0); +} + +struct msginfo *subatomic_tracker(uint32_t origid) +{ + struct msginfo *mp; + if ( (mp= subatomic_find(origid)) == 0 ) + { + mp = subatomic_add(origid); + subatomic_status(mp,0); + } + return(mp); +} + +char *subatomic_hexstr(char *jsonstr) +{ + char *hexstr; int32_t i,c,n = (int32_t)strlen(jsonstr); + hexstr = malloc(2*n + 3); + strcpy(hexstr,jsonstr); + for (i=0; iorigid); + jaddnum(item,"price",mp->price); + jaddnum(item,"openrequest",mp->openrequestid); + jaddstr(item,"base",mp->base.name); + jaddstr(item,"basecoin",mp->base.coin); + jadd64bits(item,"basesatoshis",mp->base.satoshis); + jadd64bits(item,"basetxfee",mp->base.txfee); + jadd64bits(item,"maxbaseamount",mp->base.maxamount); + jaddstr(item,"rel",mp->rel.name); + jaddstr(item,"relcoin",mp->rel.coin); + jadd64bits(item,"relsatoshis",mp->rel.satoshis); + jadd64bits(item,"reltxfee",mp->rel.txfee); + jadd64bits(item,"maxrelamount",mp->rel.maxamount); + jaddstr(item,"alice",mp->alice.pubkey); + jaddstr(item,"alicesecp",mp->alice.secp); + jaddstr(item,"bob",mp->bob.pubkey); + jaddstr(item,"bobsecp",mp->bob.secp); + if ( subatomic_zonly(&mp->rel) != 0 ) + jaddstr(item,"bobZaddr",mp->bob.recvZaddr); + else jaddstr(item,"bobaddr",mp->bob.recvaddr); + if ( mp->rel.istoken != 0 ) + jaddstr(item,"bobtoken",mp->rel.tokenid); + if ( subatomic_zonly(&mp->base) != 0 ) + jaddstr(item,"aliceZaddr",mp->alice.recvZaddr); + else jaddstr(item,"aliceaddr",mp->alice.recvaddr); + if ( mp->base.istoken != 0 ) + jaddstr(item,"alicetoken",mp->base.tokenid); + return(item); +} + +uint64_t subatomic_orderbook_mpset(struct msginfo *mp,char *basecheck) +{ + cJSON *retjson; char *tagA,*tagB,*senderpub,*str,tmpstr[32]; int32_t matches=0; double volA,volB; int64_t txfee=0; + strcpy(mp->base.name,basecheck); + strcpy(mp->base.coin,subatomic_checkname(tmpstr,mp,0,basecheck)); + mp->rel.txfee = subatomic_txfee(mp->rel.coin); + if ( (retjson= dpow_get(mp->origid)) != 0 ) + { + //fprintf(stderr,"dpow_get.(%s) (%s/%s)\n",jprint(retjson,0),mp->base.coin,mp->rel.coin); + if ( (senderpub= jstr(retjson,"senderpub")) != 0 && is_hexstr(senderpub,0) == 66 && (tagA= jstr(retjson,"tagA")) != 0 && (tagB= jstr(retjson,"tagB")) != 0 && strncmp(tagB,mp->rel.name,strlen(mp->rel.name)) == 0 && strlen(tagA) < sizeof(mp->base.name) ) + { + strcpy(mp->base.name,tagA); + strcpy(mp->base.coin,subatomic_checkname(tmpstr,mp,0,tagA)); + if ( basecheck[0] == 0 || strncmp(basecheck,tagA,strlen(basecheck)) == 0 ) + matches = 1; + else if ( strcmp(tagA,mp->base.name) == 0 ) + matches = 1; + else if ( mp->bobflag != 0 && tagA[0] == '#' && strcmp(mp->base.name,"#allfiles") == 0 ) + matches = 1; + if ( matches != 0 ) + { + if ( (str= jstr(retjson,"decrypted")) != 0 && strlen(str) < 128 ) + strcpy(mp->payload,str); + mp->locktime = juint(retjson,"timestamp") + SUBATOMIC_LOCKTIME; + mp->base.txfee = subatomic_txfee(mp->base.coin); + strcpy(mp->senderpub,senderpub); + volB = jdouble(retjson,"amountB"); + volA = jdouble(retjson,"amountA"); + mp->base.maxamount = volA*SATOSHIDEN + 0.0000000049999; + mp->rel.maxamount = volB*SATOSHIDEN + 0.0000000049999; + if ( 0 && mp->rel.istoken == 0 ) + txfee = mp->rel.txfee; + if ( mp->base.maxamount != 0 && mp->rel.maxamount != 0 && volA > SMALLVAL && volB > SMALLVAL && mp->rel.satoshis <= mp->rel.maxamount ) + { + mp->price = volA / volB; + mp->base.satoshis = (mp->rel.satoshis - txfee) * mp->price; + //fprintf(stderr,"base satoshis.%llu\n",(long long)mp->base.satoshis); + } else fprintf(stderr,"%u rel %llu vs (%llu %llu)\n",mp->origid,(long long)mp->rel.satoshis,(long long)mp->base.maxamount,(long long)mp->rel.maxamount); + } else printf("%u didnt match (%s) tagA.%s %s, tagB.%s %s %d %d\n",mp->origid,basecheck,tagA,mp->base.name,tagB,mp->rel.name,tagA[0] == '#', strcmp(mp->base.name,"#allfiles") == 0); + } else printf("%u didnt compare tagA.%s %s, tagB.%s %s\n",mp->origid,tagA,mp->base.name,tagB,mp->rel.name); + free_json(retjson); + } + return(mp->base.satoshis); +} + +char *randhashstr(char *str) +{ + bits256 rands; int32_t i; + for (i=0; i<32; i++) + rands.bytes[i] = rand() >> 17; + bits256_str(str,rands); + return(str); +} + +void subatomic_extrafields(cJSON *dest,cJSON *src) +{ + char *str; + if ( (str= jstr(src,"approval")) != 0 ) + jaddstr(dest,"approval",str); + if ( (str= jstr(src,"opened")) != 0 ) + jaddstr(dest,"opened",str); + if ( (str= jstr(src,"payamount")) != 0 ) + jaddstr(dest,"payamount",str); + if ( (str= jstr(src,"destaddr")) != 0 ) + jaddstr(dest,"destaddr",str); + if ( (str= jstr(src,"bobpayment")) != 0 ) + jaddstr(dest,"bobpayment",str); + if ( (str= jstr(src,"alicepayment")) != 0 ) + jaddstr(dest,"alicepayment",str); + if ( (str= jstr(src,"bobaddr")) != 0 ) + jaddstr(dest,"bobaddr",str); + if ( (str= jstr(src,"bobZaddr")) != 0 ) + jaddstr(dest,"bobZaddr",str); + if ( (str= jstr(src,"aliceaddr")) != 0 ) + jaddstr(dest,"aliceaddr",str); + if ( (str= jstr(src,"aliceZaddr")) != 0 ) + jaddstr(dest,"aliceZaddr",str); + if ( (str= jstr(src,"alicetoken")) != 0 ) + jaddstr(dest,"alicetoken",str); + if ( (str= jstr(src,"bobtoken")) != 0 ) + jaddstr(dest,"bobtoken",str); +} + +char *subatomic_submit(cJSON *argjson,int32_t tobob) +{ + char *jsonstr,*hexstr; + jaddnum(argjson,"tobob",tobob != 0); + jsonstr = jprint(argjson,1); + hexstr = subatomic_hexstr(jsonstr); + free(jsonstr); + return(hexstr); +} + +#define SCRIPT_OP_IF 0x63 +#define SCRIPT_OP_ELSE 0x67 +#define SCRIPT_OP_DUP 0x76 +#define SCRIPT_OP_ENDIF 0x68 +#define SCRIPT_OP_TRUE 0x51 +#define SCRIPT_OP_2 0x52 +#define SCRIPT_OP_3 0x53 +#define SCRIPT_OP_DROP 0x75 +#define SCRIPT_OP_EQUALVERIFY 0x88 +#define SCRIPT_OP_HASH160 0xa9 +#define SCRIPT_OP_EQUAL 0x87 +#define SCRIPT_OP_CHECKSIG 0xac +#define SCRIPT_OP_CHECKMULTISIG 0xae +#define SCRIPT_OP_CHECKMULTISIGVERIFY 0xaf +#define SCRIPT_OP_CHECKLOCKTIMEVERIFY 0xb1 + +int32_t subatomic_redeemscript(char *redeemscript,uint32_t locktime,char *pubkeyA,char *pubkeyB) // not needed +{ + // if ( refund ) OP_HASH160 <2of2 multisig hash> OP_EQUAL // standard multisig + // else CLTV OP_DROP OP_CHECKSIG // standard spend + uint8_t pubkeyAbytes[33],pubkeyBbytes[33],hex[4096]; int32_t i,n = 0; + decode_hex(pubkeyAbytes,33,pubkeyA); + decode_hex(pubkeyBbytes,33,pubkeyB); + hex[n++] = SCRIPT_OP_IF; + hex[n++] = SCRIPT_OP_2; + hex[n++] = 33, memcpy(&hex[n],pubkeyAbytes,33), n += 33; + hex[n++] = 33, memcpy(&hex[n],pubkeyBbytes,33), n += 33; + hex[n++] = SCRIPT_OP_2; + hex[n++] = SCRIPT_OP_CHECKMULTISIG; + hex[n++] = SCRIPT_OP_ELSE; + hex[n++] = 4; + hex[n++] = locktime & 0xff, locktime >>= 8; + hex[n++] = locktime & 0xff, locktime >>= 8; + hex[n++] = locktime & 0xff, locktime >>= 8; + hex[n++] = locktime & 0xff; + hex[n++] = SCRIPT_OP_CHECKLOCKTIMEVERIFY; + hex[n++] = SCRIPT_OP_DROP; + hex[n++] = 33; memcpy(&hex[n],pubkeyAbytes,33); n += 33; + hex[n++] = SCRIPT_OP_CHECKSIG; + hex[n++] = SCRIPT_OP_ENDIF; + for (i=0; i>4) & 0xf); + redeemscript[i*2 + 1] = hexbyte(hex[i] & 0xf); + } + redeemscript[n*2] = 0; + /*tmpbuf[0] = SCRIPT_OP_HASH160; + tmpbuf[1] = 20; + calc_OP_HASH160(scriptPubKey,tmpbuf+2,redeemscript); + tmpbuf[22] = SCRIPT_OP_EQUAL; + init_hexbytes_noT(scriptPubKey,tmpbuf,23); + if ( p2shaddr != 0 ) + { + p2shaddr[0] = 0; + if ( (btc_addr= base58_encode_check(addrtype,true,tmpbuf+2,20)) != 0 ) + { + if ( strlen(btc_addr->str) < 36 ) + strcpy(p2shaddr,btc_addr->str); + cstr_free(btc_addr,true); + } + }*/ + return(n); +} + +int32_t subatomic_approved(struct msginfo *mp,cJSON *approval,cJSON *msgjson,char *senderpub) +{ + char *hexstr,numstr[32],redeemscript[1024],*coin,*acname=""; cJSON *retjson,*decodejson; int32_t i,retval = 0; + subatomic_extrafields(approval,msgjson); + if ( mp->OTCmode == 0 ) + { + coin = (mp->bobflag != 0) ? mp->base.coin : mp->rel.coin; // the other side gets this coin + if ( strcmp(coin,"KMD") != 0 ) + { + acname = coin; + coin = ""; + } + if ( get_createmultisig2(coin,acname,mp->msigaddr,mp->redeemscript,mp->alice.secp,mp->bob.secp) != 0 ) + { + subatomic_redeemscript(redeemscript,mp->locktime,mp->alice.secp,mp->bob.secp); + if ( (decodejson= get_decodescript(coin,acname,redeemscript)) != 0 ) + { + fprintf(stderr,"%s %s msigaddr.%s %s -> %s %s\n",mp->bobflag!=0?"bob":"alice",(mp->bobflag != 0) ? mp->base.coin : mp->rel.coin,mp->msigaddr,mp->redeemscript,redeemscript,jprint(decodejson,0)); + free(decodejson); + } + } + } + sprintf(numstr,"%u",mp->origid); + for (i=0; numstr[i]!=0; i++) + sprintf(&mp->approval[i<<1],"%02x",numstr[i]); + sprintf(&mp->approval[i<<1],"%02x",' '); + i++; + mp->approval[i<<1] = 0; + jaddstr(approval,"approval",mp->approval); + hexstr = subatomic_submit(approval,!mp->bobflag); + if ( (retjson= dpow_broadcast(SUBATOMIC_PRIORITY,hexstr,(char *)"inbox",(char *)"approved",senderpub,"","")) != 0 ) + { + if ( (mp->approvalid= juint(retjson,"id")) != 0 ) + retval = 1; + printf("%u approvalid.%u (%s)\n",mp->origid,mp->approvalid,senderpub); + subatomic_status(mp,SUBATOMIC_APPROVED); + free_json(retjson); + } + free(hexstr); + return(retval); +} + +int32_t subatomic_opened(struct msginfo *mp,cJSON *opened,cJSON *msgjson,char *senderpub) +{ + char *hexstr,channelstr[65]; cJSON *retjson; int32_t retval = 0; + subatomic_extrafields(opened,msgjson); + jaddstr(opened,"opened",randhashstr(channelstr)); + hexstr = subatomic_submit(opened,!mp->bobflag); + if ( (retjson= dpow_broadcast(SUBATOMIC_PRIORITY,hexstr,(char *)"inbox",(char *)"opened",senderpub,"","")) != 0 ) + { + if ( (mp->openedid= juint(retjson,"id")) != 0 ) + retval = 1; + printf("%u openedid.%u\n",mp->origid,mp->openedid); + subatomic_status(mp,SUBATOMIC_OPENED); + free_json(retjson); + } + free(hexstr); + return(retval); +} + +int32_t subatomic_payment(struct msginfo *mp,cJSON *payment,cJSON *msgjson,char *senderpub) +{ + bits256 txid; uint64_t paytoshis; cJSON *retjson; char numstr[32],*coin,*dest,*hexstr; int32_t retval = 0; + if ( mp->bobflag == 0 ) + { + coin = mp->rel.name; + paytoshis = mp->rel.satoshis; + if ( subatomic_zonly(&mp->rel) != 0 ) + dest = mp->bob.recvZaddr; + else dest = mp->bob.recvaddr; + sprintf(numstr,"%llu",(long long)paytoshis); + jaddstr(payment,"alicepays",numstr); + jaddstr(payment,"bobdestaddr",dest); + txid = subatomic_coinpayment(mp->origid,mp->OTCmode,&mp->rel,dest,paytoshis,mp->approval,mp->bob.secp,senderpub); + jaddbits256(payment,"alicepayment",txid); + mp->alicepayment = txid; + hexstr = 0; // get it from rawtransaction of txid + jaddstr(payment,"alicetx",hexstr); + } + else + { + coin = mp->base.name; + paytoshis = mp->base.satoshis; + if ( subatomic_zonly(&mp->base) != 0 ) + dest = mp->alice.recvZaddr; + else dest = mp->alice.recvaddr; + sprintf(numstr,"%llu",(long long)paytoshis); + jaddstr(payment,"bobpays",numstr); + jaddstr(payment,"alicedestaddr",dest); + txid = subatomic_coinpayment(mp->origid,mp->OTCmode,&mp->base,dest,paytoshis,mp->approval,mp->alice.secp,senderpub); + jaddbits256(payment,"bobpayment",txid); + mp->bobpayment = txid; + hexstr = 0; // get it from rawtransaction of txid + jaddstr(payment,"bobtx",hexstr); + } + hexstr = subatomic_submit(payment,!mp->bobflag); + if ( (retjson= dpow_broadcast(SUBATOMIC_PRIORITY,hexstr,(char *)"inbox",(char *)"payment",senderpub,"","")) != 0 ) + { + if ( (mp->paymentids[0]= juint(retjson,"id")) != 0 ) + retval = 1; + printf("%u: %.8f %s -> %s, paymentid[0] %u\n",mp->origid,dstr(paytoshis),coin,dest,mp->paymentids[0]); + subatomic_status(mp,SUBATOMIC_PAYMENT); + free_json(retjson); + } + free(hexstr); + return(retval); +} + +int32_t subatomic_paidinfull(struct msginfo *mp,cJSON *paid,cJSON *msgjson,char *senderpub) +{ + char *hexstr; cJSON *retjson; int32_t retval = 0; + jaddstr(paid,"paid","in full"); + subatomic_extrafields(paid,msgjson); + hexstr = subatomic_submit(paid,!mp->bobflag); + if ( (retjson= dpow_broadcast(SUBATOMIC_PRIORITY,hexstr,(char *)"inbox",(char *)"paid",senderpub,"","")) != 0 ) + { + if ( (mp->paidid= juint(retjson,"id")) != 0 ) + retval = 1; + printf("%u paidid.%u\n",mp->origid,mp->paidid); + subatomic_status(mp,SUBATOMIC_PAIDINFULL); + free_json(retjson); + } + free(hexstr); + return(retval); +} + +int32_t subatomic_closed(struct msginfo *mp,cJSON *closed,cJSON *msgjson,char *senderpub) +{ + char *hexstr; cJSON *retjson; int32_t retval = 0; + jaddnum(closed,"closed",mp->origid); + subatomic_extrafields(closed,msgjson); + hexstr = subatomic_submit(closed,!mp->bobflag); + if ( (retjson= dpow_broadcast(SUBATOMIC_PRIORITY,hexstr,(char *)"inbox",(char *)"closed",senderpub,"","")) != 0 ) + { + if ( (mp->closedid= juint(retjson,"id")) != 0 ) + retval = 1; + subatomic_status(mp,SUBATOMIC_CLOSED); + printf("%u closedid.%u\n",mp->origid,mp->closedid); + free_json(retjson); + } + free(hexstr); + return(retval); +} + +uint32_t subatomic_alice_openrequest(struct msginfo *origmp) +{ + struct msginfo *mp; cJSON *retjson,*openrequest; char *hexstr,*str,tmpstr[32]; + mp = subatomic_tracker(origmp->origid); + mp->origid = origmp->origid; + mp->rel.satoshis = origmp->rel.satoshis; + mp->rel.istoken = origmp->rel.istoken; + strcpy(mp->rel.tokenid,origmp->rel.tokenid); + strcpy(mp->rel.name,origmp->rel.name); + strcpy(mp->rel.coin,subatomic_checkname(tmpstr,mp,1,origmp->rel.name)); + strcpy(mp->alice.pubkey,DPOW_pubkeystr); + strcpy(mp->alice.secp,DPOW_secpkeystr); + strcpy(mp->alice.recvZaddr,DPOW_recvZaddr); + strcpy(mp->alice.recvaddr,DPOW_recvaddr); + printf("rel.%s/%s %s openrequest %u status.%d (%s/%s)\n",mp->rel.name,mp->rel.coin,mp->rel.tokenid,mp->origid,mp->status,mp->alice.recvaddr,mp->alice.recvZaddr); + if ( mp->status == 0 && subatomic_orderbook_mpset(mp,"") != 0 ) + { + strcpy(mp->bob.pubkey,mp->senderpub); + if ( subatomic_zonly(&mp->base) != 0 || subatomic_zonly(&mp->rel) != 0 ) + mp->OTCmode = 1; + else mp->OTCmode = SUBATOMIC_OTCDEFAULT; + strcpy(origmp->base.name,mp->base.name); + strcpy(origmp->base.coin,mp->base.coin); + origmp->base.istoken = mp->base.istoken; + strcpy(origmp->base.tokenid,mp->base.tokenid); + origmp->OTCmode = mp->OTCmode; + if ( mp->rel.istoken != 0 && ((mp->rel.satoshis % SATOSHIDEN) != 0 || mp->rel.iszaddr != 0) ) + { + printf("%u cant do zaddr or fractional rel %s.%s tokens %.8f\n",mp->origid,mp->rel.coin,mp->rel.tokenid,dstr(mp->rel.satoshis)); + return(0); + } + else if ( mp->base.istoken != 0 && ((mp->base.satoshis % SATOSHIDEN) != 0 || mp->base.iszaddr != 0 ) ) + { + printf("%u cant do zaddr or fractional base %s.%s tokens %.8f\n",mp->origid,mp->base.coin,mp->base.tokenid,dstr(mp->base.satoshis)); + return(0); + } + else if ( (openrequest= subatomic_mpjson(mp)) != 0 ) + { + hexstr = subatomic_submit(openrequest,!mp->bobflag); + if ( (retjson= dpow_broadcast(SUBATOMIC_PRIORITY,hexstr,(char *)"inbox",(char *)"openrequest",mp->bob.pubkey,"","")) != 0 ) + { + mp->openrequestid = juint(retjson,"id"); + printf("%u openrequest.%u -> (%s)\n",mp->origid,mp->openrequestid,mp->bob.pubkey); + subatomic_status(mp,SUBATOMIC_OPENREQUEST); + free_json(retjson); + } + free(hexstr); + } + } + return(mp->openrequestid); +} + +void subatomic_bob_gotopenrequest(uint32_t inboxid,char *senderpub,cJSON *msgjson,char *basename,char *relname) +{ + struct msginfo *mp; cJSON *approval; int32_t origid; char *addr,tmpstr[32],*coin,*acname=""; + origid = juint(msgjson,"origid"); + mp = subatomic_tracker(origid); + strcpy(mp->base.name,basename); + strcpy(mp->base.coin,subatomic_checkname(tmpstr,mp,0,basename)); + strcpy(mp->rel.name,relname); + strcpy(mp->rel.coin,subatomic_checkname(tmpstr,mp,1,relname)); + mp->origid = origid; + mp->rel.satoshis = j64bits(msgjson,"relsatoshis"); + mp->bobflag = 1; + strcpy(mp->bob.pubkey,DPOW_pubkeystr); + strcpy(mp->bob.secp,DPOW_secpkeystr); + strcpy(mp->bob.recvZaddr,DPOW_recvZaddr); + strcpy(mp->bob.recvaddr,DPOW_recvaddr); + if ( (addr= jstr(msgjson,"aliceaddr")) != 0 ) + strcpy(mp->alice.recvaddr,addr); + if ( (addr= jstr(msgjson,"aliceZaddr")) != 0 ) + strcpy(mp->alice.recvZaddr,addr); + if ( (addr= jstr(msgjson,"alicesecp")) != 0 ) + strcpy(mp->alice.secp,addr); + if ( subatomic_zonly(&mp->base) != 0 || subatomic_zonly(&mp->rel) != 0 ) + mp->OTCmode = 1; + else mp->OTCmode = SUBATOMIC_OTCDEFAULT; + printf("%u got open request\n",mp->origid); + if ( mp->status == 0 && subatomic_orderbook_mpset(mp,basename) != 0 && (approval= subatomic_mpjson(mp)) != 0 ) + { + if ( mp->rel.istoken != 0 && ((mp->rel.satoshis % SATOSHIDEN) != 0 || mp->rel.iszaddr != 0) ) + { + printf("%u cant do zaddr or fractional rel %s.%s tokens %.8f\n",mp->origid,mp->rel.coin,mp->rel.tokenid,dstr(mp->rel.satoshis)); + subatomic_closed(mp,approval,msgjson,senderpub); + return; + } + else if ( mp->base.istoken != 0 && ((mp->base.satoshis % SATOSHIDEN) != 0 || mp->base.iszaddr != 0 ) ) + { + printf("%u cant do zaddr or fractional base %s.%s tokens %.8f\n",mp->origid,mp->base.coin,mp->base.tokenid,dstr(mp->base.satoshis)); + subatomic_closed(mp,approval,msgjson,senderpub); + return; + } + else if ( subatomic_getbalance(&mp->base) < mp->base.satoshis ) + { + printf("%u bob node low on %s funds! %.8f not enough for %.8f\n",mp->origid,mp->base.coin,dstr(subatomic_getbalance(&mp->base)),dstr(mp->base.satoshis)); + subatomic_closed(mp,approval,msgjson,senderpub); + } + else + { + printf("%u bob (%s/%s) gotopenrequest origid.%u status.%d (%s/%s) SENDERPUB.(%s)\n",mp->origid,mp->base.name,mp->rel.name,mp->origid,mp->status,mp->bob.recvaddr,mp->bob.recvZaddr,senderpub); + subatomic_approved(mp,approval,msgjson,senderpub); + } + } +} + +int32_t subatomic_channelapproved(uint32_t inboxid,char *senderpub,cJSON *msgjson,struct msginfo *origmp) +{ + struct msginfo *mp; cJSON *approval; char *addr,*coin,*acname; int32_t retval = 0; + mp = subatomic_tracker(juint(msgjson,"origid")); + if ( subatomic_orderbook_mpset(mp,mp->base.name) != 0 && (approval= subatomic_mpjson(mp)) != 0 ) + { + printf("%u iambob.%d (%s/%s) channelapproved origid.%u status.%d\n",mp->origid,mp->bobflag,mp->base.name,mp->rel.name,mp->origid,mp->status); + if ( mp->bobflag == 0 && mp->status == SUBATOMIC_OPENREQUEST ) + { + if ( (addr= jstr(msgjson,"bobaddr")) != 0 ) + strcpy(mp->bob.recvaddr,addr); + if ( (addr= jstr(msgjson,"bobZaddr")) != 0 ) + strcpy(mp->bob.recvZaddr,addr); + if ( (addr= jstr(msgjson,"bobsecp")) != 0 ) + strcpy(mp->bob.secp,addr); + retval = subatomic_approved(mp,approval,msgjson,senderpub); + } + else if ( mp->bobflag != 0 && mp->status == SUBATOMIC_APPROVED ) + retval = subatomic_opened(mp,approval,msgjson,senderpub); + } + return(retval); +} + +int32_t subatomic_incomingopened(uint32_t inboxid,char *senderpub,cJSON *msgjson,struct msginfo *origmp) +{ + struct msginfo *mp; cJSON *payment; int32_t retval = 0; + mp = subatomic_tracker(juint(msgjson,"origid")); + if ( subatomic_orderbook_mpset(mp,mp->base.name) != 0 && (payment= subatomic_mpjson(mp)) != 0 ) + { + printf("%u iambob.%d (%s/%s) incomingchannel status.%d\n",mp->origid,mp->bobflag,mp->base.name,mp->rel.name,mp->status); + if ( mp->bobflag == 0 && mp->status == SUBATOMIC_APPROVED ) + retval = subatomic_payment(mp,payment,msgjson,senderpub); + else if ( mp->bobflag != 0 && mp->status == SUBATOMIC_OPENED ) + retval = 1; // nothing to do + } + return(retval); +} + +int32_t subatomic_incomingpayment(uint32_t inboxid,char *senderpub,cJSON *msgjson,struct msginfo *origmp) +{ + static FILE *fp; + struct msginfo *mp; cJSON *pay,*rawtx,*retjson; bits256 txid; char str[65],*hexstr; int32_t retval = 0; + mp = subatomic_tracker(juint(msgjson,"origid")); + if ( subatomic_orderbook_mpset(mp,mp->base.name) != 0 && (pay= subatomic_mpjson(mp)) != 0 ) + { + printf("%u iambob.%d (%s/%s) incomingpayment status.%d\n",mp->origid,mp->bobflag,mp->base.name,mp->rel.name,mp->status); + if ( mp->bobflag == 0 ) + { + txid = jbits256(msgjson,"bobpayment"); + jaddbits256(msgjson,"alicepayment",mp->alicepayment); + printf("%u alice waits for %s.%s to be in mempool (%.8f -> %s)\n",mp->origid,mp->base.name,bits256_str(str,txid),dstr(mp->base.satoshis),subatomic_zonly(&mp->base) == 0 ? mp->alice.recvaddr : mp->alice.recvZaddr); + hexstr = jstr(msgjson,"bobtx"); + if ( (rawtx= subatomic_txidwait(&mp->base,txid,hexstr,SUBATOMIC_TIMEOUT,senderpub)) != 0 ) + { + if ( subatomic_verifypayment(&mp->base,rawtx,mp->base.satoshis,subatomic_zonly(&mp->base) == 0 ? mp->alice.recvaddr : mp->alice.recvZaddr,txid) >= 0 ) + mp->gotpayment = 1; + free_json(rawtx); + } + if ( mp->gotpayment != 0 ) + { + printf("%u SWAP COMPLETE <<<<<<<<<<<<<<<<\n",mp->origid); + SUBATOMIC_retval = 0; + if ( mp->base.iszaddr == 0 ) + { + sprintf(str,"%u",mp->origid); + if ( (retjson= dpow_broadcast(SUBATOMIC_PRIORITY,bits256_str(str,mp->alicepayment),(char *)"completed",str,DPOW_pubkeystr,"","")) != 0 ) + free_json(retjson); + } + } + else + { + printf("%u SWAP INCOMPLETE, waiting on %s.%s\n",mp->origid,mp->base.name,bits256_str(str,txid)); + if ( (fp= fopen("SUBATOMIC.incomplete","a+")) != 0 ) + { + char *jsonstr = jprint(msgjson,0); + fwrite(jsonstr,1,strlen(jsonstr),fp); + fputc('\n',fp); + fclose(fp); + free(jsonstr); + } + if ( mp->base.iszaddr == 0 ) + { + sprintf(str,"%u",mp->origid); + if ( (retjson= dpow_broadcast(SUBATOMIC_PRIORITY,bits256_str(str,mp->alicepayment),(char *)"incomplete",str,DPOW_pubkeystr,"","")) != 0 ) + free_json(retjson); + } + subatomic_closed(mp,pay,msgjson,senderpub); + exit(-1); + } + } + if ( mp->gotpayment != 0 ) + retval = subatomic_paidinfull(mp,pay,msgjson,senderpub); + else + { + if ( mp->bobflag != 0 && mp->status == SUBATOMIC_OPENED ) + { + txid = jbits256(msgjson,"alicepayment"); + printf("%u bob waits for %s.%s to be in mempool (%.8f -> %s)\n",mp->origid,mp->rel.name,bits256_str(str,txid),dstr(mp->rel.satoshis),subatomic_zonly(&mp->rel) == 0 ? mp->bob.recvaddr : mp->bob.recvZaddr); + hexstr = jstr(msgjson,"alicetx"); + if ( (rawtx= subatomic_txidwait(&mp->rel,txid,hexstr,SUBATOMIC_TIMEOUT,senderpub)) != 0 ) + { + if ( subatomic_verifypayment(&mp->rel,rawtx,mp->rel.satoshis,subatomic_zonly(&mp->rel) == 0 ? mp->bob.recvaddr : mp->bob.recvZaddr,txid) >= 0 ) + mp->gotpayment = 1; + free_json(rawtx); + } + if ( mp->gotpayment != 0 ) + { + retval = subatomic_payment(mp,pay,msgjson,senderpub); + jaddbits256(msgjson,"bobpayment",mp->bobpayment); + if ( mp->rel.iszaddr == 0 ) + { + sprintf(str,"%u",mp->origid); + if ( (retjson= dpow_broadcast(SUBATOMIC_PRIORITY,bits256_str(str,mp->bobpayment),(char *)"completed",str,DPOW_pubkeystr,"","")) != 0 ) + free_json(retjson); + } + printf("%u SWAP COMPLETE <<<<<<<<<<<<<<<<\n",mp->origid); + if ( (fp= fopen("SUBATOMIC.proof","rb+")) == 0 ) + fp = fopen("SUBATOMIC.proof","wb"); + if ( fp != 0 ) + { + char *jsonstr = jprint(msgjson,0); + fseek(fp,0,SEEK_END); + fwrite(jsonstr,1,strlen(jsonstr),fp); + fputc('\n',fp); + fflush(fp); + free(jsonstr); + } + } else printf("%u SWAP INCOMPLETE: %s\n",mp->origid,jprint(msgjson,0)); + } + } + } + return(retval); +} + +int32_t subatomic_incomingfullypaid(uint32_t inboxid,char *senderpub,cJSON *msgjson,struct msginfo *origmp) +{ + struct msginfo *mp; cJSON *closed; int32_t retval = 0; + mp = subatomic_tracker(juint(msgjson,"origid")); + if ( subatomic_orderbook_mpset(mp,mp->base.name) != 0 && (closed= subatomic_mpjson(mp)) != 0 ) + { + printf("%u iambob.%d (%s/%s) incomingfullypaid status.%d\n",mp->origid,mp->bobflag,mp->base.name,mp->rel.name,mp->status); + // error check msgjson vs M + if ( mp->bobflag == 0 && mp->status == SUBATOMIC_PAIDINFULL ) + retval = subatomic_closed(mp,closed,msgjson,senderpub); + else if ( mp->bobflag != 0 && mp->status == SUBATOMIC_PAYMENT ) + retval = subatomic_paidinfull(mp,closed,msgjson,senderpub); + } + return(retval); +} + +int32_t subatomic_incomingclosed(uint32_t inboxid,char *senderpub,cJSON *msgjson,struct msginfo *origmp) +{ + struct msginfo *mp; cJSON *closed; int32_t retval = 0; + mp = subatomic_tracker(juint(msgjson,"origid")); + if ( subatomic_orderbook_mpset(mp,mp->base.name) != 0 && (closed= subatomic_mpjson(mp)) != 0 ) + { + printf("%u iambob.%d (%s/%s) incomingclose status.%d\n",mp->origid,mp->bobflag,mp->base.name,mp->rel.name,mp->status); + if ( mp->bobflag != 0 ) + dpow_cancel(mp->origid); + if ( mp->status < SUBATOMIC_CLOSED ) + { + retval = subatomic_closed(mp,closed,msgjson,senderpub); + subatomic_status(mp,SUBATOMIC_CLOSED); + } + retval = 1; + } + return(retval); +} + +int32_t subatomic_ismine(int32_t bobflag,cJSON *json,char *basename,char *relname) +{ + char *base,*rel; + if ( (base= jstr(json,"base")) != 0 && (rel= jstr(json,"rel")) != 0 ) + { + if ( strcmp(base,basename) == 0 && strcmp(rel,relname) == 0 ) + return(1); + if ( bobflag != 0 ) + { + if ( strcmp(basename,"#allfiles") == 0 && base[0] == '#' ) + return(1); + fprintf(stderr,"skip ismine (%s/%s) vs (%s/%s)\n",basename,relname,base,rel); + } + } + return(0); +} + +void subatomic_tokensregister(int32_t priority) +{ + char *token_name,*tokenid,existing[65]; cJSON *tokens,*token; int32_t i,numtokens; + if ( SUBATOMIC_json != 0 && (tokens= jarray(&numtokens,SUBATOMIC_json,"tokens")) != 0 ) + { + for (i=0; i 0 ) + { + for (j=0; j %s, %u %llu %u\n",mp->bobflag,mp->base.name,mp->rel.name,mp->origid,(long long)mp->rel.satoshis,mp->openrequestid); + while ( 1 ) + { + if ( msgs == 0 ) + { + sleep(1); + fflush(stdout); + if ( mp->bobflag != 0 ) + { + dpow_pubkeyregister(SUBATOMIC_PRIORITY); + subatomic_tokensregister(SUBATOMIC_PRIORITY); + subatomic_filesregister(SUBATOMIC_PRIORITY); + } + } + msgs = 0; + for (iter=0; iter<(int32_t)(sizeof(tagBs)/sizeof(*tagBs)); iter++) + { + tagB = tagBs[iter]; + if ( (ptrs= dpow_inboxcheck(&n,&stopats[iter],tagB)) != 0 ) + { + for (i=0; ijsonstr)) != 0 ) + { + if ( jint(inboxjson,"tobob") != mp->bobflag ) + continue; + if ( subatomic_ismine(mp->bobflag,inboxjson,mp->base.name,mp->rel.name) != 0 ) + { + if ( strcmp(tagB,"openrequest") == 0 && mp->bobflag != 0 ) + subatomic_bob_gotopenrequest(ptr->shorthash,ptr->senderpub,inboxjson,mp->base.name,mp->rel.name); + else if ( strcmp(tagB,"approved") == 0 ) + mask |= subatomic_channelapproved(ptr->shorthash,ptr->senderpub,inboxjson,mp) << 0; + else if ( strcmp(tagB,"opened") == 0 ) + mask |= subatomic_incomingopened(ptr->shorthash,ptr->senderpub,inboxjson,mp) << 1; + else if ( strcmp(tagB,"payment") == 0 ) + mask |= subatomic_incomingpayment(ptr->shorthash,ptr->senderpub,inboxjson,mp) << 2; + else if ( strcmp(tagB,"paid") == 0 ) + mask |= subatomic_incomingfullypaid(ptr->shorthash,ptr->senderpub,inboxjson,mp) << 3; + else if ( strcmp(tagB,"closed") == 0 ) + mask |= subatomic_incomingclosed(ptr->shorthash,ptr->senderpub,inboxjson,mp) * 0x1f; + else fprintf(stderr,"iambob.%d unknown unexpected tagB.(%s)\n",mp->bobflag,tagB); + } + free_json(inboxjson); + } else fprintf(stderr,"subatomic iambob.%d loop got unparseable(%s)\n",mp->bobflag,ptr->jsonstr); + free(ptr); + ptrs[i] = 0; + } + } + free(ptrs); + } + } + if ( mp->bobflag == 0 && (mask & 0x1f) == 0x1f ) + { + printf("alice %u %llu %u finished\n",mp->origid,(long long)mp->rel.satoshis,mp->openrequestid); + break; + } + } +} + +int32_t main(int32_t argc,char **argv) +{ + char *fname = "subatomic.json"; + int32_t i,height; char *coin,*kcli,*subatomic,*hashstr,*acname=(char *)""; cJSON *retjson; bits256 blockhash; char checkstr[65],str[65],str2[65],tmpstr[32]; long fsize; struct msginfo M; + memset(&M,0,sizeof(M)); + srand((int32_t)time(NULL)); + if ( (subatomic= filestr(&fsize,fname)) == 0 ) + { + fprintf(stderr,"cant load %s file\n",fname); + exit(-1); + } + if ( (SUBATOMIC_json= cJSON_Parse(subatomic)) == 0 ) + { + fprintf(stderr,"cant parse subatomic.json file (%s)\n",subatomic); + exit(-1); + } + free(subatomic); + if ( argc >= 4 ) + { + if ( dpow_pubkey() < 0 ) + { + fprintf(stderr,"couldnt set pubkey for DEX\n"); + return(-1); + } + coin = (char *)argv[1]; + if ( argv[2][0] != 0 ) + REFCOIN_CLI = (char *)argv[2]; + else + { + if ( strcmp(coin,"KMD") != 0 ) + { + acname = coin; + } + } + hashstr = (char *)argv[3]; + strcpy(M.rel.coin,subatomic_checkname(tmpstr,&M,1,coin)); + strcpy(M.rel.name,coin); + if ( argc == 4 && strlen(hashstr) == 64 ) // for blocknotify usage, seems not needed + { + height = get_coinheight(coin,acname,&blockhash); + bits256_str(checkstr,blockhash); + if ( strcmp(checkstr,hashstr) == 0 ) + { + fprintf(stderr,"%s: (%s) %s height.%d\n",coin,REFCOIN_CLI!=0?REFCOIN_CLI:"",checkstr,height); + if ( (retjson= dpow_ntzdata(coin,SUBATOMIC_PRIORITY,height,blockhash)) != 0 ) + free_json(retjson); + } else fprintf(stderr,"coin.%s (%s) %s vs %s, height.%d\n",coin,REFCOIN_CLI!=0?REFCOIN_CLI:"",checkstr,hashstr,height); + if ( strcmp("BTC",coin) != 0 ) + { + bits256 prevntzhash,ntzhash; int32_t prevntzheight,ntzheight; uint32_t ntztime,prevntztime; char hexstr[81]; cJSON *retjson2; + prevntzhash = dpow_ntzhash(coin,&prevntzheight,&prevntztime); + if ( (retjson= get_getinfo(coin,acname)) != 0 ) + { + ntzheight = juint(retjson,"notarized"); + ntzhash = jbits256(retjson,"notarizedhash"); + if ( ntzheight > prevntzheight ) + { + get_coinmerkleroot(coin,acname,ntzhash,&ntztime); + fprintf(stderr,"NOTARIZATION %s.%d %s t.%u\n",coin,ntzheight,bits256_str(str,ntzhash),ntztime); + bits256_str(hexstr,ntzhash); + sprintf(&hexstr[64],"%08x",ntzheight); + sprintf(&hexstr[72],"%08x",ntztime); + hexstr[80] = 0; + if ( (retjson2= dpow_broadcast(SUBATOMIC_PRIORITY,hexstr,coin,"notarizations",DPOW_pubkeystr,"","")) != 0 ) + free_json(retjson2); + } + else if ( ntzheight == prevntzheight && memcmp(&prevntzhash,&ntzhash,32) != 0 ) + fprintf(stderr,"NTZ ERROR %s.%d %s != %s\n",coin,ntzheight,bits256_str(str,ntzhash),bits256_str(str2,prevntzhash)); + free_json(retjson); + } + } + } + else if ( argc == 5 && atol(hashstr) > 10000 ) + { + char checkstr[32]; uint64_t mult = 1; + M.origid = (uint32_t)atol(hashstr); + sprintf(checkstr,"%u",M.origid); + if ( strcmp(checkstr,hashstr) == 0 ) // alice + { + M.rel.satoshis = (uint64_t)(atof(argv[4])*SATOSHIDEN+0.0000000049999); + for (i=0; M.rel.name[i]!=0; i++) + if ( M.rel.name[i] == '.' ) + { + mult = SATOSHIDEN; + break; + } + if ( subatomic_getbalance(&M.rel) < M.rel.satoshis/mult ) + { + fprintf(stderr,"not enough balance %s %.8f for %.8f\n",M.rel.coin,dstr(subatomic_getbalance(&M.rel)),dstr(M.rel.satoshis/mult)); + return(-1); + } + fprintf(stderr,"subatomic_channel_alice (%s/%s) %s %u with %.8f %llu\n",M.rel.name,M.rel.coin,hashstr,M.origid,atof(argv[4]),(long long)M.rel.satoshis); + dpow_pubkeyregister(SUBATOMIC_PRIORITY); + M.openrequestid = subatomic_alice_openrequest(&M); + if ( M.openrequestid != 0 ) + subatomic_loop(&M); + } else fprintf(stderr,"checkstr mismatch %s %s != %s\n",coin,hashstr,checkstr); + } + else + { + M.bobflag = 1; + strcpy(M.base.name,hashstr); + strcpy(M.base.coin,subatomic_checkname(tmpstr,&M,0,hashstr)); + subatomic_loop(&M); // while ( 1 ) loop for each relcoin -> basecoin + } + } + return(SUBATOMIC_retval); +} + diff --git a/src/cc/dapps/subatomic.json b/src/cc/dapps/subatomic.json new file mode 100644 index 000000000..7832fdb9e --- /dev/null +++ b/src/cc/dapps/subatomic.json @@ -0,0 +1,27 @@ +{ +"authorized": [ + {"chmex":"030754bffcf6dfcb34a20c486ff5a5be5546b9cc16fba9692165272b3f8e98c4af" }, + {"SHossain":"03c8657bd57b6ceb14514a10e99fe8a0cec5a9bc24592df7f66f050e670e4f6bac" }, + {"satinder":"03732f8ef851ff234c74d0df575c2c5b159e2bab3faca4ec52b3f217d5cda5361d" }, + {"ml777":"02453d028c74cb9551e1aaf35113383b6ecbd9f06ff23a4ab1a953429b9763e345" }, + {"tonylhub":"0218e0f435d4544404c25a7759b7f7174d821215085ef936218c5569d975af468b" }, + {"gthub":"036c7de9a5090fbad78b9eea41549ccacc07bd0e9e7f8d290c88f470f3569e1a35" }, + {"zkTrader":"026c6b0b35ec0adc2f8a5c648da1fce634f798c69d5e9fe518400447e88398b830" }, + {"nutellalicka":"03aee08860e0340f0f490a3ef3718d6676882f2d63d4f536dfebb1d348b82c79ee" }, + {"gcharang":"02d3431950c2f0f9654217b6ce3d44468d3a9ca7255741767fdeee7c5ec6b47567" }, + {"jl777":"02b27de3ee5335518b06f69f4fbabb029cfc737613b100996841d5532b324a5a61" } +], +"tokens":[ + {"RICK.demo":"2b1feef719ecb526b07416dd432bce603ac6dc8bfe794cddf105cb52f6aae3cd"} +], +"files":[ + {"filename":"hushd","prices":[{"HUSH":0.1}, {"PIRATE":1}]} +], +"externalcoins":[ + { "BTC":"bitcoin-cli" }, + { "KMD":"komodod-cli" }, + { "CHIPS":"chips-cli" }, + { "PIRATE":"pirate-cli" } +] +} + diff --git a/src/cc/makecustom b/src/cc/makecustom index 7f1c789c9..3516b4023 100755 --- a/src/cc/makecustom +++ b/src/cc/makecustom @@ -1,5 +1,5 @@ #!/bin/sh -if make -f Makefile_custom "$@"; then +if HOST="$HOST" make -B -f Makefile_custom "$@"; then echo CUSTOMCC BUILD SUCCESSFUL else echo CUSTOMCC BUILD FAILED diff --git a/src/chain.h b/src/chain.h index 03fc75660..77d17114e 100644 --- a/src/chain.h +++ b/src/chain.h @@ -1,6 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin Core developers -// Copyright (c) 2019 The Hush 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. @@ -276,9 +276,12 @@ public: //! inputs and outputs. int64_t nShieldedTx; - //! (memory only) Number of shielded outputs in the block up to and including this block. + //! (memory only) Number of shielded outputs int64_t nShieldedOutputs; + //! (memory only) Number of shielded spends + int64_t nShieldedSpends; + //! (memory only) Number of fully shielded transactions. A fully shielded transaction is defined //! as a transaction containing JoinSplits and only shielded inputs and outputs, i.e. no transparent // inputs or outputs: z->z or z->(z,z) or z->(z,z,z,) etc... @@ -332,6 +335,9 @@ public: //! (memory only) Number of shielded outputs in the chain up to and including this block. int64_t nChainShieldedOutputs; + //! (memory only) Number of shielded spends in the chain up to and including this block. + int64_t nChainShieldedSpends; + //! (memory only) Number of fully shielded transactions. A fully shielded transaction is defined //! as a transaction containing JoinSplits and only shielded inputs and outputs, i.e. no transparent // inputs or outputs: z->z or z->(z,z) or z->(z,z,z,) etc... @@ -429,18 +435,20 @@ public: nChainNotarizations = 0; nChainFullyShieldedTx = 0; nChainShieldedOutputs = 0; + nChainShieldedSpends = 0; nChainShieldedPayments = 0; nChainShieldingPayments = 0; nChainDeshieldingPayments = 0; nChainFullyShieldedPayments = 0; - // Shieldex Index stats + // Shielded Index stats nPayments = 0; nShieldedTx = 0; nShieldingTx = 0; nNotarizations = 0; nDeshieldingTx = 0; nShieldedOutputs = 0; + nShieldedSpends = 0; nFullyShieldedTx = 0; nShieldedPayments = 0; nShieldingPayments = 0; @@ -679,6 +687,7 @@ public: READWRITE(nDeshieldingPayments); READWRITE(nFullyShieldedPayments); READWRITE(nShieldedOutputs); + READWRITE(nShieldedSpends); } } diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 0a2b819e7..f14e2d9ef 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -544,6 +544,14 @@ int32_t MAX_BLOCK_SIZE(int32_t height) else return(2000000); } +// Change the Hush blocktime at run-time(!) +void hush_changeblocktime() +{ + pCurrentParams->consensus.nMaxFutureBlockTime = 7 * ASSETCHAINS_BLOCKTIME; + pCurrentParams->consensus.nPowTargetSpacing = ASSETCHAINS_BLOCKTIME; + fprintf(stderr,"HUSH blocktime changing to %d seconds\n",ASSETCHAINS_BLOCKTIME); +} + void komodo_setactivation(int32_t height) { pCurrentParams->consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = height; diff --git a/src/chainparams.h b/src/chainparams.h index daa16af8c..7bd1057ec 100644 --- a/src/chainparams.h +++ b/src/chainparams.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. diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index 7fd94e4e7..026475f88 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -74,7 +74,7 @@ namespace Checkpoints { fWorkAfter = nExpensiveAfter*fSigcheckVerificationFactor; } - return fWorkBefore / (fWorkBefore + fWorkAfter); + return std::min(fWorkBefore / (fWorkBefore + fWorkAfter), 1.0); } int GetTotalBlocksEstimate(const CChainParams::CCheckpointData& data) diff --git a/src/clientversion.h b/src/clientversion.h index eaa792d62..c62e6d3e0 100644 --- a/src/clientversion.h +++ b/src/clientversion.h @@ -33,8 +33,8 @@ //! These need to be macros, as clientversion.cpp's and bitcoin*-res.rc's voodoo requires it // Must be kept in sync with configure.ac ! #define CLIENT_VERSION_MAJOR 3 -#define CLIENT_VERSION_MINOR 3 -#define CLIENT_VERSION_REVISION 1 +#define CLIENT_VERSION_MINOR 4 +#define CLIENT_VERSION_REVISION 0 #define CLIENT_VERSION_BUILD 50 //! Set to true for release, false for prerelease or test build diff --git a/src/coins.cpp b/src/coins.cpp index b8370e193..03b046a70 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2012-2014 The Bitcoin Core developers -// Copyright (c) 2019 The Hush 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. @@ -65,7 +65,6 @@ bool CCoins::Spend(uint32_t nPos) Cleanup(); return true; } -bool CCoinsView::GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const { return false; } bool CCoinsView::GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const { return false; } bool CCoinsView::GetNullifier(const uint256 &nullifier, ShieldedType type) const { return false; } bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) const { return false; } @@ -85,7 +84,6 @@ bool CCoinsView::GetStats(CCoinsStats &stats) const { return false; } CCoinsViewBacked::CCoinsViewBacked(CCoinsView *viewIn) : base(viewIn) { } -bool CCoinsViewBacked::GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const { return base->GetSproutAnchorAt(rt, tree); } bool CCoinsViewBacked::GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const { return base->GetSaplingAnchorAt(rt, tree); } bool CCoinsViewBacked::GetNullifier(const uint256 &nullifier, ShieldedType type) const { return base->GetNullifier(nullifier, type); } bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) const { return base->GetCoins(txid, coins); } @@ -139,30 +137,6 @@ CCoinsMap::const_iterator CCoinsViewCache::FetchCoins(const uint256 &txid) const return ret; } - -bool CCoinsViewCache::GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const { - CAnchorsSproutMap::const_iterator it = cacheSproutAnchors.find(rt); - if (it != cacheSproutAnchors.end()) { - if (it->second.entered) { - tree = it->second.tree; - return true; - } else { - return false; - } - } - - if (!base->GetSproutAnchorAt(rt, tree)) { - return false; - } - - CAnchorsSproutMap::iterator ret = cacheSproutAnchors.insert(std::make_pair(rt, CAnchorsSproutCacheEntry())).first; - ret->second.entered = true; - ret->second.tree = tree; - cachedCoinsUsage += ret->second.tree.DynamicMemoryUsage(); - - return true; -} - bool CCoinsViewCache::GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const { CAnchorsSaplingMap::const_iterator it = cacheSaplingAnchors.find(rt); if (it != cacheSaplingAnchors.end()) { @@ -271,7 +245,6 @@ void CCoinsViewCache::BringBestAnchorIntoCache( SproutMerkleTree &tree ) { - assert(GetSproutAnchorAt(currentRoot, tree)); } template<> @@ -436,8 +409,8 @@ void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) { void BatchWriteNullifiers(CNullifiersMap &mapNullifiers, CNullifiersMap &cacheNullifiers) { - if(fZdebug) - LogPrintf("%s\n", __FUNCTION__); + //if(fZdebug) + // LogPrintf("%s\n", __FUNCTION__); for (CNullifiersMap::iterator child_it = mapNullifiers.begin(); child_it != mapNullifiers.end();) { if (child_it->second.flags & CNullifiersCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization). CNullifiersMap::iterator parent_it = cacheNullifiers.find(child_it->first); @@ -550,9 +523,9 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, bool CCoinsViewCache::Flush() { bool fOk = base->BatchWrite(cacheCoins, hashBlock, hashSproutAnchor, hashSaplingAnchor, cacheSproutAnchors, cacheSaplingAnchors, cacheSproutNullifiers, cacheSaplingNullifiers); cacheCoins.clear(); - cacheSproutAnchors.clear(); + //cacheSproutAnchors.clear(); cacheSaplingAnchors.clear(); - cacheSproutNullifiers.clear(); + //cacheSproutNullifiers.clear(); cacheSaplingNullifiers.clear(); cachedCoinsUsage = 0; return fOk; @@ -624,37 +597,8 @@ CAmount CCoinsViewCache::GetValueIn(int32_t nHeight,int64_t *interestp,const CTr } -bool CCoinsViewCache::HaveJoinSplitRequirements(const CTransaction& tx) const +bool CCoinsViewCache::HaveShieldedRequirements(const CTransaction& tx) const { - boost::unordered_map intermediates; - - BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) - { - BOOST_FOREACH(const uint256& nullifier, joinsplit.nullifiers) - { - if (GetNullifier(nullifier, SPROUT)) { - // If the nullifier is set, this transaction - // double-spends! - return false; - } - } - - SproutMerkleTree tree; - auto it = intermediates.find(joinsplit.anchor); - if (it != intermediates.end()) { - tree = it->second; - } else if (!GetSproutAnchorAt(joinsplit.anchor, tree)) { - return false; - } - - BOOST_FOREACH(const uint256& commitment, joinsplit.commitments) - { - tree.append(commitment); - } - - intermediates.insert(std::make_pair(tree.root(), tree)); - } - for (const SpendDescription &spendDescription : tx.vShieldedSpend) { if (GetNullifier(spendDescription.nullifier, SAPLING)) { // Prevent double spends LogPrintf("%s: sapling nullifier %s exists, preventing double spend\n", __FUNCTION__, spendDescription.nullifier.GetHex().c_str()); diff --git a/src/coins.h b/src/coins.h index cc8b19f68..2d08be42c 100644 --- a/src/coins.h +++ b/src/coins.h @@ -372,9 +372,6 @@ struct CCoinsStats class CCoinsView { public: - //! Retrieve the tree (Sprout) at a particular anchored root in the chain - virtual bool GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const; - //! Retrieve the tree (Sapling) at a particular anchored root in the chain virtual bool GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const; @@ -421,7 +418,6 @@ protected: public: CCoinsViewBacked(CCoinsView *viewIn); - bool GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const; bool GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const; bool GetNullifier(const uint256 &nullifier, ShieldedType type) const; bool GetCoins(const uint256 &txid, CCoins &coins) const; @@ -493,7 +489,6 @@ public: CNullifiersMap getNullifiers(); // Standard CCoinsView methods - bool GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const; bool GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const; bool GetNullifier(const uint256 &nullifier, ShieldedType type) const; bool GetCoins(const uint256 &txid, CCoins &coins) const; @@ -550,7 +545,7 @@ public: size_t DynamicMemoryUsage() const; /** - * Amount of bitcoins coming in to a transaction + * Amount of HUSH coming in to a transaction * Note that lightweight clients may not know anything besides the hash of previous transactions, * so may not be able to calculate this. * @@ -562,8 +557,8 @@ public: //! Check whether all prevouts of the transaction are present in the UTXO set represented by this view bool HaveInputs(const CTransaction& tx) const; - //! Check whether all joinsplit requirements (anchors/nullifiers) are satisfied - bool HaveJoinSplitRequirements(const CTransaction& tx) const; + //! Check whether all shielded requirements (anchors/nullifiers) are satisfied + bool HaveShieldedRequirements(const CTransaction& tx) const; //! Return priority of tx at height nHeight double GetPriority(const CTransaction &tx, int nHeight) const; diff --git a/src/consensus/params.h b/src/consensus/params.h index 67d84af0b..e4242ad33 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -1,7 +1,8 @@ // 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. +// file COPYING or https://www.opensource.org/licenses/mit-license.php /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * diff --git a/src/consensus/upgrades.cpp b/src/consensus/upgrades.cpp index b75e0c002..984ca377e 100644 --- a/src/consensus/upgrades.cpp +++ b/src/consensus/upgrades.cpp @@ -1,3 +1,4 @@ +// Copyright (c) 2019-2020 The Hush developers // Copyright (c) 2018 The Zcash developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/cryptoconditions/Makefile.am b/src/cryptoconditions/Makefile.am index 787b11ac6..615ac5783 100644 --- a/src/cryptoconditions/Makefile.am +++ b/src/cryptoconditions/Makefile.am @@ -15,7 +15,7 @@ AM_CFLAGS = -I$(top_srcdir)/src/asn -I$(top_srcdir)/include -I$(top_srcdir)/src/ LIBSECP256K1=src/include/secp256k1/libsecp256k1.la $(LIBSECP256K1): $(wildcard src/secp256k1/*) - $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) -march:x86-64 -g + $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) -g CRYPTOCONDITIONS_CORE=libcryptoconditions_core.la diff --git a/src/cryptoconditions/src/anon.c b/src/cryptoconditions/src/anon.c index 55d7a3b7f..a1bd6b4a3 100644 --- a/src/cryptoconditions/src/anon.c +++ b/src/cryptoconditions/src/anon.c @@ -1,3 +1,4 @@ +// Copyright (c) 2019-2020 The Hush developers /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * * * @@ -53,11 +54,8 @@ static void anonToJSON(const CC *cond, cJSON *params) { } -static unsigned char *anonFingerprint(const CC *cond) { - unsigned char *out = calloc(1, 32); - //fprintf(stderr,"anon fingerprint %p %p\n",out,cond->fingerprint); +static void anonFingerprint(const CC *cond, uint8_t *out) { memcpy(out, cond->fingerprint, 32); - return out; } diff --git a/src/cryptoconditions/src/asn/OCTET_STRING.c b/src/cryptoconditions/src/asn/OCTET_STRING.c index 5420dedec..a886ff8fa 100644 --- a/src/cryptoconditions/src/asn/OCTET_STRING.c +++ b/src/cryptoconditions/src/asn/OCTET_STRING.c @@ -1714,7 +1714,9 @@ OCTET_STRING_free(asn_TYPE_descriptor_t *td, void *sptr, int contents_only) { OCTET_STRING_t *st = (OCTET_STRING_t *)sptr; asn_OCTET_STRING_specifics_t *specs; asn_struct_ctx_t *ctx; +#if !defined(__aarch64__) struct _stack *stck; +#endif if(!td || !st) return; @@ -1731,6 +1733,15 @@ OCTET_STRING_free(asn_TYPE_descriptor_t *td, void *sptr, int contents_only) { st->buf = 0; } +/* Attention !!! + * this is quick & dirty workaround for memory corruption bug on aarch64-linux-gnu + * - downside: allows memory leakage + * - issue description: On Raspberry Pi 4 @ 64bit linux, daemon crashes with "free(): invalid pointer" error + * - probable cause: misaligned memory access to nested structs containing pointers + * - TODO: use the latest asn1c compiler on CryptoConditions.asn, maybe generate cpp instead of c code... investigation in progress + */ + +#if !defined(__aarch64__) /* * Remove decode-time stack. */ @@ -1747,6 +1758,7 @@ OCTET_STRING_free(asn_TYPE_descriptor_t *td, void *sptr, int contents_only) { if(!contents_only) { FREEMEM(st); } +#endif } /* diff --git a/src/cryptoconditions/src/cryptoconditions.c b/src/cryptoconditions/src/cryptoconditions.c index 74949affc..6642b0345 100644 --- a/src/cryptoconditions/src/cryptoconditions.c +++ b/src/cryptoconditions/src/cryptoconditions.c @@ -1,3 +1,4 @@ +// Copyright (c) 2019-2020 The Hush developers /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * * * @@ -65,8 +66,8 @@ void appendUriSubtypes(uint32_t mask, unsigned char *buf) { char *cc_conditionUri(const CC *cond) { - unsigned char *fp = cond->type->fingerprint(cond); - if (!fp) return NULL; + unsigned char *fp = calloc(1, 32); + cond->type->fingerprint(cond, fp); unsigned char *encoded = base64_encode(fp, 32); @@ -118,13 +119,13 @@ uint32_t fromAsnSubtypes(const ConditionTypes_t types) { size_t cc_conditionBinary(const CC *cond, unsigned char *buf) { Condition_t *asn = calloc(1, sizeof(Condition_t)); asnCondition(cond, asn); + size_t out = 0; asn_enc_rval_t rc = der_encode_to_buffer(&asn_DEF_Condition, asn, buf, 1000); - if (rc.encoded == -1) { - fprintf(stderr, "CONDITION NOT ENCODED\n"); - return 0; - } + if (rc.encoded == -1) goto end; + out = rc.encoded; +end: ASN_STRUCT_FREE(asn_DEF_Condition, asn); - return rc.encoded; + return out; } @@ -146,10 +147,12 @@ void asnCondition(const CC *cond, Condition_t *asn) { // This may look a little weird - we dont have a reference here to the correct // union choice for the condition type, so we just assign everything to the threshold // type. This works out nicely since the union choices have the same binary interface. + CompoundSha256Condition_t *choice = &asn->choice.thresholdSha256; choice->cost = cc_getCost(cond); - choice->fingerprint.buf = cond->type->fingerprint(cond); choice->fingerprint.size = 32; + choice->fingerprint.buf = calloc(1, 32); + cond->type->fingerprint(cond, choice->fingerprint.buf); choice->subtypes = asnSubtypes(cond->type->getSubtypes(cond)); } diff --git a/src/cryptoconditions/src/ed25519.c b/src/cryptoconditions/src/ed25519.c index 8d73d3cf1..33b332071 100644 --- a/src/cryptoconditions/src/ed25519.c +++ b/src/cryptoconditions/src/ed25519.c @@ -1,3 +1,4 @@ +// Copyright (c) 2019-2020 The Hush developers /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * * * @@ -25,11 +26,10 @@ struct CCType CC_Ed25519Type; -static unsigned char *ed25519Fingerprint(const CC *cond) { +static void ed25519Fingerprint(const CC *cond, uint8_t *out) { Ed25519FingerprintContents_t *fp = calloc(1, sizeof(Ed25519FingerprintContents_t)); - //fprintf(stderr,"ed25519 fingerprint %p %p\n",fp,cond->publicKey); OCTET_STRING_fromBuf(&fp->publicKey, cond->publicKey, 32); - return hashFingerprintContents(&asn_DEF_Ed25519FingerprintContents, fp); + hashFingerprintContents(&asn_DEF_Ed25519FingerprintContents, fp, out); } diff --git a/src/cryptoconditions/src/eval.c b/src/cryptoconditions/src/eval.c index 99ff1ebf5..a017d181d 100644 --- a/src/cryptoconditions/src/eval.c +++ b/src/cryptoconditions/src/eval.c @@ -1,3 +1,4 @@ +// Copyright (c) 2019-2020 The Hush developers /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * * * @@ -25,11 +26,8 @@ struct CCType CC_EvalType; -static unsigned char *evalFingerprint(const CC *cond) { - unsigned char *hash = calloc(1, 32); - //fprintf(stderr,"evalfingerprint %p %p\n",hash,cond->code); - sha256(cond->code, cond->codeLength, hash); - return hash; +static void evalFingerprint(const CC *cond, uint8_t *out) { + sha256(cond->code, cond->codeLength, out); } @@ -105,7 +103,7 @@ static uint32_t evalSubtypes(const CC *cond) { */ int jsonVerifyEval(CC *cond, void *context) { if (cond->codeLength == 5 && 0 == memcmp(cond->code, "TEST", 4)) { - return cond->code[5]; + return cond->code[4]; } fprintf(stderr, "Cannot verify eval; user function unknown\n"); return 0; diff --git a/src/cryptoconditions/src/include/secp256k1/Makefile.am b/src/cryptoconditions/src/include/secp256k1/Makefile.am index 52303e4e4..13c83fe18 100644 --- a/src/cryptoconditions/src/include/secp256k1/Makefile.am +++ b/src/cryptoconditions/src/include/secp256k1/Makefile.am @@ -71,7 +71,7 @@ endif endif libsecp256k1_la_SOURCES = src/secp256k1.c -libsecp256k1_la_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES) -march=x86-64 -g +libsecp256k1_la_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES) -g libsecp256k1_la_LIBADD = $(JNI_LIB) $(SECP_LIBS) $(COMMON_LIB) libsecp256k1_jni_la_SOURCES = src/java/org_bitcoin_NativeSecp256k1.c src/java/org_bitcoin_Secp256k1Context.c diff --git a/src/cryptoconditions/src/include/secp256k1/src/ecmult_const.h b/src/cryptoconditions/src/include/secp256k1/src/ecmult_const.h index bdb9ae43a..5a36ba40b 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/ecmult_const.h +++ b/src/cryptoconditions/src/include/secp256k1/src/ecmult_const.h @@ -36,4 +36,4 @@ static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, cons #endif - +#endif diff --git a/src/cryptoconditions/src/internal.h b/src/cryptoconditions/src/internal.h index 790e28962..3d24214ce 100644 --- a/src/cryptoconditions/src/internal.h +++ b/src/cryptoconditions/src/internal.h @@ -1,3 +1,4 @@ +// Copyright (c) 2019-2020 The Hush developers /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * * * @@ -41,7 +42,7 @@ typedef struct CCType { char name[100]; Condition_PR asnType; int (*visitChildren)(CC *cond, CCVisitor visitor); - unsigned char *(*fingerprint)(const CC *cond); + void (*fingerprint)(const CC *cond, uint8_t *fp); unsigned long (*getCost)(const CC *cond); uint32_t (*getSubtypes)(const CC *cond); CC *(*fromJSON)(const cJSON *params, char *err); @@ -77,7 +78,7 @@ struct CCType *getTypeByAsnEnum(Condition_PR present); */ unsigned char *base64_encode(const unsigned char *data, size_t input_length); unsigned char *base64_decode(const unsigned char *data_, size_t *output_length); -unsigned char *hashFingerprintContents(asn_TYPE_descriptor_t *asnType, void *fp); +void hashFingerprintContents(asn_TYPE_descriptor_t *asnType, void *fp, uint8_t* out); void dumpStr(unsigned char *str, size_t len); int checkString(const cJSON *value, char *key, char *err); int checkDecodeBase64(const cJSON *value, char *key, char *err, unsigned char **data, size_t *size); diff --git a/src/cryptoconditions/src/json_rpc.c b/src/cryptoconditions/src/json_rpc.c index 150bcb12b..c4fde8080 100644 --- a/src/cryptoconditions/src/json_rpc.c +++ b/src/cryptoconditions/src/json_rpc.c @@ -1,3 +1,4 @@ +// Copyright (c) 2019-2020 The Hush developers /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * * * diff --git a/src/cryptoconditions/src/prefix.c b/src/cryptoconditions/src/prefix.c index 45c6d8033..ea339df35 100644 --- a/src/cryptoconditions/src/prefix.c +++ b/src/cryptoconditions/src/prefix.c @@ -1,3 +1,4 @@ +// Copyright (c) 2019-2020 The Hush developers /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * * * @@ -37,13 +38,12 @@ static int prefixVisitChildren(CC *cond, CCVisitor visitor) { } -static unsigned char *prefixFingerprint(const CC *cond) { +static void prefixFingerprint(const CC *cond, uint8_t *out) { PrefixFingerprintContents_t *fp = calloc(1, sizeof(PrefixFingerprintContents_t)); - //fprintf(stderr,"prefixfinger %p %p\n",fp,cond->prefix); - asnCondition(cond->subcondition, &fp->subcondition); // TODO: check asnCondition for safety + asnCondition(cond->subcondition, &fp->subcondition); fp->maxMessageLength = cond->maxMessageLength; OCTET_STRING_fromBuf(&fp->prefix, cond->prefix, cond->prefixLength); - return hashFingerprintContents(&asn_DEF_PrefixFingerprintContents, fp); + hashFingerprintContents(&asn_DEF_PrefixFingerprintContents, fp, out); } diff --git a/src/cryptoconditions/src/preimage.c b/src/cryptoconditions/src/preimage.c index 9e7fe12f4..2fee86b88 100644 --- a/src/cryptoconditions/src/preimage.c +++ b/src/cryptoconditions/src/preimage.c @@ -1,3 +1,4 @@ +// Copyright (c) 2019-2020 The Hush developers /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * * * @@ -44,11 +45,8 @@ static unsigned long preimageCost(const CC *cond) { } -static unsigned char *preimageFingerprint(const CC *cond) { - unsigned char *hash = calloc(1, 32); - //fprintf(stderr,"preimage %p %p\n",hash,cond->preimage); - sha256(cond->preimage, cond->preimageLength, hash); - return hash; +static void preimageFingerprint(const CC *cond, uint8_t *out) { + sha256(cond->preimage, cond->preimageLength, out); } diff --git a/src/cryptoconditions/src/secp256k1.c b/src/cryptoconditions/src/secp256k1.c index a16115bb8..d5319d32b 100644 --- a/src/cryptoconditions/src/secp256k1.c +++ b/src/cryptoconditions/src/secp256k1.c @@ -1,3 +1,4 @@ +// Copyright (c) 2019-2020 The Hush developers /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * * * @@ -88,11 +89,10 @@ void initVerify() { } -static unsigned char *secp256k1Fingerprint(const CC *cond) { +static void secp256k1Fingerprint(const CC *cond, uint8_t *out) { Secp256k1FingerprintContents_t *fp = calloc(1, sizeof(Secp256k1FingerprintContents_t)); - //fprintf(stderr,"secpfinger %p %p size %d vs %d\n",fp,cond->publicKey,(int32_t)sizeof(Secp256k1FingerprintContents_t),(int32_t)SECP256K1_PK_SIZE); OCTET_STRING_fromBuf(&fp->publicKey, cond->publicKey, SECP256K1_PK_SIZE); - return hashFingerprintContents(&asn_DEF_Secp256k1FingerprintContents, fp); + hashFingerprintContents(&asn_DEF_Secp256k1FingerprintContents, fp, out); } diff --git a/src/cryptoconditions/src/threshold.c b/src/cryptoconditions/src/threshold.c index 9547f4f8c..e8e12435e 100644 --- a/src/cryptoconditions/src/threshold.c +++ b/src/cryptoconditions/src/threshold.c @@ -1,3 +1,4 @@ +// Copyright (c) 2019-2020 The Hush developers /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * * * @@ -94,17 +95,15 @@ static int cmpConditionBin(const void *a, const void *b) { } -static unsigned char *thresholdFingerprint(const CC *cond) { - /* Create fingerprint */ +static void thresholdFingerprint(const CC *cond, uint8_t *out) { ThresholdFingerprintContents_t *fp = calloc(1, sizeof(ThresholdFingerprintContents_t)); - //fprintf(stderr,"thresholdfinger %p\n",fp); fp->threshold = cond->threshold; for (int i=0; isize; i++) { Condition_t *asnCond = asnConditionNew(cond->subconditions[i]); asn_set_add(&fp->subconditions2, asnCond); } qsort(fp->subconditions2.list.array, cond->size, sizeof(Condition_t*), cmpConditionBin); - return hashFingerprintContents(&asn_DEF_ThresholdFingerprintContents, fp); + hashFingerprintContents(&asn_DEF_ThresholdFingerprintContents, fp, out); } diff --git a/src/cryptoconditions/src/utils.c b/src/cryptoconditions/src/utils.c index 6a2167119..ac2256f18 100644 --- a/src/cryptoconditions/src/utils.c +++ b/src/cryptoconditions/src/utils.c @@ -1,3 +1,4 @@ +// Copyright (c) 2019-2020 The Hush developers /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * * * @@ -210,17 +211,15 @@ void jsonAddBase64(cJSON *params, char *key, unsigned char *bin, size_t size) { } -unsigned char *hashFingerprintContents(asn_TYPE_descriptor_t *asnType, void *fp) { +void hashFingerprintContents(asn_TYPE_descriptor_t *asnType, void *fp, uint8_t *out) { unsigned char buf[BUF_SIZE]; asn_enc_rval_t rc = der_encode_to_buffer(asnType, fp, buf, BUF_SIZE); ASN_STRUCT_FREE(*asnType, fp); if (rc.encoded < 1) { fprintf(stderr, "Encoding fingerprint failed\n"); - return 0; + return; } - unsigned char *hash = calloc(1,32); - sha256(buf, rc.encoded, hash); - return hash; + sha256(buf, rc.encoded, out); } @@ -301,5 +300,3 @@ int jsonGetHexOptional(const cJSON *params, char *key, char *err, unsigned char } return checkDecodeHex(item, key, err, data, size); } - - diff --git a/src/cryptoconditions/tests/test_failure_modes.py b/src/cryptoconditions/tests/test_failure_modes.py index 59b0b3f24..435e20c88 100644 --- a/src/cryptoconditions/tests/test_failure_modes.py +++ b/src/cryptoconditions/tests/test_failure_modes.py @@ -82,4 +82,25 @@ def test_malleability_checked(): assert not cc_rfb(b'\xa2\x13\xa0\x0f\xa0\x06\x80\x04abcd\xa0\x05\x80\x03abc\xa1\x00') +def test_large_threshold(): + conds = [{ + 'type': "secp256k1-sha-256", + "publicKey": "02D5D969305535AC29A77079C11D4F0DD40661CF96E04E974A5E8D7E374EE225AA" + }] + + for i in range(250): + conds.append({ + "type": "eval-sha-256", + "code": "VEVTVAE" + }) + + r = jsonRPC("encodeCondition", { + "type": "threshold-sha-256", + "subfulfillments": conds, + "threshold": 251 + }) + assert 'error' not in r, r + + + so.cc_conditionUri.restype = ctypes.c_char_p diff --git a/src/gtest/main.cpp b/src/gtest/main.cpp index bdebedeb5..28114834c 100644 --- a/src/gtest/main.cpp +++ b/src/gtest/main.cpp @@ -5,9 +5,6 @@ #include "zcash/JoinSplit.hpp" #include "util.h" -#include -#include - #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"; diff --git a/src/gtest/test_circuit.cpp b/src/gtest/test_circuit.cpp deleted file mode 100644 index ab2a8ecb6..000000000 --- a/src/gtest/test_circuit.cpp +++ /dev/null @@ -1,183 +0,0 @@ -#include -#include "uint256.h" - -#include "zcash/util.h" - -#include -#include -#include - -#include -#include -#include -#include - -#include "zcash/IncrementalMerkleTree.hpp" - -using namespace libsnark; -using namespace libzcash; - -#include "zcash/circuit/utils.tcc" -#include "zcash/circuit/merkle.tcc" - -template -void test_value_equals(uint64_t i) { - protoboard pb; - pb_variable_array num; - num.allocate(pb, 64, ""); - num.fill_with_bits(pb, uint64_to_bool_vector(i)); - pb.add_r1cs_constraint(r1cs_constraint( - packed_addition(num), - FieldT::one(), - FieldT::one() * i - ), ""); - ASSERT_TRUE(pb.is_satisfied()); -} - -TEST(circuit, values) -{ - typedef Fr FieldT; - test_value_equals(0); - test_value_equals(1); - test_value_equals(3); - test_value_equals(5391); - test_value_equals(883128374); - test_value_equals(173419028459); - test_value_equals(2205843009213693953); -} - -TEST(circuit, endianness) -{ - std::vector 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 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 bad = {0, 1, 2, 3}; - - ASSERT_THROW(swap_endianness_u64(bad), std::length_error); -} - -template -bool test_merkle_gadget( - bool enforce_a, - bool enforce_b, - bool write_root_first -) -{ - protoboard pb; - digest_variable root(pb, 256, "root"); - pb.set_input_sizes(256); - - digest_variable commitment1(pb, 256, "commitment1"); - digest_variable commitment2(pb, 256, "commitment2"); - - pb_variable commitment1_read; - commitment1_read.allocate(pb); - pb_variable commitment2_read; - commitment2_read.allocate(pb); - - merkle_tree_gadget mgadget1(pb, commitment1, root, commitment1_read); - merkle_tree_gadget 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 FieldT; - - // Test the normal case - ASSERT_TRUE(test_merkle_gadget(true, true, false)); - ASSERT_TRUE(test_merkle_gadget(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(true, false, false)); - ASSERT_TRUE(test_merkle_gadget(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(false, true, false)); - - // Test the last again, except this time write the root first. - ASSERT_TRUE(test_merkle_gadget(false, true, true)); -} diff --git a/src/gtest/test_foundersreward.cpp b/src/gtest/test_foundersreward.cpp deleted file mode 100644 index 7e5a3cf05..000000000 --- a/src/gtest/test_foundersreward.cpp +++ /dev/null @@ -1,194 +0,0 @@ -#include - -#include "main.h" -#include "utilmoneystr.h" -#include "chainparams.h" -#include "utilstrencodings.h" -#include "zcash/Address.hpp" -#include "wallet/wallet.h" -#include "amount.h" -#include -#include -#include -#include -#include -#include "util.h" - -#ifndef disable_founders -// To run tests: -// ./zcash-gtest --gtest_filter="founders_reward_test.*" - -// -// Enable this test to generate and print 48 testnet 2-of-3 multisig addresses. -// The output can be copied into chainparams.cpp. -// The temporary wallet file can be renamed as wallet.dat and used for testing with zcashd. -// -#if 0 -TEST(founders_reward_test, create_testnet_2of3multisig) { - SelectParams(CBaseChainParams::TESTNET); - boost::filesystem::path pathTemp = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); - boost::filesystem::create_directories(pathTemp); - mapArgs["-datadir"] = pathTemp.string(); - bool fFirstRun; - auto pWallet = std::make_shared("wallet.dat"); - ASSERT_EQ(DB_LOAD_OK, pWallet->LoadWallet(fFirstRun)); - pWallet->TopUpKeyPool(); - std::cout << "Test wallet and logs saved in folder: " << pathTemp.native() << std::endl; - - int numKeys = 48; - std::vector pubkeys; - pubkeys.resize(3); - CPubKey newKey; - std::vector addresses; - for (int i = 0; i < numKeys; i++) { - ASSERT_TRUE(pWallet->GetKeyFromPool(newKey)); - pubkeys[0] = newKey; - pWallet->SetAddressBook(newKey.GetID(), "", "receive"); - - ASSERT_TRUE(pWallet->GetKeyFromPool(newKey)); - pubkeys[1] = newKey; - pWallet->SetAddressBook(newKey.GetID(), "", "receive"); - - ASSERT_TRUE(pWallet->GetKeyFromPool(newKey)); - pubkeys[2] = newKey; - pWallet->SetAddressBook(newKey.GetID(), "", "receive"); - - CScript result = GetScriptForMultisig(2, pubkeys); - ASSERT_FALSE(result.size() > MAX_SCRIPT_ELEMENT_SIZE); - CScriptID innerID(result); - pWallet->AddCScript(result); - pWallet->SetAddressBook(innerID, "", "receive"); - - std::string address = EncodeDestination(innerID); - addresses.push_back(address); - } - - // Print out the addresses, 4 on each line. - std::string s = "vFoundersRewardAddress = {\n"; - int i=0; - int colsPerRow = 4; - ASSERT_TRUE(numKeys % colsPerRow == 0); - int numRows = numKeys/colsPerRow; - for (int row=0; rowFlush(true); -} -#endif - - -// Utility method to check the number of unique addresses from height 1 to maxHeight -void checkNumberOfUniqueAddresses(int nUnique) { - int maxHeight = Params().GetConsensus().GetLastFoundersRewardBlockHeight(); - std::set addresses; - for (int i = 1; i <= maxHeight; i++) { - addresses.insert(Params().GetFoundersRewardAddressAtHeight(i)); - } - ASSERT_TRUE(addresses.size() == nUnique); -} - - -TEST(founders_reward_test, general) { - SelectParams(CBaseChainParams::TESTNET); - - CChainParams params = Params(); - - // Fourth testnet reward: - // address = t2ENg7hHVqqs9JwU5cgjvSbxnT2a9USNfhy - // script.ToString() = OP_HASH160 55d64928e69829d9376c776550b6cc710d427153 OP_EQUAL - // HexStr(script) = a91455d64928e69829d9376c776550b6cc710d42715387 - EXPECT_EQ(HexStr(params.GetFoundersRewardScriptAtHeight(1)), "a914ef775f1f997f122a062fff1a2d7443abd1f9c64287"); - EXPECT_EQ(params.GetFoundersRewardAddressAtHeight(1), "t2UNzUUx8mWBCRYPRezvA363EYXyEpHokyi"); - EXPECT_EQ(HexStr(params.GetFoundersRewardScriptAtHeight(53126)), "a914ac67f4c072668138d88a86ff21b27207b283212f87"); - EXPECT_EQ(params.GetFoundersRewardAddressAtHeight(53126), "t2NGQjYMQhFndDHguvUw4wZdNdsssA6K7x2"); - EXPECT_EQ(HexStr(params.GetFoundersRewardScriptAtHeight(53127)), "a91455d64928e69829d9376c776550b6cc710d42715387"); - EXPECT_EQ(params.GetFoundersRewardAddressAtHeight(53127), "t2ENg7hHVqqs9JwU5cgjvSbxnT2a9USNfhy"); - - int maxHeight = params.GetConsensus().GetLastFoundersRewardBlockHeight(); - - // If the block height parameter is out of bounds, there is an assert. - EXPECT_DEATH(params.GetFoundersRewardScriptAtHeight(0), "nHeight"); - EXPECT_DEATH(params.GetFoundersRewardScriptAtHeight(maxHeight+1), "nHeight"); - EXPECT_DEATH(params.GetFoundersRewardAddressAtHeight(0), "nHeight"); - EXPECT_DEATH(params.GetFoundersRewardAddressAtHeight(maxHeight+1), "nHeight"); -} - - -#define NUM_MAINNET_FOUNDER_ADDRESSES 48 - -TEST(founders_reward_test, mainnet) { - SelectParams(CBaseChainParams::MAIN); - checkNumberOfUniqueAddresses(NUM_MAINNET_FOUNDER_ADDRESSES); -} - - -#define NUM_TESTNET_FOUNDER_ADDRESSES 48 - -TEST(founders_reward_test, testnet) { - SelectParams(CBaseChainParams::TESTNET); - checkNumberOfUniqueAddresses(NUM_TESTNET_FOUNDER_ADDRESSES); -} - - -#define NUM_REGTEST_FOUNDER_ADDRESSES 1 - -TEST(founders_reward_test, regtest) { - SelectParams(CBaseChainParams::REGTEST); - checkNumberOfUniqueAddresses(NUM_REGTEST_FOUNDER_ADDRESSES); -} - - - -// Test that 10% founders reward is fully rewarded after the first halving and slow start shift. -// On Mainnet, this would be 2,100,000 ZEC after 850,000 blocks (840,000 + 10,000). -TEST(founders_reward_test, slow_start_subsidy) { - SelectParams(CBaseChainParams::MAIN); - CChainParams params = Params(); - - int maxHeight = params.GetConsensus().GetLastFoundersRewardBlockHeight(); - CAmount totalSubsidy = 0; - for (int nHeight = 1; nHeight <= maxHeight; nHeight++) { - CAmount nSubsidy = GetBlockSubsidy(nHeight, params.GetConsensus()) / 5; - totalSubsidy += nSubsidy; - } - - ASSERT_TRUE(totalSubsidy == MAX_MONEY/10.0); -} - - -// For use with mainnet and testnet which each have 48 addresses. -// Verify the number of rewards each individual address receives. -void verifyNumberOfRewards() { - CChainParams params = Params(); - int maxHeight = params.GetConsensus().GetLastFoundersRewardBlockHeight(); - std::multiset ms; - for (int nHeight = 1; nHeight <= maxHeight; nHeight++) { - ms.insert(params.GetFoundersRewardAddressAtHeight(nHeight)); - } - - ASSERT_TRUE(ms.count(params.GetFoundersRewardAddressAtIndex(0)) == 17708); - for (int i = 1; i <= 46; i++) { - ASSERT_TRUE(ms.count(params.GetFoundersRewardAddressAtIndex(i)) == 17709); - } - ASSERT_TRUE(ms.count(params.GetFoundersRewardAddressAtIndex(47)) == 17677); -} - -// Verify the number of rewards going to each mainnet address -TEST(founders_reward_test, per_address_reward_mainnet) { - SelectParams(CBaseChainParams::MAIN); - verifyNumberOfRewards(); -} - -// Verify the number of rewards going to each testnet address -TEST(founders_reward_test, per_address_reward_testnet) { - SelectParams(CBaseChainParams::TESTNET); - verifyNumberOfRewards(); -} -#endif diff --git a/src/gtest/test_joinsplit.cpp b/src/gtest/test_joinsplit.cpp deleted file mode 100644 index 4de2fc471..000000000 --- a/src/gtest/test_joinsplit.cpp +++ /dev/null @@ -1,616 +0,0 @@ -#include - -#include "utilstrencodings.h" - -#include -#include - -#include "zcash/prf.h" -#include "util.h" -#include "streams.h" -#include "version.h" -#include "serialize.h" -#include "primitives/transaction.h" -#include "zcash/JoinSplit.hpp" -#include "zcash/Note.hpp" -#include "zcash/NoteEncryption.hpp" -#include "zcash/IncrementalMerkleTree.hpp" - -#include - -using namespace libzcash; - -extern ZCJoinSplit* params; - -typedef std::array SproutProofs; -// Make both the PHGR and Groth proof for a Sprout statement, -// and store the results in JSDescription objects. -SproutProofs makeSproutProofs( - ZCJoinSplit& js, - const std::array& inputs, - const std::array& outputs, - const uint256& joinSplitPubKey, - uint64_t vpub_old, - 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}; - -} - -bool verifySproutProofs( - ZCJoinSplit& js, - const SproutProofs& jsdescs, - 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; -} - - -void test_full_api(ZCJoinSplit* js) -{ - // Create verification context. - auto verifier = libzcash::ProofVerifier::Strict(); - - // The recipient's information. - SproutSpendingKey recipient_key = SproutSpendingKey::random(); - SproutPaymentAddress recipient_addr = recipient_key.address(); - - // Create the commitment tree - SproutMerkleTree tree; - - // Set up a JoinSplit description - uint64_t vpub_old = 10; - uint64_t vpub_new = 0; - uint256 joinSplitPubKey = random_uint256(); - uint256 rt = tree.root(); - SproutProofs jsdescs; - - { - std::array inputs = { - JSInput(), // dummy input - JSInput() // dummy input - }; - - std::array outputs = { - JSOutput(recipient_addr, 10), - JSOutput() // dummy output - }; - - std::array output_notes; - - // Perform the proofs - jsdescs = makeSproutProofs( - *js, - inputs, - outputs, - joinSplitPubKey, - vpub_old, - vpub_new, - rt - ); - } - - // Verify both PHGR and Groth Proof: - ASSERT_TRUE(verifySproutProofs(*js, jsdescs, joinSplitPubKey)); - - // Run tests using both phgr and groth as basis for field values - for (auto jsdesc : jsdescs) - { - SproutMerkleTree tree; - SproutProofs jsdescs2; - // Recipient should decrypt - // Now the recipient should spend the money again - auto h_sig = js->h_sig(jsdesc.randomSeed, jsdesc.nullifiers, joinSplitPubKey); - ZCNoteDecryption decryptor(recipient_key.receiving_key()); - - auto note_pt = SproutNotePlaintext::decrypt( - decryptor, - jsdesc.ciphertexts[0], - jsdesc.ephemeralKey, - h_sig, - 0 - ); - - auto decrypted_note = note_pt.note(recipient_addr); - - ASSERT_TRUE(decrypted_note.value() == 10); - - // Insert the commitments from the last tx into the tree - tree.append(jsdesc.commitments[0]); - auto witness_recipient = tree.witness(); - tree.append(jsdesc.commitments[1]); - witness_recipient.append(jsdesc.commitments[1]); - vpub_old = 0; - vpub_new = 1; - rt = tree.root(); - auto joinSplitPubKey2 = random_uint256(); - - { - std::array inputs = { - JSInput(), // dummy input - JSInput(witness_recipient, decrypted_note, recipient_key) - }; - - SproutSpendingKey second_recipient = SproutSpendingKey::random(); - SproutPaymentAddress second_addr = second_recipient.address(); - - std::array outputs = { - JSOutput(second_addr, 9), - JSOutput() // dummy output - }; - - std::array output_notes; - - - // Perform the proofs - jsdescs2 = makeSproutProofs( - *js, - inputs, - outputs, - joinSplitPubKey2, - vpub_old, - vpub_new, - rt - ); - - } - - - // Verify both PHGR and Groth Proof: - ASSERT_TRUE(verifySproutProofs(*js, jsdescs2, joinSplitPubKey2)); - } -} - -// Invokes the API (but does not compute a proof) -// to test exceptions -void invokeAPI( - ZCJoinSplit* js, - const std::array& inputs, - const std::array& outputs, - uint64_t vpub_old, - uint64_t vpub_new, - const uint256& rt -) { - uint256 ephemeralKey; - uint256 randomSeed; - uint256 joinSplitPubKey = random_uint256(); - std::array macs; - std::array nullifiers; - std::array commitments; - std::array ciphertexts; - - std::array 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, - inputs, - outputs, - output_notes, - ciphertexts, - ephemeralKey, - joinSplitPubKey, - randomSeed, - macs, - nullifiers, - commitments, - vpub_old, - vpub_new, - rt, - false - ); -} - -void invokeAPIFailure( - ZCJoinSplit* js, - const std::array& inputs, - const std::array& outputs, - uint64_t vpub_old, - uint64_t vpub_new, - const uint256& rt, - std::string reason -) -{ - try { - invokeAPI(js, inputs, outputs, vpub_old, vpub_new, rt); - FAIL() << "It worked, when it shouldn't have!"; - } catch(std::invalid_argument const & err) { - EXPECT_EQ(err.what(), reason); - } catch(...) { - FAIL() << "Expected invalid_argument exception."; - } -} - -TEST(joinsplit, h_sig) -{ -/* -// by Taylor Hornby - -import pyblake2 -import binascii - -def hSig(randomSeed, nf1, nf2, joinSplitPubKey): - return pyblake2.blake2b( - data=(randomSeed + nf1 + nf2 + joinSplitPubKey), - digest_size=32, - person=b"ZcashComputehSig" - ).digest() - -INCREASING = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F" - -TEST_VECTORS = [ - [b"a" * 32, b"b" * 32, b"c" * 32, b"d" * 32], - [b"\x00" * 32, b"\x00" * 32, b"\x00" * 32, b"\x00" * 32], - [b"\xFF" * 32, b"\xFF" * 32, b"\xFF" * 32, b"\xFF" * 32], - [INCREASING, INCREASING, INCREASING, INCREASING] -] - -for test_input in TEST_VECTORS: - print "---" - print "\"" + binascii.hexlify(test_input[0][::-1]) + "\"" - print "\"" + binascii.hexlify(test_input[1][::-1]) + "\"" - print "\"" + binascii.hexlify(test_input[2][::-1]) + "\"" - print "\"" + binascii.hexlify(test_input[3][::-1]) + "\"" - print "\"" + binascii.hexlify(hSig(test_input[0], test_input[1], test_input[2], test_input[3])[::-1]) + "\"" -*/ - - std::vector> tests = { - { - "6161616161616161616161616161616161616161616161616161616161616161", - "6262626262626262626262626262626262626262626262626262626262626262", - "6363636363636363636363636363636363636363636363636363636363636363", - "6464646464646464646464646464646464646464646464646464646464646464", - "a8cba69f1fa329c055756b4af900f8a00b61e44f4cb8a1824ceb58b90a5b8113" - }, - { - "0000000000000000000000000000000000000000000000000000000000000000", - "0000000000000000000000000000000000000000000000000000000000000000", - "0000000000000000000000000000000000000000000000000000000000000000", - "0000000000000000000000000000000000000000000000000000000000000000", - "697322276b5dd93b12fb1fcbd2144b2960f24c73aac6c6a0811447be1e7f1e19" - }, - { - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - "4961048919f0ca79d49c9378c36a91a8767060001f4212fe6f7d426f3ccf9f32" - }, - { - "1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100", - "1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100", - "1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100", - "1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100", - "b61110ec162693bc3d9ca7fb0eec3afd2e278e2f41394b3ff11d7cb761ad4b27" - } - }; - - BOOST_FOREACH(std::vector& v, tests) { - auto expected = ZCJoinSplit::h_sig( - uint256S(v[0]), - {uint256S(v[1]), uint256S(v[2])}, - uint256S(v[3]) - ); - - EXPECT_EQ(expected, uint256S(v[4])); - } -} - -void increment_note_witnesses( - const uint256& element, - std::vector& witnesses, - SproutMerkleTree& tree -) -{ - tree.append(element); - for (SproutWitness& w : witnesses) { - w.append(element); - } - witnesses.push_back(tree.witness()); -} - -TEST(joinsplit, full_api_test) -{ - { - std::vector witnesses; - SproutMerkleTree tree; - increment_note_witnesses(uint256(), witnesses, tree); - SproutSpendingKey sk = SproutSpendingKey::random(); - SproutPaymentAddress addr = sk.address(); - SproutNote note1(addr.a_pk, 100, random_uint256(), random_uint256()); - increment_note_witnesses(note1.cm(), witnesses, tree); - SproutNote note2(addr.a_pk, 100, random_uint256(), random_uint256()); - increment_note_witnesses(note2.cm(), witnesses, tree); - SproutNote note3(addr.a_pk, 2100000000000001, random_uint256(), random_uint256()); - increment_note_witnesses(note3.cm(), witnesses, tree); - SproutNote note4(addr.a_pk, 1900000000000000, random_uint256(), random_uint256()); - increment_note_witnesses(note4.cm(), witnesses, tree); - SproutNote note5(addr.a_pk, 1900000000000000, random_uint256(), random_uint256()); - increment_note_witnesses(note5.cm(), witnesses, tree); - - // Should work - invokeAPI(params, - { - JSInput(), - JSInput() - }, - { - JSOutput(), - JSOutput() - }, - 0, - 0, - tree.root()); - - // lhs > MAX_MONEY - invokeAPIFailure(params, - { - JSInput(), - JSInput() - }, - { - JSOutput(), - JSOutput() - }, - 2100000000000001, - 0, - tree.root(), - "nonsensical vpub_old value"); - - // rhs > MAX_MONEY - invokeAPIFailure(params, - { - JSInput(), - JSInput() - }, - { - JSOutput(), - JSOutput() - }, - 0, - 2100000000000001, - tree.root(), - "nonsensical vpub_new value"); - - // input witness for the wrong element - invokeAPIFailure(params, - { - JSInput(witnesses[0], note1, sk), - JSInput() - }, - { - JSOutput(), - JSOutput() - }, - 0, - 100, - tree.root(), - "witness of wrong element for joinsplit input"); - - // input witness doesn't match up with - // real root - invokeAPIFailure(params, - { - JSInput(witnesses[1], note1, sk), - JSInput() - }, - { - JSOutput(), - JSOutput() - }, - 0, - 100, - uint256(), - "joinsplit not anchored to the correct root"); - - // input is in the tree now! this should work - invokeAPI(params, - { - JSInput(witnesses[1], note1, sk), - JSInput() - }, - { - JSOutput(), - JSOutput() - }, - 0, - 100, - tree.root()); - - // Wrong secret key - invokeAPIFailure(params, - { - JSInput(witnesses[1], note1, SproutSpendingKey::random()), - JSInput() - }, - { - JSOutput(), - JSOutput() - }, - 0, - 0, - tree.root(), - "input note not authorized to spend with given key"); - - // Absurd input value - invokeAPIFailure(params, - { - JSInput(witnesses[3], note3, sk), - JSInput() - }, - { - JSOutput(), - JSOutput() - }, - 0, - 0, - tree.root(), - "nonsensical input note value"); - - // Absurd total input value - invokeAPIFailure(params, - { - JSInput(witnesses[4], note4, sk), - JSInput(witnesses[5], note5, sk) - }, - { - JSOutput(), - JSOutput() - }, - 0, - 0, - tree.root(), - "nonsensical left hand size of joinsplit balance"); - - // Absurd output value - invokeAPIFailure(params, - { - JSInput(), - JSInput() - }, - { - JSOutput(addr, 2100000000000001), - JSOutput() - }, - 0, - 0, - tree.root(), - "nonsensical output value"); - - // Absurd total output value - invokeAPIFailure(params, - { - JSInput(), - JSInput() - }, - { - JSOutput(addr, 1900000000000000), - JSOutput(addr, 1900000000000000) - }, - 0, - 0, - tree.root(), - "nonsensical right hand side of joinsplit balance"); - - // Absurd total output value - invokeAPIFailure(params, - { - JSInput(), - JSInput() - }, - { - JSOutput(addr, 1900000000000000), - JSOutput() - }, - 0, - 0, - tree.root(), - "invalid joinsplit balance"); - } - - test_full_api(params); -} - -TEST(joinsplit, note_plaintexts) -{ - uint252 a_sk = uint252(uint256S("f6da8716682d600f74fc16bd0187faad6a26b4aa4c24d5c055b216d94516840e")); - uint256 a_pk = PRF_addr_a_pk(a_sk); - uint256 sk_enc = ZCNoteEncryption::generate_privkey(a_sk); - uint256 pk_enc = ZCNoteEncryption::generate_pubkey(sk_enc); - SproutPaymentAddress addr_pk(a_pk, pk_enc); - - uint256 h_sig; - - ZCNoteEncryption encryptor(h_sig); - uint256 epk = encryptor.get_epk(); - - SproutNote note(a_pk, - 1945813, - random_uint256(), - random_uint256() - ); - - std::array memo; - - SproutNotePlaintext note_pt(note, memo); - - ZCNoteEncryption::Ciphertext ct = note_pt.encrypt(encryptor, pk_enc); - - ZCNoteDecryption decryptor(sk_enc); - - auto decrypted = SproutNotePlaintext::decrypt(decryptor, ct, epk, h_sig, 0); - auto decrypted_note = decrypted.note(addr_pk); - - ASSERT_TRUE(decrypted_note.a_pk == note.a_pk); - ASSERT_TRUE(decrypted_note.rho == note.rho); - ASSERT_TRUE(decrypted_note.r == note.r); - ASSERT_TRUE(decrypted_note.value() == note.value()); - - ASSERT_TRUE(decrypted.memo() == note_pt.memo()); - - // Check memo() returns by reference, not return by value, for use cases such as: - // std::string data(plaintext.memo().begin(), plaintext.memo().end()); - ASSERT_TRUE(decrypted.memo().data() == decrypted.memo().data()); - - // Check serialization of note plaintext - CDataStream ss(SER_DISK, PROTOCOL_VERSION); - ss << note_pt; - SproutNotePlaintext note_pt2; - ss >> note_pt2; - ASSERT_EQ(note_pt.value(), note.value()); - ASSERT_EQ(note_pt.value(), note_pt2.value()); - ASSERT_EQ(note_pt.memo(), note_pt2.memo()); - ASSERT_EQ(note_pt.rho, note_pt2.rho); - ASSERT_EQ(note_pt.r, note_pt2.r); -} - -TEST(joinsplit, note_class) -{ - uint252 a_sk = uint252(uint256S("f6da8716682d600f74fc16bd0187faad6a26b4aa4c24d5c055b216d94516840e")); - uint256 a_pk = PRF_addr_a_pk(a_sk); - uint256 sk_enc = ZCNoteEncryption::generate_privkey(a_sk); - uint256 pk_enc = ZCNoteEncryption::generate_pubkey(sk_enc); - SproutPaymentAddress addr_pk(a_pk, pk_enc); - - SproutNote note(a_pk, - 1945813, - random_uint256(), - random_uint256()); - - SproutNote clone = note; - ASSERT_NE(¬e, &clone); - ASSERT_EQ(note.value(), clone.value()); - ASSERT_EQ(note.cm(), clone.cm()); - ASSERT_EQ(note.rho, clone.rho); - ASSERT_EQ(note.r, clone.r); - ASSERT_EQ(note.a_pk, clone.a_pk); -} diff --git a/src/gtest/test_keystore.cpp b/src/gtest/test_keystore.cpp index ccf9cb9ba..a8c984984 100644 --- a/src/gtest/test_keystore.cpp +++ b/src/gtest/test_keystore.cpp @@ -95,101 +95,6 @@ TEST(keystore_tests, sapling_keys) { } } -TEST(keystore_tests, store_and_retrieve_spending_key) { - CBasicKeyStore keyStore; - libzcash::SproutSpendingKey skOut; - - std::set addrs; - keyStore.GetSproutPaymentAddresses(addrs); - EXPECT_EQ(0, addrs.size()); - - auto sk = libzcash::SproutSpendingKey::random(); - auto addr = sk.address(); - - // Sanity-check: we can't get a key we haven't added - EXPECT_FALSE(keyStore.HaveSproutSpendingKey(addr)); - EXPECT_FALSE(keyStore.GetSproutSpendingKey(addr, skOut)); - - keyStore.AddSproutSpendingKey(sk); - EXPECT_TRUE(keyStore.HaveSproutSpendingKey(addr)); - EXPECT_TRUE(keyStore.GetSproutSpendingKey(addr, skOut)); - EXPECT_EQ(sk, skOut); - - keyStore.GetSproutPaymentAddresses(addrs); - EXPECT_EQ(1, addrs.size()); - EXPECT_EQ(1, addrs.count(addr)); -} - -TEST(keystore_tests, store_and_retrieve_note_decryptor) { - CBasicKeyStore keyStore; - ZCNoteDecryption decOut; - - auto sk = libzcash::SproutSpendingKey::random(); - auto addr = sk.address(); - - EXPECT_FALSE(keyStore.GetNoteDecryptor(addr, decOut)); - - keyStore.AddSproutSpendingKey(sk); - EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut)); - EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut); -} - -TEST(keystore_tests, StoreAndRetrieveViewingKey) { - CBasicKeyStore keyStore; - libzcash::SproutViewingKey vkOut; - libzcash::SproutSpendingKey skOut; - ZCNoteDecryption decOut; - - auto sk = libzcash::SproutSpendingKey::random(); - auto vk = sk.viewing_key(); - auto addr = sk.address(); - - // Sanity-check: we can't get a viewing key we haven't added - EXPECT_FALSE(keyStore.HaveSproutViewingKey(addr)); - EXPECT_FALSE(keyStore.GetSproutViewingKey(addr, vkOut)); - - // and we shouldn't have a spending key or decryptor either - EXPECT_FALSE(keyStore.HaveSproutSpendingKey(addr)); - EXPECT_FALSE(keyStore.GetSproutSpendingKey(addr, skOut)); - EXPECT_FALSE(keyStore.GetNoteDecryptor(addr, decOut)); - - // and we can't find it in our list of addresses - std::set addresses; - keyStore.GetSproutPaymentAddresses(addresses); - EXPECT_FALSE(addresses.count(addr)); - - keyStore.AddSproutViewingKey(vk); - EXPECT_TRUE(keyStore.HaveSproutViewingKey(addr)); - EXPECT_TRUE(keyStore.GetSproutViewingKey(addr, vkOut)); - EXPECT_EQ(vk, vkOut); - - // We should still not have the spending key... - EXPECT_FALSE(keyStore.HaveSproutSpendingKey(addr)); - EXPECT_FALSE(keyStore.GetSproutSpendingKey(addr, skOut)); - - // ... but we should have a decryptor - EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut)); - EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut); - - // ... and we should find it in our list of addresses - addresses.clear(); - keyStore.GetSproutPaymentAddresses(addresses); - EXPECT_TRUE(addresses.count(addr)); - - keyStore.RemoveSproutViewingKey(vk); - EXPECT_FALSE(keyStore.HaveSproutViewingKey(addr)); - EXPECT_FALSE(keyStore.GetSproutViewingKey(addr, vkOut)); - EXPECT_FALSE(keyStore.HaveSproutSpendingKey(addr)); - EXPECT_FALSE(keyStore.GetSproutSpendingKey(addr, skOut)); - addresses.clear(); - keyStore.GetSproutPaymentAddresses(addresses); - EXPECT_FALSE(addresses.count(addr)); - - // We still have a decryptor because those are cached in memory - // (and also we only remove viewing keys when adding a spending key) - EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut)); - EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut); -} // Sapling TEST(keystore_tests, StoreAndRetrieveSaplingSpendingKey) { @@ -280,9 +185,6 @@ TEST(keystore_tests, StoreAndRetrieveHDSeedInEncryptedStore) { // 3) Test adding a new seed to an already-encrypted key store TestCCryptoKeyStore keyStore2; - // Add a Sprout address so the wallet has something to test when decrypting - ASSERT_TRUE(keyStore2.AddSproutSpendingKey(libzcash::SproutSpendingKey::random())); - ASSERT_TRUE(keyStore2.EncryptKeys(vMasterKey)); ASSERT_TRUE(keyStore2.Unlock(vMasterKey)); @@ -296,78 +198,4 @@ TEST(keystore_tests, StoreAndRetrieveHDSeedInEncryptedStore) { EXPECT_EQ(seed3, seedOut); } -TEST(keystore_tests, store_and_retrieve_spending_key_in_encrypted_store) { - TestCCryptoKeyStore keyStore; - uint256 r {GetRandHash()}; - CKeyingMaterial vMasterKey (r.begin(), r.end()); - libzcash::SproutSpendingKey keyOut; - ZCNoteDecryption decOut; - std::set addrs; - - // 1) Test adding a key to an unencrypted key store, then encrypting it - auto sk = libzcash::SproutSpendingKey::random(); - auto addr = sk.address(); - EXPECT_FALSE(keyStore.GetNoteDecryptor(addr, decOut)); - - keyStore.AddSproutSpendingKey(sk); - ASSERT_TRUE(keyStore.HaveSproutSpendingKey(addr)); - ASSERT_TRUE(keyStore.GetSproutSpendingKey(addr, keyOut)); - ASSERT_EQ(sk, keyOut); - EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut)); - EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut); - - ASSERT_TRUE(keyStore.EncryptKeys(vMasterKey)); - ASSERT_TRUE(keyStore.HaveSproutSpendingKey(addr)); - ASSERT_FALSE(keyStore.GetSproutSpendingKey(addr, keyOut)); - EXPECT_TRUE(keyStore.GetNoteDecryptor(addr, decOut)); - EXPECT_EQ(ZCNoteDecryption(sk.receiving_key()), decOut); - - // Unlocking with a random key should fail - uint256 r2 {GetRandHash()}; - CKeyingMaterial vRandomKey (r2.begin(), r2.end()); - EXPECT_FALSE(keyStore.Unlock(vRandomKey)); - - // Unlocking with a slightly-modified vMasterKey should fail - CKeyingMaterial vModifiedKey (r.begin(), r.end()); - vModifiedKey[0] += 1; - EXPECT_FALSE(keyStore.Unlock(vModifiedKey)); - - // Unlocking with vMasterKey should succeed - ASSERT_TRUE(keyStore.Unlock(vMasterKey)); - ASSERT_TRUE(keyStore.GetSproutSpendingKey(addr, keyOut)); - ASSERT_EQ(sk, keyOut); - - keyStore.GetSproutPaymentAddresses(addrs); - ASSERT_EQ(1, addrs.size()); - ASSERT_EQ(1, addrs.count(addr)); - - // 2) Test adding a spending key to an already-encrypted key store - auto sk2 = libzcash::SproutSpendingKey::random(); - auto addr2 = sk2.address(); - EXPECT_FALSE(keyStore.GetNoteDecryptor(addr2, decOut)); - - keyStore.AddSproutSpendingKey(sk2); - ASSERT_TRUE(keyStore.HaveSproutSpendingKey(addr2)); - ASSERT_TRUE(keyStore.GetSproutSpendingKey(addr2, keyOut)); - ASSERT_EQ(sk2, keyOut); - EXPECT_TRUE(keyStore.GetNoteDecryptor(addr2, decOut)); - EXPECT_EQ(ZCNoteDecryption(sk2.receiving_key()), decOut); - - ASSERT_TRUE(keyStore.Lock()); - ASSERT_TRUE(keyStore.HaveSproutSpendingKey(addr2)); - ASSERT_FALSE(keyStore.GetSproutSpendingKey(addr2, keyOut)); - EXPECT_TRUE(keyStore.GetNoteDecryptor(addr2, decOut)); - EXPECT_EQ(ZCNoteDecryption(sk2.receiving_key()), decOut); - - ASSERT_TRUE(keyStore.Unlock(vMasterKey)); - ASSERT_TRUE(keyStore.GetSproutSpendingKey(addr2, keyOut)); - ASSERT_EQ(sk2, keyOut); - EXPECT_TRUE(keyStore.GetNoteDecryptor(addr2, decOut)); - EXPECT_EQ(ZCNoteDecryption(sk2.receiving_key()), decOut); - - keyStore.GetSproutPaymentAddresses(addrs); - ASSERT_EQ(2, addrs.size()); - ASSERT_EQ(1, addrs.count(addr)); - ASSERT_EQ(1, addrs.count(addr2)); -} #endif diff --git a/src/gtest/test_merkletree.cpp b/src/gtest/test_merkletree.cpp index 23c39c044..ad3c2ad06 100644 --- a/src/gtest/test_merkletree.cpp +++ b/src/gtest/test_merkletree.cpp @@ -1,14 +1,12 @@ #include #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 -#include -#include -#include - #include #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 FieldT; - - protoboard pb; - pb_variable_array positions; - digest_variable commitment(pb, 256, "commitment"); - digest_variable root(pb, 256, "root"); - positions.allocate(pb, INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, "pos"); - merkle_authentication_path_variable> authvars(pb, INCREMENTAL_MERKLE_TREE_DEPTH_TESTING, "auth"); - merkle_tree_check_read_gadget> 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 commitment_bv; - { - uint256 witnessed_commitment = wit.element(); - std::vector 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 root_bv; - { - uint256 witroot = wit.root(); - std::vector 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 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 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"); diff --git a/src/gtest/test_paymentdisclosure.cpp b/src/gtest/test_paymentdisclosure.cpp deleted file mode 100644 index c166cdbe1..000000000 --- a/src/gtest/test_paymentdisclosure.cpp +++ /dev/null @@ -1,211 +0,0 @@ -#include - -#include "main.h" -#include "utilmoneystr.h" -#include "chainparams.h" -#include "utilstrencodings.h" -#include "zcash/Address.hpp" -#include "wallet/wallet.h" -#include "amount.h" - -#include -#include -#include -#include -#include -#include -#include -#include "util.h" - -#include "paymentdisclosure.h" -#include "paymentdisclosuredb.h" - -#include "sodium.h" - -#include -#include -#include - -using namespace std; - -/* - To run tests: - ./zcash-gtest --gtest_filter="paymentdisclosure.*" - - Note: As an experimental feature, writing your own tests may require option flags to be set. - mapArgs["-experimentalfeatures"] = true; - mapArgs["-paymentdisclosure"] = true; -*/ - -#define NUM_TRIES 10000 - -#define DUMP_DATABASE_TO_STDOUT false - -static boost::uuids::random_generator uuidgen; - -static uint256 random_uint256() -{ - uint256 ret; - randombytes_buf(ret.begin(), 32); - return ret; -} - -// Subclass of PaymentDisclosureDB to add debugging methods -class PaymentDisclosureDBTest : public PaymentDisclosureDB { -public: - PaymentDisclosureDBTest(const boost::filesystem::path& dbPath) : PaymentDisclosureDB(dbPath) {} - - void DebugDumpAllStdout() { - ASSERT_NE(db, nullptr); - std::lock_guard guard(lock_); - - // Iterate over each item in the database and print them - leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions()); - - for (it->SeekToFirst(); it->Valid(); it->Next()) { - cout << it->key().ToString() << " : "; - // << it->value().ToString() << endl; - try { - std::string strValue = it->value().ToString(); - PaymentDisclosureInfo info; - CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(), SER_DISK, CLIENT_VERSION); - ssValue >> info; - cout << info.ToString() << std::endl; - } catch (const std::exception& e) { - cout << e.what() << std::endl; - } - } - - if (false == it->status().ok()) { - cerr << "An error was found iterating over the database" << endl; - cerr << it->status().ToString() << endl; - } - - delete it; - } -}; - - - -// This test creates random payment disclosure blobs and checks that they can be -// 1. inserted and retrieved from a database -// 2. serialized and deserialized without corruption -// Note that the zpd: prefix is not part of the payment disclosure blob itself. It is only -// used as convention to improve the user experience when sharing payment disclosure blobs. -TEST(paymentdisclosure, mainnet) { - SelectParams(CBaseChainParams::MAIN); - - boost::filesystem::path pathTemp = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); - boost::filesystem::create_directories(pathTemp); - mapArgs["-datadir"] = pathTemp.string(); - - std::cout << "Test payment disclosure database created in folder: " << pathTemp.string() << std::endl; - - PaymentDisclosureDBTest mydb(pathTemp); - - for (int i=0; i vch(&buffer[0], &buffer[0] + 32); - uint256 joinSplitPrivKey = uint256(vch); - - // Create payment disclosure key and info data to store in test database - size_t js = random_uint256().GetCheapHash() % std::numeric_limits::max(); - uint8_t n = random_uint256().GetCheapHash() % std::numeric_limits::max(); - PaymentDisclosureKey key { random_uint256(), js, n}; - PaymentDisclosureInfo info; - info.esk = random_uint256(); - info.joinSplitPrivKey = joinSplitPrivKey; - info.zaddr = libzcash::SproutSpendingKey::random().address(); - ASSERT_TRUE(mydb.Put(key, info)); - - // Retrieve info from test database into new local variable and test it matches - PaymentDisclosureInfo info2; - ASSERT_TRUE(mydb.Get(key, info2)); - ASSERT_EQ(info, info2); - - // Modify this local variable and confirm it no longer matches - info2.esk = random_uint256(); - info2.joinSplitPrivKey = random_uint256(); - info2.zaddr = libzcash::SproutSpendingKey::random().address(); - ASSERT_NE(info, info2); - - // Using the payment info object, let's create a dummy payload - PaymentDisclosurePayload payload; - payload.version = PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL; - payload.esk = info.esk; - payload.txid = key.hash; - payload.js = key.js; - payload.n = key.n; - payload.message = "random-" + boost::uuids::to_string(uuidgen()); // random message - payload.zaddr = info.zaddr; - - // Serialize and hash the payload to generate a signature - uint256 dataToBeSigned = SerializeHash(payload, SER_GETHASH, 0); - - // Compute the payload signature - unsigned char payloadSig[64]; - if (!(crypto_sign_detached(&payloadSig[0], NULL, - dataToBeSigned.begin(), 32, - &buffer[0] // buffer containing both private and public key required - ) == 0)) - { - throw std::runtime_error("crypto_sign_detached failed"); - } - - // Sanity check - if (!(crypto_sign_verify_detached(&payloadSig[0], - dataToBeSigned.begin(), 32, - joinSplitPubKey.begin() - ) == 0)) - { - throw std::runtime_error("crypto_sign_verify_detached failed"); - } - - // Convert signature buffer to boost array - std::array arrayPayloadSig; - memcpy(arrayPayloadSig.data(), &payloadSig[0], 64); - - // Payment disclosure blob to pass around - PaymentDisclosure pd = {payload, arrayPayloadSig}; - - // Test payment disclosure constructors - PaymentDisclosure pd2(payload, arrayPayloadSig); - ASSERT_EQ(pd, pd2); - PaymentDisclosure pd3(joinSplitPubKey, key, info, payload.message); - ASSERT_EQ(pd, pd3); - - // Verify serialization and deserialization works - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << pd; - std::string ssHexString = HexStr(ss.begin(), ss.end()); - - PaymentDisclosure pdTmp; - CDataStream ssTmp(ParseHex(ssHexString), SER_NETWORK, PROTOCOL_VERSION); - ssTmp >> pdTmp; - ASSERT_EQ(pd, pdTmp); - - CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION); - ss2 << pdTmp; - std::string ss2HexString = HexStr(ss2.begin(), ss2.end()); - ASSERT_EQ(ssHexString, ss2HexString); - - // Verify marker - ASSERT_EQ(pd.payload.marker, PAYMENT_DISCLOSURE_PAYLOAD_MAGIC_BYTES); - ASSERT_EQ(pdTmp.payload.marker, PAYMENT_DISCLOSURE_PAYLOAD_MAGIC_BYTES); - ASSERT_EQ(0, ssHexString.find("706462ff")); // Little endian encoding of PAYMENT_DISCLOSURE_PAYLOAD_MAGIC_BYTES value - - // Sanity check - PaymentDisclosure pdDummy; - ASSERT_NE(pd, pdDummy); - } - -#if DUMP_DATABASE_TO_STDOUT == true - mydb.DebugDumpAllStdout(); -#endif -} diff --git a/src/gtest/test_proofs.cpp b/src/gtest/test_proofs.cpp deleted file mode 100644 index 5b5c19395..000000000 --- a/src/gtest/test_proofs.cpp +++ /dev/null @@ -1,702 +0,0 @@ -#include -#include "zcash/Proof.hpp" - -#include - -#include -#include -#include - -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(); - 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(); - - 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(); - - 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(); - - ASSERT_TRUE(e == e4); - } -} - -template -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(s).to_libsnark_fq(); -} - -curve_Fq2 deserialize_fq2(std::string s) -{ - return deserialize_tv(s).to_libsnark_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(); - - 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(); - - ASSERT_TRUE(e == e4); - } -} - -TEST(proofs, zksnark_serializes_properly) -{ - auto example = libsnark::generate_r1cs_example_with_field_input(250, 4); - example.constraint_system.swap_AB_if_beneficial(); - auto kp = libsnark::r1cs_ppzksnark_generator(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>(); - - 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( - 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( - 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>(); - - ASSERT_TRUE(proof == newproof); - ASSERT_TRUE(libsnark::r1cs_ppzksnark_verifier_strong_IC( - 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() == 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() == -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(), 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(), 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(); - } 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() == 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() == -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(), 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(), 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(); - } 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() == 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() == e); - } -} diff --git a/src/gtest/test_transaction.cpp b/src/gtest/test_transaction.cpp deleted file mode 100644 index 1350768ff..000000000 --- a/src/gtest/test_transaction.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include - -#include "primitives/transaction.h" -#include "zcash/Note.hpp" -#include "zcash/Address.hpp" - -#include - -extern ZCJoinSplit* params; -extern int GenZero(int n); -extern int GenMax(int n); - -TEST(Transaction, JSDescriptionRandomized) { - // construct a merkle tree - SproutMerkleTree merkleTree; - - libzcash::SproutSpendingKey k = libzcash::SproutSpendingKey::random(); - libzcash::SproutPaymentAddress addr = k.address(); - - libzcash::SproutNote note(addr.a_pk, 100, uint256(), uint256()); - - // commitment from coin - uint256 commitment = note.cm(); - - // insert commitment into the merkle tree - merkleTree.append(commitment); - - // compute the merkle root we will be working with - uint256 rt = merkleTree.root(); - - auto witness = merkleTree.witness(); - - // create JSDescription - uint256 joinSplitPubKey; - std::array inputs = { - libzcash::JSInput(witness, note, k), - libzcash::JSInput() // dummy input of zero value - }; - std::array outputs = { - libzcash::JSOutput(addr, 50), - libzcash::JSOutput(addr, 50) - }; - std::array inputMap; - std::array outputMap; - - { - auto jsdesc = JSDescription::Randomized( - false, - *params, joinSplitPubKey, rt, - inputs, outputs, - inputMap, outputMap, - 0, 0, false); - - std::set inputSet(inputMap.begin(), inputMap.end()); - std::set expectedInputSet {0, 1}; - EXPECT_EQ(expectedInputSet, inputSet); - - std::set outputSet(outputMap.begin(), outputMap.end()); - std::set expectedOutputSet {0, 1}; - EXPECT_EQ(expectedOutputSet, outputSet); - } - - { - auto jsdesc = JSDescription::Randomized( - false, - *params, joinSplitPubKey, rt, - inputs, outputs, - inputMap, outputMap, - 0, 0, false, nullptr, GenZero); - - std::array expectedInputMap {1, 0}; - std::array expectedOutputMap {1, 0}; - EXPECT_EQ(expectedInputMap, inputMap); - EXPECT_EQ(expectedOutputMap, outputMap); - } - - { - auto jsdesc = JSDescription::Randomized( - false, - *params, joinSplitPubKey, rt, - inputs, outputs, - inputMap, outputMap, - 0, 0, false, nullptr, GenMax); - - std::array expectedInputMap {0, 1}; - std::array expectedOutputMap {0, 1}; - EXPECT_EQ(expectedInputMap, inputMap); - EXPECT_EQ(expectedOutputMap, outputMap); - } -} diff --git a/src/httpserver.cpp b/src/httpserver.cpp index e1d235665..603e1e6ae 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -11,6 +11,7 @@ #include "rpc/protocol.h" // For HTTP status codes #include "sync.h" #include "ui_interface.h" +#include "utilstrencodings.h" #include #include @@ -251,21 +252,25 @@ static void http_request_cb(struct evhttp_request* req, void* arg) { std::unique_ptr hreq(new HTTPRequest(req)); - LogPrint("http", "Received a %s request for %s from %s\n", - RequestMethodString(hreq->GetRequestMethod()), hreq->GetURI(), hreq->GetPeer().ToString()); - // Early address-based allow check if (!ClientAllowed(hreq->GetPeer())) { + LogPrint("http", "HTTP request from %s rejected: Client network is not allowed RPC access\n", + hreq->GetPeer().ToString()); hreq->WriteReply(HTTP_FORBIDDEN); return; } // Early reject unknown HTTP methods if (hreq->GetRequestMethod() == HTTPRequest::UNKNOWN) { + LogPrint("http", "HTTP request from %s rejected: Unknown HTTP request method\n", + hreq->GetPeer().ToString()); hreq->WriteReply(HTTP_BADMETHOD); return; } + LogPrint("http", "Received a %s request for %s from %s\n", + RequestMethodString(hreq->GetRequestMethod()), SanitizeString(hreq->GetURI(), SAFE_CHARS_URI).substr(0, 100), hreq->GetPeer().ToString()); + // Find registered handler for prefix std::string strURI = hreq->GetURI(); std::string path; diff --git a/src/hush-cli b/src/hush-cli index bf4511073..9cc47207a 100755 --- a/src/hush-cli +++ b/src/hush-cli @@ -1,5 +1,6 @@ #!/bin/bash -# Copyright (c) 2019 Hush developers +# Copyright (c) 2019-2020 Hush developers +# Released under the GPLv3 # set working directory to the location of this script # readlink -f does not always exist diff --git a/src/hush-tx b/src/hush-tx index 2152315ad..17f8bc6b8 100755 --- a/src/hush-tx +++ b/src/hush-tx @@ -1,5 +1,6 @@ #!/bin/bash -# Copyright (c) 2019 Hush developers +# Copyright (c) 2019-2020 Hush developers +# Released under the GPLv3 # set working directory to the location of this script DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" diff --git a/src/init.cpp b/src/init.cpp index 7f660c555..d52888503 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -57,6 +57,7 @@ #ifdef ENABLE_WALLET #include "wallet/wallet.h" #include "wallet/walletdb.h" +#include "wallet/asyncrpcoperation_saplingconsolidation.h" #endif #include @@ -79,16 +80,10 @@ #include #include -#include - #if ENABLE_ZMQ #include "zmq/zmqnotificationinterface.h" #endif -#if ENABLE_PROTON -#include "amqp/amqpnotificationinterface.h" -#endif - #include "librustzcash.h" using namespace std; @@ -102,7 +97,7 @@ extern int32_t KOMODO_SNAPSHOT_INTERVAL; extern void komodo_init(int32_t height); -ZCJoinSplit* pzcashParams = NULL; +//ZCJoinSplit* pzcashParams = NULL; #ifdef ENABLE_WALLET CWallet* pwalletMain = NULL; @@ -113,10 +108,6 @@ bool fFeeEstimatesInitialized = false; static CZMQNotificationInterface* pzmqNotificationInterface = NULL; #endif -#if ENABLE_PROTON -static AMQPNotificationInterface* pAMQPNotificationInterface = NULL; -#endif - #ifdef WIN32 // Win32 LevelDB doesn't use file descriptors, and the ones used for // accessing block files don't count towards the fd_set size limit @@ -286,14 +277,6 @@ void Shutdown() } #endif -#if ENABLE_PROTON - if (pAMQPNotificationInterface) { - UnregisterValidationInterface(pAMQPNotificationInterface); - delete pAMQPNotificationInterface; - pAMQPNotificationInterface = NULL; - } -#endif - #ifndef WIN32 try { boost::filesystem::remove(GetPidFile()); @@ -306,8 +289,8 @@ void Shutdown() delete pwalletMain; pwalletMain = NULL; #endif - delete pzcashParams; - pzcashParams = NULL; + //delete pzcashParams; + //pzcashParams = NULL; globalVerifyHandle.reset(); ECC_Stop(); LogPrintf("%s: done\n", __func__); @@ -400,6 +383,7 @@ std::string HelpMessage(HelpMessageMode mode) #ifndef _WIN32 strUsage += HelpMessageOpt("-pid=", strprintf(_("Specify pid file (default: %s)"), "komodod.pid")); #endif + strUsage += HelpMessageOpt("-txexpirynotify=", _("Execute command when transaction expires (%s in cmd is replaced by transaction id)")); strUsage += HelpMessageOpt("-prune=", strprintf(_("Reduce storage requirements by pruning (deleting) old blocks. This mode disables wallet support and is incompatible with -txindex. " "Warning: Reverting this setting requires re-downloading the entire blockchain. " "(default: 0 = disable pruning blocks, >%u = target size in MiB to use for block files)"), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024)); @@ -449,11 +433,18 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageGroup(_("Wallet options:")); strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls")); strUsage += HelpMessageOpt("-keypool=", strprintf(_("Set key pool size to (default: %u)"), 100)); + strUsage += HelpMessageOpt("-consolidation", _("Enable auto Sapling note consolidation (default: false)")); + strUsage += HelpMessageOpt("-consolidatesaplingaddress=", _("Specify Sapling Address to Consolidate. (default: all)")); + strUsage += HelpMessageOpt("-consolidationtxfee", strprintf(_("Fee amount in Puposhis used send consolidation transactions. (default %i)"), DEFAULT_CONSOLIDATION_FEE)); + strUsage += HelpMessageOpt("-deletetx", _("Enable Old Transaction Deletion")); + strUsage += HelpMessageOpt("-deleteinterval", strprintf(_("Delete transaction every blocks during inital block download (default: %i)"), DEFAULT_TX_DELETE_INTERVAL)); + strUsage += HelpMessageOpt("-keeptxnum", strprintf(_("Keep the last transactions (default: %i)"), DEFAULT_TX_RETENTION_LASTTX)); + strUsage += HelpMessageOpt("-keeptxfornblocks", strprintf(_("Keep transactions for at least blocks (default: %i)"), DEFAULT_TX_RETENTION_BLOCKS)); if (showDebug) strUsage += HelpMessageOpt("-mintxfee=", strprintf("Fees (in %s/kB) smaller than this are considered zero fee for transaction creation (default: %s)", CURRENCY_UNIT, FormatMoney(CWallet::minTxFee.GetFeePerK()))); - strUsage += HelpMessageOpt("-paytxfee=", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"), - CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK()))); + strUsage += HelpMessageOpt("-opretmintxfee=", strprintf(_("Minimum fee (in %s/kB) to allow for OP_RETURN transactions (default: %s)"), CURRENCY_UNIT, 400000 )); + strUsage += HelpMessageOpt("-paytxfee=", strprintf(_("Fee (in %s/kB) to add to transactions you send (default: %s)"), CURRENCY_UNIT, FormatMoney(payTxFee.GetFeePerK()))); strUsage += HelpMessageOpt("-rescan", _("Rescan the block chain for missing wallet transactions") + " " + _("on startup")); strUsage += HelpMessageOpt("-salvagewallet", _("Attempt to recover private keys from a corrupt wallet.dat") + " " + _("on startup")); strUsage += HelpMessageOpt("-sendfreetransactions", strprintf(_("Send transactions as zero-fee transactions if possible (default: %u)"), 0)); @@ -479,14 +470,6 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-zmqpubrawtx=
", _("Enable publish raw transaction in
")); #endif -#if ENABLE_PROTON - strUsage += HelpMessageGroup(_("AMQP 1.0 notification options:")); - strUsage += HelpMessageOpt("-amqppubhashblock=
", _("Enable publish hash block in
")); - strUsage += HelpMessageOpt("-amqppubhashtx=
", _("Enable publish hash transaction in
")); - strUsage += HelpMessageOpt("-amqppubrawblock=
", _("Enable publish raw block in
")); - strUsage += HelpMessageOpt("-amqppubrawtx=
", _("Enable publish raw transaction in
")); -#endif - strUsage += HelpMessageGroup(_("Debugging/Testing options:")); if (showDebug) { @@ -500,7 +483,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-stopafterblockimport", strprintf("Stop running after importing blocks from disk (default: %u)", 0)); strUsage += HelpMessageOpt("-nuparams=hexBranchId:activationHeight", "Use given activation height for specified network upgrade (regtest-only)"); } - string debugCategories = "addrman, alert, bench, coindb, db, estimatefee, http, libevent, lock, mempool, net, partitioncheck, pow, proxy, prune, " + string debugCategories = "addrman, alert, bench, coindb, db, deletetx, estimatefee, http, libevent, lock, mempool, net, partitioncheck, pow, proxy, prune, " "rand, reindex, rpc, selectcoins, tor, zmq, zrpc, zrpcunsafe (implies zrpc)"; // Don't translate these strUsage += HelpMessageOpt("-debug=", strprintf(_("Output debugging information (default: %u, supplying is optional)"), 0) + ". " + _("If is not supplied or if = 1, output all debugging information.") + " " + _(" can be:") + " " + debugCategories + "."); @@ -569,16 +552,13 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-rpcservertimeout=", strprintf("Timeout during HTTP requests (default: %d)", DEFAULT_HTTP_SERVER_TIMEOUT)); } - // Disabled until we can lock notes and also tune performance of libsnark which by default uses multiple threads - //strUsage += HelpMessageOpt("-rpcasyncthreads=", strprintf(_("Set the number of threads to service Async RPC calls (default: %d)"), 1)); - if (mode == HMM_BITCOIND) { strUsage += HelpMessageGroup(_("Metrics Options (only if -daemon and -printtoconsole are not set):")); strUsage += HelpMessageOpt("-showmetrics", _("Show metrics on stdout (default: 1 if running in a console, 0 otherwise)")); strUsage += HelpMessageOpt("-metricsui", _("Set to 1 for a persistent metrics screen, 0 for sequential metrics output (default: 1 if running in a console, 0 otherwise)")); strUsage += HelpMessageOpt("-metricsrefreshtime", strprintf(_("Number of seconds between metrics refreshes (default: %u if running in a console, %u otherwise)"), 1, 600)); } - strUsage += HelpMessageGroup(_("Komodo Asset Chain options:")); + strUsage += HelpMessageGroup(_("Hush Smart Chain options:")); strUsage += HelpMessageOpt("-ac_algo", _("Choose PoW mining algorithm, default is Equihash")); strUsage += HelpMessageOpt("-ac_blocktime", _("Block time in seconds, default is 60")); strUsage += HelpMessageOpt("-ac_cc", _("Cryptoconditions, default 0")); @@ -615,6 +595,14 @@ static void BlockNotifyCallback(const uint256& hashNewTip) boost::thread t(runCommand, strCmd); // thread runs free } +static void TxExpiryNotifyCallback(const uint256& txid) +{ + std::string strCmd = GetArg("-txexpirynotify", ""); + + boost::replace_all(strCmd, "%s", txid.GetHex()); + boost::thread t(runCommand, strCmd); // thread runs free +} + struct CImportingNow { CImportingNow() { @@ -733,22 +721,6 @@ void ThreadImport(std::vector vImportFiles) } } -void ThreadNotifyRecentlyAdded() -{ - while (true) { - // Run the notifier on an integer second in the steady clock. - auto now = std::chrono::steady_clock::now().time_since_epoch(); - auto nextFire = std::chrono::duration_cast( - now + std::chrono::seconds(1)); - std::this_thread::sleep_until( - std::chrono::time_point(nextFire)); - - boost::this_thread::interruption_point(); - - mempool.NotifyRecentlyAdded(); - } -} - /** Sanity checks * Ensure that Hush is running in a usable environment with all * necessary library support. @@ -1046,10 +1018,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (mapArgs.count("-developerencryptwallet")) { fprintf(stderr,"%s wallet encryption error\n", __FUNCTION__); return InitError(_("Wallet encryption requires -experimentalfeatures.")); - } - else if (mapArgs.count("-paymentdisclosure")) { - fprintf(stderr,"%s payment disclosure error\n", __FUNCTION__); - return InitError(_("Payment disclosure requires -experimentalfeatures.")); + //TODO: make this non experimental } else if (mapArgs.count("-zmergetoaddress")) { fprintf(stderr,"%s zmerge error\n", __FUNCTION__); return InitError(_("RPC method z_mergetoaddress requires -experimentalfeatures.")); @@ -1456,10 +1425,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } //fprintf(stderr,"%s tik15\n", __FUNCTION__); - // These must be disabled for now, they are buggy and we probably don't - // want any of libsnark's profiling in production anyway. - libsnark::inhibit_profiling_info = true; - libsnark::inhibit_profiling_counters = true; if ( KOMODO_NSPV_FULLNODE ) { @@ -1635,21 +1600,6 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } #endif -#if ENABLE_PROTON - pAMQPNotificationInterface = AMQPNotificationInterface::CreateWithArguments(mapArgs); - - if (pAMQPNotificationInterface) { - - // AMQP support is currently an experimental feature, so fail if user configured AMQP notifications - // without enabling experimental features. - if (!fExperimentalMode) { - return InitError(_("AMQP support requires -experimentalfeatures.")); - } - - RegisterValidationInterface(pAMQPNotificationInterface); - } -#endif - if ( KOMODO_NSPV_SUPERLITE ) { std::vector vImportFiles; @@ -1953,6 +1903,42 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) pwalletMain->GenerateNewSeed(); } + //Set Sapling Consolidation + pwalletMain->fSaplingConsolidationEnabled = GetBoolArg("-consolidation", false); + fConsolidationTxFee = GetArg("-consolidationtxfee", DEFAULT_CONSOLIDATION_FEE); + fConsolidationMapUsed = !mapMultiArgs["-consolidatesaplingaddress"].empty(); + + //Validate Sapling Addresses + vector& vaddresses = mapMultiArgs["-consolidatesaplingaddress"]; + for (int i = 0; i < vaddresses.size(); i++) { + LogPrintf("Consolidating Sapling Address: %s\n", vaddresses[i]); + auto zAddress = DecodePaymentAddress(vaddresses[i]); + if (!IsValidPaymentAddress(zAddress)) { + return InitError("Invalid consolidation address"); + } + } + + //Set Transaction Deletion Options + fTxDeleteEnabled = GetBoolArg("-deletetx", false); + fTxConflictDeleteEnabled = GetBoolArg("-deleteconflicttx", true); + + fDeleteInterval = GetArg("-deleteinterval", DEFAULT_TX_DELETE_INTERVAL); + if (fDeleteInterval < 1) + return InitError("deleteinterval must be greater than 0"); + + fKeepLastNTransactions = GetArg("-keeptxnum", DEFAULT_TX_RETENTION_LASTTX); + if (fKeepLastNTransactions < 1) + return InitError("keeptxnum must be greater than 0"); + + fDeleteTransactionsAfterNBlocks = GetArg("-keeptxfornblocks", DEFAULT_TX_RETENTION_BLOCKS); + if (fDeleteTransactionsAfterNBlocks < 1) + return InitError("keeptxfornblocks must be greater than 0"); + + if (fDeleteTransactionsAfterNBlocks < MAX_REORG_LENGTH + 1 ) { + LogPrintf("keeptxfornblock is less the MAX_REORG_LENGTH, Setting to %i\n", MAX_REORG_LENGTH + 1); + fDeleteTransactionsAfterNBlocks = MAX_REORG_LENGTH + 1; + } + if (fFirstRun) { // Create new keyUser and set as default key @@ -2053,6 +2039,24 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } #endif // ENABLE_MINING + // Start the thread that notifies listeners of transactions that have been + // recently added to the mempool, or have been added to or removed from the + // chain. We perform this before step 10 (import blocks) so that the + // original value of chainActive.Tip(), which corresponds with the wallet's + // view of the chaintip, is passed to ThreadNotifyWallets before the chain + // tip changes again. + { + CBlockIndex *pindexLastTip; + { + LOCK(cs_main); + pindexLastTip = chainActive.Tip(); + } + boost::function threadnotifywallets = boost::bind(&ThreadNotifyWallets, pindexLastTip); + threadGroup.create_thread( + boost::bind(&TraceThread>, "txnotify", threadnotifywallets) + ); + } + // ********************************************************* Step 9: data directory maintenance // if pruning, unset the service bit and perform the initial blockstore prune @@ -2077,6 +2081,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) if (mapArgs.count("-blocknotify")) uiInterface.NotifyBlockTip.connect(BlockNotifyCallback); + if (mapArgs.count("-txexpirynotify")) + uiInterface.NotifyTxExpiration.connect(TxExpiryNotifyCallback); if ( KOMODO_REWIND >= 0 ) { uiInterface.InitMessage(_("Activating best chain...")); @@ -2094,10 +2100,22 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) vImportFiles.push_back(strFile); } threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles)); - if (chainActive.Tip() == NULL) { - LogPrintf("Waiting for genesis block to be imported...\n"); - while (!fRequestShutdown && chainActive.Tip() == NULL) + + // Wait for genesis block to be processed + bool fHaveGenesis = false; + while (!fHaveGenesis && !fRequestShutdown) { + { + LOCK(cs_main); + fHaveGenesis = (chainActive.Tip() != NULL); MilliSleep(10); + } + + if (!fHaveGenesis) { + MilliSleep(10); + } + } + if (!fHaveGenesis) { + return false; } // ********************************************************* Step 11: start node @@ -2113,17 +2131,11 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size()); LogPrintf("nBestHeight = %d\n", chainActive.Height()); #ifdef ENABLE_WALLET - RescanWallets(); - LogPrintf("setKeyPool.size() = %u\n", pwalletMain ? pwalletMain->setKeyPool.size() : 0); LogPrintf("mapWallet.size() = %u\n", pwalletMain ? pwalletMain->mapWallet.size() : 0); LogPrintf("mapAddressBook.size() = %u\n", pwalletMain ? pwalletMain->mapAddressBook.size() : 0); #endif - // Start the thread that notifies listeners of transactions that have been - // recently added to the mempool. - threadGroup.create_thread(boost::bind(&TraceThread, "txnotify", &ThreadNotifyRecentlyAdded)); - if (GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION)) StartTorControl(threadGroup, scheduler); diff --git a/src/init.h b/src/init.h index 108339865..c68d59419 100644 --- a/src/init.h +++ b/src/init.h @@ -23,7 +23,7 @@ #include -#include "zcash/JoinSplit.hpp" +//#include "zcash/JoinSplit.hpp" class CScheduler; class CWallet; @@ -34,7 +34,7 @@ class thread_group; } // namespace boost extern CWallet* pwalletMain; -extern ZCJoinSplit* pzcashParams; +//extern ZCJoinSplit* pzcashParams; void StartShutdown(); bool ShutdownRequested(); diff --git a/src/key.h b/src/key.h index 857e8a8ae..16492b151 100644 --- a/src/key.h +++ b/src/key.h @@ -1,6 +1,7 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin Core developers // Copyright (c) 2017 The Zcash 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. diff --git a/src/key_io.cpp b/src/key_io.cpp index dd4176fee..2e0dfeb9a 100644 --- a/src/key_io.cpp +++ b/src/key_io.cpp @@ -1,5 +1,6 @@ // Copyright (c) 2014-2016 The Bitcoin Core developers // Copyright (c) 2016-2018 The Zcash 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. @@ -84,15 +85,6 @@ private: public: PaymentAddressEncoder(const CChainParams& params) : m_params(params) {} - std::string operator()(const libzcash::SproutPaymentAddress& zaddr) const - { - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << zaddr; - std::vector data = m_params.Base58Prefix(CChainParams::ZCPAYMENT_ADDRRESS); - data.insert(data.end(), ss.begin(), ss.end()); - return EncodeBase58Check(data); - } - std::string operator()(const libzcash::SaplingPaymentAddress& zaddr) const { CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); @@ -107,6 +99,7 @@ public: } std::string operator()(const libzcash::InvalidEncoding& no) const { return {}; } + std::string operator()(const libzcash::SproutPaymentAddress& zaddr) const { return {}; } }; class ViewingKeyEncoder : public boost::static_visitor @@ -117,17 +110,6 @@ private: public: ViewingKeyEncoder(const CChainParams& params) : m_params(params) {} - std::string operator()(const libzcash::SproutViewingKey& vk) const - { - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << vk; - std::vector data = m_params.Base58Prefix(CChainParams::ZCVIEWING_KEY); - data.insert(data.end(), ss.begin(), ss.end()); - std::string ret = EncodeBase58Check(data); - memory_cleanse(data.data(), data.size()); - return ret; - } - std::string operator()(const libzcash::SaplingIncomingViewingKey& vk) const { CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); @@ -152,17 +134,6 @@ private: public: SpendingKeyEncoder(const CChainParams& params) : m_params(params) {} - std::string operator()(const libzcash::SproutSpendingKey& zkey) const - { - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << zkey; - std::vector data = m_params.Base58Prefix(CChainParams::ZCSPENDING_KEY); - data.insert(data.end(), ss.begin(), ss.end()); - std::string ret = EncodeBase58Check(data); - memory_cleanse(data.data(), data.size()); - return ret; - } - std::string operator()(const libzcash::SaplingExtendedSpendingKey& zkey) const { CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); @@ -324,18 +295,6 @@ std::string EncodePaymentAddress(const libzcash::PaymentAddress& zaddr) libzcash::PaymentAddress DecodePaymentAddress(const std::string& str) { std::vector data; - if (DecodeBase58Check(str, data)) { - const std::vector& zaddr_prefix = Params().Base58Prefix(CChainParams::ZCPAYMENT_ADDRRESS); - if ((data.size() == libzcash::SerializedSproutPaymentAddressSize + zaddr_prefix.size()) && - std::equal(zaddr_prefix.begin(), zaddr_prefix.end(), data.begin())) { - CSerializeData serialized(data.begin() + zaddr_prefix.size(), data.end()); - CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION); - libzcash::SproutPaymentAddress ret; - ss >> ret; - return ret; - } - } - data.clear(); auto bech = bech32::Decode(str); if (bech.first == Params().Bech32HRP(CChainParams::SAPLING_PAYMENT_ADDRESS) && bech.second.size() == ConvertedSaplingPaymentAddressSize) { @@ -363,20 +322,6 @@ std::string EncodeViewingKey(const libzcash::ViewingKey& vk) libzcash::ViewingKey DecodeViewingKey(const std::string& str) { std::vector data; - if (DecodeBase58Check(str, data)) { - const std::vector& vk_prefix = Params().Base58Prefix(CChainParams::ZCVIEWING_KEY); - if ((data.size() == libzcash::SerializedSproutViewingKeySize + vk_prefix.size()) && - std::equal(vk_prefix.begin(), vk_prefix.end(), data.begin())) { - CSerializeData serialized(data.begin() + vk_prefix.size(), data.end()); - CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION); - libzcash::SproutViewingKey ret; - ss >> ret; - memory_cleanse(serialized.data(), serialized.size()); - memory_cleanse(data.data(), data.size()); - return ret; - } - } - data.clear(); auto bech = bech32::Decode(str); if(bech.first == Params().Bech32HRP(CChainParams::SAPLING_INCOMING_VIEWING_KEY) && bech.second.size() == ConvertedSaplingIncomingViewingKeySize) { @@ -400,20 +345,6 @@ std::string EncodeSpendingKey(const libzcash::SpendingKey& zkey) libzcash::SpendingKey DecodeSpendingKey(const std::string& str) { std::vector data; - if (DecodeBase58Check(str, data)) { - const std::vector& zkey_prefix = Params().Base58Prefix(CChainParams::ZCSPENDING_KEY); - if ((data.size() == libzcash::SerializedSproutSpendingKeySize + zkey_prefix.size()) && - std::equal(zkey_prefix.begin(), zkey_prefix.end(), data.begin())) { - CSerializeData serialized(data.begin() + zkey_prefix.size(), data.end()); - CDataStream ss(serialized, SER_NETWORK, PROTOCOL_VERSION); - libzcash::SproutSpendingKey ret; - ss >> ret; - memory_cleanse(serialized.data(), serialized.size()); - memory_cleanse(data.data(), data.size()); - return ret; - } - } - data.clear(); auto bech = bech32::Decode(str); if (bech.first == Params().Bech32HRP(CChainParams::SAPLING_EXTENDED_SPEND_KEY) && bech.second.size() == ConvertedSaplingExtendedSpendingKeySize) { diff --git a/src/key_io.h b/src/key_io.h index 013469ab6..567c9a2f2 100644 --- a/src/key_io.h +++ b/src/key_io.h @@ -1,6 +1,7 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2015 The Bitcoin Core developers // Copyright (c) 2016-2018 The Zcash 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. diff --git a/src/keystore.cpp b/src/keystore.cpp index 34bab456c..ca4fa3712 100644 --- a/src/keystore.cpp +++ b/src/keystore.cpp @@ -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. @@ -128,15 +129,6 @@ bool CBasicKeyStore::HaveWatchOnly() const return (!setWatchOnly.empty()); } -bool CBasicKeyStore::AddSproutSpendingKey(const libzcash::SproutSpendingKey &sk) -{ - LOCK(cs_SpendingKeyStore); - auto address = sk.address(); - mapSproutSpendingKeys[address] = sk; - mapNoteDecryptors.insert(std::make_pair(address, ZCNoteDecryption(sk.receiving_key()))); - return true; -} - //! Sapling bool CBasicKeyStore::AddSaplingSpendingKey( const libzcash::SaplingExtendedSpendingKey &sk, @@ -155,14 +147,6 @@ bool CBasicKeyStore::AddSaplingSpendingKey( return true; } -bool CBasicKeyStore::AddSproutViewingKey(const libzcash::SproutViewingKey &vk) -{ - LOCK(cs_SpendingKeyStore); - auto address = vk.address(); - mapSproutViewingKeys[address] = vk; - mapNoteDecryptors.insert(std::make_pair(address, ZCNoteDecryption(vk.sk_enc))); - return true; -} bool CBasicKeyStore::AddSaplingFullViewingKey( const libzcash::SaplingFullViewingKey &fvk, @@ -190,18 +174,7 @@ bool CBasicKeyStore::AddSaplingIncomingViewingKey( return true; } -bool CBasicKeyStore::RemoveSproutViewingKey(const libzcash::SproutViewingKey &vk) -{ - LOCK(cs_SpendingKeyStore); - mapSproutViewingKeys.erase(vk.address()); - return true; -} -bool CBasicKeyStore::HaveSproutViewingKey(const libzcash::SproutPaymentAddress &address) const -{ - LOCK(cs_SpendingKeyStore); - return mapSproutViewingKeys.count(address) > 0; -} bool CBasicKeyStore::HaveSaplingFullViewingKey(const libzcash::SaplingIncomingViewingKey &ivk) const { @@ -215,19 +188,6 @@ bool CBasicKeyStore::HaveSaplingIncomingViewingKey(const libzcash::SaplingPaymen return mapSaplingIncomingViewingKeys.count(addr) > 0; } -bool CBasicKeyStore::GetSproutViewingKey( - const libzcash::SproutPaymentAddress &address, - libzcash::SproutViewingKey &vkOut) const -{ - LOCK(cs_SpendingKeyStore); - SproutViewingKeyMap::const_iterator mi = mapSproutViewingKeys.find(address); - if (mi != mapSproutViewingKeys.end()) { - vkOut = mi->second; - return true; - } - return false; -} - bool CBasicKeyStore::GetSaplingFullViewingKey(const libzcash::SaplingIncomingViewingKey &ivk, libzcash::SaplingFullViewingKey &fvkOut) const { diff --git a/src/keystore.h b/src/keystore.h index c2e1f25d9..6f34d9bc4 100644 --- a/src/keystore.h +++ b/src/keystore.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. @@ -70,14 +71,6 @@ public: virtual bool HaveWatchOnly(const CScript &dest) const =0; virtual bool HaveWatchOnly() const =0; - //! Add a spending key to the store. - virtual bool AddSproutSpendingKey(const libzcash::SproutSpendingKey &sk) =0; - - //! Check whether a spending key corresponding to a given payment address is present in the store. - virtual bool HaveSproutSpendingKey(const libzcash::SproutPaymentAddress &address) const =0; - virtual bool GetSproutSpendingKey(const libzcash::SproutPaymentAddress &address, libzcash::SproutSpendingKey& skOut) const =0; - virtual void GetSproutPaymentAddresses(std::set &setAddress) const =0; - //! Add a Sapling spending key to the store. virtual bool AddSaplingSpendingKey( const libzcash::SaplingExtendedSpendingKey &sk, @@ -106,21 +99,11 @@ public: libzcash::SaplingIncomingViewingKey& ivkOut) const =0; virtual void GetSaplingPaymentAddresses(std::set &setAddress) const =0; - //! Support for Sprout viewing keys - virtual bool AddSproutViewingKey(const libzcash::SproutViewingKey &vk) =0; - virtual bool RemoveSproutViewingKey(const libzcash::SproutViewingKey &vk) =0; - virtual bool HaveSproutViewingKey(const libzcash::SproutPaymentAddress &address) const =0; - virtual bool GetSproutViewingKey( - const libzcash::SproutPaymentAddress &address, - libzcash::SproutViewingKey& vkOut) const =0; }; typedef std::map KeyMap; typedef std::map ScriptMap; typedef std::set WatchOnlySet; -typedef std::map SproutSpendingKeyMap; -typedef std::map SproutViewingKeyMap; -typedef std::map NoteDecryptorMap; // Full viewing key has equivalent functionality to a transparent address // When encrypting wallet, encrypt SaplingSpendingKeyMap, while leaving SaplingFullViewingKeyMap unencrypted @@ -137,10 +120,7 @@ protected: KeyMap mapKeys; ScriptMap mapScripts; WatchOnlySet setWatchOnly; - SproutSpendingKeyMap mapSproutSpendingKeys; - SproutViewingKeyMap mapSproutViewingKeys; - NoteDecryptorMap mapNoteDecryptors; - + SaplingSpendingKeyMap mapSaplingSpendingKeys; SaplingFullViewingKeyMap mapSaplingFullViewingKeys; SaplingIncomingViewingKeyMap mapSaplingIncomingViewingKeys; @@ -195,62 +175,6 @@ public: virtual bool HaveWatchOnly(const CScript &dest) const; virtual bool HaveWatchOnly() const; - bool AddSproutSpendingKey(const libzcash::SproutSpendingKey &sk); - bool HaveSproutSpendingKey(const libzcash::SproutPaymentAddress &address) const - { - bool result; - { - LOCK(cs_SpendingKeyStore); - result = (mapSproutSpendingKeys.count(address) > 0); - } - return result; - } - bool GetSproutSpendingKey(const libzcash::SproutPaymentAddress &address, libzcash::SproutSpendingKey &skOut) const - { - { - LOCK(cs_SpendingKeyStore); - SproutSpendingKeyMap::const_iterator mi = mapSproutSpendingKeys.find(address); - if (mi != mapSproutSpendingKeys.end()) - { - skOut = mi->second; - return true; - } - } - return false; - } - bool GetNoteDecryptor(const libzcash::SproutPaymentAddress &address, ZCNoteDecryption &decOut) const - { - { - LOCK(cs_SpendingKeyStore); - NoteDecryptorMap::const_iterator mi = mapNoteDecryptors.find(address); - if (mi != mapNoteDecryptors.end()) - { - decOut = mi->second; - return true; - } - } - return false; - } - void GetSproutPaymentAddresses(std::set &setAddress) const - { - setAddress.clear(); - { - LOCK(cs_SpendingKeyStore); - SproutSpendingKeyMap::const_iterator mi = mapSproutSpendingKeys.begin(); - while (mi != mapSproutSpendingKeys.end()) - { - setAddress.insert((*mi).first); - mi++; - } - SproutViewingKeyMap::const_iterator mvi = mapSproutViewingKeys.begin(); - while (mvi != mapSproutViewingKeys.end()) - { - setAddress.insert((*mvi).first); - mvi++; - } - } - } - //! Sapling bool AddSaplingSpendingKey( const libzcash::SaplingExtendedSpendingKey &sk, @@ -313,17 +237,10 @@ public: } } - virtual bool AddSproutViewingKey(const libzcash::SproutViewingKey &vk); - virtual bool RemoveSproutViewingKey(const libzcash::SproutViewingKey &vk); - virtual bool HaveSproutViewingKey(const libzcash::SproutPaymentAddress &address) const; - virtual bool GetSproutViewingKey( - const libzcash::SproutPaymentAddress &address, - libzcash::SproutViewingKey& vkOut) const; }; typedef std::vector > CKeyingMaterial; typedef std::map > > CryptedKeyMap; -typedef std::map > CryptedSproutSpendingKeyMap; //! Sapling typedef std::map > CryptedSaplingSpendingKeyMap; diff --git a/src/komodo-tx.cpp b/src/komodo-tx.cpp index 7e0477eb7..0f0b59421 100644 --- a/src/komodo-tx.cpp +++ b/src/komodo-tx.cpp @@ -1,4 +1,5 @@ // 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. diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index b89aa5c0a..930d7ddf8 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -20,10 +20,11 @@ #include #include #include "consensus/params.h" -#include "primitives/nonce.h" +//#include "primitives/nonce.h" #include "komodo_defs.h" #include "script/standard.h" #include "cc/CCinclude.h" +#include "sietch.h" int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp); int32_t komodo_electednotary(int32_t *numnotariesp,uint8_t *pubkey33,int32_t height,uint32_t timestamp); @@ -70,6 +71,7 @@ int tx_height( const uint256 &hash ){ uint256 hashBlock; if (!GetTransaction(hash, tx, hashBlock, true)) { fprintf(stderr,"tx hash %s does not exist!\n", hash.ToString().c_str() ); + return nHeight; } BlockMap::const_iterator it = mapBlockIndex.find(hashBlock); @@ -78,6 +80,7 @@ int tx_height( const uint256 &hash ){ //fprintf(stderr,"blockHash %s height %d\n",hashBlock.ToString().c_str(), nHeight); } else { // Unconfirmed xtns + fprintf(stderr,"tx %s is unconfirmed\n", hash.ToString().c_str() ); //fprintf(stderr,"block hash %s does not exist!\n", hashBlock.ToString().c_str() ); } return nHeight; @@ -1532,8 +1535,8 @@ uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeigh //fprintf(stderr,"blocktime.%u -> ",blocktime); if ( blocktime < prevtime+3 ) blocktime = prevtime+3; - if ( blocktime < GetAdjustedTime()-60 ) - blocktime = GetAdjustedTime()+30; + if ( blocktime < GetTime()-60 ) + blocktime = GetTime()+30; //fprintf(stderr,"blocktime.%u txtime.%u\n",blocktime,txtime); } if ( value == 0 || txtime == 0 || blocktime == 0 || prevtime == 0 ) diff --git a/src/komodo_curve25519.h b/src/komodo_curve25519.h index cba40561b..b2f3ea49f 100644 --- a/src/komodo_curve25519.h +++ b/src/komodo_curve25519.h @@ -81,7 +81,8 @@ bits320 fexpand(bits256 basepoint) return(out); } -#if __amd64__ +#if defined(__x86_64__) || defined(_WIN64) || defined(__aarch64__) || defined(__amd64__) || defined(__amd64) || defined(_M_X64) || defined(_M_IA64) + // donna: special gcc mode for 128-bit integers. It's implemented on 64-bit platforms only as far as I know. typedef unsigned uint128_t __attribute__((mode(TI))); diff --git a/src/komodo_defs.h b/src/komodo_defs.h index 34b1cc364..e482390bb 100644 --- a/src/komodo_defs.h +++ b/src/komodo_defs.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Hush developers +// Copyright (c) 2019-2020 The Hush developers /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * * * @@ -34,33 +34,34 @@ #define KOMODO_FIRSTFUNGIBLEID 100 #define KOMODO_SAPLING_ACTIVATION 1544832000 // Dec 15th, 2018 #define KOMODO_SAPLING_DEADLINE 1550188800 // Feb 15th, 2019 -#define ASSETCHAINS_STAKED_BLOCK_FUTURE_MAX 57 -#define ASSETCHAINS_STAKED_BLOCK_FUTURE_HALF 27 -#define ASSETCHAINS_STAKED_MIN_POW_DIFF 536900000 // 537000000 537300000 #define _COINBASE_MATURITY 100 // KMD Notary Seasons // 1: May 1st 2018 1530921600 // 2: July 15th 2019 1563148800 -> estimated height 1444000 -// 3: 3rd season ending isnt known, so use very far times in future. +// 3: 3rd season // 1751328000 = dummy timestamp, 1 July 2025! // 7113400 = 5x current KMD blockheight. -// to add 4th season, change NUM_KMD_SEASONS to 4, and add timestamp and height of activation to these arrays. +// to add seasons, change NUM_KMD_SEASONS, and add timestamp and height of activation to these arrays. -#define NUM_KMD_SEASONS 4 +#define NUM_KMD_SEASONS 6 #define NUM_KMD_NOTARIES 64 // $ ./contrib/block_time.pl 166250 // Hush Block 166250 will happen at roughly: // Wed Jan 29 08:14:12 2020 Eastern # 1580303652 // Wed Jan 29 13:14:12 2020 GMT # 1580303652 -const uint32_t nHushHardforkHeight = 166250; +const uint32_t nHushHardforkHeight = 166250; +// $ ./contrib/block_time.pl 245555 +// Hush Block 245555 will happen at roughly... now +const uint32_t nHushHardforkHeight2 = 245055; // No coins/code are currently using timestamp activated fork -const uint32_t nHushHardforkTimestamp = 1580303652; // Jan 29nd 1pm GMT +const uint32_t nHushHardforkTimestamp = 1580303652; // Jan 29nd 1pm GMT +const uint32_t nHushHardforkTimestamp2 = 1594425600; // Jul 11th 12a GMT -static const uint32_t KMD_SEASON_TIMESTAMPS[NUM_KMD_SEASONS] = {1525132800, 1563148800, nHushHardforkTimestamp, 1751328000}; -static const int32_t KMD_SEASON_HEIGHTS[NUM_KMD_SEASONS] = {1,2,nHushHardforkHeight, 5*nHushHardforkHeight}; +static const uint32_t KMD_SEASON_TIMESTAMPS[NUM_KMD_SEASONS] = {1525132800, 1563148800, nHushHardforkTimestamp, nHushHardforkTimestamp2, nHushHardforkTimestamp2*5, nHushHardforkTimestamp2*6}; +static const int32_t KMD_SEASON_HEIGHTS[NUM_KMD_SEASONS] = {1,2,nHushHardforkHeight, nHushHardforkHeight2, (int)340000, 5*nHushHardforkHeight2}; // Era array of pubkeys. Add extra seasons to bottom as requried, after adding appropriate info above. static const char *notaries_elected[NUM_KMD_SEASONS][NUM_KMD_NOTARIES][2] = @@ -329,7 +330,74 @@ static const char *notaries_elected[NUM_KMD_SEASONS][NUM_KMD_NOTARIES][2] = {"gt_AR", "0307c1cf89bd8ed4db1b09a0a98cf5f746fc77df3803ecc8611cf9455ec0ce6960" }, {"patchkez_SH", "03d7c187689bf829ca076a30bbf36d2e67bb74e16a3290d8a55df21d6cb15c80c1" }, {"decker_AR", "02a85540db8d41c7e60bf0d33d1364b4151cad883dd032878ea4c037f67b769635" } - } + }, + { + // Season 4 https://github.com/KomodoPlatform/dPoW/blob/s4/iguana/3rd_party + {"alien_AR", "024f20c096b085308e21893383f44b4faf1cdedea9ad53cc7d7e7fbfa0c30c1e71" }, + {"alien_EU", "022b85908191788f409506ebcf96a892f3274f352864c3ed566c5a16de63953236" }, + {"alien_NA", "022f62b56ddfd07c9860921c701285ac39bb3ac8f6f083d1b59c8f4943be3de162" }, + {"alright_DEV", "03b6f9493658bdd102503585a08ae642b49d6a68fb69ac3626f9737cd7581abdfa" }, + {"artemii235_DEV", "037a20916d2e9ea575300ac9d729507c23a606b9a200c8e913d7c9832f912a1fa7" }, + {"chainmakers_NA", "028803e07bcc521fde264b7191a944f9b3612e8ee4e24a99bcd903f6976240839a" }, + {"chainzilla_SH", "0311dde03c2dd654ce78323b718ed3ad73a464d1bde97820f3395f54788b5420dd" }, + {"chmex_AR", "030cd487e10fbf142e0e8d582e702ecb775f378569c3cb5acd0ff97b6b12803588" }, + {"chmex_EU", "030bf7bd7ad0515c33b5d5d9a91e0729baf801b9002f80495ae535ea1cebb352cb" }, + {"cipi_EU", "026f4f66385daaf8313ef30ffe4988e7db497132682dca185a70763d93e1417d9d" }, + {"cipi_NA", "03f4e69edcb4fa3b2095cb8cb1ca010f4ec4972eac5d8822397e5c8d87aa21a739" }, + {"daemonfox_NA", "023c7584b1006d4a62a4b4c9c1ede390a3789316547897d5ed49ff9385a3acb411" }, + {"dappvader_SH", "025199bc04bcb8a17976d9fe8bc87763a6150c2727321aa59bf34a2b49f2f3a0ce" }, + {"decker_AR", "02a85540db8d41c7e60bf0d33d1364b4151cad883dd032878ea4c037f67b769635" }, + {"decker_DEV", "02fca8ee50e49f480de275745618db7b0b3680b0bdcce7dcae7d2e0fd5c3345744" }, + {"decker_EU", "027777775b89ff548c3be54fb0c9455437d87f38bfce83bdef113899881b219c9e" }, + {"dragonhound_NA", "029912212d370ee0fb4d38eefd8bfcd8ab04e2c3b0354020789c29ddf2a35c72d6" }, + {"dudezmobi_AR", "033c121d3f8d450174674a73f3b7f140b2717a7d51ea19ee597e2e8e8f9d5ed87f" }, + {"etszombi_AR", "03bfcbca83f11e622fa4eed9a1fa25dba377981ea3b22e3d0a4015f9a932af9272" }, + {"etszombi_EU", "03a5c083c78ba397970f20b544a01c13e7ed36ca8a5ae26d5fe7bd38b92b6a0c94" }, + {"fullmoon_AR", "03639bc56d3fecf856f17759a441c5893668e7c2d460f3d216798a413cd6766bb2" }, + {"fullmoon_NA", "03e388bcc579ac2675f8fadfa921eec186dcea8d2b43de1eed6caba23d5a962b74" }, + {"fullmoon_SH", "03a5cfda2b097c808834ccdd805828c811b519611feabdfe6b3644312e53f6748f" }, + {"gcharang_SH", "02a654037d12cdd609f4fad48e15ec54538e03f61fdae1acb855f16ebacac6bd73" }, + {"greer_NA", "0262da6aaa0b295b8e2f120035924758a4a630f899316dc63ee15ef03e9b7b2b23" }, + {"indenodes_AR", "0242778789986d614f75bcf629081651b851a12ab1cc10c73995b27b90febb75a2" }, + {"indenodes_EU", "03a416533cace0814455a1bb1cd7861ce825a543c6f6284a432c4c8d8875b7ace9" }, + {"indenodes_NA", "02b3908eda4078f0e9b6704451cdc24d418e899c0f515fab338d7494da6f0a647b" }, + {"indenodes_SH", "031d1584cf0eb4a2d314465e49e2677226b1615c3718013b8d6b4854c15676a58c" }, + {"karasugoi_NA", "02f803e6f159824a181cc5d709f3d1e7ff65f19e1899920724aeb4e3d2d869f911" }, + {"madmax_AR", "027afddbcf690230dd8d435ec16a7bfb0083e6b77030f763437f291dfc40a579d0" }, + {"madmax_EU", "0397ec3a4ad84b3009566d260c89f1c4404e86e5d044964747c9371277e38f5995" }, + {"madmax_NA", "036d3afebe1eab09f4c38c3ee6a4659ad390f3df92787c11437a58c59a29e408e6" }, + {"marmarachain_AR", "028690ca1e3afdf8a38b421f6a41f5ff407afc96d5a7a6a488330aae26c8b086bb" }, + {"mcrypt_SH", "027a4ca7b11d3456ff558c08bb04483a89c7f383448461fd0b6b3b07424aabe9a4" }, + {"metaphilibert_AR", "0239e34ad22957bbf4c8df824401f237b2afe8d40f7a645ecd43e8f27dde1ab0da" }, + {"metaphilibert_SH", "03b21ff042bf1730b28bde43f44c064578b41996117ac7634b567c3773089e3be3" }, + {"mihailo_EU", "036494e7c9467c8c7ff3bf29e841907fb0fa24241866569944ea422479ec0e6252" }, + {"mrlynch_AR", "03e67440141f53a08684c329ebc852b018e41f905da88e52aa4a6dc5aa4b12447a" }, + {"mylo_SH", "026d5f29d09ff3f33e14db4811606249b2438c6bcf964876714f81d1f2d952acde" }, + {"node9_EU", "0392e4c9400e69f28c6b9e89d586da69d5a6af7702f1045eaa6ebc1996f0496e1f" }, + {"nodeone_NA", "0310a249c6c2dcc29f2135715138a9ddb8e01c0eab701cbd0b96d9cec660dbdc58" }, + {"nutellalicka_SH", "0284c4d3cb97dd8a32d10fb32b1855ae18cf845dad542e3b8937ca0e998fb54ecc" }, + {"oszy_EU", "03c53bd421de4a29ce68c8cc83f802e1181e77c08f8f16684490d61452ea8d023a" }, + {"patchkez_SH", "028c08db6e7242681f50db6c234fe3d6e12fb1a915350311be26373bac0d457d49" }, + {"pbca26_NA", "03c18431bb6bc95672f640f19998a196becd2851d5dcba4795fe8d85b7d77eab81" }, + {"peer2cloud_AR", "0243958faf9ae4d43b598b859ddc595c170c4cf50f8e4517d660ae5bc72aeb821b" }, + {"phba2061_EU", "03369187ce134bd7793ee34af7756fe1ab27202e09306491cdd5d8ad2c71697937" }, + {"phm87_SH", "03889a10f9df2caef57220628515693cf25316fe1b0693b0241419e75d0d0e66ed" }, + {"pirate_EU", "0240011b95cde819f298fe0f507b2260c9fecdab784924076d4d1e54c522103cb1" }, + {"pirate_NA", "02ad7ef25d2dd461e361120cd3efe7cbce5e9512c361e9185aac33dd303d758613" }, + {"pungocloud_SH", "02641c36ae6747b88150a463a1fe65cf7a9d1c00a64387c73f296f0b64e77c7d3f" }, + {"smdmitry_AR", "0397b7584cb29717b721c0c587d4462477efc1f36a56921f133c9d17b0cd7f278a" }, + {"starfleet_EU", "03c6e047218f34644ccba67e317b9da5d28e68bbbb6b9973aef1281d2bafa46496" }, + {"strob_NA", "02285bf2f9e96068ecac14bc6f770e394927b4da9f5ba833eaa9468b5d47f203a3" }, + {"strob_SH", "0213751a1c59d3489ca85b3d62a3d606dcef7f0428aa021c1978ea16fb38a2fad6" }, + {"swisscertifiers_EU", "02e7722ebba9f8b5ebfb4e87d4fa58cc75aef677535b9cfc060c7d9471aacd9c9e" }, + {"titomane_AR", "03958bd8d13fe6946b8d0d0fbbc3861c72542560d0276e80a4c6b5fe55bc758b81" }, + {"titomane_EU", "02276090e483db1a01a802456b10831b3b6e0a6ad3ece9b2a01f4aad0e480c8edc" }, + {"titomane_SH", "02abf206bafc8048dbdc042b8eb6b1e356ea5dbe149eae3532b4811d4905e5cf01" }, + {"tonyl_AR", "0229e499e3f2e065ced402ceb8aaf3d5ab8bd3793aa074305e9fa30772ce604908" }, + {"tonyl_DEV", "0258b77d7dcfc6c2628b0b6b438951a6e74201fb2cd180a795e4c37fcf8e78a678" }, + {"webworker01_NA", "02de90c720c007229374772505a43917a84ed129d5fbcfa4949cc2e9b563351124" }, + {"zatjum_SH", "0241c5660ca540780be66603b1791127a1261d56abbcb7562c297eec8e4fc078fb" } + } }; #define SETBIT(bits,bitoffset) (((uint8_t *)bits)[(bitoffset) >> 3] |= (1 << ((bitoffset) & 7))) diff --git a/src/komodo_notary.h b/src/komodo_notary.h index 8114a86af..d5591aa29 100644 --- a/src/komodo_notary.h +++ b/src/komodo_notary.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019 The Hush developers +// Copyright (c) 2019-2020 The Hush developers /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * * * diff --git a/src/main.cpp b/src/main.cpp index 2e0394779..ac9be64b3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -85,6 +85,7 @@ int32_t komodo_block2pubkey33(uint8_t *pubkey33,CBlock *block); //void komodo_broadcast(CBlock *pblock,int32_t limit); bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey); void komodo_setactivation(int32_t height); +void hush_changeblocktime(); void komodo_pricesupdate(int32_t height,CBlock *pblock); BlockMap mapBlockIndex; @@ -114,6 +115,8 @@ bool fAlerts = DEFAULT_ALERTS; /* If the tip is older than this (in seconds), the node is considered to be in initial block download. */ int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE; +bool ishush3 = strncmp(ASSETCHAINS_SYMBOL, "HUSH3",5) == 0 ? true : false; +int32_t nFirstHalvingHeight = 340000; unsigned int expiryDelta = DEFAULT_TX_EXPIRY_DELTA; extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; @@ -957,7 +960,7 @@ bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime) } else if (!txin.IsFinal()) { - LogPrintf("non-final txin seq.%x locktime.%u vs nTime.%u\n",txin.nSequence,(uint32_t)tx.nLockTime,(uint32_t)nBlockTime); + LogPrintf("non-final txin txid.%s seq.%x locktime.%u vs nTime.%u\n",tx.GetHash().ToString().c_str(),txin.nSequence,(uint32_t)tx.nLockTime,(uint32_t)nBlockTime); return false; } } @@ -998,7 +1001,7 @@ bool CheckFinalTx(const CTransaction &tx, int flags) // However this changes once median past time-locks are enforced: const int64_t nBlockTime = (flags & LOCKTIME_MEDIAN_TIME_PAST) ? chainActive.Tip()->GetMedianTimePast() - : GetAdjustedTime(); + : GetTime(); return IsFinalTx(tx, nBlockHeight, nBlockTime); } @@ -1224,9 +1227,9 @@ bool ContextualCheckTransaction(int32_t slowflag,const CBlock *block, CBlockInde if (IsExpiredTx(tx, nHeight)) { // Don't increase banscore if the transaction only just expired int expiredDosLevel = IsExpiredTx(tx, nHeight - 1) ? (dosLevel > 10 ? dosLevel : 10) : 0; - string strHex = EncodeHexTx(tx); + //string strHex = EncodeHexTx(tx); //fprintf(stderr, "transaction exipred.%s\n",strHex.c_str()); - return state.DoS(expiredDosLevel, error("ContextualCheckTransaction(): transaction %s is expired, expiry block %i vs current block %i\n txhex.%s",tx.GetHash().ToString(),tx.nExpiryHeight,nHeight,strHex), REJECT_INVALID, "tx-overwinter-expired"); + return state.DoS(expiredDosLevel, error("ContextualCheckTransaction(): transaction %s is expired, expiry block %i vs current block %i\n",tx.GetHash().ToString(),tx.nExpiryHeight,nHeight), REJECT_INVALID, "tx-overwinter-expired"); } } @@ -1327,6 +1330,7 @@ bool ContextualCheckTransaction(int32_t slowflag,const CBlock *block, CBlockInde )) { librustzcash_sapling_verification_ctx_free(ctx); + fprintf(stderr,"%s: Invalid sapling binding sig! tx=%s valueBalance=%li, bindingSig.size=%li\n", __func__, tx.GetHash().ToString().c_str(), tx.valueBalance, tx.bindingSig.size() ); return state.DoS(100, error("ContextualCheckTransaction(): Sapling binding signature invalid"), REJECT_INVALID, "bad-txns-sapling-binding-signature-invalid"); } @@ -1366,16 +1370,8 @@ bool CheckTransaction(uint32_t tiptime,const CTransaction& tx, CValidationState if (!CheckTransactionWithoutProofVerification(tiptime,tx, state)) { return false; - } else { - // Ensure that zk-SNARKs v|| y - BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) { - if (!joinsplit.Verify(*pzcashParams, verifier, tx.joinSplitPubKey)) { - return state.DoS(100, error("CheckTransaction(): joinsplit does not verify"), - REJECT_INVALID, "bad-txns-joinsplit-verification-failed"); - } - } - return true; } + return true; } int32_t komodo_isnotaryvout(char *coinaddr,uint32_t tiptime) // from ac_private chains only @@ -1584,17 +1580,18 @@ bool CheckTransactionWithoutProofVerification(uint32_t tiptime,const CTransactio else if ( joinsplit.vpub_new != 0 && joinsplit.vpub_old == 0 ) z_t++; } + if ( ASSETCHAINS_PRIVATE != 0 && invalid_private_taddr != 0 ) { static uint32_t counter; if ( counter++ < 10 ) fprintf(stderr,"found taddr in private chain: z_z.%d z_t.%d t_z.%d vinsize.%d\n",z_z,z_t,t_z,(int32_t)tx.vin.size()); if ( z_t == 0 || z_z != 0 || t_z != 0 || tx.vin.size() != 0 ) - return state.DoS(100, error("CheckTransaction(): this is a private chain, only sprout -> taddr allowed until deadline"),REJECT_INVALID, "bad-txns-acprivacy-chain"); + return state.DoS(100, error("CheckTransaction(): this is a private chain, sending to taddrs not allowed"),REJECT_INVALID, "bad-txns-acprivacy-chain"); } if ( ASSETCHAINS_TXPOW != 0 ) { - // genesis coinbase 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b + // BTC genesis coinbase 4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b uint256 txid = tx.GetHash(); if ( ((ASSETCHAINS_TXPOW & 2) != 0 && iscoinbase != 0) || ((ASSETCHAINS_TXPOW & 1) != 0 && iscoinbase == 0) ) { @@ -1740,6 +1737,23 @@ CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowF bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,bool* pfMissingInputs, bool fRejectAbsurdFee, int dosLevel) { AssertLockHeld(cs_main); + const uint32_t z2zTransitionWindow = 10; + const uint32_t z2zTransitionStart = 340000 - z2zTransitionWindow; + const uint32_t nHeight = chainActive.Height(); + + // This only applies to HUSH3, other chains can start off z2z via ac_private=1 + if(ishush3) { + if((nHeight >= z2zTransitionStart) || (nHeight <= 340000)) { + // During the z2z transition window, only coinbase tx's as part of blocks are allowed + // Theory: We want an empty mempool at our fork block height, and the only way to assure that + // is to have an empty mempool for a few previous blocks, to take care of potential re-orgs + // and edge cases. This empty mempool assures there will be no transactions involving taddrs + // stuck in the mempool, when the z2z rule takes effect. + // Thanks to jl777 for helping design this + fprintf(stderr,"%s: rejecting all tx's during z2z transition window at height=%d\n", __func__,nHeight); + return false; + } + } if (pfMissingInputs) *pfMissingInputs = false; uint32_t tiptime; @@ -1893,10 +1907,10 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa } // are the joinsplit's requirements met? - if (!view.HaveJoinSplitRequirements(tx)) + if (!view.HaveShieldedRequirements(tx)) { //fprintf(stderr,"accept failure.2\n"); - return state.Invalid(error("AcceptToMemoryPool: joinsplit requirements not met"),REJECT_DUPLICATE, "bad-txns-joinsplit-requirements-not-met"); + return state.Invalid(error("AcceptToMemoryPool: shielded requirements not met"),REJECT_DUPLICATE, "bad-txns-joinsplit-requirements-not-met"); } // Bring the best block into scope @@ -2060,8 +2074,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa } } } - // This should be here still? - //SyncWithWallets(tx, NULL); return true; } @@ -2719,9 +2731,9 @@ namespace Consensus { if (!inputs.HaveInputs(tx)) return state.Invalid(error("CheckInputs(): %s inputs unavailable", tx.GetHash().ToString())); - // are the JoinSplit's requirements met? - if (!inputs.HaveJoinSplitRequirements(tx)) - return state.Invalid(error("CheckInputs(): %s JoinSplit requirements not met", tx.GetHash().ToString())); + // are the shielded requirements met? + if (!inputs.HaveShieldedRequirements(tx)) + return state.Invalid(error("CheckInputs(): %s shielded requirements not met", tx.GetHash().ToString())); CAmount nValueIn = 0; CAmount nFees = 0; @@ -3217,6 +3229,16 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex // move best block pointer to prevout block view.SetBestBlock(pindex->pprev->GetBlockHash()); + // If disconnecting a block brings us back before our blocktime halving height, go back + // to our original blocktime so our DAA has the correct target for that height + int nHeight = pindex->pprev->GetHeight(); + if (ishush3 && (ASSETCHAINS_BLOCKTIME != 150) && (nHeight < nFirstHalvingHeight)) { + LogPrintf("%s: Setting blocktime to 150s at height %d!\n",__func__,nHeight); + ASSETCHAINS_BLOCKTIME = 150; + hush_changeblocktime(); + } + + if (pfClean) { *pfClean = fClean; return true; @@ -3277,7 +3299,7 @@ void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const if (bestHeader == NULL || initialDownloadCheck()) return; static int64_t lastAlertTime = 0; - int64_t now = GetAdjustedTime(); + int64_t now = GetTime(); if (lastAlertTime > now-60*60*24) return; // Alert at most once per day const int SPAN_HOURS=4; @@ -3287,7 +3309,7 @@ void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const boost::math::poisson_distribution poisson(BLOCKS_EXPECTED); std::string strWarning; - int64_t startTime = GetAdjustedTime()-SPAN_SECONDS; + int64_t startTime = GetTime()-SPAN_SECONDS; LOCK(cs); const CBlockIndex* i = bestHeader; @@ -3340,6 +3362,7 @@ static int64_t nTimeTotal = 0; bool FindBlockPos(int32_t tmpflag,CValidationState &state, CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64_t nTime, bool fKnown = false); bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos); + bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck,bool fCheckPOW) { CDiskBlockPos blockPos; @@ -3350,6 +3373,24 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin return(false); //fprintf(stderr,"connectblock ht.%d\n",(int32_t)pindex->GetHeight()); AssertLockHeld(cs_main); + + bool ishush3 = strncmp(ASSETCHAINS_SYMBOL, "HUSH3",5) == 0 ? true : false; + + // At startup, HUSH3 doesn't know a block height yet and so we must wait until + // connecting a block to set our private/blocktime flags, which are height-dependent + if(!ASSETCHAINS_PRIVATE && ishush3) { + unsigned int nHeight = pindex->GetHeight(); + if(nHeight >= nFirstHalvingHeight) { + fprintf(stderr, "%s: Going full z2z at height %d!\n",__func__,pindex->GetHeight()); + ASSETCHAINS_PRIVATE = 1; + } + } + if (ishush3 && (ASSETCHAINS_BLOCKTIME != 75) && (chainActive.Height() >= nFirstHalvingHeight)) { + LogPrintf("%s: Blocktime halving to 75s at height %d!\n",__func__,pindex->GetHeight()); + ASSETCHAINS_BLOCKTIME = 75; + hush_changeblocktime(); + } + bool fExpensiveChecks = true; if (fCheckpointsEnabled) { CBlockIndex *pindexLastCheckpoint = Checkpoints::GetLastCheckpoint(chainparams.Checkpoints()); @@ -3443,7 +3484,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin // Before the genesis block, there was an empty tree SproutMerkleTree tree; pindex->hashSproutAnchor = tree.root(); - // The genesis block contained no JoinSplits + // The genesis block contained no JoinSplits, lulz pindex->hashFinalSproutRoot = pindex->hashSproutAnchor; } return true; @@ -3502,13 +3543,13 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin // This should never fail: we should always be able to get the root // that is on the tip of our chain - assert(view.GetSproutAnchorAt(old_sprout_tree_root, sprout_tree)); + //assert(view.GetSproutAnchorAt(old_sprout_tree_root, sprout_tree)); - { + //{ // Consistency check: the root of the tree we're given should // match what we asked for. - assert(sprout_tree.root() == old_sprout_tree_root); - } + //assert(sprout_tree.root() == old_sprout_tree_root); + //} SaplingMerkleTree sapling_tree; assert(view.GetSaplingAnchorAt(view.GetBestAnchor(SAPLING), sapling_tree)); @@ -3536,10 +3577,9 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin return state.DoS(100, error("ConnectBlock(): inputs missing/spent"), REJECT_INVALID, "bad-txns-inputs-missingorspent"); } - // are the JoinSplit's requirements met? - if (!view.HaveJoinSplitRequirements(tx)) - return state.DoS(100, error("ConnectBlock(): JoinSplit requirements not met"), - REJECT_INVALID, "bad-txns-joinsplit-requirements-not-met"); + // are the shielded requirements met? + if (!view.HaveShieldedRequirements(tx)) + return state.DoS(100, error("ConnectBlock(): shielded requirements not met"), REJECT_INVALID, "bad-txns-joinsplit-requirements-not-met"); if (fAddressIndex || fSpentIndex) { @@ -3637,21 +3677,12 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin } } - //if ( ASSETCHAINS_SYMBOL[0] == 0 ) - // komodo_earned_interest(pindex->GetHeight(),sum); CTxUndo undoDummy; if (i > 0) { blockundo.vtxundo.push_back(CTxUndo()); } UpdateCoins(tx, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->GetHeight()); - BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) { - BOOST_FOREACH(const uint256 ¬e_commitment, joinsplit.commitments) { - // Insert the note commitments into our temporary tree. - - sprout_tree.append(note_commitment); - } - } BOOST_FOREACH(const OutputDescription &outputDescription, tx.vShieldedOutput) { sapling_tree.append(outputDescription.cm); @@ -3661,7 +3692,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION); } - view.PushAnchor(sprout_tree); + //view.PushAnchor(sprout_tree); view.PushAnchor(sapling_tree); if (!fJustCheck) { pindex->hashFinalSproutRoot = sprout_tree.root(); @@ -3952,8 +3983,16 @@ void static UpdateTip(CBlockIndex *pindexNew) { if ( ASSETCHAINS_SYMBOL[0] == 0 ) { progress = Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), chainActive.LastTip()); } else { - int32_t longestchain = komodo_longestchain(); - progress = (longestchain > 0 ) ? (double) chainActive.Height() / longestchain : 1.0; + int32_t longestchain = komodo_longestchain(); + progress = (longestchain > 0 ) ? (double) chainActive.Height() / longestchain : 1.0; + } + + if(ishush3) { + if (ASSETCHAINS_BLOCKTIME != 75 && (chainActive.Height() >= nFirstHalvingHeight)) { + LogPrintf("%s: Blocktime halving to 75s at height %d!\n",__func__,chainActive.Height()); + ASSETCHAINS_BLOCKTIME = 75; + hush_changeblocktime(); + } } LogPrintf("%s: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f cache=%.1fMiB(%utx)\n", __func__, @@ -3964,33 +4003,6 @@ void static UpdateTip(CBlockIndex *pindexNew) { pcoinsTip->DynamicMemoryUsage() * (1.0 / (1<<20)), pcoinsTip->GetCacheSize()); cvBlockChange.notify_all(); - - /* - // https://github.com/zcash/zcash/issues/3992 -> https://github.com/zcash/zcash/commit/346d11d3eb2f8162df0cb00b1d1f49d542495198 - - // Check the version of the last 100 blocks to see if we need to upgrade: - static bool fWarned = false; - if (!IsInitialBlockDownload() && !fWarned) - { - int nUpgraded = 0; - const CBlockIndex* pindex = chainActive.Tip(); - for (int i = 0; i < 100 && pindex != NULL; i++) - { - if (pindex->nVersion > CBlock::CURRENT_VERSION) - ++nUpgraded; - pindex = pindex->pprev; - } - if (nUpgraded > 0) - LogPrintf("%s: %d of last 100 blocks above version %d\n", __func__, nUpgraded, (int)CBlock::CURRENT_VERSION); - if (nUpgraded > 100/2) - { - // strMiscWarning is read by GetWarnings(), called by the JSON-RPC code to warn the user: - strMiscWarning = _("Warning: This version is obsolete; upgrade required!"); - CAlert::Notify(strMiscWarning, true); - fWarned = true; - } - } - */ } /** @@ -4068,21 +4080,8 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) { // Update chainActive and related variables. UpdateTip(pindexDelete->pprev); - // Get the current commitment tree - SproutMerkleTree newSproutTree; - SaplingMerkleTree newSaplingTree; - assert(pcoinsTip->GetSproutAnchorAt(pcoinsTip->GetBestAnchor(SPROUT), newSproutTree)); - assert(pcoinsTip->GetSaplingAnchorAt(pcoinsTip->GetBestAnchor(SAPLING), newSaplingTree)); - // Let wallets know transactions went from 1-confirmed to - // 0-confirmed or conflicted: - std::vector TxToRemove; - for (int i = 0; i < block.vtx.size(); i++) - { - CTransaction &tx = block.vtx[i]; - SyncWithWallets(tx, NULL); - } - // Update cached incremental witnesses - GetMainSignals().ChainTip(pindexDelete, &block, newSproutTree, newSaplingTree, false); + // Updates to connected wallets are triggered by ThreadNotifyWallets + return true; } @@ -4156,6 +4155,11 @@ static int64_t nTimeFlush = 0; static int64_t nTimeChainState = 0; static int64_t nTimePostConnect = 0; +// Protected by cs_main +std::map> recentlyConflictedTxs; +uint64_t nRecentlyConflictedSequence = 0; +uint64_t nNotifiedSequence = 0; + /** * Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock * corresponding to pindexNew, to bypass loading it again from disk. @@ -4175,14 +4179,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * } KOMODO_CONNECTING = (int32_t)pindexNew->GetHeight(); //fprintf(stderr,"%s connecting ht.%d maxsize.%d vs %d\n",ASSETCHAINS_SYMBOL,(int32_t)pindexNew->GetHeight(),MAX_BLOCK_SIZE(pindexNew->GetHeight()),(int32_t)::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION)); - // Get the current commitment tree - SproutMerkleTree oldSproutTree; - SaplingMerkleTree oldSaplingTree; - if ( KOMODO_NSPV_FULLNODE ) - { - assert(pcoinsTip->GetSproutAnchorAt(pcoinsTip->GetBestAnchor(SPROUT), oldSproutTree)); - assert(pcoinsTip->GetSaplingAnchorAt(pcoinsTip->GetBestAnchor(SAPLING), oldSaplingTree)); - } + // Apply the block atomically to the chain state. int64_t nTime2 = GetTimeMicros(); nTimeReadFromDisk += nTime2 - nTime1; int64_t nTime3; @@ -4220,29 +4217,25 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * } int64_t nTime5 = GetTimeMicros(); nTimeChainState += nTime5 - nTime4; LogPrint("bench", " - Writing chainstate: %.2fms [%.2fs]\n", (nTime5 - nTime4) * 0.001, nTimeChainState * 0.000001); + // Remove conflicting transactions from the mempool. - list txConflicted; + std::list txConflicted; mempool.removeForBlock(pblock->vtx, pindexNew->GetHeight(), txConflicted, !IsInitialBlockDownload()); // Remove transactions that expire at new block height from mempool - mempool.removeExpired(pindexNew->GetHeight()); + auto ids = mempool.removeExpired(pindexNew->GetHeight()); + + for (auto id : ids) { + uiInterface.NotifyTxExpiration(id); + } // Update chainActive & related variables. UpdateTip(pindexNew); - if ( KOMODO_NSPV_FULLNODE ) - { - // Tell wallet about transactions that went from mempool - // to conflicted: - BOOST_FOREACH(const CTransaction &tx, txConflicted) { - SyncWithWallets(tx, NULL); - } - // ... and about transactions that got confirmed: - BOOST_FOREACH(const CTransaction &tx, pblock->vtx) { - SyncWithWallets(tx, pblock); - } - } - // Update cached incremental witnesses - GetMainSignals().ChainTip(pindexNew, pblock, oldSproutTree, oldSaplingTree, true); + + // Cache the conflicted transactions for subsequent notification. + // Updates to connected wallets are triggered by ThreadNotifyWallets + recentlyConflictedTxs.insert(std::make_pair(pindexNew, txConflicted)); + nRecentlyConflictedSequence += 1; EnforceNodeDeprecation(pindexNew->GetHeight()); @@ -4278,6 +4271,30 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * //fprintf(stderr,"%s: returning true\n", __FUNCTION__); return true; } +std::pair>, uint64_t> DrainRecentlyConflicted() +{ + uint64_t recentlyConflictedSequence; + std::map> txs; + { + LOCK(cs_main); + recentlyConflictedSequence = nRecentlyConflictedSequence; + txs.swap(recentlyConflictedTxs); + } + + return std::make_pair(txs, recentlyConflictedSequence); +} + +void SetChainNotifiedSequence(uint64_t recentlyConflictedSequence) { + assert(Params().NetworkIDString() == "regtest"); + LOCK(cs_main); + nNotifiedSequence = recentlyConflictedSequence; +} + +bool ChainIsFullyNotified() { + assert(Params().NetworkIDString() == "regtest"); + LOCK(cs_main); + return nRecentlyConflictedSequence == nNotifiedSequence; +} /** * Return the tip of the chain with the most work in it, that isn't @@ -4717,7 +4734,7 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl CAmount sproutValue = 0; CAmount saplingValue = 0; bool isShieldedTx = false; - unsigned int nShieldedSpends=0,nShieldedOutputs=0,nPayments=0, nShieldedOutputsInBlock=0; + unsigned int nShieldedSpends=0,nShieldedSpendsInBlock=0,nShieldedOutputs=0,nPayments=0,nShieldedOutputsInBlock=0; unsigned int nShieldedTx=0,nFullyShieldedTx=0,nDeshieldingTx=0,nShieldingTx=0; unsigned int nShieldedPayments=0,nFullyShieldedPayments=0,nShieldingPayments=0,nDeshieldingPayments=0; unsigned int nNotarizations=0; @@ -4805,8 +4822,12 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl // No shielded payments, add transparent payments minus a change address nPayments += tx.vout.size() > 1 ? tx.vout.size()-1 : tx.vout.size(); } - // To calculate the anonset we must track the sum of zouts in every tx, in every block. -- Duke + // To calculate the anonset we must track the sum of spends and zouts in every tx, in every block. -- Duke nShieldedOutputsInBlock += nShieldedOutputs; + nShieldedSpendsInBlock += nShieldedSpends; + if (fZdebug) { + fprintf(stderr,"%s: tx=%s has zspends=%d zouts=%d\n", __FUNCTION__, tx.GetHash().ToString().c_str(), nShieldedSpendsInBlock, nShieldedOutputsInBlock ); + } } pindexNew->nSproutValue = sproutValue; @@ -4823,6 +4844,7 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl pindexNew->nPayments = nPayments; pindexNew->nShieldedTx = nShieldedTx; pindexNew->nShieldedOutputs = nShieldedOutputsInBlock; + pindexNew->nShieldedSpends = nShieldedSpendsInBlock; pindexNew->nFullyShieldedTx = nFullyShieldedTx; pindexNew->nDeshieldingTx = nDeshieldingTx; pindexNew->nShieldingTx = nShieldingTx; @@ -4845,12 +4867,15 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl queue.pop_front(); pindex->nChainTx = (pindex->pprev ? pindex->pprev->nChainTx : 0) + pindex->nTx; + // Update -zindex stats if (fZindex) { - if (fZdebug) - fprintf(stderr,"%s: setting blockchain zstats with zouts=%d\n", __FUNCTION__, nShieldedOutputsInBlock ); + if (fZdebug) { + fprintf(stderr,"%s: setting blockchain zstats with zspends=%d, zouts=%d\n", __FUNCTION__, nShieldedSpendsInBlock, nShieldedOutputsInBlock ); + } pindex->nChainNotarizations = (pindex->pprev ? pindex->pprev->nChainNotarizations : 0) + pindex->nNotarizations; pindex->nChainShieldedTx = (pindex->pprev ? pindex->pprev->nChainShieldedTx : 0) + pindex->nShieldedTx; pindex->nChainShieldedOutputs = (pindex->pprev ? pindex->pprev->nChainShieldedOutputs : 0) + pindex->nShieldedOutputs; + pindex->nChainShieldedSpends = (pindex->pprev ? pindex->pprev->nChainShieldedSpends : 0) + pindex->nShieldedSpends; pindex->nChainFullyShieldedTx = (pindex->pprev ? pindex->pprev->nChainFullyShieldedTx : 0) + pindex->nFullyShieldedTx; pindex->nChainShieldingTx = (pindex->pprev ? pindex->pprev->nChainShieldingTx : 0) + pindex->nShieldingTx; pindex->nChainDeshieldingTx = (pindex->pprev ? pindex->pprev->nChainDeshieldingTx : 0) + pindex->nDeshieldingTx; @@ -5106,28 +5131,28 @@ bool CheckBlockHeader(int32_t *futureblockp,int32_t height,CBlockIndex *pindex, *futureblockp = 0; if ( ASSETCHAINS_ADAPTIVEPOW > 0 ) { - if (blockhdr.GetBlockTime() > GetAdjustedTime() + 4) + if (blockhdr.GetBlockTime() > GetTime() + 4) { - //LogPrintf("CheckBlockHeader block from future %d error",blockhdr.GetBlockTime() - GetAdjustedTime()); + //LogPrintf("CheckBlockHeader block from future %d error",blockhdr.GetBlockTime() - GetTime()); return false; } } - else if (blockhdr.GetBlockTime() > GetAdjustedTime() + 60) + else if (blockhdr.GetBlockTime() > GetTime() + 60) { /*CBlockIndex *tipindex; - //fprintf(stderr,"ht.%d future block %u vs time.%u + 60\n",height,(uint32_t)blockhdr.GetBlockTime(),(uint32_t)GetAdjustedTime()); - if ( (tipindex= chainActive.Tip()) != 0 && tipindex->GetBlockHash() == blockhdr.hashPrevBlock && blockhdr.GetBlockTime() < GetAdjustedTime() + 60 + 5 ) + //fprintf(stderr,"ht.%d future block %u vs time.%u + 60\n",height,(uint32_t)blockhdr.GetBlockTime(),(uint32_t)GetTime()); + if ( (tipindex= chainActive.Tip()) != 0 && tipindex->GetBlockHash() == blockhdr.hashPrevBlock && blockhdr.GetBlockTime() < GetTime() + 60 + 5 ) { - //fprintf(stderr,"it is the next block, let's wait for %d seconds\n",GetAdjustedTime() + 60 - blockhdr.GetBlockTime()); - while ( blockhdr.GetBlockTime() > GetAdjustedTime() + 60 ) + //fprintf(stderr,"it is the next block, let's wait for %d seconds\n",GetTime() + 60 - blockhdr.GetBlockTime()); + while ( blockhdr.GetBlockTime() > GetTime() + 60 ) sleep(1); //fprintf(stderr,"now its valid\n"); } else*/ { - if (blockhdr.GetBlockTime() < GetAdjustedTime() + 300) + if (blockhdr.GetBlockTime() < GetTime() + 300) *futureblockp = 1; - //LogPrintf("CheckBlockHeader block from future %d error",blockhdr.GetBlockTime() - GetAdjustedTime()); + //LogPrintf("CheckBlockHeader block from future %d error",blockhdr.GetBlockTime() - GetTime()); return false; //state.Invalid(error("CheckBlockHeader(): block timestamp too far in the future"),REJECT_INVALID, "time-too-new"); } } @@ -5316,11 +5341,6 @@ bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const C return(false); } - if (ptx) - { - SyncWithWallets(*ptx, &block); - } - if ( ASSETCHAINS_CC != 0 ) { LOCK2(cs_main,mempool.cs); @@ -5380,7 +5400,7 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta } // Check that timestamp is not too far in the future - if (block.GetBlockTime() > GetAdjustedTime() + consensusParams.nMaxFutureBlockTime) + if (block.GetBlockTime() > GetTime() + consensusParams.nMaxFutureBlockTime) { return state.Invalid(error("%s: block timestamp too far in the future", __func__), REJECT_INVALID, "time-too-new"); @@ -6094,7 +6114,7 @@ CBlockIndex * InsertBlockIndex(uint256 hash) // Create new CBlockIndex* pindexNew = new CBlockIndex(); if (!pindexNew) - throw runtime_error("LoadBlockIndex(): new CBlockIndex failed"); + throw runtime_error("InsertBlockIndex(): new CBlockIndex failed"); mi = mapBlockIndex.insert(make_pair(hash, pindexNew)).first; pindexNew->phashBlock = &((*mi).first); //fprintf(stderr,"inserted to block index %s\n",hash.ToString().c_str()); @@ -6311,6 +6331,13 @@ bool static LoadBlockIndexDB() chainActive.SetTip(it->second); + // Try to detect if we are z2z based on height of blocks on disk + // This helps to set it correctly on startup before a new block is connected + if(ishush3 && chainActive.Height() >= 340000) { + LogPrintf("%s: enabled ac_private=1 at height=%d\n", __func__, chainActive.Height()); + ASSETCHAINS_PRIVATE = 1; + } + // Set hashFinalSproutRoot for the end of best chain it->second->hashFinalSproutRoot = pcoinsTip->GetBestAnchor(SPROUT); @@ -6373,7 +6400,7 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth CBlockIndex* pindexFailure = NULL; int nGoodTransactions = 0; CValidationState state; - // No need to verify JoinSplits twice + // No need to verify shielded req's twice auto verifier = libzcash::ProofVerifier::Disabled(); //fprintf(stderr,"start VerifyDB %u\n",(uint32_t)time(NULL)); for (CBlockIndex* pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev) @@ -7391,9 +7418,10 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pfrom->nStartingHeight, addrMe.ToString(), pfrom->id, remoteAddr); - int64_t nTimeOffset = nTime - GetTime(); - pfrom->nTimeOffset = nTimeOffset; - AddTimeData(pfrom->addr, nTimeOffset); + //int64_t nTimeOffset = nTime - GetTime(); + //pfrom->nTimeOffset = nTimeOffset; + //AddTimeData(pfrom->addr, nTimeOffset); + pfrom->nTimeOffset = timeWarning.AddTimeData(pfrom->addr, nTime, GetTime()); } @@ -7469,7 +7497,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // Store the new addresses vector vAddrOk; - int64_t nNow = GetAdjustedTime(); + int64_t nNow = GetTime(); int64_t nSince = nNow - 10 * 60; BOOST_FOREACH(CAddress& addr, vAddr) { @@ -7679,7 +7707,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, // not a direct successor. pfrom->PushMessage("getheaders", chainActive.GetLocator(pindexBestHeader), inv.hash); CNodeState *nodestate = State(pfrom->GetId()); - if (chainActive.Tip()->GetBlockTime() > GetAdjustedTime() - chainparams.GetConsensus().nPowTargetSpacing * 20 && + if (chainActive.Tip()->GetBlockTime() > GetTime() - chainparams.GetConsensus().nPowTargetSpacing * 20 && nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER) { vToFetch.push_back(inv); // Mark block as in flight already, even though the actual "getdata" message only goes out @@ -8442,7 +8470,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) bool fFetch = state.fPreferredDownload || (nPreferredDownload == 0 && !pto->fClient && !pto->fOneShot); // Download if this is a nice peer, or we have no nice peers and this one might do. if (!state.fSyncStarted && !pto->fClient && !fImporting && !fReindex && pindexBestHeader!=0) { // Only actively request headers from a single peer, unless we're close to today. - if ((nSyncStarted == 0 && fFetch) || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 60) { + if ((nSyncStarted == 0 && fFetch) || pindexBestHeader->GetBlockTime() > GetTime() - 24 * 60 * 60) { state.fSyncStarted = true; nSyncStarted++; CBlockIndex *pindexStart = pindexBestHeader->pprev ? pindexBestHeader->pprev : pindexBestHeader; diff --git a/src/main.h b/src/main.h index c4bf4ea64..060b6b7cc 100644 --- a/src/main.h +++ b/src/main.h @@ -949,4 +949,8 @@ uint64_t CalculateCurrentUsage(); /** Return a CMutableTransaction with contextual default values based on set of consensus rules at height */ CMutableTransaction CreateNewContextualCMutableTransaction(const Consensus::Params& consensusParams, int nHeight); +std::pair>, uint64_t> DrainRecentlyConflicted(); +void SetChainNotifiedSequence(uint64_t recentlyConflictedSequence); +bool ChainIsFullyNotified(); + #endif // BITCOIN_MAIN_H diff --git a/src/metrics.cpp b/src/metrics.cpp index ff0863a19..adbef02f2 100644 --- a/src/metrics.cpp +++ b/src/metrics.cpp @@ -288,7 +288,7 @@ int printMiningStatus(bool mining) } else if (IsInitialBlockDownload()) { std::cout << _("Mining is paused while downloading blocks.") << std::endl; } else { - std::cout << _("Mining is paused (a JoinSplit may be in progress).") << std::endl; + std::cout << _("Mining is paused, enhance your calm") << std::endl; } } lines++; diff --git a/src/miner.cpp b/src/miner.cpp index 079e2bbf9..4ab19638b 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -1,8 +1,8 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin Core developers -// Copyright (c) 2019 The Hush 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. +// file COPYING or https://www.opensource.org/licenses/mit-license.php /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * @@ -126,8 +126,8 @@ extern int8_t ASSETCHAINS_ADAPTIVEPOW; void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev) { if ( ASSETCHAINS_ADAPTIVEPOW <= 0 ) - pblock->nTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); - else pblock->nTime = std::max((int64_t)(pindexPrev->nTime+1), GetAdjustedTime()); + pblock->nTime = std::max(pindexPrev->GetMedianTimePast()+1, GetTime()); + else pblock->nTime = std::max((int64_t)(pindexPrev->nTime+1), GetTime()); // Updating time can change work required on testnet: if (ASSETCHAINS_ADAPTIVEPOW > 0 || consensusParams.nPowAllowMinDifficultyBlocksAfterHeight != boost::none) @@ -239,7 +239,7 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 bool sapling = NetworkUpgradeActive(nHeight, consensusParams, Consensus::UPGRADE_SAPLING); const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast(); - uint32_t proposedTime = GetAdjustedTime(); + uint32_t proposedTime = GetTime(); voutsum = GetBlockSubsidy(nHeight,consensusParams) + 10000*COIN; // approx fees if (proposedTime == nMedianTimePast) @@ -248,12 +248,12 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 // forward as quickly as possible for (int i; i < 100; i++) { - proposedTime = GetAdjustedTime(); + proposedTime = GetTime(); if (proposedTime == nMedianTimePast) MilliSleep(10); } } - pblock->nTime = GetAdjustedTime(); + pblock->nTime = GetTime(); // Now we have the block time + height, we can get the active notaries. int8_t numSN = 0; uint8_t notarypubkeys[64][33] = {0}; if ( ASSETCHAINS_NOTARY_PAY[0] != 0 ) @@ -340,7 +340,7 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 if (!mempool.mapTx.count(txin.prevout.hash)) { LogPrintf("ERROR: mempool transaction missing input\n"); - if (fDebug) assert("mempool transaction missing input" == 0); + // if (fDebug) assert("mempool transaction missing input" == 0); fMissingInputs = true; if (porphan) vOrphan.pop_back(); @@ -472,6 +472,40 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 // Size limits unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); + + // Opret spam limits + if (mapArgs.count("-opretmintxfee")) + { + CAmount n = 0; + CFeeRate opretMinFeeRate; + if (ParseMoney(mapArgs["-opretmintxfee"], n) && n > 0) + opretMinFeeRate = CFeeRate(n); + else + opretMinFeeRate = CFeeRate(400000); // default opretMinFeeRate (1 HUSH per 250 Kb = 0.004 per 1 Kb = 400000 puposhis per 1 Kb) + + bool fSpamTx = false; + unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION); + unsigned int nTxOpretSize = 0; + + // calc total oprets size + BOOST_FOREACH(const CTxOut& txout, tx.vout) { + if (txout.scriptPubKey.IsOpReturn()) { + CScript::const_iterator it = txout.scriptPubKey.begin() + 1; + opcodetype op; + std::vector opretData; + if (txout.scriptPubKey.GetOp(it, op, opretData)) { + //std::cerr << HexStr(opretData.begin(), opretData.end()) << std::endl; + nTxOpretSize += opretData.size(); + } + } + } + + if ((nTxOpretSize > 256) && (feeRate < opretMinFeeRate)) fSpamTx = true; + // std::cerr << tx.GetHash().ToString() << " nTxSize." << nTxSize << " nTxOpretSize." << nTxOpretSize << " feeRate." << feeRate.ToString() << " opretMinFeeRate." << opretMinFeeRate.ToString() << " fSpamTx." << fSpamTx << std::endl; + if (fSpamTx) continue; + // std::cerr << tx.GetHash().ToString() << " vecPriority.size() = " << vecPriority.size() << std::endl; + } + if (nBlockSize + nTxSize >= nBlockMaxSize-512) // room for extra autotx { //fprintf(stderr,"nBlockSize %d + %d nTxSize >= %d nBlockMaxSize\n",(int32_t)nBlockSize,(int32_t)nTxSize,(int32_t)nBlockMaxSize); @@ -569,8 +603,8 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 nLastBlockTx = nBlockTx; nLastBlockSize = nBlockSize; if ( ASSETCHAINS_ADAPTIVEPOW <= 0 ) - blocktime = 1 + std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); - else blocktime = 1 + std::max((int64_t)(pindexPrev->nTime+1), GetAdjustedTime()); + blocktime = 1 + std::max(pindexPrev->GetMedianTimePast()+1, GetTime()); + else blocktime = 1 + std::max((int64_t)(pindexPrev->nTime+1), GetTime()); //pblock->nTime = blocktime + 1; pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus()); @@ -590,8 +624,8 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32 //fprintf(stderr,"mine ht.%d with %.8f\n",nHeight,(double)txNew.vout[0].nValue/COIN); txNew.nExpiryHeight = 0; if ( ASSETCHAINS_ADAPTIVEPOW <= 0 ) - txNew.nLockTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); - else txNew.nLockTime = std::max((int64_t)(pindexPrev->nTime+1), GetAdjustedTime()); + txNew.nLockTime = std::max(pindexPrev->GetMedianTimePast()+1, GetTime()); + else txNew.nLockTime = std::max((int64_t)(pindexPrev->nTime+1), GetTime()); if ( ASSETCHAINS_SYMBOL[0] == 0 && IS_KOMODO_NOTARY != 0 && My_notaryid >= 0 ) @@ -949,6 +983,9 @@ static bool ProcessBlockFound(CBlock* pblock) } } + // Inform about the new block + GetMainSignals().BlockFound(pblock->GetHash()); + #ifdef ENABLE_WALLET // Remove key from key pool if ( IS_KOMODO_NOTARY == 0 ) @@ -1331,10 +1368,10 @@ void static BitcoinMiner() // MilliSleep(30); return false; } - if ( IS_KOMODO_NOTARY != 0 && B.nTime > GetAdjustedTime() ) + if ( IS_KOMODO_NOTARY != 0 && B.nTime > GetTime() ) { - //fprintf(stderr,"need to wait %d seconds to submit block\n",(int32_t)(B.nTime - GetAdjustedTime())); - while ( GetAdjustedTime() < B.nTime-2 ) + //fprintf(stderr,"need to wait %d seconds to submit block\n",(int32_t)(B.nTime - GetTime())); + while ( GetTime() < B.nTime-2 ) { sleep(1); if ( chainActive.LastTip()->GetHeight() >= Mining_height ) diff --git a/src/net.cpp b/src/net.cpp index efb69bfe9..5be64b291 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin Core developers -// Copyright (c) 2019 The Hush 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. @@ -193,7 +193,7 @@ CAddress GetLocalAddress(const CNetAddr *paddrPeer) ret = CAddress(addr); } ret.nServices = nLocalServices; - ret.nTime = GetAdjustedTime(); + ret.nTime = GetTime(); return ret; } @@ -393,7 +393,7 @@ CNode* ConnectNode(CAddress addrConnect, const char *pszDest) /// debug print LogPrint("net", "trying connection %s lastseen=%.1fhrs\n", pszDest ? pszDest : addrConnect.ToString(), - pszDest ? 0.0 : (double)(GetAdjustedTime() - addrConnect.nTime)/3600.0); + pszDest ? 0.0 : (double)(GetTime() - addrConnect.nTime)/3600.0); // Connect SOCKET hSocket; @@ -458,7 +458,7 @@ void CNode::PushVersion() { int nBestHeight = g_signals.GetHeight().get_value_or(0); - int64_t nTime = (fInbound ? GetAdjustedTime() : GetTime()); + int64_t nTime = (fInbound ? GetTime() : GetTime()); CAddress addrYou = (addr.IsRoutable() && !IsProxy(addr) ? addr : CAddress(CService("0.0.0.0",0))); CAddress addrMe = GetLocalAddress(&addr); GetRandBytes((unsigned char*)&nLocalHostNonce, sizeof(nLocalHostNonce)); @@ -1429,7 +1429,7 @@ void ThreadOpenConnections() } } - int64_t nANow = GetAdjustedTime(); + int64_t nANow = GetTime(); int nTries = 0; while (true) diff --git a/src/paymentdisclosure.cpp b/src/paymentdisclosure.cpp deleted file mode 100644 index eb55a0536..000000000 --- a/src/paymentdisclosure.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2017 The Zcash developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "paymentdisclosure.h" - -#include "key_io.h" -#include "util.h" - -std::string PaymentDisclosureInfo::ToString() const { - return strprintf("PaymentDisclosureInfo(version=%d, esk=%s, joinSplitPrivKey=, address=%s)", - version, esk.ToString(), EncodePaymentAddress(zaddr)); -} - -std::string PaymentDisclosure::ToString() const { - std::string s = HexStr(payloadSig.begin(), payloadSig.end()); - return strprintf("PaymentDisclosure(payload=%s, payloadSig=%s)", payload.ToString(), s); -} - -std::string PaymentDisclosurePayload::ToString() const { - return strprintf("PaymentDisclosurePayload(version=%d, esk=%s, txid=%s, js=%d, n=%d, address=%s, message=%s)", - version, esk.ToString(), txid.ToString(), js, n, EncodePaymentAddress(zaddr), message); -} - -PaymentDisclosure::PaymentDisclosure(const uint256 &joinSplitPubKey, const PaymentDisclosureKey &key, const PaymentDisclosureInfo &info, const std::string &message) -{ - // Populate payload member variable - payload.version = info.version; // experimental = 0, production = 1 etc. - payload.esk = info.esk; - payload.txid = key.hash; - payload.js = key.js; - payload.n = key.n; - payload.zaddr = info.zaddr; - payload.message = message; - - // Serialize and hash the payload to generate a signature - uint256 dataToBeSigned = SerializeHash(payload, SER_GETHASH, 0); - - LogPrint("paymentdisclosure", "Payment Disclosure: signing raw payload = %s\n", dataToBeSigned.ToString()); - - // Prepare buffer to store ed25519 key pair in libsodium-compatible format - unsigned char bufferKeyPair[64]; - memcpy(&bufferKeyPair[0], info.joinSplitPrivKey.begin(), 32); - memcpy(&bufferKeyPair[32], joinSplitPubKey.begin(), 32); - - // Compute payload signature member variable - if (!(crypto_sign_detached(payloadSig.data(), NULL, - dataToBeSigned.begin(), 32, - &bufferKeyPair[0] - ) == 0)) - { - throw std::runtime_error("crypto_sign_detached failed"); - } - - // Sanity check - if (!(crypto_sign_verify_detached(payloadSig.data(), - dataToBeSigned.begin(), 32, - joinSplitPubKey.begin()) == 0)) - { - throw std::runtime_error("crypto_sign_verify_detached failed"); - } - - std::string sigString = HexStr(payloadSig.data(), payloadSig.data() + payloadSig.size()); - LogPrint("paymentdisclosure", "Payment Disclosure: signature = %s\n", sigString); -} diff --git a/src/paymentdisclosure.h b/src/paymentdisclosure.h deleted file mode 100644 index 28a1d4cdc..000000000 --- a/src/paymentdisclosure.h +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright (c) 2017 The Zcash developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef ZCASH_PAYMENTDISCLOSURE_H -#define ZCASH_PAYMENTDISCLOSURE_H - -#include "uint256.h" -#include "clientversion.h" -#include "serialize.h" -#include "streams.h" -#include "version.h" - -// For JSOutPoint -#include "wallet/wallet.h" - -#include -#include -#include - - -// Ensure that the two different protocol messages, payment disclosure blobs and transactions, -// which are signed with the same key, joinSplitPrivKey, have disjoint encodings such that an -// encoding from one context will be rejected in the other. We know that the set of valid -// transaction versions is currently ({1..INT32_MAX}) so we will use a negative value for -// payment disclosure of -10328976 which in hex is 0xFF626470. Serialization is in little endian -// format, so a payment disclosure hex string begins 706462FF, which in ISO-8859-1 is "pdbÿ". -#define PAYMENT_DISCLOSURE_PAYLOAD_MAGIC_BYTES -10328976 - -#define PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL 0 - -#define PAYMENT_DISCLOSURE_BLOB_STRING_PREFIX "zpd:" - -typedef JSOutPoint PaymentDisclosureKey; - -struct PaymentDisclosureInfo { - uint8_t version; // 0 = experimental, 1 = first production version, etc. - uint256 esk; // zcash/NoteEncryption.cpp - uint256 joinSplitPrivKey; // primitives/transaction.h - // ed25519 - not tied to implementation e.g. libsodium, see ed25519 rfc - - libzcash::SproutPaymentAddress zaddr; - - PaymentDisclosureInfo() : version(PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL) { - } - - PaymentDisclosureInfo(uint8_t v, uint256 esk, uint256 key, libzcash::SproutPaymentAddress zaddr) : version(v), esk(esk), joinSplitPrivKey(key), zaddr(zaddr) { } - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(version); - READWRITE(esk); - READWRITE(joinSplitPrivKey); - READWRITE(zaddr); - } - - std::string ToString() const; - - friend bool operator==(const PaymentDisclosureInfo& a, const PaymentDisclosureInfo& b) { - return (a.version == b.version && a.esk == b.esk && a.joinSplitPrivKey == b.joinSplitPrivKey && a.zaddr == b.zaddr); - } - - friend bool operator!=(const PaymentDisclosureInfo& a, const PaymentDisclosureInfo& b) { - return !(a == b); - } - -}; - - -struct PaymentDisclosurePayload { - int32_t marker = PAYMENT_DISCLOSURE_PAYLOAD_MAGIC_BYTES; // to be disjoint from transaction encoding - uint8_t version; // 0 = experimental, 1 = first production version, etc. - uint256 esk; // zcash/NoteEncryption.cpp - uint256 txid; // primitives/transaction.h - uint64_t js; // Index into CTransaction.vjoinsplit - uint8_t n; // Index into JSDescription fields of length ZC_NUM_JS_OUTPUTS - libzcash::SproutPaymentAddress zaddr; // zcash/Address.hpp - std::string message; // parameter to RPC call - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(marker); - READWRITE(version); - READWRITE(esk); - READWRITE(txid); - READWRITE(js); - READWRITE(n); - READWRITE(zaddr); - READWRITE(message); - } - - std::string ToString() const; - - friend bool operator==(const PaymentDisclosurePayload& a, const PaymentDisclosurePayload& b) { - return ( - a.version == b.version && - a.esk == b.esk && - a.txid == b.txid && - a.js == b.js && - a.n == b.n && - a.zaddr == b.zaddr && - a.message == b.message - ); - } - - friend bool operator!=(const PaymentDisclosurePayload& a, const PaymentDisclosurePayload& b) { - return !(a == b); - } -}; - -struct PaymentDisclosure { - PaymentDisclosurePayload payload; - std::array payloadSig; - // We use boost array because serialize doesn't like char buffer, otherwise we could do: unsigned char payloadSig[64]; - - PaymentDisclosure() {}; - PaymentDisclosure(const PaymentDisclosurePayload payload, const std::array sig) : payload(payload), payloadSig(sig) {}; - PaymentDisclosure(const uint256& joinSplitPubKey, const PaymentDisclosureKey& key, const PaymentDisclosureInfo& info, const std::string& message); - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(payload); - READWRITE(payloadSig); - } - - std::string ToString() const; - - friend bool operator==(const PaymentDisclosure& a, const PaymentDisclosure& b) { - return (a.payload == b.payload && a.payloadSig == b.payloadSig); - } - - friend bool operator!=(const PaymentDisclosure& a, const PaymentDisclosure& b) { - return !(a == b); - } -}; - - - -typedef std::pair PaymentDisclosureKeyInfo; - - -#endif // ZCASH_PAYMENTDISCLOSURE_H diff --git a/src/paymentdisclosuredb.cpp b/src/paymentdisclosuredb.cpp deleted file mode 100644 index 8840dcda0..000000000 --- a/src/paymentdisclosuredb.cpp +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) 2017 The Zcash developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "paymentdisclosuredb.h" - -#include "util.h" -#include "dbwrapper.h" - -#include - -using namespace std; - -static boost::filesystem::path emptyPath; - -/** - * Static method to return the shared/default payment disclosure database. - */ -shared_ptr PaymentDisclosureDB::sharedInstance() { - // Thread-safe in C++11 and gcc 4.3 - static shared_ptr ptr = std::make_shared(); - return ptr; -} - -// C++11 delegated constructor -PaymentDisclosureDB::PaymentDisclosureDB() : PaymentDisclosureDB(emptyPath) { -} - -PaymentDisclosureDB::PaymentDisclosureDB(const boost::filesystem::path& dbPath) { - boost::filesystem::path path(dbPath); - if (path.empty()) { - path = GetDataDir() / "paymentdisclosure"; - LogPrintf("PaymentDisclosure: using default path for database: %s\n", path.string()); - } else { - LogPrintf("PaymentDisclosure: using custom path for database: %s\n", path.string()); - } - - TryCreateDirectory(path); - options.create_if_missing = true; - leveldb::Status status = leveldb::DB::Open(options, path.string(), &db); - dbwrapper_private::HandleError(status); // throws exception - LogPrintf("PaymentDisclosure: Opened LevelDB successfully\n"); -} - -PaymentDisclosureDB::~PaymentDisclosureDB() { - if (db != nullptr) { - delete db; - } -} - -bool PaymentDisclosureDB::Put(const PaymentDisclosureKey& key, const PaymentDisclosureInfo& info) -{ - if (db == nullptr) { - return false; - } - - std::lock_guard guard(lock_); - - CDataStream ssValue(SER_DISK, CLIENT_VERSION); - ssValue.reserve(GetSerializeSize(ssValue, info)); - ssValue << info; - leveldb::Slice slice(&ssValue[0], ssValue.size()); - - leveldb::Status status = db->Put(writeOptions, key.ToString(), slice); - dbwrapper_private::HandleError(status); - return true; -} - -bool PaymentDisclosureDB::Get(const PaymentDisclosureKey& key, PaymentDisclosureInfo& info) -{ - if (db == nullptr) { - return false; - } - - std::lock_guard guard(lock_); - - std::string strValue; - leveldb::Status status = db->Get(readOptions, key.ToString(), &strValue); - if (!status.ok()) { - if (status.IsNotFound()) - return false; - LogPrintf("PaymentDisclosure: LevelDB read failure: %s\n", status.ToString()); - dbwrapper_private::HandleError(status); - } - - try { - CDataStream ssValue(strValue.data(), strValue.data() + strValue.size(), SER_DISK, CLIENT_VERSION); - ssValue >> info; - } catch (const std::exception&) { - return false; - } - return true; -} diff --git a/src/paymentdisclosuredb.h b/src/paymentdisclosuredb.h deleted file mode 100644 index 9352cac8f..000000000 --- a/src/paymentdisclosuredb.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2017 The Zcash developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef ZCASH_PAYMENTDISCLOSUREDB_H -#define ZCASH_PAYMENTDISCLOSUREDB_H - -#include "paymentdisclosure.h" - -#include -#include -#include -#include -#include - -#include - -#include - - -class PaymentDisclosureDB -{ -protected: - leveldb::DB* db = nullptr; - leveldb::Options options; - leveldb::ReadOptions readOptions; - leveldb::WriteOptions writeOptions; - mutable std::mutex lock_; - -public: - static std::shared_ptr sharedInstance(); - - PaymentDisclosureDB(); - PaymentDisclosureDB(const boost::filesystem::path& dbPath); - ~PaymentDisclosureDB(); - - bool Put(const PaymentDisclosureKey& key, const PaymentDisclosureInfo& info); - bool Get(const PaymentDisclosureKey& key, PaymentDisclosureInfo& info); -}; - - -#endif // ZCASH_PAYMENTDISCLOSUREDB_H diff --git a/src/pow.cpp b/src/pow.cpp index 79c41feb4..6d0262699 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin Core developers -// Copyright (c) 2019 The Hush 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. @@ -298,6 +298,9 @@ arith_uint256 zawy_TSA_EMA(int32_t height,int32_t tipdiff,arith_uint256 prevTarg unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params) { + if (pindexLast->GetHeight() == 340000) { + LogPrintf("%s: Using blocktime=%d\n",__func__,ASSETCHAINS_BLOCKTIME); + } if (ASSETCHAINS_ALGO != ASSETCHAINS_EQUIHASH && ASSETCHAINS_STAKED == 0) return lwmaGetNextWorkRequired(pindexLast, pblock, params); diff --git a/src/primitives/block.h b/src/primitives/block.h index ea93d6f50..9a6ddf100 100644 --- a/src/primitives/block.h +++ b/src/primitives/block.h @@ -1,6 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2013 The Bitcoin Core developers -// Copyright (c) 2019 The Hush 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. @@ -23,7 +23,7 @@ #define BITCOIN_PRIMITIVES_BLOCK_H #include "primitives/transaction.h" -#include "primitives/nonce.h" +//#include "primitives/nonce.h" #include "serialize.h" #include "uint256.h" #include "arith_uint256.h" diff --git a/src/primitives/nonce.cpp b/src/primitives/nonce.cpp deleted file mode 100644 index a1fbd667d..000000000 --- a/src/primitives/nonce.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2019 The Hush Developers -// Copyright (c) 2018 Michael Toutonghi -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -/****************************************************************************** - * Copyright © 2014-2019 The SuperNET Developers. * - * * - * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * - * the top-level directory of this distribution for the individual copyright * - * holder information and the developer policies on copyright and licensing. * - * * - * Unless otherwise agreed in a custom licensing agreement, no part of the * - * SuperNET software, including this file may be copied, modified, propagated * - * or distributed except according to the terms contained in the LICENSE file * - * * - * Removal or modification of this copyright notice is prohibited. * - * * - ******************************************************************************/ - -#include "hash.h" -#include "nonce.h" -#include - diff --git a/src/primitives/nonce.h b/src/primitives/nonce.h deleted file mode 100644 index b17a9f01b..000000000 --- a/src/primitives/nonce.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) 2019 Hush Developers -// Copyright (c) 2018 Michael Toutonghi -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -/****************************************************************************** - * Copyright © 2014-2019 The SuperNET Developers. * - * * - * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * - * the top-level directory of this distribution for the individual copyright * - * holder information and the developer policies on copyright and licensing. * - * * - * Unless otherwise agreed in a custom licensing agreement, no part of the * - * SuperNET software, including this file may be copied, modified, propagated * - * or distributed except according to the terms contained in the LICENSE file * - * * - * Removal or modification of this copyright notice is prohibited. * - * * - ******************************************************************************/ - -#ifndef BITCOIN_PRIMITIVES_NONCE_H -#define BITCOIN_PRIMITIVES_NONCE_H - -#include "serialize.h" -#include "uint256.h" -#include "arith_uint256.h" - - -#endif // BITCOIN_PRIMITIVES_NONCE_H diff --git a/src/primitives/transaction.cpp b/src/primitives/transaction.cpp index ea24f9d23..53aeeda99 100644 --- a/src/primitives/transaction.cpp +++ b/src/primitives/transaction.cpp @@ -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. @@ -26,139 +27,6 @@ #include "librustzcash.h" -JSDescription::JSDescription( - bool makeGrothProof, - ZCJoinSplit& params, - const uint256& joinSplitPubKey, - const uint256& anchor, - const std::array& inputs, - const std::array& outputs, - CAmount vpub_old, - CAmount vpub_new, - bool computeProof, - uint256 *esk // payment disclosure -) : vpub_old(vpub_old), vpub_new(vpub_new), anchor(anchor) -{ - std::array notes; - - proof = params.prove( - makeGrothProof, - inputs, - outputs, - notes, - ciphertexts, - ephemeralKey, - joinSplitPubKey, - randomSeed, - macs, - nullifiers, - commitments, - vpub_old, - vpub_new, - anchor, - computeProof, - esk // payment disclosure - ); -} - -JSDescription JSDescription::Randomized( - bool makeGrothProof, - ZCJoinSplit& params, - const uint256& joinSplitPubKey, - const uint256& anchor, - std::array& inputs, - std::array& outputs, - std::array& inputMap, - std::array& outputMap, - CAmount vpub_old, - CAmount vpub_new, - bool computeProof, - uint256 *esk, // payment disclosure - std::function gen -) -{ - // Randomize the order of the inputs and outputs - inputMap = {0, 1}; - outputMap = {0, 1}; - - assert(gen); - - MappedShuffle(inputs.begin(), inputMap.begin(), ZC_NUM_JS_INPUTS, gen); - MappedShuffle(outputs.begin(), outputMap.begin(), ZC_NUM_JS_OUTPUTS, gen); - - return JSDescription( - makeGrothProof, - params, joinSplitPubKey, anchor, inputs, outputs, - vpub_old, vpub_new, computeProof, - esk // payment disclosure - ); -} - -class SproutProofVerifier : public boost::static_visitor -{ - ZCJoinSplit& params; - libzcash::ProofVerifier& verifier; - const uint256& joinSplitPubKey; - const JSDescription& jsdesc; - -public: - SproutProofVerifier( - ZCJoinSplit& params, - libzcash::ProofVerifier& verifier, - const uint256& joinSplitPubKey, - const JSDescription& jsdesc - ) : params(params), jsdesc(jsdesc), verifier(verifier), joinSplitPubKey(joinSplitPubKey) {} - - bool operator()(const libzcash::PHGRProof& proof) const - { - return params.verify( - proof, - verifier, - joinSplitPubKey, - jsdesc.randomSeed, - jsdesc.macs, - jsdesc.nullifiers, - jsdesc.commitments, - jsdesc.vpub_old, - jsdesc.vpub_new, - jsdesc.anchor - ); - } - - bool operator()(const libzcash::GrothProof& proof) const - { - uint256 h_sig = params.h_sig(jsdesc.randomSeed, jsdesc.nullifiers, joinSplitPubKey); - - return librustzcash_sprout_verify( - proof.begin(), - jsdesc.anchor.begin(), - h_sig.begin(), - jsdesc.macs[0].begin(), - jsdesc.macs[1].begin(), - jsdesc.nullifiers[0].begin(), - jsdesc.nullifiers[1].begin(), - jsdesc.commitments[0].begin(), - jsdesc.commitments[1].begin(), - jsdesc.vpub_old, - jsdesc.vpub_new - ); - } -}; - -bool JSDescription::Verify( - ZCJoinSplit& params, - libzcash::ProofVerifier& verifier, - const uint256& joinSplitPubKey -) const { - auto pv = SproutProofVerifier(params, verifier, joinSplitPubKey, *this); - return boost::apply_visitor(pv, proof); -} - -uint256 JSDescription::h_sig(ZCJoinSplit& params, const uint256& joinSplitPubKey) const -{ - return params.h_sig(randomSeed, nullifiers, joinSplitPubKey); -} - std::string COutPoint::ToString() const { return strprintf("COutPoint(%s, %u)", hash.ToString().substr(0,10), n); diff --git a/src/primitives/transaction.h b/src/primitives/transaction.h index e83a519b1..7a46b9c00 100644 --- a/src/primitives/transaction.h +++ b/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. @@ -43,10 +44,16 @@ #include "zcash/Zcash.h" #include "zcash/JoinSplit.hpp" #include "zcash/Proof.hpp" +#include "zcash/Note.hpp" extern uint32_t ASSETCHAINS_MAGIC; extern std::string ASSETCHAINS_SELFIMPORT; +#define JOINSPLIT_SIZE GetSerializeSize(JSDescription(), SER_NETWORK, PROTOCOL_VERSION) +#define OUTPUTDESCRIPTION_SIZE GetSerializeSize(OutputDescription(), SER_NETWORK, PROTOCOL_VERSION) +#define SPENDDESCRIPTION_SIZE GetSerializeSize(SpendDescription(), SER_NETWORK, PROTOCOL_VERSION) + + // Overwinter transaction version static const int32_t OVERWINTER_TX_VERSION = 3; static_assert(OVERWINTER_TX_VERSION >= OVERWINTER_MIN_TX_VERSION, @@ -251,7 +258,6 @@ public: JSDescription(): vpub_old(0), vpub_new(0) { } JSDescription( - bool makeGrothProof, ZCJoinSplit& params, const uint256& joinSplitPubKey, const uint256& rt, @@ -264,7 +270,6 @@ public: ); static JSDescription Randomized( - bool makeGrothProof, ZCJoinSplit& params, const uint256& joinSplitPubKey, const uint256& rt, diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 0b22255d1..6e2efbd57 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin Core developers -// Copyright (c) 2019 The Hush 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. @@ -1668,9 +1668,10 @@ UniValue getblockchaininfo(const UniValue& params, bool fHelp, const CPubKey& my obj.push_back(Pair("chainwork", chainActive.LastTip()->chainPower.chainWork.GetHex())); obj.push_back(Pair("pruned", fPruneMode)); - SproutMerkleTree tree; - pcoinsTip->GetSproutAnchorAt(pcoinsTip->GetBestAnchor(SPROUT), tree); - obj.push_back(Pair("commitments", static_cast(tree.size()))); + //SproutMerkleTree tree; + //pcoinsTip->GetSproutAnchorAt(pcoinsTip->GetBestAnchor(SPROUT), tree); + //obj.push_back(Pair("commitments", static_cast(tree.size()))); + obj.push_back(Pair("commitments", 0)); CBlockIndex* tip = chainActive.LastTip(); UniValue valuePools(UniValue::VARR); @@ -1875,9 +1876,11 @@ inline CBlockIndex* LookupBlockIndex(const uint256& hash) return it == mapBlockIndex.end() ? nullptr : it->second; } +// Every coin can have different number of coinbase due to Founders Reward addresses/etc +#define COINBASE_PER_BLOCK 2 // given a transaction count X, subtract out coinbase and dpow transactions // to give an "organic count". We return 0 instead of negative values -#define ORG(X) ( (X - blockcount - nNotarizationsDiff) > 0 ? (X - blockcount - nNotarizationsDiff) : 0 ) +#define ORG(X) ( (X - COINBASE_PER_BLOCK*blockcount - nNotarizationsDiff) > 0 ? (X - COINBASE_PER_BLOCK*blockcount - nNotarizationsDiff) : 0 ) //TODO: Allow custom error message in this macro #define THROW_IF_SYNCING(INSYNC) if (INSYNC == 0) { throw runtime_error(strprintf("%s: Chain still syncing at height %d, aborting to prevent garbage data. Please wait until the chain is synced to run this RPC",__FUNCTION__,chainActive.Tip()->GetHeight())); } @@ -1901,6 +1904,7 @@ UniValue getchaintxstats(const UniValue& params, bool fHelp, const CPubKey& mypk " \"nullifiers\": xxxxx, (numeric) The total number of shielded nullifiers in the chain up to that point.\n" " \"shielded_txcount\": xxxxx, (numeric) The total number of shielded (containing a zaddr) transactions in the chain up to that point.\n" " \"shielded_outputs\": xxxxx, (numeric) The total number of shielded outputs in the chain up to that point.\n" + " \"shielded_spends\": xxxxx, (numeric) The total number of shielded spends in the chain up to that point.\n" " \"shielded_pool_size\": xxxxx, (numeric) The total number of unspent shielded outputs, i.e. the Shielded Pool or Anonymity Set (anonset).\n" " \"shielding_txcount\": xxxxx, (numeric) The total number of shielding (containing a zaddr output) transactions in the chain up to that point.\n" " \"deshielding_txcount\": xxxxx, (numeric) The total number of deshielding (containing a zaddr input) transactions in the chain up to that point.\n" @@ -2000,9 +2004,11 @@ UniValue getchaintxstats(const UniValue& params, bool fHelp, const CPubKey& mypk ret.pushKV("shielding_payments", (int64_t)pindex->nChainShieldingPayments); int64_t nullifierCount = pwalletMain->NullifierCount(); + //TODO: this is unreliable, is only a cache or subset of total nullifiers ret.pushKV("nullifiers", (int64_t)nullifierCount); - ret.pushKV("shielded_pool_size", (int64_t)pindex->nChainShieldedOutputs - nullifierCount); + ret.pushKV("shielded_pool_size", (int64_t)(pindex->nChainShieldedOutputs - pindex->nChainShieldedSpends)); ret.pushKV("shielded_outputs", (int64_t)pindex->nChainShieldedOutputs); + ret.pushKV("shielded_spends", (int64_t)pindex->nChainShieldedSpends); } if (blockcount > 0) { diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index ddc0915d7..4f11a476f 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -1,5 +1,6 @@ // Copyright (c) 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. @@ -130,12 +131,6 @@ static const CRPCConvertParam vRPCConvertParams[] = { "getaddressdeltas", 0}, { "getaddressutxos", 0}, { "getaddressmempool", 0}, - { "zcrawjoinsplit", 1 }, - { "zcrawjoinsplit", 2 }, - { "zcrawjoinsplit", 3 }, - { "zcrawjoinsplit", 4 }, - { "zcbenchmark", 1 }, - { "zcbenchmark", 2 }, { "getblocksubsidy", 0}, { "z_listaddresses", 0}, { "z_listreceivedbyaddress", 1}, @@ -144,6 +139,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "z_listunspent", 2 }, { "z_listunspent", 3 }, { "z_getbalance", 1}, + { "z_getnotescount", 0}, { "z_gettotalbalance", 0}, { "z_gettotalbalance", 1}, { "z_gettotalbalance", 2}, @@ -168,8 +164,17 @@ static const CRPCConvertParam vRPCConvertParams[] = { "kvupdate", 4 }, { "z_importkey", 2 }, { "z_importviewingkey", 2 }, - { "z_getpaymentdisclosure", 1}, - { "z_getpaymentdisclosure", 2}, + { "z_listsentbyaddress", 1}, + { "z_listsentbyaddress", 2}, + { "z_listsentbyaddress", 3}, + { "z_listsentbyaddress", 4}, + { "z_listsentbyaddress", 5}, + { "z_listreceivedbyaddress", 1}, + { "z_listreceivedbyaddress", 2}, + { "z_listreceivedbyaddress", 3}, + { "z_listreceivedbyaddress", 4}, + { "z_listreceivedbyaddress", 5}, + // crosschain { "assetchainproof", 1}, { "crosschainproof", 1}, @@ -178,6 +183,10 @@ static const CRPCConvertParam vRPCConvertParams[] = { "height_MoM", 1}, { "calc_MoM", 2}, { "migrate_completeimporttransaction", 1}, + { "getalldata", 0}, + { "getalldata", 1}, + { "getalldata", 2}, + { "getalldata", 3} }; class CRPCConvertTable diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp index 6f983bea7..d741a9748 100644 --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -1,5 +1,6 @@ // Copyright (c) 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. @@ -203,9 +204,9 @@ UniValue getinfo(const UniValue& params, bool fHelp, const CPubKey& mypk) " \"version\": xxxxx, (numeric) the server version\n" " \"protocolversion\": xxxxx, (numeric) the protocol version\n" " \"walletversion\": xxxxx, (numeric) the wallet version\n" - " \"balance\": xxxxxxx, (numeric) the total Komodo balance of the wallet\n" + " \"balance\": xxxxxxx, (numeric) the total Hush balance of the wallet\n" " \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n" - " \"timeoffset\": xxxxx, (numeric) the time offset\n" + " \"timeoffset\": xxxxx, (numeric) the time offset (deprecated, always 0)\n" " \"connections\": xxxxx, (numeric) the number of connections\n" " \"proxy\": \"host:port\", (string, optional) the proxy used by the server\n" " \"difficulty\": xxxxxx, (numeric) the current difficulty\n" @@ -285,7 +286,7 @@ UniValue getinfo(const UniValue& params, bool fHelp, const CPubKey& mypk) #endif obj.push_back(Pair("sapling", ASSETCHAINS_SAPLING)); } - obj.push_back(Pair("timeoffset", GetTimeOffset())); + obj.push_back(Pair("timeoffset", 0)); obj.push_back(Pair("connections", (int)vNodes.size())); obj.push_back(Pair("proxy", (proxy.IsValid() ? proxy.proxy.ToStringIPPort() : string()))); obj.push_back(Pair("testnet", Params().TestnetToBeDeprecatedFieldRPC())); @@ -420,12 +421,12 @@ UniValue coinsupply(const UniValue& params, bool fHelp, const CPubKey& mypk) "\nResult:\n" "{\n" " \"result\" : \"success\", (string) If the request was successful.\n" - " \"coin\" : \"KMD\", (string) The currency symbol of the coin for asset chains, otherwise KMD.\n" + " \"coin\" : \"HUSH3\", (string) The currency symbol of the coin for asset chains, otherwise HUSH3.\n" " \"height\" : 420, (integer) The height of this coin supply data\n" - " \"supply\" : \"777.0\", (float) The transparent coin supply\n" - " \"zfunds\" : \"0.777\", (float) The shielded coin supply (in zaddrs)\n" - " \"sprout\" : \"0.077\", (float) The sprout coin supply (in zcaddrs)\n" - " \"total\" : \"777.777\", (float) The total coin supply, i.e. sum of supply + zfunds\n" + " \"supply\" : \"555.0\", (float) The transparent coin supply\n" + " \"zfunds\" : \"0.55555\", (float) The shielded coin supply (in zaddrs)\n" + " \"sprout\" : \"0.000\", (float) The sprout coin supply (in zcaddrs)\n" + " \"total\" : \"555.55555\", (float) The total coin supply, i.e. sum of supply + zfunds\n" "}\n" "\nExamples:\n" + HelpExampleCli("coinsupply", "420") @@ -536,14 +537,14 @@ UniValue validateaddress(const UniValue& params, bool fHelp, const CPubKey& mypk { if (fHelp || params.size() != 1) throw runtime_error( - "validateaddress \"komodoaddress\"\n" - "\nReturn information about the given Komodo address.\n" + "validateaddress \"hushaddress\"\n" + "\nReturn information about the given Hush address.\n" "\nArguments:\n" - "1. \"komodoaddress\" (string, required) The Komodo address to validate\n" + "1. \"hushaddress\" (string, required) The Hush address to validate\n" "\nResult:\n" "{\n" " \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\n" - " \"address\" : \"komodoaddress\", (string) The Komodo address validated\n" + " \"address\" : \"hushaddress\", (string) The Hush address validated\n" " \"scriptPubKey\" : \"hex\", (string) The hex encoded scriptPubKey generated by the address\n" " \"ismine\" : true|false, (boolean) If the address is yours or not\n" " \"isscript\" : true|false, (boolean) If the key is a script\n" @@ -589,43 +590,6 @@ UniValue validateaddress(const UniValue& params, bool fHelp, const CPubKey& mypk } -class DescribePaymentAddressVisitor : public boost::static_visitor -{ -public: - UniValue operator()(const libzcash::InvalidEncoding &zaddr) const { return UniValue(UniValue::VOBJ); } - - UniValue operator()(const libzcash::SproutPaymentAddress &zaddr) const { - UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("type", "sprout")); - obj.push_back(Pair("payingkey", zaddr.a_pk.GetHex())); - obj.push_back(Pair("transmissionkey", zaddr.pk_enc.GetHex())); -#ifdef ENABLE_WALLET - if (pwalletMain) { - obj.push_back(Pair("ismine", pwalletMain->HaveSproutSpendingKey(zaddr))); - } -#endif - return obj; - } - - UniValue operator()(const libzcash::SaplingPaymentAddress &zaddr) const { - UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("type", "sapling")); - obj.push_back(Pair("diversifier", HexStr(zaddr.d))); - obj.push_back(Pair("diversifiedtransmissionkey", zaddr.pk_d.GetHex())); -#ifdef ENABLE_WALLET - if (pwalletMain) { - libzcash::SaplingIncomingViewingKey ivk; - libzcash::SaplingFullViewingKey fvk; - bool isMine = pwalletMain->GetSaplingIncomingViewingKey(zaddr, ivk) && - pwalletMain->GetSaplingFullViewingKey(ivk, fvk) && - pwalletMain->HaveSaplingSpendingKey(fvk); - obj.push_back(Pair("ismine", isMine)); - } -#endif - return obj; - } -}; - UniValue z_validateaddress(const UniValue& params, bool fHelp, const CPubKey& mypk) { if (fHelp || params.size() != 1) @@ -638,17 +602,15 @@ UniValue z_validateaddress(const UniValue& params, bool fHelp, const CPubKey& my "{\n" " \"isvalid\" : true|false, (boolean) If the address is valid or not. If not, this is the only property returned.\n" " \"address\" : \"zaddr\", (string) The z address validated\n" - " \"type\" : \"xxxx\", (string) \"sprout\" or \"sapling\"\n" + " \"type\" : \"xxxx\", (string) \"sapling\"\n" " \"ismine\" : true|false, (boolean) If the address is yours or not\n" - " \"payingkey\" : \"hex\", (string) [sprout] The hex value of the paying key, a_pk\n" - " \"transmissionkey\" : \"hex\", (string) [sprout] The hex value of the transmission key, pk_enc\n" " \"diversifier\" : \"hex\", (string) [sapling] The hex value of the diversifier, d\n" " \"diversifiedtransmissionkey\" : \"hex\", (string) [sapling] The hex value of pk_d\n" "}\n" "\nExamples:\n" - + HelpExampleCli("z_validateaddress", "\"zcWsmqT4X2V4jgxbgiCzyrAfRT1vi1F4sn7M5Pkh66izzw8Uk7LBGAH3DtcSMJeUb2pi3W4SQF8LMKkU2cUuVP68yAGcomL\"") - + HelpExampleRpc("z_validateaddress", "\"zcWsmqT4X2V4jgxbgiCzyrAfRT1vi1F4sn7M5Pkh66izzw8Uk7LBGAH3DtcSMJeUb2pi3W4SQF8LMKkU2cUuVP68yAGcomL\"") + + HelpExampleCli("z_validateaddress", "\"zs1z7rejlpsa98s2rrrfkwmaxu53e4ue0ulcrw0h4x5g8jl04tak0d3mm47vdtahatqrlkngh9slya\"") + + HelpExampleRpc("z_validateaddress", "\"zs1z7rejlpsa98s2rrrfkwmaxu53e4ue0ulcrw0h4x5g8jl04tak0d3mm47vdtahatqrlkngh9slya\"") ); @@ -664,11 +626,25 @@ UniValue z_validateaddress(const UniValue& params, bool fHelp, const CPubKey& my UniValue ret(UniValue::VOBJ); ret.push_back(Pair("isvalid", isValid)); - if (isValid) + auto zaddr = boost::get(&address); + if (isValid && (zaddr != nullptr)) { ret.push_back(Pair("address", strAddress)); - UniValue detail = boost::apply_visitor(DescribePaymentAddressVisitor(), address); - ret.pushKVs(detail); + UniValue obj(UniValue::VOBJ); + obj.push_back(Pair("type", "sapling")); + obj.push_back(Pair("diversifier", HexStr(zaddr->d))); + obj.push_back(Pair("diversifiedtransmissionkey", zaddr->pk_d.GetHex())); +#ifdef ENABLE_WALLET + if (pwalletMain) { + libzcash::SaplingIncomingViewingKey ivk; + libzcash::SaplingFullViewingKey fvk; + bool isMine = pwalletMain->GetSaplingIncomingViewingKey(*zaddr, ivk) && + pwalletMain->GetSaplingFullViewingKey(ivk, fvk) && + pwalletMain->HaveSaplingSpendingKey(fvk); + obj.push_back(Pair("ismine", isMine)); + } +#endif + ret.pushKVs(obj); } return ret; } @@ -747,9 +723,9 @@ UniValue createmultisig(const UniValue& params, bool fHelp, const CPubKey& mypk) "\nArguments:\n" "1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n" - "2. \"keys\" (string, required) A json array of keys which are Komodo addresses or hex-encoded public keys\n" + "2. \"keys\" (string, required) A json array of keys which are Hush addresses or hex-encoded public keys\n" " [\n" - " \"key\" (string) Komodo address or hex-encoded public key\n" + " \"key\" (string) Hush address or hex-encoded public key\n" " ,...\n" " ]\n" @@ -783,10 +759,10 @@ UniValue verifymessage(const UniValue& params, bool fHelp, const CPubKey& mypk) { if (fHelp || params.size() != 3) throw runtime_error( - "verifymessage \"komodoaddress\" \"signature\" \"message\"\n" + "verifymessage \"hushaddress\" \"signature\" \"message\"\n" "\nVerify a signed message\n" "\nArguments:\n" - "1. \"komodoaddress\" (string, required) The Komodo address to use for the signature.\n" + "1. \"hushaddress\" (string, required) The Hush address to use for the signature.\n" "2. \"signature\" (string, required) The signature provided by the signer in base 64 encoding (see signmessage).\n" "3. \"message\" (string, required) The message that was signed.\n" "\nResult:\n" diff --git a/src/rpc/net.cpp b/src/rpc/net.cpp index 39e080d86..c93f6a409 100644 --- a/src/rpc/net.cpp +++ b/src/rpc/net.cpp @@ -1,6 +1,7 @@ // 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. +// file COPYING or https://www.opensource.org/licenses/mit-license.php /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * @@ -108,7 +109,7 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp, const CPubKey& mypk) " \"bytessent\": n, (numeric) The total bytes sent\n" " \"bytesrecv\": n, (numeric) The total bytes received\n" " \"conntime\": ttt, (numeric) The connection time in seconds since epoch (Jan 1 1970 GMT)\n" - " \"timeoffset\": ttt, (numeric) The time offset in seconds\n" + " \"timeoffset\": ttt, (numeric) The time offset in seconds (deprecated, always 0)\n" " \"pingtime\": n, (numeric) ping time\n" " \"pingwait\": n, (numeric) ping wait\n" " \"version\": v, (numeric) The peer version, such as 170002\n" @@ -151,7 +152,7 @@ UniValue getpeerinfo(const UniValue& params, bool fHelp, const CPubKey& mypk) obj.push_back(Pair("bytessent", stats.nSendBytes)); obj.push_back(Pair("bytesrecv", stats.nRecvBytes)); obj.push_back(Pair("conntime", stats.nTimeConnected)); - obj.push_back(Pair("timeoffset", stats.nTimeOffset)); + obj.push_back(Pair("timeoffset", 0)); obj.push_back(Pair("pingtime", stats.dPingTime)); if (stats.dPingWait > 0.0) obj.push_back(Pair("pingwait", stats.dPingWait)); @@ -502,7 +503,7 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp, const CPubKey& mypk) " \"subversion\": \"/MagicBean:x.y.z[-v]/\", (string) the server subversion string\n" " \"protocolversion\": xxxxx, (numeric) the protocol version\n" " \"localservices\": \"xxxxxxxxxxxxxxxx\", (string) the services we offer to the network\n" - " \"timeoffset\": xxxxx, (numeric) the time offset\n" + " \"timeoffset\": xxxxx, (numeric) the time offset (deprecated, always 0)\n" " \"connections\": xxxxx, (numeric) the number of connections\n" " \"networks\": [ (array) information per network\n" " {\n" @@ -536,7 +537,7 @@ UniValue getnetworkinfo(const UniValue& params, bool fHelp, const CPubKey& mypk) obj.push_back(Pair("subversion", strSubVersion)); obj.push_back(Pair("protocolversion",PROTOCOL_VERSION)); obj.push_back(Pair("localservices", strprintf("%016x", nLocalServices))); - obj.push_back(Pair("timeoffset", GetTimeOffset())); + obj.push_back(Pair("timeoffset", 0)); obj.push_back(Pair("connections", (int)vNodes.size())); obj.push_back(Pair("networks", GetNetworksInfo())); obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()))); diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index c052395a6..56c038596 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin Core developers -// Copyright (c) 2019 The Hush 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. @@ -651,11 +651,6 @@ static const CRPCCommand vRPCCommands[] = { "wallet", "walletlock", &walletlock, true }, { "wallet", "walletpassphrasechange", &walletpassphrasechange, true }, { "wallet", "walletpassphrase", &walletpassphrase, true }, - { "wallet", "zcbenchmark", &zc_benchmark, true }, - { "wallet", "zcrawkeygen", &zc_raw_keygen, true }, - { "wallet", "zcrawjoinsplit", &zc_raw_joinsplit, true }, - { "wallet", "zcrawreceive", &zc_raw_receive, true }, - { "wallet", "zcsamplejoinsplit", &zc_sample_joinsplit, true }, { "wallet", "z_listreceivedbyaddress",&z_listreceivedbyaddress,false }, { "wallet", "z_getbalance", &z_getbalance, false }, { "wallet", "z_gettotalbalance", &z_gettotalbalance, false }, @@ -674,11 +669,7 @@ static const CRPCCommand vRPCCommands[] = { "wallet", "z_importviewingkey", &z_importviewingkey, true }, { "wallet", "z_exportwallet", &z_exportwallet, true }, { "wallet", "z_importwallet", &z_importwallet, true }, - { "wallet", "opreturn_burn", &opreturn_burn, true }, - - // TODO: rearrange into another category - { "disclosure", "z_getpaymentdisclosure", &z_getpaymentdisclosure, true }, - { "disclosure", "z_validatepaymentdisclosure", &z_validatepaymentdisclosure, true } + { "wallet", "opreturn_burn", &opreturn_burn, true } #endif // ENABLE_WALLET }; diff --git a/src/rpc/server.h b/src/rpc/server.h index 6ce27894a..6568977d7 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -1,6 +1,6 @@ // Copyright (c) 2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin Core developers -// Copyright (c) 2019 The Hush 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. @@ -402,11 +402,6 @@ extern UniValue getnetworkinfo(const UniValue& params, bool fHelp, const CPubKey extern UniValue getdeprecationinfo(const UniValue& params, bool fHelp, const CPubKey& mypk); extern UniValue setmocktime(const UniValue& params, bool fHelp, const CPubKey& mypk); extern UniValue resendwallettransactions(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue zc_benchmark(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue zc_raw_keygen(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue zc_raw_receive(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue zc_sample_joinsplit(const UniValue& params, bool fHelp, const CPubKey& mypk); extern UniValue jumblr_deposit(const UniValue& params, bool fHelp, const CPubKey& mypk); extern UniValue jumblr_secret(const UniValue& params, bool fHelp, const CPubKey& mypk); @@ -494,6 +489,7 @@ extern UniValue z_getoperationstatus(const UniValue& params, bool fHelp, const C extern UniValue z_getoperationresult(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp extern UniValue z_listoperationids(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp extern UniValue opreturn_burn(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp +extern UniValue rescan(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp extern UniValue z_validateaddress(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcmisc.cpp extern UniValue z_getpaymentdisclosure(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcdisclosure.cpp extern UniValue z_validatepaymentdisclosure(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcdisclosure.cpp diff --git a/src/rpcblockchain.old b/src/rpcblockchain.old deleted file mode 100644 index a91f73a63..000000000 --- a/src/rpcblockchain.old +++ /dev/null @@ -1,1625 +0,0 @@ -// Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "amount.h" -#include "chain.h" -#include "chainparams.h" -#include "checkpoints.h" -#include "crosschain.h" -#include "base58.h" -#include "consensus/validation.h" -#include "cc/eval.h" -#include "main.h" -#include "primitives/transaction.h" -#include "rpcserver.h" -#include "sync.h" -#include "util.h" -#include "script/script.h" -#include "script/script_error.h" -#include "script/sign.h" -#include "script/standard.h" - -#include - -#include - -#include - -using namespace std; - -extern void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry); -void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); -int32_t komodo_longestchain(); -int32_t komodo_dpowconfs(int32_t height,int32_t numconfs); -<<<<<<< HEAD:src/rpcblockchain.old -extern int32_t KOMODO_LONGESTCHAIN; -======= ->>>>>>> master:src/rpcblockchain.cpp - -double GetDifficultyINTERNAL(const CBlockIndex* blockindex, bool networkDifficulty) -{ - // Floating point number that is a multiple of the minimum difficulty, - // minimum difficulty = 1.0. - if (blockindex == NULL) - { - if (chainActive.LastTip() == NULL) - return 1.0; - else - blockindex = chainActive.LastTip(); - } - - uint32_t bits; - if (networkDifficulty) { - bits = GetNextWorkRequired(blockindex, nullptr, Params().GetConsensus()); - } else { - bits = blockindex->nBits; - } - - uint32_t powLimit = - UintToArith256(Params().GetConsensus().powLimit).GetCompact(); - int nShift = (bits >> 24) & 0xff; - int nShiftAmount = (powLimit >> 24) & 0xff; - - double dDiff = - (double)(powLimit & 0x00ffffff) / - (double)(bits & 0x00ffffff); - - while (nShift < nShiftAmount) - { - dDiff *= 256.0; - nShift++; - } - while (nShift > nShiftAmount) - { - dDiff /= 256.0; - nShift--; - } - - return dDiff; -} - -double GetDifficulty(const CBlockIndex* blockindex) -{ - return GetDifficultyINTERNAL(blockindex, false); -} - -double GetNetworkDifficulty(const CBlockIndex* blockindex) -{ - return GetDifficultyINTERNAL(blockindex, true); -} - -static UniValue ValuePoolDesc( - const std::string &name, - const boost::optional chainValue, - const boost::optional valueDelta) -{ - UniValue rv(UniValue::VOBJ); - rv.push_back(Pair("id", name)); - rv.push_back(Pair("monitored", (bool)chainValue)); - if (chainValue) { - rv.push_back(Pair("chainValue", ValueFromAmount(*chainValue))); - rv.push_back(Pair("chainValueZat", *chainValue)); - } - if (valueDelta) { - rv.push_back(Pair("valueDelta", ValueFromAmount(*valueDelta))); - rv.push_back(Pair("valueDeltaZat", *valueDelta)); - } - return rv; -} - -UniValue blockheaderToJSON(const CBlockIndex* blockindex) -{ - UniValue result(UniValue::VOBJ); - if ( blockindex == 0 ) - { - result.push_back(Pair("error", "null blockhash")); - return(result); - } - result.push_back(Pair("hash", blockindex->GetBlockHash().GetHex())); - int confirmations = -1; - // Only report confirmations if the block is on the main chain - if (chainActive.Contains(blockindex)) - confirmations = chainActive.Height() - blockindex->nHeight + 1; - result.push_back(Pair("confirmations", komodo_dpowconfs(blockindex->nHeight,confirmations))); - result.push_back(Pair("rawconfirmations", confirmations)); - result.push_back(Pair("height", blockindex->nHeight)); - result.push_back(Pair("version", blockindex->nVersion)); - result.push_back(Pair("merkleroot", blockindex->hashMerkleRoot.GetHex())); - result.push_back(Pair("time", (int64_t)blockindex->nTime)); - result.push_back(Pair("nonce", blockindex->nNonce.GetHex())); - result.push_back(Pair("solution", HexStr(blockindex->nSolution))); - result.push_back(Pair("bits", strprintf("%08x", blockindex->nBits))); - result.push_back(Pair("difficulty", GetDifficulty(blockindex))); - result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); - result.push_back(Pair("segid", (int64_t)blockindex->segid)); - - if (blockindex->pprev) - result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); - CBlockIndex *pnext = chainActive.Next(blockindex); - if (pnext) - result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex())); - return result; -} - -UniValue blockToDeltasJSON(const CBlock& block, const CBlockIndex* blockindex) -{ - UniValue result(UniValue::VOBJ); - result.push_back(Pair("hash", block.GetHash().GetHex())); - int confirmations = -1; - // Only report confirmations if the block is on the main chain - if (chainActive.Contains(blockindex)) { - confirmations = chainActive.Height() - blockindex->nHeight + 1; - } else { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block is an orphan"); - } - result.push_back(Pair("confirmations", komodo_dpowconfs(blockindex->nHeight,confirmations))); - result.push_back(Pair("rawconfirmations", confirmations)); - result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION))); - result.push_back(Pair("height", blockindex->nHeight)); - result.push_back(Pair("version", block.nVersion)); - result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); - result.push_back(Pair("segid", (int64_t)blockindex->segid)); - - UniValue deltas(UniValue::VARR); - - for (unsigned int i = 0; i < block.vtx.size(); i++) { - const CTransaction &tx = block.vtx[i]; - const uint256 txhash = tx.GetHash(); - - UniValue entry(UniValue::VOBJ); - entry.push_back(Pair("txid", txhash.GetHex())); - entry.push_back(Pair("index", (int)i)); - - UniValue inputs(UniValue::VARR); - - if (!tx.IsCoinBase()) { - - for (size_t j = 0; j < tx.vin.size(); j++) { - const CTxIn input = tx.vin[j]; - - UniValue delta(UniValue::VOBJ); - - CSpentIndexValue spentInfo; - CSpentIndexKey spentKey(input.prevout.hash, input.prevout.n); - - if (GetSpentIndex(spentKey, spentInfo)) { - if (spentInfo.addressType == 1) { - delta.push_back(Pair("address", CBitcoinAddress(CKeyID(spentInfo.addressHash)).ToString())); - } - else if (spentInfo.addressType == 2) { - delta.push_back(Pair("address", CBitcoinAddress(CScriptID(spentInfo.addressHash)).ToString())); - } - else { - continue; - } - delta.push_back(Pair("satoshis", -1 * spentInfo.satoshis)); - delta.push_back(Pair("index", (int)j)); - delta.push_back(Pair("prevtxid", input.prevout.hash.GetHex())); - delta.push_back(Pair("prevout", (int)input.prevout.n)); - - inputs.push_back(delta); - } else { - throw JSONRPCError(RPC_INTERNAL_ERROR, "Spent information not available"); - } - - } - } - - entry.push_back(Pair("inputs", inputs)); - - UniValue outputs(UniValue::VARR); - - for (unsigned int k = 0; k < tx.vout.size(); k++) { - const CTxOut &out = tx.vout[k]; - - UniValue delta(UniValue::VOBJ); - - if (out.scriptPubKey.IsPayToScriptHash()) { - vector hashBytes(out.scriptPubKey.begin()+2, out.scriptPubKey.begin()+22); - delta.push_back(Pair("address", CBitcoinAddress(CScriptID(uint160(hashBytes))).ToString())); - - } - else if (out.scriptPubKey.IsPayToPublicKeyHash()) { - vector hashBytes(out.scriptPubKey.begin()+3, out.scriptPubKey.begin()+23); - delta.push_back(Pair("address", CBitcoinAddress(CKeyID(uint160(hashBytes))).ToString())); - } - else if (out.scriptPubKey.IsPayToPublicKey() || out.scriptPubKey.IsPayToCryptoCondition()) { - CTxDestination address; - if (ExtractDestination(out.scriptPubKey, address)) - { - //vector hashBytes(out.scriptPubKey.begin()+1, out.scriptPubKey.begin()+34); - //xxx delta.push_back(Pair("address", CBitcoinAddress(CKeyID(uint160(hashBytes))).ToString())); - delta.push_back(Pair("address", CBitcoinAddress(address).ToString())); - } - } - else { - continue; - } - - delta.push_back(Pair("satoshis", out.nValue)); - delta.push_back(Pair("index", (int)k)); - - outputs.push_back(delta); - } - - entry.push_back(Pair("outputs", outputs)); - deltas.push_back(entry); - - } - result.push_back(Pair("deltas", deltas)); - result.push_back(Pair("time", block.GetBlockTime())); - result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast())); - result.push_back(Pair("nonce", block.nNonce.GetHex())); - result.push_back(Pair("bits", strprintf("%08x", block.nBits))); - result.push_back(Pair("difficulty", GetDifficulty(blockindex))); - result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); - - if (blockindex->pprev) - result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); - CBlockIndex *pnext = chainActive.Next(blockindex); - if (pnext) - result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex())); - return result; -} - -UniValue blockToJSON(const CBlock& block, const CBlockIndex* blockindex, bool txDetails = false) -{ - UniValue result(UniValue::VOBJ); - result.push_back(Pair("hash", block.GetHash().GetHex())); - int confirmations = -1; - // Only report confirmations if the block is on the main chain - if (chainActive.Contains(blockindex)) - confirmations = chainActive.Height() - blockindex->nHeight + 1; - result.push_back(Pair("confirmations", komodo_dpowconfs(blockindex->nHeight,confirmations))); - result.push_back(Pair("rawconfirmations", confirmations)); - result.push_back(Pair("size", (int)::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION))); - result.push_back(Pair("height", blockindex->nHeight)); - result.push_back(Pair("version", block.nVersion)); - result.push_back(Pair("merkleroot", block.hashMerkleRoot.GetHex())); - result.push_back(Pair("segid", (int64_t)blockindex->segid)); - UniValue txs(UniValue::VARR); - BOOST_FOREACH(const CTransaction&tx, block.vtx) - { - if(txDetails) - { - UniValue objTx(UniValue::VOBJ); - TxToJSON(tx, uint256(), objTx); - txs.push_back(objTx); - } - else - txs.push_back(tx.GetHash().GetHex()); - } - result.push_back(Pair("tx", txs)); - result.push_back(Pair("time", block.GetBlockTime())); - result.push_back(Pair("nonce", block.nNonce.GetHex())); - result.push_back(Pair("solution", HexStr(block.nSolution))); - result.push_back(Pair("bits", strprintf("%08x", block.nBits))); - result.push_back(Pair("difficulty", GetDifficulty(blockindex))); - result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); - result.push_back(Pair("anchor", blockindex->hashAnchorEnd.GetHex())); - - UniValue valuePools(UniValue::VARR); - valuePools.push_back(ValuePoolDesc("sprout", blockindex->nChainSproutValue, blockindex->nSproutValue)); - result.push_back(Pair("valuePools", valuePools)); - - if (blockindex->pprev) - result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex())); - CBlockIndex *pnext = chainActive.Next(blockindex); - if (pnext) - result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex())); - return result; -} - -UniValue getblockcount(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 0) - throw runtime_error( - "getblockcount\n" - "\nReturns the number of blocks in the best valid block chain.\n" - "\nResult:\n" - "n (numeric) The current block count\n" - "\nExamples:\n" - + HelpExampleCli("getblockcount", "") - + HelpExampleRpc("getblockcount", "") - ); - - LOCK(cs_main); - return chainActive.Height(); -} - -UniValue getbestblockhash(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 0) - throw runtime_error( - "getbestblockhash\n" - "\nReturns the hash of the best (tip) block in the longest block chain.\n" - "\nResult\n" - "\"hex\" (string) the block hash hex encoded\n" - "\nExamples\n" - + HelpExampleCli("getbestblockhash", "") - + HelpExampleRpc("getbestblockhash", "") - ); - - LOCK(cs_main); - return chainActive.LastTip()->GetBlockHash().GetHex(); -} - -UniValue getdifficulty(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 0) - throw runtime_error( - "getdifficulty\n" - "\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n" - "\nResult:\n" - "n.nnn (numeric) the proof-of-work difficulty as a multiple of the minimum difficulty.\n" - "\nExamples:\n" - + HelpExampleCli("getdifficulty", "") - + HelpExampleRpc("getdifficulty", "") - ); - - LOCK(cs_main); - return GetNetworkDifficulty(); -} - -bool myIsutxo_spentinmempool(uint256 txid,int32_t vout) -{ - //char *uint256_str(char *str,uint256); char str[65]; - //LOCK(mempool.cs); - BOOST_FOREACH(const CTxMemPoolEntry &e,mempool.mapTx) - { - const CTransaction &tx = e.GetTx(); - const uint256 &hash = tx.GetHash(); - BOOST_FOREACH(const CTxIn &txin,tx.vin) - { - //fprintf(stderr,"%s/v%d ",uint256_str(str,txin.prevout.hash),txin.prevout.n); - if ( txin.prevout.n == vout && txin.prevout.hash == txid ) - return(true); - } - //fprintf(stderr,"are vins for %s\n",uint256_str(str,hash)); - } - return(false); -} - -bool mytxid_inmempool(uint256 txid) -{ - BOOST_FOREACH(const CTxMemPoolEntry &e,mempool.mapTx) - { - const CTransaction &tx = e.GetTx(); - const uint256 &hash = tx.GetHash(); - if ( txid == hash ) - return(true); - } - return(false); -} - -UniValue mempoolToJSON(bool fVerbose = false) -{ - if (fVerbose) - { - LOCK(mempool.cs); - UniValue o(UniValue::VOBJ); - BOOST_FOREACH(const CTxMemPoolEntry& e, mempool.mapTx) - { - const uint256& hash = e.GetTx().GetHash(); - UniValue info(UniValue::VOBJ); - info.push_back(Pair("size", (int)e.GetTxSize())); - info.push_back(Pair("fee", ValueFromAmount(e.GetFee()))); - info.push_back(Pair("time", e.GetTime())); - info.push_back(Pair("height", (int)e.GetHeight())); - info.push_back(Pair("startingpriority", e.GetPriority(e.GetHeight()))); - info.push_back(Pair("currentpriority", e.GetPriority(chainActive.Height()))); - const CTransaction& tx = e.GetTx(); - set setDepends; - BOOST_FOREACH(const CTxIn& txin, tx.vin) - { - if (mempool.exists(txin.prevout.hash)) - setDepends.insert(txin.prevout.hash.ToString()); - } - - UniValue depends(UniValue::VARR); - BOOST_FOREACH(const string& dep, setDepends) - { - depends.push_back(dep); - } - - info.push_back(Pair("depends", depends)); - o.push_back(Pair(hash.ToString(), info)); - } - return o; - } - else - { - vector vtxid; - mempool.queryHashes(vtxid); - - UniValue a(UniValue::VARR); - BOOST_FOREACH(const uint256& hash, vtxid) - a.push_back(hash.ToString()); - - return a; - } -} - -UniValue getrawmempool(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() > 1) - throw runtime_error( - "getrawmempool ( verbose )\n" - "\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n" - "\nArguments:\n" - "1. verbose (boolean, optional, default=false) true for a json object, false for array of transaction ids\n" - "\nResult: (for verbose = false):\n" - "[ (json array of string)\n" - " \"transactionid\" (string) The transaction id\n" - " ,...\n" - "]\n" - "\nResult: (for verbose = true):\n" - "{ (json object)\n" - " \"transactionid\" : { (json object)\n" - " \"size\" : n, (numeric) transaction size in bytes\n" - " \"fee\" : n, (numeric) transaction fee in " + CURRENCY_UNIT + "\n" - " \"time\" : n, (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT\n" - " \"height\" : n, (numeric) block height when transaction entered pool\n" - " \"startingpriority\" : n, (numeric) priority when transaction entered pool\n" - " \"currentpriority\" : n, (numeric) transaction priority now\n" - " \"depends\" : [ (array) unconfirmed transactions used as inputs for this transaction\n" - " \"transactionid\", (string) parent transaction id\n" - " ... ]\n" - " }, ...\n" - "}\n" - "\nExamples\n" - + HelpExampleCli("getrawmempool", "true") - + HelpExampleRpc("getrawmempool", "true") - ); - - LOCK(cs_main); - - bool fVerbose = false; - if (params.size() > 0) - fVerbose = params[0].get_bool(); - - return mempoolToJSON(fVerbose); -} - -UniValue getblockdeltas(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error(""); - - std::string strHash = params[0].get_str(); - uint256 hash(uint256S(strHash)); - - if (mapBlockIndex.count(hash) == 0) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); - - CBlock block; - CBlockIndex* pblockindex = mapBlockIndex[hash]; - - if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not available (pruned data)"); - - if(!ReadBlockFromDisk(block, pblockindex,1)) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); - - return blockToDeltasJSON(block, pblockindex); -} - -UniValue getblockhashes(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() < 2) - throw runtime_error( - "getblockhashes timestamp\n" - "\nReturns array of hashes of blocks within the timestamp range provided.\n" - "\nArguments:\n" - "1. high (numeric, required) The newer block timestamp\n" - "2. low (numeric, required) The older block timestamp\n" - "3. options (string, required) A json object\n" - " {\n" - " \"noOrphans\":true (boolean) will only include blocks on the main chain\n" - " \"logicalTimes\":true (boolean) will include logical timestamps with hashes\n" - " }\n" - "\nResult:\n" - "[\n" - " \"hash\" (string) The block hash\n" - "]\n" - "[\n" - " {\n" - " \"blockhash\": (string) The block hash\n" - " \"logicalts\": (numeric) The logical timestamp\n" - " }\n" - "]\n" - "\nExamples:\n" - + HelpExampleCli("getblockhashes", "1231614698 1231024505") - + HelpExampleRpc("getblockhashes", "1231614698, 1231024505") - + HelpExampleCli("getblockhashes", "1231614698 1231024505 '{\"noOrphans\":false, \"logicalTimes\":true}'") - ); - - unsigned int high = params[0].get_int(); - unsigned int low = params[1].get_int(); - bool fActiveOnly = false; - bool fLogicalTS = false; - - if (params.size() > 2) { - if (params[2].isObject()) { - UniValue noOrphans = find_value(params[2].get_obj(), "noOrphans"); - UniValue returnLogical = find_value(params[2].get_obj(), "logicalTimes"); - - if (noOrphans.isBool()) - fActiveOnly = noOrphans.get_bool(); - - if (returnLogical.isBool()) - fLogicalTS = returnLogical.get_bool(); - } - } - - std::vector > blockHashes; - - if (fActiveOnly) - LOCK(cs_main); - - if (!GetTimestampIndex(high, low, fActiveOnly, blockHashes)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available for block hashes"); - } - - UniValue result(UniValue::VARR); - - for (std::vector >::const_iterator it=blockHashes.begin(); it!=blockHashes.end(); it++) { - if (fLogicalTS) { - UniValue item(UniValue::VOBJ); - item.push_back(Pair("blockhash", it->first.GetHex())); - item.push_back(Pair("logicalts", (int)it->second)); - result.push_back(item); - } else { - result.push_back(it->first.GetHex()); - } - } - - return result; -} - -UniValue getblockhash(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "getblockhash index\n" - "\nReturns hash of block in best-block-chain at index provided.\n" - "\nArguments:\n" - "1. index (numeric, required) The block index\n" - "\nResult:\n" - "\"hash\" (string) The block hash\n" - "\nExamples:\n" - + HelpExampleCli("getblockhash", "1000") - + HelpExampleRpc("getblockhash", "1000") - ); - - LOCK(cs_main); - - int nHeight = params[0].get_int(); - if (nHeight < 0 || nHeight > chainActive.Height()) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range"); - - CBlockIndex* pblockindex = chainActive[nHeight]; - return pblockindex->GetBlockHash().GetHex(); -} - -/*uint256 _komodo_getblockhash(int32_t nHeight) -{ - uint256 hash; - LOCK(cs_main); - if ( nHeight >= 0 && nHeight <= chainActive.Height() ) - { - CBlockIndex* pblockindex = chainActive[nHeight]; - hash = pblockindex->GetBlockHash(); - int32_t i; - for (i=0; i<32; i++) - printf("%02x",((uint8_t *)&hash)[i]); - printf(" blockhash.%d\n",nHeight); - } else memset(&hash,0,sizeof(hash)); - return(hash); -}*/ - -UniValue getblockheader(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( - "getblockheader \"hash\" ( verbose )\n" - "\nIf verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'.\n" - "If verbose is true, returns an Object with information about blockheader .\n" - "\nArguments:\n" - "1. \"hash\" (string, required) The block hash\n" - "2. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data\n" - "\nResult (for verbose = true):\n" - "{\n" - " \"hash\" : \"hash\", (string) the block hash (same as provided)\n" - " \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n" - " \"height\" : n, (numeric) The block height or index\n" - " \"version\" : n, (numeric) The block version\n" - " \"merkleroot\" : \"xxxx\", (string) The merkle root\n" - " \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n" - " \"nonce\" : n, (numeric) The nonce\n" - " \"bits\" : \"1d00ffff\", (string) The bits\n" - " \"difficulty\" : x.xxx, (numeric) The difficulty\n" - " \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n" - " \"nextblockhash\" : \"hash\" (string) The hash of the next block\n" - "}\n" - "\nResult (for verbose=false):\n" - "\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n" - "\nExamples:\n" - + HelpExampleCli("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"") - + HelpExampleRpc("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"") - ); - - LOCK(cs_main); - - std::string strHash = params[0].get_str(); - uint256 hash(uint256S(strHash)); - - bool fVerbose = true; - if (params.size() > 1) - fVerbose = params[1].get_bool(); - - if (mapBlockIndex.count(hash) == 0) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); - - CBlockIndex* pblockindex = mapBlockIndex[hash]; - - if (!fVerbose) - { - CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION); - ssBlock << pblockindex->GetBlockHeader(); - std::string strHex = HexStr(ssBlock.begin(), ssBlock.end()); - return strHex; - } - - return blockheaderToJSON(pblockindex); -} - -UniValue getblock(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( - "getblock \"hash|height\" ( verbose )\n" - "\nIf verbose is false, returns a string that is serialized, hex-encoded data for block 'hash|height'.\n" - "If verbose is true, returns an Object with information about block .\n" - "\nArguments:\n" - "1. \"hash|height\" (string, required) The block hash or height\n" - "2. verbose (boolean, optional, default=true) true for a json object, false for the hex encoded data\n" - "\nResult (for verbose = true):\n" - "{\n" - " \"hash\" : \"hash\", (string) the block hash (same as provided hash)\n" - " \"confirmations\" : n, (numeric) The number of confirmations, or -1 if the block is not on the main chain\n" - " \"size\" : n, (numeric) The block size\n" - " \"height\" : n, (numeric) The block height or index (same as provided height)\n" - " \"version\" : n, (numeric) The block version\n" - " \"merkleroot\" : \"xxxx\", (string) The merkle root\n" - " \"tx\" : [ (array of string) The transaction ids\n" - " \"transactionid\" (string) The transaction id\n" - " ,...\n" - " ],\n" - " \"time\" : ttt, (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n" - " \"nonce\" : n, (numeric) The nonce\n" - " \"bits\" : \"1d00ffff\", (string) The bits\n" - " \"difficulty\" : x.xxx, (numeric) The difficulty\n" - " \"previousblockhash\" : \"hash\", (string) The hash of the previous block\n" - " \"nextblockhash\" : \"hash\" (string) The hash of the next block\n" - "}\n" - "\nResult (for verbose=false):\n" - "\"data\" (string) A string that is serialized, hex-encoded data for block 'hash'.\n" - "\nExamples:\n" - + HelpExampleCli("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"") - + HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"") - + HelpExampleCli("getblock", "12800") - + HelpExampleRpc("getblock", "12800") - ); - - LOCK(cs_main); - - std::string strHash = params[0].get_str(); - - // If height is supplied, find the hash - if (strHash.size() < (2 * sizeof(uint256))) { - // std::stoi allows characters, whereas we want to be strict - regex r("[[:digit:]]+"); - if (!regex_match(strHash, r)) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block height parameter"); - } - - int nHeight = -1; - try { - nHeight = std::stoi(strHash); - } - catch (const std::exception &e) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid block height parameter"); - } - - if (nHeight < 0 || nHeight > chainActive.Height()) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range"); - } - strHash = chainActive[nHeight]->GetBlockHash().GetHex(); - } - - uint256 hash(uint256S(strHash)); - - bool fVerbose = true; - if (params.size() > 1) - fVerbose = params[1].get_bool(); - - if (mapBlockIndex.count(hash) == 0) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); - - CBlock block; - CBlockIndex* pblockindex = mapBlockIndex[hash]; - - if (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not available (pruned data)"); - - if(!ReadBlockFromDisk(block, pblockindex,1)) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); - - if (!fVerbose) - { - CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION); - ssBlock << block; - std::string strHex = HexStr(ssBlock.begin(), ssBlock.end()); - return strHex; - } - - return blockToJSON(block, pblockindex); -} - -UniValue gettxoutsetinfo(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 0) - throw runtime_error( - "gettxoutsetinfo\n" - "\nReturns statistics about the unspent transaction output set.\n" - "Note this call may take some time.\n" - "\nResult:\n" - "{\n" - " \"height\":n, (numeric) The current block height (index)\n" - " \"bestblock\": \"hex\", (string) the best block hash hex\n" - " \"transactions\": n, (numeric) The number of transactions\n" - " \"txouts\": n, (numeric) The number of output transactions\n" - " \"bytes_serialized\": n, (numeric) The serialized size\n" - " \"hash_serialized\": \"hash\", (string) The serialized hash\n" - " \"total_amount\": x.xxx (numeric) The total amount\n" - "}\n" - "\nExamples:\n" - + HelpExampleCli("gettxoutsetinfo", "") - + HelpExampleRpc("gettxoutsetinfo", "") - ); - - UniValue ret(UniValue::VOBJ); - - CCoinsStats stats; - FlushStateToDisk(); - if (pcoinsTip->GetStats(stats)) { - ret.push_back(Pair("height", (int64_t)stats.nHeight)); - ret.push_back(Pair("bestblock", stats.hashBlock.GetHex())); - ret.push_back(Pair("transactions", (int64_t)stats.nTransactions)); - ret.push_back(Pair("txouts", (int64_t)stats.nTransactionOutputs)); - ret.push_back(Pair("bytes_serialized", (int64_t)stats.nSerializedSize)); - ret.push_back(Pair("hash_serialized", stats.hashSerialized.GetHex())); - ret.push_back(Pair("total_amount", ValueFromAmount(stats.nTotalAmount))); - } - return ret; -} - -#include "komodo_defs.h" -#include "komodo_structs.h" - -#define IGUANA_MAXSCRIPTSIZE 10001 -#define KOMODO_KVDURATION 1440 -#define KOMODO_KVBINARY 2 -extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; -uint64_t komodo_paxprice(uint64_t *seedp,int32_t height,char *base,char *rel,uint64_t basevolume); -int32_t komodo_paxprices(int32_t *heights,uint64_t *prices,int32_t max,char *base,char *rel); -int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp); -char *bitcoin_address(char *coinaddr,uint8_t addrtype,uint8_t *pubkey_or_rmd160,int32_t len); -int32_t komodo_minerids(uint8_t *minerids,int32_t height,int32_t width); -int32_t komodo_kvsearch(uint256 *refpubkeyp,int32_t current_height,uint32_t *flagsp,int32_t *heightp,uint8_t value[IGUANA_MAXSCRIPTSIZE],uint8_t *key,int32_t keylen); - -UniValue kvsearch(const UniValue& params, bool fHelp) -{ - UniValue ret(UniValue::VOBJ); uint32_t flags; uint8_t value[IGUANA_MAXSCRIPTSIZE*8],key[IGUANA_MAXSCRIPTSIZE*8]; int32_t duration,j,height,valuesize,keylen; uint256 refpubkey; static uint256 zeroes; - if (fHelp || params.size() != 1 ) - throw runtime_error( - "kvsearch key\n" - "\nSearch for a key stored via the kvupdate command. This feature is only available for asset chains.\n" - "\nArguments:\n" - "1. key (string, required) search the chain for this key\n" - "\nResult:\n" - "{\n" - " \"coin\": \"xxxxx\", (string) chain the key is stored on\n" - " \"currentheight\": xxxxx, (numeric) current height of the chain\n" - " \"key\": \"xxxxx\", (string) key\n" - " \"keylen\": xxxxx, (string) length of the key \n" - " \"owner\": \"xxxxx\" (string) hex string representing the owner of the key \n" - " \"height\": xxxxx, (numeric) height the key was stored at\n" - " \"expiration\": xxxxx, (numeric) height the key will expire\n" - " \"flags\": x (numeric) 1 if the key was created with a password; 0 otherwise.\n" - " \"value\": \"xxxxx\", (string) stored value\n" - " \"valuesize\": xxxxx (string) amount of characters stored\n" - "}\n" - "\nExamples:\n" - + HelpExampleCli("kvsearch", "examplekey") - + HelpExampleRpc("kvsearch", "\"examplekey\"") - ); - LOCK(cs_main); - if ( (keylen= (int32_t)strlen(params[0].get_str().c_str())) > 0 ) - { - ret.push_back(Pair("coin",(char *)(ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL))); - ret.push_back(Pair("currentheight", (int64_t)chainActive.LastTip()->nHeight)); - ret.push_back(Pair("key",params[0].get_str())); - ret.push_back(Pair("keylen",keylen)); - if ( keylen < sizeof(key) ) - { - memcpy(key,params[0].get_str().c_str(),keylen); - if ( (valuesize= komodo_kvsearch(&refpubkey,chainActive.LastTip()->nHeight,&flags,&height,value,key,keylen)) >= 0 ) - { - std::string val; char *valuestr; - val.resize(valuesize); - valuestr = (char *)val.data(); - memcpy(valuestr,value,valuesize); - if ( memcmp(&zeroes,&refpubkey,sizeof(refpubkey)) != 0 ) - ret.push_back(Pair("owner",refpubkey.GetHex())); - ret.push_back(Pair("height",height)); - duration = ((flags >> 2) + 1) * KOMODO_KVDURATION; - ret.push_back(Pair("expiration", (int64_t)(height+duration))); - ret.push_back(Pair("flags",(int64_t)flags)); - ret.push_back(Pair("value",val)); - ret.push_back(Pair("valuesize",valuesize)); - } else ret.push_back(Pair("error",(char *)"cant find key")); - } else ret.push_back(Pair("error",(char *)"key too big")); - } else ret.push_back(Pair("error",(char *)"null key")); - return ret; -} - -UniValue minerids(const UniValue& params, bool fHelp) -{ - uint32_t timestamp = 0; UniValue ret(UniValue::VOBJ); UniValue a(UniValue::VARR); uint8_t minerids[2000],pubkeys[65][33]; int32_t i,j,n,numnotaries,tally[129]; - if ( fHelp || params.size() != 1 ) - throw runtime_error("minerids needs height\n"); - LOCK(cs_main); - int32_t height = atoi(params[0].get_str().c_str()); - if ( height <= 0 ) - height = chainActive.LastTip()->nHeight; - else - { - CBlockIndex *pblockindex = chainActive[height]; - if ( pblockindex != 0 ) - timestamp = pblockindex->GetBlockTime(); - } - if ( (n= komodo_minerids(minerids,height,(int32_t)(sizeof(minerids)/sizeof(*minerids)))) > 0 ) - { - memset(tally,0,sizeof(tally)); - numnotaries = komodo_notaries(pubkeys,height,timestamp); - if ( numnotaries > 0 ) - { - for (i=0; i= numnotaries ) - tally[128]++; - else tally[minerids[i]]++; - } - for (i=0; i<64; i++) - { - UniValue item(UniValue::VOBJ); std::string hex,kmdaddress; char *hexstr,kmdaddr[64],*ptr; int32_t m; - hex.resize(66); - hexstr = (char *)hex.data(); - for (j=0; j<33; j++) - sprintf(&hexstr[j*2],"%02x",pubkeys[i][j]); - item.push_back(Pair("notaryid", i)); - - bitcoin_address(kmdaddr,60,pubkeys[i],33); - m = (int32_t)strlen(kmdaddr); - kmdaddress.resize(m); - ptr = (char *)kmdaddress.data(); - memcpy(ptr,kmdaddr,m); - item.push_back(Pair("KMDaddress", kmdaddress)); - - item.push_back(Pair("pubkey", hex)); - item.push_back(Pair("blocks", tally[i])); - a.push_back(item); - } - UniValue item(UniValue::VOBJ); - item.push_back(Pair("pubkey", (char *)"external miners")); - item.push_back(Pair("blocks", tally[128])); - a.push_back(item); - } - ret.push_back(Pair("mined", a)); - ret.push_back(Pair("numnotaries", numnotaries)); - } else ret.push_back(Pair("error", (char *)"couldnt extract minerids")); - return ret; -} - -UniValue notaries(const UniValue& params, bool fHelp) -{ - UniValue a(UniValue::VARR); uint32_t timestamp=0; UniValue ret(UniValue::VOBJ); int32_t i,j,n,m; char *hexstr; uint8_t pubkeys[64][33]; char btcaddr[64],kmdaddr[64],*ptr; - if ( fHelp || (params.size() != 1 && params.size() != 2) ) - throw runtime_error("notaries height timestamp\n"); - LOCK(cs_main); - int32_t height = atoi(params[0].get_str().c_str()); - if ( params.size() == 2 ) - timestamp = (uint32_t)atol(params[1].get_str().c_str()); - else timestamp = (uint32_t)time(NULL); - if ( height < 0 ) - { - height = chainActive.LastTip()->nHeight; - timestamp = chainActive.LastTip()->GetBlockTime(); - } - else if ( params.size() < 2 ) - { - CBlockIndex *pblockindex = chainActive[height]; - if ( pblockindex != 0 ) - timestamp = pblockindex->GetBlockTime(); - } - if ( (n= komodo_notaries(pubkeys,height,timestamp)) > 0 ) - { - for (i=0; i 0 ) - ret.push_back(Pair("withdraws", opretbuf)); - else ret.push_back(Pair("withdraws", (char *)"")); - for (baseid=0; baseid<32; baseid++) - { - UniValue item(UniValue::VOBJ); UniValue obj(UniValue::VOBJ); - if ( pax_fiatstatus(&available,&deposited,&issued,&withdrawn,&approved,&redeemed,CURRENCIES[baseid]) == 0 ) - { - if ( deposited != 0 || issued != 0 || withdrawn != 0 || approved != 0 || redeemed != 0 ) - { - item.push_back(Pair("available", ValueFromAmount(available))); - item.push_back(Pair("deposited", ValueFromAmount(deposited))); - item.push_back(Pair("issued", ValueFromAmount(issued))); - item.push_back(Pair("withdrawn", ValueFromAmount(withdrawn))); - item.push_back(Pair("approved", ValueFromAmount(approved))); - item.push_back(Pair("redeemed", ValueFromAmount(redeemed))); - obj.push_back(Pair(CURRENCIES[baseid],item)); - a.push_back(obj); - } - } - } - ret.push_back(Pair("fiatstatus", a)); - return ret; -} - -UniValue paxprice(const UniValue& params, bool fHelp) -{ - if ( fHelp || params.size() > 4 || params.size() < 2 ) - throw runtime_error("paxprice \"base\" \"rel\" height\n"); - LOCK(cs_main); - UniValue ret(UniValue::VOBJ); uint64_t basevolume=0,relvolume,seed; - std::string base = params[0].get_str(); - std::string rel = params[1].get_str(); - int32_t height; - if ( params.size() == 2 ) - height = chainActive.LastTip()->nHeight; - else height = atoi(params[2].get_str().c_str()); - //if ( params.size() == 3 || (basevolume= COIN * atof(params[3].get_str().c_str())) == 0 ) - basevolume = 100000; - relvolume = komodo_paxprice(&seed,height,(char *)base.c_str(),(char *)rel.c_str(),basevolume); - ret.push_back(Pair("base", base)); - ret.push_back(Pair("rel", rel)); - ret.push_back(Pair("height", height)); - char seedstr[32]; - sprintf(seedstr,"%llu",(long long)seed); - ret.push_back(Pair("seed", seedstr)); - if ( height < 0 || height > chainActive.Height() ) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range"); - else - { - CBlockIndex *pblockindex = chainActive[height]; - if ( pblockindex != 0 ) - ret.push_back(Pair("timestamp", (int64_t)pblockindex->nTime)); - if ( basevolume != 0 && relvolume != 0 ) - { - ret.push_back(Pair("price",((double)relvolume / (double)basevolume))); - ret.push_back(Pair("invprice",((double)basevolume / (double)relvolume))); - ret.push_back(Pair("basevolume",ValueFromAmount(basevolume))); - ret.push_back(Pair("relvolume",ValueFromAmount(relvolume))); - } else ret.push_back(Pair("error", "overflow or error in one or more of parameters")); - } - return ret; -} - -UniValue paxprices(const UniValue& params, bool fHelp) -{ - if ( fHelp || params.size() != 3 ) - throw runtime_error("paxprices \"base\" \"rel\" maxsamples\n"); - LOCK(cs_main); - UniValue ret(UniValue::VOBJ); uint64_t relvolume,prices[4096]; uint32_t i,n; int32_t heights[sizeof(prices)/sizeof(*prices)]; - std::string base = params[0].get_str(); - std::string rel = params[1].get_str(); - int32_t maxsamples = atoi(params[2].get_str().c_str()); - if ( maxsamples < 1 ) - maxsamples = 1; - else if ( maxsamples > sizeof(heights)/sizeof(*heights) ) - maxsamples = sizeof(heights)/sizeof(*heights); - ret.push_back(Pair("base", base)); - ret.push_back(Pair("rel", rel)); - n = komodo_paxprices(heights,prices,maxsamples,(char *)base.c_str(),(char *)rel.c_str()); - UniValue a(UniValue::VARR); - for (i=0; i chainActive.Height() ) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range"); - else - { - CBlockIndex *pblockindex = chainActive[heights[i]]; - - item.push_back(Pair("t", (int64_t)pblockindex->nTime)); - item.push_back(Pair("p", (double)prices[i] / COIN)); - a.push_back(item); - } - } - ret.push_back(Pair("array", a)); - return ret; -} - -uint64_t komodo_accrued_interest(int32_t *txheightp,uint32_t *locktimep,uint256 hash,int32_t n,int32_t checkheight,uint64_t checkvalue,int32_t tipheight); - -UniValue gettxout(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() < 2 || params.size() > 3) - throw runtime_error( - "gettxout \"txid\" n ( includemempool )\n" - "\nReturns details about an unspent transaction output.\n" - "\nArguments:\n" - "1. \"txid\" (string, required) The transaction id\n" - "2. n (numeric, required) vout value\n" - "3. includemempool (boolean, optional) Whether to include the mempool\n" - "\nResult:\n" - "{\n" - " \"bestblock\" : \"hash\", (string) the block hash\n" - " \"confirmations\" : n, (numeric) The number of confirmations\n" - " \"value\" : x.xxx, (numeric) The transaction value in " + CURRENCY_UNIT + "\n" - " \"scriptPubKey\" : { (json object)\n" - " \"asm\" : \"code\", (string) \n" - " \"hex\" : \"hex\", (string) \n" - " \"reqSigs\" : n, (numeric) Number of required signatures\n" - " \"type\" : \"pubkeyhash\", (string) The type, eg pubkeyhash\n" - " \"addresses\" : [ (array of string) array of Komodo addresses\n" - " \"komodoaddress\" (string) Komodo address\n" - " ,...\n" - " ]\n" - " },\n" - " \"version\" : n, (numeric) The version\n" - " \"coinbase\" : true|false (boolean) Coinbase or not\n" - "}\n" - - "\nExamples:\n" - "\nGet unspent transactions\n" - + HelpExampleCli("listunspent", "") + - "\nView the details\n" - + HelpExampleCli("gettxout", "\"txid\" 1") + - "\nAs a json rpc call\n" - + HelpExampleRpc("gettxout", "\"txid\", 1") - ); - - LOCK(cs_main); - - UniValue ret(UniValue::VOBJ); - - std::string strHash = params[0].get_str(); - uint256 hash(uint256S(strHash)); - int n = params[1].get_int(); - bool fMempool = true; - if (params.size() > 2) - fMempool = params[2].get_bool(); - - CCoins coins; - if (fMempool) { - LOCK(mempool.cs); - CCoinsViewMemPool view(pcoinsTip, mempool); - if (!view.GetCoins(hash, coins)) - return NullUniValue; - mempool.pruneSpent(hash, coins); // TODO: this should be done by the CCoinsViewMemPool - } else { - if (!pcoinsTip->GetCoins(hash, coins)) - return NullUniValue; - } - if (n<0 || (unsigned int)n>=coins.vout.size() || coins.vout[n].IsNull()) - return NullUniValue; - - BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); - CBlockIndex *pindex = it->second; - ret.push_back(Pair("bestblock", pindex->GetBlockHash().GetHex())); - if ((unsigned int)coins.nHeight == MEMPOOL_HEIGHT) - ret.push_back(Pair("confirmations", 0)); - else - { - ret.push_back(Pair("confirmations", komodo_dpowconfs(coins.nHeight,pindex->nHeight - coins.nHeight + 1))); - ret.push_back(Pair("rawconfirmations", pindex->nHeight - coins.nHeight + 1)); - } - ret.push_back(Pair("value", ValueFromAmount(coins.vout[n].nValue))); - uint64_t interest; int32_t txheight; uint32_t locktime; - if ( (interest= komodo_accrued_interest(&txheight,&locktime,hash,n,coins.nHeight,coins.vout[n].nValue,(int32_t)pindex->nHeight)) != 0 ) - ret.push_back(Pair("interest", ValueFromAmount(interest))); - UniValue o(UniValue::VOBJ); - ScriptPubKeyToJSON(coins.vout[n].scriptPubKey, o, true); - ret.push_back(Pair("scriptPubKey", o)); - ret.push_back(Pair("version", coins.nVersion)); - ret.push_back(Pair("coinbase", coins.fCoinBase)); - - return ret; -} - -UniValue verifychain(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() > 2) - throw runtime_error( - "verifychain ( checklevel numblocks )\n" - "\nVerifies blockchain database.\n" - "\nArguments:\n" - "1. checklevel (numeric, optional, 0-4, default=3) How thorough the block verification is.\n" - "2. numblocks (numeric, optional, default=288, 0=all) The number of blocks to check.\n" - "\nResult:\n" - "true|false (boolean) Verified or not\n" - "\nExamples:\n" - + HelpExampleCli("verifychain", "") - + HelpExampleRpc("verifychain", "") - ); - - LOCK(cs_main); - - int nCheckLevel = GetArg("-checklevel", 3); - int nCheckDepth = GetArg("-checkblocks", 288); - if (params.size() > 0) - nCheckLevel = params[0].get_int(); - if (params.size() > 1) - nCheckDepth = params[1].get_int(); - - return CVerifyDB().VerifyDB(pcoinsTip, nCheckLevel, nCheckDepth); -} - -/** Implementation of IsSuperMajority with better feedback */ -static UniValue SoftForkMajorityDesc(int minVersion, CBlockIndex* pindex, int nRequired, const Consensus::Params& consensusParams) -{ - int nFound = 0; - CBlockIndex* pstart = pindex; - for (int i = 0; i < consensusParams.nMajorityWindow && pstart != NULL; i++) - { - if (pstart->nVersion >= minVersion) - ++nFound; - pstart = pstart->pprev; - } - - UniValue rv(UniValue::VOBJ); - rv.push_back(Pair("status", nFound >= nRequired)); - rv.push_back(Pair("found", nFound)); - rv.push_back(Pair("required", nRequired)); - rv.push_back(Pair("window", consensusParams.nMajorityWindow)); - return rv; -} - -static UniValue SoftForkDesc(const std::string &name, int version, CBlockIndex* pindex, const Consensus::Params& consensusParams) -{ - UniValue rv(UniValue::VOBJ); - rv.push_back(Pair("id", name)); - rv.push_back(Pair("version", version)); - rv.push_back(Pair("enforce", SoftForkMajorityDesc(version, pindex, consensusParams.nMajorityEnforceBlockUpgrade, consensusParams))); - rv.push_back(Pair("reject", SoftForkMajorityDesc(version, pindex, consensusParams.nMajorityRejectBlockOutdated, consensusParams))); - return rv; -} - -static UniValue NetworkUpgradeDesc(const Consensus::Params& consensusParams, Consensus::UpgradeIndex idx, int height) -{ - UniValue rv(UniValue::VOBJ); - auto upgrade = NetworkUpgradeInfo[idx]; - rv.push_back(Pair("name", upgrade.strName)); - rv.push_back(Pair("activationheight", consensusParams.vUpgrades[idx].nActivationHeight)); - switch (NetworkUpgradeState(height, consensusParams, idx)) { - case UPGRADE_DISABLED: rv.push_back(Pair("status", "disabled")); break; - case UPGRADE_PENDING: rv.push_back(Pair("status", "pending")); break; - case UPGRADE_ACTIVE: rv.push_back(Pair("status", "active")); break; - } - rv.push_back(Pair("info", upgrade.strInfo)); - return rv; -} - -void NetworkUpgradeDescPushBack( - UniValue& networkUpgrades, - const Consensus::Params& consensusParams, - Consensus::UpgradeIndex idx, - int height) -{ - // Network upgrades with an activation height of NO_ACTIVATION_HEIGHT are - // hidden. This is used when network upgrade implementations are merged - // without specifying the activation height. - if (consensusParams.vUpgrades[idx].nActivationHeight != Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT) { - networkUpgrades.push_back(Pair( - HexInt(NetworkUpgradeInfo[idx].nBranchId), - NetworkUpgradeDesc(consensusParams, idx, height))); - } -} - - -UniValue getblockchaininfo(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 0) - throw runtime_error( - "getblockchaininfo\n" - "Returns an object containing various state info regarding block chain processing.\n" - "\nNote that when the chain tip is at the last block before a network upgrade activation,\n" - "consensus.chaintip != consensus.nextblock.\n" - "\nResult:\n" - "{\n" - " \"chain\": \"xxxx\", (string) current network name as defined in BIP70 (main, test, regtest)\n" - " \"blocks\": xxxxxx, (numeric) the current number of blocks processed in the server\n" - " \"headers\": xxxxxx, (numeric) the current number of headers we have validated\n" - " \"bestblockhash\": \"...\", (string) the hash of the currently best block\n" - " \"difficulty\": xxxxxx, (numeric) the current difficulty\n" - " \"verificationprogress\": xxxx, (numeric) estimate of verification progress [0..1]\n" - " \"chainwork\": \"xxxx\" (string) total amount of work in active chain, in hexadecimal\n" - " \"size_on_disk\": xxxxxx, (numeric) the estimated size of the block and undo files on disk\n" - " \"commitments\": xxxxxx, (numeric) the current number of note commitments in the commitment tree\n" - " \"softforks\": [ (array) status of softforks in progress\n" - " {\n" - " \"id\": \"xxxx\", (string) name of softfork\n" - " \"version\": xx, (numeric) block version\n" - " \"enforce\": { (object) progress toward enforcing the softfork rules for new-version blocks\n" - " \"status\": xx, (boolean) true if threshold reached\n" - " \"found\": xx, (numeric) number of blocks with the new version found\n" - " \"required\": xx, (numeric) number of blocks required to trigger\n" - " \"window\": xx, (numeric) maximum size of examined window of recent blocks\n" - " },\n" - " \"reject\": { ... } (object) progress toward rejecting pre-softfork blocks (same fields as \"enforce\")\n" - " }, ...\n" - " ],\n" - " \"upgrades\": { (object) status of network upgrades\n" - " \"xxxx\" : { (string) branch ID of the upgrade\n" - " \"name\": \"xxxx\", (string) name of upgrade\n" - " \"activationheight\": xxxxxx, (numeric) block height of activation\n" - " \"status\": \"xxxx\", (string) status of upgrade\n" - " \"info\": \"xxxx\", (string) additional information about upgrade\n" - " }, ...\n" - " },\n" - " \"consensus\": { (object) branch IDs of the current and upcoming consensus rules\n" - " \"chaintip\": \"xxxxxxxx\", (string) branch ID used to validate the current chain tip\n" - " \"nextblock\": \"xxxxxxxx\" (string) branch ID that the next block will be validated under\n" - " }\n" - "}\n" - "\nExamples:\n" - + HelpExampleCli("getblockchaininfo", "") - + HelpExampleRpc("getblockchaininfo", "") - ); - - LOCK(cs_main); - double progress; - if ( ASSETCHAINS_SYMBOL[0] == 0 ) { - progress = Checkpoints::GuessVerificationProgress(Params().Checkpoints(), chainActive.LastTip()); - } else { - int32_t longestchain = KOMODO_LONGESTCHAIN;//komodo_longestchain(); - progress = (longestchain > 0 ) ? (double) chainActive.Height() / longestchain : 1.0; - } - UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("chain", Params().NetworkIDString())); - obj.push_back(Pair("blocks", (int)chainActive.Height())); - obj.push_back(Pair("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1)); - obj.push_back(Pair("bestblockhash", chainActive.LastTip()->GetBlockHash().GetHex())); - obj.push_back(Pair("difficulty", (double)GetNetworkDifficulty())); - obj.push_back(Pair("verificationprogress", progress)); - obj.push_back(Pair("chainwork", chainActive.LastTip()->nChainWork.GetHex())); - obj.push_back(Pair("pruned", fPruneMode)); - obj.push_back(Pair("size_on_disk", CalculateCurrentUsage())); - - ZCIncrementalMerkleTree tree; - pcoinsTip->GetAnchorAt(pcoinsTip->GetBestAnchor(), tree); - #ifdef __APPLE__ - obj.push_back(Pair("commitments", (uint64_t)tree.size())); - #else - obj.push_back(Pair("commitments", tree.size())); - #endif - - CBlockIndex* tip = chainActive.LastTip(); - UniValue valuePools(UniValue::VARR); - valuePools.push_back(ValuePoolDesc("sprout", tip->nChainSproutValue, boost::none)); - obj.push_back(Pair("valuePools", valuePools)); - - const Consensus::Params& consensusParams = Params().GetConsensus(); - UniValue softforks(UniValue::VARR); - softforks.push_back(SoftForkDesc("bip34", 2, tip, consensusParams)); - softforks.push_back(SoftForkDesc("bip66", 3, tip, consensusParams)); - softforks.push_back(SoftForkDesc("bip65", 4, tip, consensusParams)); - obj.push_back(Pair("softforks", softforks)); - - UniValue upgrades(UniValue::VOBJ); - for (int i = Consensus::UPGRADE_OVERWINTER; i < Consensus::MAX_NETWORK_UPGRADES; i++) { - NetworkUpgradeDescPushBack(upgrades, consensusParams, Consensus::UpgradeIndex(i), tip->nHeight); - } - obj.push_back(Pair("upgrades", upgrades)); - - UniValue consensus(UniValue::VOBJ); - consensus.push_back(Pair("chaintip", HexInt(CurrentEpochBranchId(tip->nHeight, consensusParams)))); - consensus.push_back(Pair("nextblock", HexInt(CurrentEpochBranchId(tip->nHeight + 1, consensusParams)))); - obj.push_back(Pair("consensus", consensus)); - - if (fPruneMode) - { - CBlockIndex *block = chainActive.LastTip(); - while (block && block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) - block = block->pprev; - - obj.push_back(Pair("pruneheight", block->nHeight)); - } - return obj; -} - -/** Comparison function for sorting the getchaintips heads. */ -struct CompareBlocksByHeight -{ - bool operator()(const CBlockIndex* a, const CBlockIndex* b) const - { - /* Make sure that unequal blocks with the same height do not compare - equal. Use the pointers themselves to make a distinction. */ - - if (a->nHeight != b->nHeight) - return (a->nHeight > b->nHeight); - - return a < b; - } -}; - -#include - -UniValue getchaintips(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 0) - throw runtime_error( - "getchaintips\n" - "Return information about all known tips in the block tree," - " including the main chain as well as orphaned branches.\n" - "\nResult:\n" - "[\n" - " {\n" - " \"height\": xxxx, (numeric) height of the chain tip\n" - " \"hash\": \"xxxx\", (string) block hash of the tip\n" - " \"branchlen\": 0 (numeric) zero for main chain\n" - " \"status\": \"active\" (string) \"active\" for the main chain\n" - " },\n" - " {\n" - " \"height\": xxxx,\n" - " \"hash\": \"xxxx\",\n" - " \"branchlen\": 1 (numeric) length of branch connecting the tip to the main chain\n" - " \"status\": \"xxxx\" (string) status of the chain (active, valid-fork, valid-headers, headers-only, invalid)\n" - " }\n" - "]\n" - "Possible values for status:\n" - "1. \"invalid\" This branch contains at least one invalid block\n" - "2. \"headers-only\" Not all blocks for this branch are available, but the headers are valid\n" - "3. \"valid-headers\" All blocks are available for this branch, but they were never fully validated\n" - "4. \"valid-fork\" This branch is not part of the active chain, but is fully validated\n" - "5. \"active\" This is the tip of the active main chain, which is certainly valid\n" - "\nExamples:\n" - + HelpExampleCli("getchaintips", "") - + HelpExampleRpc("getchaintips", "") - ); - - LOCK(cs_main); - - /* Build up a list of chain tips. We start with the list of all - known blocks, and successively remove blocks that appear as pprev - of another block. */ - /*static pthread_mutex_t mutex; static int32_t didinit; - if ( didinit == 0 ) - { - pthread_mutex_init(&mutex,NULL); - didinit = 1; - } - pthread_mutex_lock(&mutex);*/ - std::set setTips; - int32_t n = 0; - BOOST_FOREACH(const PAIRTYPE(const uint256, CBlockIndex*)& item, mapBlockIndex) - { - n++; - setTips.insert(item.second); - } - fprintf(stderr,"iterations getchaintips %d\n",n); - n = 0; - BOOST_FOREACH(const PAIRTYPE(const uint256, CBlockIndex*)& item, mapBlockIndex) - { - const CBlockIndex* pprev=0; - n++; - if ( item.second != 0 ) - pprev = item.second->pprev; - if (pprev) - setTips.erase(pprev); - } - fprintf(stderr,"iterations getchaintips %d\n",n); - //pthread_mutex_unlock(&mutex); - - // Always report the currently active tip. - setTips.insert(chainActive.LastTip()); - - /* Construct the output array. */ - UniValue res(UniValue::VARR); const CBlockIndex *forked; - BOOST_FOREACH(const CBlockIndex* block, setTips) - BOOST_FOREACH(const CBlockIndex* block, setTips) - { - UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("height", block->nHeight)); - obj.push_back(Pair("hash", block->phashBlock->GetHex())); - forked = chainActive.FindFork(block); - if ( forked != 0 ) - { - const int branchLen = block->nHeight - forked->nHeight; - obj.push_back(Pair("branchlen", branchLen)); - - string status; - if (chainActive.Contains(block)) { - // This block is part of the currently active chain. - status = "active"; - } else if (block->nStatus & BLOCK_FAILED_MASK) { - // This block or one of its ancestors is invalid. - status = "invalid"; - } else if (block->nChainTx == 0) { - // This block cannot be connected because full block data for it or one of its parents is missing. - status = "headers-only"; - } else if (block->IsValid(BLOCK_VALID_SCRIPTS)) { - // This block is fully validated, but no longer part of the active chain. It was probably the active block once, but was reorganized. - status = "valid-fork"; - } else if (block->IsValid(BLOCK_VALID_TREE)) { - // The headers for this block are valid, but it has not been validated. It was probably never part of the most-work chain. - status = "valid-headers"; - } else { - // No clue. - status = "unknown"; - } - obj.push_back(Pair("status", status)); - } - res.push_back(obj); - } - - return res; -} - -UniValue mempoolInfoToJSON() -{ - UniValue ret(UniValue::VOBJ); - ret.push_back(Pair("size", (int64_t) mempool.size())); - ret.push_back(Pair("bytes", (int64_t) mempool.GetTotalTxSize())); - ret.push_back(Pair("usage", (int64_t) mempool.DynamicMemoryUsage())); - - return ret; -} - -UniValue getmempoolinfo(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 0) - throw runtime_error( - "getmempoolinfo\n" - "\nReturns details on the active state of the TX memory pool.\n" - "\nResult:\n" - "{\n" - " \"size\": xxxxx (numeric) Current tx count\n" - " \"bytes\": xxxxx (numeric) Sum of all tx sizes\n" - " \"usage\": xxxxx (numeric) Total memory usage for the mempool\n" - "}\n" - "\nExamples:\n" - + HelpExampleCli("getmempoolinfo", "") - + HelpExampleRpc("getmempoolinfo", "") - ); - - return mempoolInfoToJSON(); -} - -UniValue invalidateblock(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "invalidateblock \"hash\"\n" - "\nPermanently marks a block as invalid, as if it violated a consensus rule.\n" - "\nArguments:\n" - "1. hash (string, required) the hash of the block to mark as invalid\n" - "\nResult:\n" - "\nExamples:\n" - + HelpExampleCli("invalidateblock", "\"blockhash\"") - + HelpExampleRpc("invalidateblock", "\"blockhash\"") - ); - - std::string strHash = params[0].get_str(); - uint256 hash(uint256S(strHash)); - CValidationState state; - - { - LOCK(cs_main); - if (mapBlockIndex.count(hash) == 0) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); - - CBlockIndex* pblockindex = mapBlockIndex[hash]; - InvalidateBlock(state, pblockindex); - } - - if (state.IsValid()) { - ActivateBestChain(state); - } - - if (!state.IsValid()) { - throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason()); - } - - return NullUniValue; -} - -UniValue reconsiderblock(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "reconsiderblock \"hash\"\n" - "\nRemoves invalidity status of a block and its descendants, reconsider them for activation.\n" - "This can be used to undo the effects of invalidateblock.\n" - "\nArguments:\n" - "1. hash (string, required) the hash of the block to reconsider\n" - "\nResult:\n" - "\nExamples:\n" - + HelpExampleCli("reconsiderblock", "\"blockhash\"") - + HelpExampleRpc("reconsiderblock", "\"blockhash\"") - ); - - std::string strHash = params[0].get_str(); - uint256 hash(uint256S(strHash)); - CValidationState state; - - { - LOCK(cs_main); - if (mapBlockIndex.count(hash) == 0) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); - - CBlockIndex* pblockindex = mapBlockIndex[hash]; - ReconsiderBlock(state, pblockindex); - } - - if (state.IsValid()) { - ActivateBestChain(state); - } - - if (!state.IsValid()) { - throw JSONRPCError(RPC_DATABASE_ERROR, state.GetRejectReason()); - } - - return NullUniValue; -} diff --git a/src/serialize.h b/src/serialize.h index 3d9c3fae6..9d23b469c 100644 --- a/src/serialize.h +++ b/src/serialize.h @@ -1,5 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin Core developers +// Copyright (c) 2009-2014 The Hush developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/snark/.gitignore b/src/snark/.gitignore deleted file mode 100644 index ea2a20f44..000000000 --- a/src/snark/.gitignore +++ /dev/null @@ -1,51 +0,0 @@ -*.o -*.a -*.so -*.d -libsnark/gtests -depinst/ -depsrc/ -README.html -doxygen/ -libsnark/gtests -libsnark/gadgetlib2/examples/tutorial -libsnark/gadgetlib2/tests/gadgetlib2_test - -libsnark/algebra/curves/tests/test_bilinearity -libsnark/algebra/curves/tests/test_groups -libsnark/algebra/fields/tests/test_fields -libsnark/common/routing_algorithms/profiling/profile_routing_algorithms -libsnark/common/routing_algorithms/tests/test_routing_algorithms -libsnark/gadgetlib1/gadgets/cpu_checkers/fooram/examples/test_fooram -libsnark/gadgetlib1/gadgets/hashes/knapsack/tests/test_knapsack_gadget -libsnark/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget -libsnark/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets -libsnark/gadgetlib1/gadgets/routing/profiling/profile_routing_gadgets -libsnark/gadgetlib1/gadgets/set_commitment/tests/test_set_commitment_gadget -libsnark/gadgetlib1/gadgets/verifiers/tests/test_r1cs_ppzksnark_verifier_gadget -libsnark/reductions/ram_to_r1cs/examples/demo_arithmetization -libsnark/relations/arithmetic_programs/qap/tests/test_qap -libsnark/relations/arithmetic_programs/ssp/tests/test_ssp -libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/profiling/profile_r1cs_mp_ppzkpcd -libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/tests/test_r1cs_mp_ppzkpcd -libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/profiling/profile_r1cs_sp_ppzkpcd -libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/tests/test_r1cs_sp_ppzkpcd -libsnark/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/demo_r1cs_ppzkadsnark -libsnark/zk_proof_systems/ppzksnark/bacs_ppzksnark/profiling/profile_bacs_ppzksnark -libsnark/zk_proof_systems/ppzksnark/bacs_ppzksnark/tests/test_bacs_ppzksnark -libsnark/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/profiling/profile_r1cs_gg_ppzksnark -libsnark/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/tests/test_r1cs_gg_ppzksnark -libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark -libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark -libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark -libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_generator -libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_prover -libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_verifier -libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/profiling/profile_ram_ppzksnark -libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/tests/test_ram_ppzksnark -libsnark/zk_proof_systems/ppzksnark/tbcs_ppzksnark/profiling/profile_tbcs_ppzksnark -libsnark/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tests/test_tbcs_ppzksnark -libsnark/zk_proof_systems/ppzksnark/uscs_ppzksnark/profiling/profile_uscs_ppzksnark -libsnark/zk_proof_systems/ppzksnark/uscs_ppzksnark/tests/test_uscs_ppzksnark -libsnark/zk_proof_systems/zksnark/ram_zksnark/profiling/profile_ram_zksnark -libsnark/zk_proof_systems/zksnark/ram_zksnark/tests/test_ram_zksnark diff --git a/src/snark/AUTHORS b/src/snark/AUTHORS deleted file mode 100644 index cdc8d66af..000000000 --- a/src/snark/AUTHORS +++ /dev/null @@ -1,22 +0,0 @@ -SCIPR Lab: - Eli Ben-Sasson - Alessandro Chiesa - Daniel Genkin - Shaul Kfir - Eran Tromer - Madars Virza - -External contributors: - Michael Backes - Manuel Barbosa - Dario Fiore - Jens Groth - Joshua A. Kroll - Shigeo MITSUNARI - Raphael Reischuk - Tadanori TERUYA - Sean Bowe - Daira Hopwood - @mugatu on forum.z.cash - David Mercer - Joshua Yabut diff --git a/src/snark/LICENSE b/src/snark/LICENSE deleted file mode 100644 index 81cea11e1..000000000 --- a/src/snark/LICENSE +++ /dev/null @@ -1,24 +0,0 @@ -The libsnark library is developed by SCIPR Lab (http://scipr-lab.org) -and contributors. - -Copyright (c) 2012-2014 SCIPR Lab and contributors (see AUTHORS file). - -All files, with the exceptions below, are released under the MIT License: - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. diff --git a/src/snark/Makefile b/src/snark/Makefile deleted file mode 100644 index 3ef82ab87..000000000 --- a/src/snark/Makefile +++ /dev/null @@ -1,289 +0,0 @@ -#******************************************************************************** -# Makefile for the libsnark library. -#******************************************************************************** -#* @author This file is part of libsnark, developed by SCIPR Lab -#* and contributors (see AUTHORS). -#* @copyright MIT license (see LICENSE file) -#*******************************************************************************/ - -# Determine building operating system -ifeq ($(OS),Windows_NT) - uname_S := Windows -else - uname_S := $(shell uname -s) -endif - -# To override these, use "make OPTFLAGS=..." etc. -CURVE = BN128 -OPTFLAGS = -O2 -march=x86-64 -g -mtune=x86-64 - -ifneq ($(PLATFORM),darwin) - FEATUREFLAGS = -DUSE_ASM -DMONTGOMERY_OUTPUT -else - FEATUREFLAGS = -DUSE_ASM -DMONTGOMERY_OUTPUT -D__SIZE_TYPE__="unsigned long long" -endif - -# Initialize this using "CXXFLAGS=... make". The makefile appends to that. -CXXFLAGS += -std=c++11 -Wall -Wextra -Wno-unused-parameter -Wno-comment -Wfatal-errors $(OPTFLAGS) $(FEATUREFLAGS) -DCURVE_$(CURVE) - -DEPSRC = depsrc -DEPINST = depinst - -CXXFLAGS += -I$(DEPINST)/include -Ilibsnark -LDFLAGS += -L$(DEPINST)/lib -Wl,-rpath,$(DEPINST)/lib -LDLIBS += -lgmpxx -lgmp -lboost_program_options -lsodium -# List of .a files to include within libsnark.a and libsnark.so: -AR_LIBS = -# List of library files to install: -INSTALL_LIBS = $(LIB_FILE) -# Sentinel file to check existence of this directory (since directories don't work as a Make dependency): -DEPINST_EXISTS = $(DEPINST)/.exists - -ifneq ($(NO_GTEST),1) - # Compile GTest from sourcecode if we can (e.g., Ubuntu). Otherwise use precompiled one (e.g., Fedora). - # See https://github.com/google/googletest/blob/master/googletest/docs/FAQ.md#why-is-it-not-recommended-to-install-a-pre-compiled-copy-of-google-test-for-example-into-usrlocal - ifneq ($(NO_COMPILE_LIBGTEST),1) - GTESTDIR=/usr/src/gtest - COMPILE_LIBGTEST = $(shell test -d $(GTESTDIR) && echo -n 1) - endif - GTEST_LDLIBS += -lgtest -lpthread -endif - -ifneq ($(NO_SUPERCOP),1) - SUPERCOP_LDLIBS += -lsupercop - INSTALL_LIBS += depinst/lib/libsupercop.a - # Would have been nicer to roll supercop into libsnark.a ("AR_LIBS += $(DEPINST)/lib/libsupercop.a"), but it doesn't support position-independent code (libsnark issue #20). -endif - -LIB_SRCS = \ - libsnark/algebra/curves/alt_bn128/alt_bn128_g1.cpp \ - libsnark/algebra/curves/alt_bn128/alt_bn128_g2.cpp \ - libsnark/algebra/curves/alt_bn128/alt_bn128_init.cpp \ - libsnark/algebra/curves/alt_bn128/alt_bn128_pairing.cpp \ - libsnark/algebra/curves/alt_bn128/alt_bn128_pp.cpp \ - libsnark/common/profiling.cpp \ - libsnark/common/utils.cpp \ - libsnark/gadgetlib1/constraint_profiling.cpp \ - -ifeq ($(CURVE),BN128) - LIB_SRCS += \ - libsnark/algebra/curves/bn128/bn128_g1.cpp \ - libsnark/algebra/curves/bn128/bn128_g2.cpp \ - libsnark/algebra/curves/bn128/bn128_gt.cpp \ - libsnark/algebra/curves/bn128/bn128_init.cpp \ - libsnark/algebra/curves/bn128/bn128_pairing.cpp \ - libsnark/algebra/curves/bn128/bn128_pp.cpp - - CXXFLAGS += -DBN_SUPPORT_SNARK - AR_LIBS += $(DEPINST)/lib/libzm.a -endif - -# FIXME: most of these are broken due to removed code. -DISABLED_EXECUTABLES = \ - libsnark/common/routing_algorithms/profiling/profile_routing_algorithms \ - libsnark/common/routing_algorithms/tests/test_routing_algorithms \ - libsnark/gadgetlib1/gadgets/cpu_checkers/fooram/examples/test_fooram \ - libsnark/gadgetlib1/gadgets/hashes/knapsack/tests/test_knapsack_gadget \ - libsnark/gadgetlib1/gadgets/routing/profiling/profile_routing_gadgets \ - libsnark/gadgetlib1/gadgets/set_commitment/tests/test_set_commitment_gadget \ - libsnark/gadgetlib1/gadgets/verifiers/tests/test_r1cs_ppzksnark_verifier_gadget \ - libsnark/reductions/ram_to_r1cs/examples/demo_arithmetization \ - libsnark/relations/arithmetic_programs/ssp/tests/test_ssp \ - libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/profiling/profile_r1cs_mp_ppzkpcd \ - libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_mp_ppzkpcd/tests/test_r1cs_mp_ppzkpcd \ - libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/profiling/profile_r1cs_sp_ppzkpcd \ - libsnark/zk_proof_systems/pcd/r1cs_pcd/r1cs_sp_ppzkpcd/tests/test_r1cs_sp_ppzkpcd \ - libsnark/zk_proof_systems/ppzksnark/bacs_ppzksnark/profiling/profile_bacs_ppzksnark \ - libsnark/zk_proof_systems/ppzksnark/bacs_ppzksnark/tests/test_bacs_ppzksnark \ - libsnark/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/profiling/profile_r1cs_gg_ppzksnark \ - libsnark/zk_proof_systems/ppzksnark/r1cs_gg_ppzksnark/tests/test_r1cs_gg_ppzksnark \ - libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark \ - libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark \ - libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_generator \ - libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_prover \ - libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/examples/demo_ram_ppzksnark_verifier \ - libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/profiling/profile_ram_ppzksnark \ - libsnark/zk_proof_systems/ppzksnark/ram_ppzksnark/tests/test_ram_ppzksnark \ - libsnark/zk_proof_systems/ppzksnark/tbcs_ppzksnark/profiling/profile_tbcs_ppzksnark \ - libsnark/zk_proof_systems/ppzksnark/tbcs_ppzksnark/tests/test_tbcs_ppzksnark \ - libsnark/zk_proof_systems/ppzksnark/uscs_ppzksnark/profiling/profile_uscs_ppzksnark \ - libsnark/zk_proof_systems/ppzksnark/uscs_ppzksnark/tests/test_uscs_ppzksnark \ - libsnark/zk_proof_systems/zksnark/ram_zksnark/profiling/profile_ram_zksnark \ - libsnark/zk_proof_systems/zksnark/ram_zksnark/tests/test_ram_zksnark - -EXECUTABLES = - -EXECUTABLES_WITH_GTEST = - -EXECUTABLES_WITH_SUPERCOP = \ - libsnark/zk_proof_systems/ppzkadsnark/r1cs_ppzkadsnark/examples/demo_r1cs_ppzkadsnark - -GTEST_TESTS = - -GTEST_SRCS = - -DOCS = README.html - -LIBSNARK_A = libsnark.a - -# For documentation of the following options, see README.md . - -ifeq ($(NO_PROCPS),1) - CXXFLAGS += -DNO_PROCPS -else - LDLIBS += -lprocps -endif - -ifeq ($(LOWMEM),1) - CXXFLAGS += -DLOWMEM -endif - -ifeq ($(PROFILE_OP_COUNTS),1) - STATIC = 1 - CXXFLAGS += -DPROFILE_OP_COUNTS -endif - -ifeq ($(STATIC),1) -ifneq ($(PLATFORM),darwin) - CXXFLAGS += -static -endif - CXXFLAGS += -DSTATIC -else - CXXFLAGS += -fPIC -endif - -ifeq ($(MULTICORE),1) - CXXFLAGS += -DMULTICORE -fopenmp -endif - -ifeq ($(CPPDEBUG),1) - CXXFLAGS += -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC - DEBUG = 1 -endif - -ifeq ($(DEBUG),1) - CXXFLAGS += -DDEBUG -ggdb3 -endif - -ifeq ($(PERFORMANCE),1) - OPTFLAGS = -O3 -march=x86-64 -g -mtune=x86-64 - CXXFLAGS += -DNDEBUG - # Enable link-time optimization: - CXXFLAGS += -flto -fuse-linker-plugin - LDFLAGS += -flto -endif - -LIB_OBJS =$(patsubst %.cpp,%.o,$(LIB_SRCS)) -EXEC_OBJS =$(patsubst %,%.o,$(EXECUTABLES) $(EXECUTABLES_WITH_GTEST) $(EXECUTABLES_WITH_SUPERCOP)) -GTEST_OBJS =$(patsubst %.cpp,%.o,$(GTEST_SRCS)) - -all: \ - $(if $(NO_GTEST),,$(EXECUTABLES_WITH_GTEST) $(GTEST_TESTS)) \ - $(if $(NO_SUPERCOP),,$(EXECUTABLES_WITH_SUPERCOP)) \ - $(EXECUTABLES) \ - $(LIBSNARK_A) \ - $(if $(NO_DOCS),,doc) - -doc: $(DOCS) - -$(DEPINST_EXISTS): - # Create placeholder directories for installed dependencies. Some make settings (including the default) require actually running ./prepare-depends.sh to populate this directory. - mkdir -p $(DEPINST)/lib $(DEPINST)/include - touch $@ - -# In order to detect changes to #include dependencies. -MMD below generates a .d file for each .o file. Include the .d file. --include $(patsubst %.o,%.d, $(LIB_OBJS) $(GTEST_OBJS) $(EXEC_OBJS) ) - -$(LIB_OBJS) $(if $(NO_GTEST),,$(GTEST_OBJS)) $(EXEC_OBJS): %.o: %.cpp - $(CXX) -o $@ $< -c -MMD $(CXXFLAGS) - -LIBGTEST_A = $(DEPINST)/lib/libgtest.a - -$(LIBGTEST_A): $(GTESTDIR)/libsnark/gtest-all.cc $(DEPINST_EXISTS) - $(CXX) -o $(DEPINST)/lib/gtest-all.o -I $(GTESTDIR) -c -isystem $(GTESTDIR)/include $< $(CXXFLAGS) - $(AR) -rv $(LIBGTEST_A) $(DEPINST)/lib/gtest-all.o - -# libsnark.a will contains all of our relevant object files, and we also mash in the .a files of relevant dependencies built by ./prepare-depends.sh -$(LIBSNARK_A): $(LIB_OBJS) $(AR_LIBS) - $(AR) q $(LIBSNARK_A) $(LIB_OBJS) - if [ -n "$(AR_LIBS)" ]; then mkdir -p tmp-ar; cd tmp-ar; for AR_LIB in $(AR_LIBS); do $(AR) x $$AR_LIB; done; $(AR) qc $(LIBSNARK_A) tmp-ar/*; cd ..; rm -r tmp-ar; fi; - $(AR) s $(LIBSNARK_A) - -libsnark.so: $(LIBSNARK_A) $(DEPINST_EXISTS) - $(CXX) -o $@ --shared -Wl,--whole-archive $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) -Wl,--no-whole-archive $(LDLIBS) - -libsnark/gadgetlib2/tests/gadgetlib2_test: \ - libsnark/gadgetlib2/tests/adapters_UTEST.cpp \ - libsnark/gadgetlib2/tests/constraint_UTEST.cpp \ - libsnark/gadgetlib2/tests/gadget_UTEST.cpp \ - libsnark/gadgetlib2/tests/integration_UTEST.cpp \ - libsnark/gadgetlib2/tests/protoboard_UTEST.cpp \ - libsnark/gadgetlib2/tests/variable_UTEST.cpp - -$(EXECUTABLES): %: %.o $(LIBSNARK_A) $(DEPINST_EXISTS) - $(CXX) -o $@ $@.o $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) $(LDLIBS) - -$(EXECUTABLES_WITH_GTEST): %: %.o $(LIBSNARK_A) $(if $(COMPILE_LIBGTEST),$(LIBGTEST_A)) $(DEPINST_EXISTS) - $(CXX) -o $@ $@.o $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) $(GTEST_LDLIBS) $(LDLIBS) - -$(EXECUTABLES_WITH_SUPERCOP): %: %.o $(LIBSNARK_A) $(DEPINST_EXISTS) - $(CXX) -o $@ $@.o $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) $(SUPERCOP_LDLIBS) $(LDLIBS) - -$(GTEST_TESTS): %: $(GTEST_OBJS) $(LIBSNARK_A) $(if $(COMPILE_LIBGTEST),$(LIBGTEST_A)) $(DEPINST_EXISTS) - $(CXX) -o $@ $(GTEST_OBJS) $(LIBSNARK_A) $(CXXFLAGS) $(LDFLAGS) $(GTEST_LDLIBS) $(LDLIBS) - - -ifeq ($(STATIC),1) -LIB_FILE = $(LIBSNARK_A) -else -LIB_FILE = libsnark.so -endif - -lib: $(LIB_FILE) - -$(DOCS): %.html: %.md - markdown_py -f $@ $^ -x toc -x extra --noisy -# TODO: Would be nice to enable "-x smartypants" but Ubuntu 12.04 doesn't support that. -# TODO: switch to redcarpet, to produce same output as GitHub's processing of README.md. But what about TOC? - -ifeq ($(PREFIX),) -install: - $(error Please provide PREFIX. E.g. make install PREFIX=/usr) -else -HEADERS_SRC=$(shell find libsnark -name '*.hpp' -o -name '*.tcc') -HEADERS_DEST=$(patsubst libsnark/%,$(PREFIX)/include/libsnark/%,$(HEADERS_SRC)) - -$(HEADERS_DEST): $(PREFIX)/include/libsnark/%: libsnark/% - mkdir -p $(shell dirname $@) - cp $< $@ - -install: $(INSTALL_LIBS) $(HEADERS_DEST) $(DEPINST_EXISTS) - mkdir -p $(PREFIX)/lib - cp -v $(INSTALL_LIBS) $(PREFIX)/lib/ -ifneq ($(NO_COPY_DEPINST),1) - cp -rv $(DEPINST)/include $(PREFIX) -endif -endif - -check: $(GTEST_TESTS) - $(GTEST_TESTS) - -doxy: - doxygen doxygen.conf - -# Clean generated files, except locally-compiled dependencies -clean: - $(RM) \ - $(LIB_OBJS) $(GTEST_OBJS) $(EXEC_OBJS) \ - $(EXECUTABLES) $(EXECUTABLES_WITH_GTEST) $(EXECUTABLES_WITH_SUPERCOP) $(GTEST_TESTS) \ - $(DOCS) \ - ${patsubst %.o,%.d,${LIB_OBJS} ${GTEST_OBJS} ${EXEC_OBJS}} \ - libsnark.so $(LIBSNARK_A) \ - $(RM) -fr doxygen/ \ - $(RM) $(LIBGTEST_A) $(DEPINST)/lib/gtest-all.o - -# Clean all, including locally-compiled dependencies -clean-all: clean - $(RM) -fr $(DEPSRC) $(DEPINST) - -.PHONY: all clean clean-all doc doxy lib install diff --git a/src/snark/README.md b/src/snark/README.md deleted file mode 100644 index d5aa34006..000000000 --- a/src/snark/README.md +++ /dev/null @@ -1,628 +0,0 @@ -libsnark: a C++ library for zkSNARK proofs -================================================================================ - --------------------------------------------------------------------------------- -Authors --------------------------------------------------------------------------------- - -The libsnark library is developed by the [SCIPR Lab] project and contributors -and is released under the MIT License (see the [LICENSE] file). - -Copyright (c) 2012-2014 SCIPR Lab and contributors (see [AUTHORS] file). - --------------------------------------------------------------------------------- -[TOC] - - - --------------------------------------------------------------------------------- -Overview --------------------------------------------------------------------------------- - -This library implements __zkSNARK__ schemes, which are a cryptographic method -for proving/verifying, in zero knowledge, the integrity of computations. - -A computation can be expressed as an NP statement, in forms such as the following: - -- "The C program _foo_, when executed, returns exit code 0 if given the input _bar_ and some additional input _qux_." -- "The Boolean circuit _foo_ is satisfiable by some input _qux_." -- "The arithmetic circuit _foo_ accepts the partial assignment _bar_, when extended into some full assignment _qux_." -- "The set of constraints _foo_ is satisfiable by the partial assignment _bar_, when extended into some full assignment _qux_." - -A prover who knows the witness for the NP statement (i.e., a satisfying input/assignment) can produce a short proof attesting to the truth of the NP statement. This proof can be verified by anyone, and offers the following properties. - -- __Zero knowledge:__ - the verifier learns nothing from the proof beside the truth of the statement (i.e., the value _qux_, in the above examples, remains secret). -- __Succinctness:__ - the proof is short and easy to verify. -- __Non-interactivity:__ - the proof is a string (i.e. it does not require back-and-forth interaction between the prover and the verifier). -- __Soundness:__ - the proof is computationally sound (i.e., it is infeasible to fake a proof of a false NP statement). Such a proof system is also called an _argument_. -- __Proof of knowledge:__ - the proof attests not just that the NP statement is true, but also that the - prover knows why (e.g., knows a valid _qux_). - -These properties are summarized by the _zkSNARK_ acronym, which stands for _Zero-Knowledge Succinct Non-interactive ARgument of Knowledge_ (though zkSNARKs are also knows as -_succinct non-interactive computationally-sound zero-knowledge proofs of knowledge_). -For formal definitions and theoretical discussions about these, see -\[BCCT12], \[BCIOP13], and the references therein. - -The libsnark library currently provides a C++ implementation of: - -1. General-purpose proof systems: - 1. A preprocessing zkSNARK for the NP-complete language "R1CS" - (_Rank-1 Constraint Systems_), which is a language that is similar to arithmetic - circuit satisfiability. - 2. A preprocessing SNARK for a language of arithmetic circuits, "BACS" - (_Bilinear Arithmetic Circuit Satisfiability_). This simplifies the writing - of NP statements when the additional flexibility of R1CS is not needed. - Internally, it reduces to R1CS. - 3. A preprocessing SNARK for the language "USCS" - (_Unitary-Square Constraint Systems_). This abstracts and implements the core - contribution of \[DFGK14] - 4. A preprocessing SNARK for a language of Boolean circuits, "TBCS" - (_Two-input Boolean Circuit Satisfiability_). Internally, it reduces to USCS. - This is much more efficient than going through R1CS. - 5. ADSNARK, a preprocessing SNARKs for proving statements on authenticated - data, as described in \[BBFR15]. - 6. Proof-Carrying Data (PCD). This uses recursive composition of SNARKs, as - explained in \[BCCT13] and optimized in \[BCTV14b]. -2. Gadget libraries (gadgetlib1 and gadgetlib2) for constructing R1CS - instances out of modular "gadget" classes. -3. Examples of applications that use the above proof systems to prove - statements about: - 1. Several toy examples. - 2. Execution of TinyRAM machine code, as explained in \[BCTV14a] and - \[BCGTV13]. (Such machine code can be obtained, e.g., by compiling from C.) - This is easily adapted to any other Random Access Machine that satisfies a - simple load-store interface. - 3. A scalable for TinyRAM using Proof-Carrying Data, as explained in \[BCTV14b] - 4. Zero-knowldge cluster MapReduce, as explained in \[CTV15]. - -The zkSNARK construction implemented by libsnark follows, extends, and -optimizes the approach described in \[BCTV14], itself an extension of -\[BCGTV13], following the approach of \[BCIOP13] and \[GGPR13]. An alternative -implementation of the basic approach is the _Pinocchio_ system of \[PGHR13]. -See these references for discussions of efficiency aspects that arise in -practical use of such constructions, as well as security and trust -considerations. - -This scheme is a _preprocessing zkSNARK_ (_ppzkSNARK_): before proofs can be -created and verified, one needs to first decide on a size/circuit/system -representing the NP statements to be proved, and run a _generator_ algorithm to -create corresponding public parameters (a long proving key and a short -verification key). - -Using the library involves the following high-level steps: - -1. Express the statements to be proved as an R1CS (or any of the other - languages above, such as arithmetic circuits, Boolean circuits, or TinyRAM). - This is done by writing C++ code that constructs an R1CS, and linking this code - together with libsnark -2. Use libsnark's generator algorithm to create the public parameters for this - statement (once and for all). -3. Use libsnark's prover algorithm to create proofs of true statements about - the satisfiability of the R1CS. -4. Use libsnark's verifier algorithm to check proofs for alleged statements. - - --------------------------------------------------------------------------------- -The NP-complete language R1CS --------------------------------------------------------------------------------- - -The ppzkSNARK supports proving/verifying membership in a specific NP-complete -language: R1CS (*rank-1 constraint systems*). An instance of the language is -specified by a set of equations over a prime field F, and each equation looks like: - < A, (1,X) > * < B , (1,X) > = < C, (1,X) > -where A,B,C are vectors over F, and X is a vector of variables. - -In particular, arithmetic (as well as boolean) circuits are easily reducible to -this language by converting each gate into a rank-1 constraint. See \[BCGTV13] -Appendix E (and "System of Rank 1 Quadratic Equations") for more details about this. - - --------------------------------------------------------------------------------- -Elliptic curve choices --------------------------------------------------------------------------------- - -The ppzkSNARK can be instantiated with different parameter choices, depending on -which elliptic curve is used. The libsnark library currently provides three -options: - -* "edwards": - an instantiation based on an Edwards curve, providing 80 bits of security. - -* "bn128": - an instantiation based on a Barreto-Naehrig curve, providing 128 - bits of security. The underlying curve implementation is - \[ate-pairing], which has incorporated our patch that changes the - BN curve to one suitable for SNARK applications. - - * This implementation uses dynamically-generated machine code for the curve - arithmetic. Some modern systems disallow execution of code on the heap, and - will thus block this implementation. - - For example, on Fedora 20 at its default settings, you will get the error - `zmInit ERR:can't protect` when running this code. To solve this, - run `sudo setsebool -P allow_execheap 1` to allow execution, - or use `make CURVE=ALT_BN128` instead. - -* "alt_bn128": - an alternative to "bn128", somewhat slower but avoids dynamic code generation. - -Note that bn128 requires an x86-64 CPU while the other curve choices -should be architecture-independent; see [portability](#portability). - - --------------------------------------------------------------------------------- -Gadget libraries --------------------------------------------------------------------------------- - -The libsnark library currently provides two libraries for conveniently constructing -R1CS instances out of reusable "gadgets". Both libraries provide a way to construct -gadgets on other gadgets as well as additional explicit equations. In this way, -complex R1CS instances can be built bottom up. - -### gadgetlib1 - -This is a low-level library which expose all features of the preprocessing -zkSNARK for R1CS. Its design is based on templates (as does the ppzkSNARK code) -to efficiently support working on multiple elliptic curves simultaneously. This -library is used for most of the constraint-building in libsnark, both internal -(reductions and Proof-Carrying Data) and examples applications. - -### gadgetlib2 - -This is an alternative library for constructing systems of polynomial equations -and, in particular, also R1CS instances. It is better documented and easier to -use than gadgetlib1, and its interface does not use templates. However, fewer -useful gadgets are provided. - - --------------------------------------------------------------------------------- -Security --------------------------------------------------------------------------------- - -The theoretical security of the underlying mathematical constructions, and the -requisite assumptions, are analyzed in detailed in the aforementioned research -papers. - -** -This code is a research-quality proof of concept, and has not -yet undergone extensive review or testing. It is thus not suitable, -as is, for use in critical or production systems. -** - -Known issues include the following: - -* The ppzkSNARK's generator and prover exhibit data-dependent running times - and memory usage. These form timing and cache-contention side channels, - which may be an issue in some applications. - -* Randomness is retrieved from /dev/urandom, but this should be - changed to a carefully considered (depending on system and threat - model) external, high-quality randomness source when creating - long-term proving/verification keys. - - --------------------------------------------------------------------------------- -Build instructions --------------------------------------------------------------------------------- - -The libsnark library relies on the following: - -- C++ build environment -- GMP for certain bit-integer arithmetic -- libprocps for reporting memory usage -- GTest for some of the unit tests - -So far we have tested these only on Linux, though we have been able to make the library work, -with some features disabled (such as memory profiling or GTest tests), on Windows via Cygwin -and on Mac OS X. (If you succeed in achieving more complete ports of the library, please -let us know!) See also the notes on [portability](#portability) below. - -For example, on a fresh install of Ubuntu 14.04, install the following packages: - - $ sudo apt-get install build-essential git libgmp3-dev libprocps3-dev libgtest-dev python-markdown libboost-all-dev libssl-dev - -Or, on Fedora 20: - - $ sudo yum install gcc-c++ make git gmp-devel procps-ng-devel gtest-devel python-markdown - -Run the following, to fetch dependencies from their GitHub repos and compile them. -(Not required if you set `CURVE` to other than the default `BN128` and also set `NO_SUPERCOP=1`.) - - $ ./prepare-depends.sh - -Then, to compile the library, tests, profiling harness and documentation, run: - - $ make - -To create just the HTML documentation, run - - $ make doc - -and then view the resulting `README.html` (which contains the very text you are reading now). - -To create Doxygen documentation summarizing all files, classes and functions, -with some (currently sparse) comments, install the `doxygen` and `graphviz` packages, then run - - $ make doxy - -(this may take a few minutes). Then view the resulting [`doxygen/index.html`](doxygen/index.html). - -### Using libsnark as a library - -To develop an application that uses libsnark, you could add it within the libsnark directory tree and adjust the Makefile, but it is far better to build libsnark as a (shared or static) library. You can then write your code in a separate directory tree, and link it against libsnark. - - -To build just the shared object library `libsnark.so`, run: - - $ make lib - -To build just the static library `libsnark.a`, run: - - $ make lib STATIC=1 - -Note that static compilation requires static versions of all libraries it depends on. -It may help to minize these dependencies by appending -`CURVE=ALT_BN128 NO_PROCPS=1 NO_GTEST=1 NO_SUPERCOP=1`. On Fedora 21, the requisite -library RPM dependencies are then: -`boost-static glibc-static gmp-static libstdc++-static openssl-static zlib-static - boost-devel glibc-devel gmp-devel gmp-devel libstdc++-devel openssl-devel openssl-devel`. - -To build *and install* the libsnark library: - - $ make install PREFIX=/install/path - -This will install `libsnark.so` into `/install/path/lib`; so your application should be linked using `-L/install/path/lib -lsnark`. It also installs the requisite headers into `/install/path/include`; so your application should be compiled using `-I/install/path/include`. - -In addition, unless you use `NO_SUPERCOP=1`, `libsupercop.a` will be installed and should be linked in using `-lsupercop`. - - -### Building on Windows using Cygwin -Install Cygwin using the graphical installer, including the `g++`, `libgmp` -and `git` packages. Then disable the dependencies not easily supported under CygWin, -using: - - $ make NO_PROCPS=1 NO_GTEST=1 NO_DOCS=1 - - -### Building on Mac OS X - -On Mac OS X, install GMP from MacPorts (`port install gmp`). Then disable the -dependencies not easily supported under CygWin, using: - - $ make NO_PROCPS=1 NO_GTEST=1 NO_DOCS=1 - -MacPorts does not write its libraries into standard system folders, so you -might need to explicitly provide the paths to the header files and libraries by -appending `CXXFLAGS=-I/opt/local/include LDFLAGS=-L/opt/local/lib` to the line -above. Similarly, to pass the paths to ate-pairing you would run -`INC_DIR=-I/opt/local/include LIB_DIR=-L/opt/local/lib ./prepare-depends.sh` -instead of `./prepare-depends.sh` above. - --------------------------------------------------------------------------------- -Tutorials --------------------------------------------------------------------------------- - -libsnark includes a tutorial, and some usage examples, for the high-level API. - -* `src/gadgetlib1/examples1` contains a simple example for constructing a - constraint system using gadgetlib1. - -* `src/gadgetlib2/examples` contains a tutorial for using gadgetlib2 to express - NP statements as constraint systems. It introduces basic terminology, design - overview, and recommended programming style. It also shows how to invoke - ppzkSNARKs on such constraint systems. The main file, `tutorial.cpp`, builds - into a standalone executable. - -* `src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark.cpp` - constructs a simple constraint system and runs the ppzksnark. See below for how to - run it. - - --------------------------------------------------------------------------------- -Executing profiling example --------------------------------------------------------------------------------- - -The command - - $ src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark 1000 10 Fr - -exercises the ppzkSNARK (first generator, then prover, then verifier) on an -R1CS instance with 1000 equations and an input consisting of 10 field elements. - -(If you get the error `zmInit ERR:can't protect`, see the discussion -[above](#elliptic-curve-choices).) - -The command - - $ src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark 1000 10 bytes - -does the same but now the input consists of 10 bytes. - - --------------------------------------------------------------------------------- -Build options --------------------------------------------------------------------------------- - -The following flags change the behavior of the compiled code. - -* `make FEATUREFLAGS='-Dname1 -Dname2 ...'` - - Override the active conditional #define names (you can see the default at the top of the Makefile). - The next bullets list the most important conditionally-#defined features. - For example, `make FEATUREFLAGS='-DBINARY_OUTPUT'` enables binary output and disables the default - assembly optimizations and Montgomery-representation output. - -* define `BINARY_OUTPUT` - - In serialization, output raw binary data (instead of decimal, when not set). - -* `make CURVE=choice` / define `CURVE_choice` (where `choice` is one of: - ALT_BN128, BN128, EDWARDS, MNT4, MNT6) - - Set the default curve to one of the above (see [elliptic curve choices](#elliptic-curve-choices)). - -* `make DEBUG=1` / define `DEBUG` - - Print additional information for debugging purposes. - -* `make LOWMEM=1` / define `LOWMEM` - - Limit the size of multi-exponentiation tables, for low-memory platforms. - -* `make NO_DOCS=1` - - Do not generate HTML documentation, e.g. on platforms where Markdown is not easily available. - -* `make NO_PROCPS=1` - - Do not link against libprocps. This disables memory profiling. - -* `make NO_GTEST=1` - - Do not link against GTest. The tutorial and test suite of gadgetlib2 tutorial won't be compiled. - -* `make NO_SUPERCOP=1` - - Do not link against SUPERCOP for optimized crypto. The ADSNARK executables will not be built. - -* `make MULTICORE=1` - - Enable parallelized execution of the ppzkSNARK generator and prover, using OpenMP. - This will utilize all cores on the CPU for heavyweight parallelizabe operations such as - FFT and multiexponentiation. The default is single-core. - - To override the maximum number of cores used, set the environment variable `OMP_NUM_THREADS` - at runtime (not compile time), e.g., `OMP_NUM_THREADS=8 test_r1cs_sp_ppzkpc`. It defaults - to the autodetected number of cores, but on some devices, dynamic core management confused - OpenMP's autodetection, so setting `OMP_NUM_THREADS` is necessary for full utilization. - -* define `NO_PT_COMPRESSION` - - Do not use point compression. - This gives much faster serialization times, at the expense of ~2x larger - sizes for serialized keys and proofs. - -* define `MONTGOMERY_OUTPUT` (on by default) - - Serialize Fp elements as their Montgomery representations. If this - option is disabled then Fp elements are serialized as their - equivalence classes, which is slower but produces human-readable - output. - -* `make PROFILE_OP_COUNTS=1` / define `PROFILE_OP_COUNTS` - - Collect counts for field and curve operations inside static variables - of the corresponding algebraic objects. This option works for all - curves except bn128. - -* define `USE_ASM` (on by default) - - Use unrolled assembly routines for F[p] arithmetic and faster heap in - multi-exponentiation. (When not set, use GMP's `mpn_*` routines instead.) - -* define `USE_MIXED_ADDITION` - - Convert each element of the proving key and verification key to - affine coordinates. This allows using mixed addition formulas in - multiexponentiation and results in slightly faster prover and - verifier runtime at expense of increased proving time. - -* `make PERFORMANCE=1` - - Enables compiler optimizations such as link-time optimization, and disables debugging aids. - (On some distributions this causes a `plugin needed to handle lto object` link error and `undefined reference`s, which can be remedied by `AR=gcc-ar make ...`.) - -Not all combinations are tested together or supported by every part of the codebase. - - --------------------------------------------------------------------------------- -Portability --------------------------------------------------------------------------------- - -libsnark is written in fairly standard C++11. - -However, having been developed on Linux on x86-64 CPUs, libsnark has some limitations -with respect to portability. Specifically: - -1. libsnark's algebraic data structures assume little-endian byte order. - -2. Profiling routines use `clock_gettime` and `readproc` calls, which are Linux-specific. - -3. Random-number generation is done by reading from `/dev/urandom`, which is - specific to Unix-like systems. - -4. libsnark binary serialization routines (see `BINARY_OUTPUT` above) assume - a fixed machine word size (i.e. sizeof(mp_limb_t) for GMP's limb data type). - Objects serialized in binary on a 64-bit system cannot be de-serialized on - a 32-bit system, and vice versa. - (The decimal serialization routines have no such limitation.) - -5. libsnark requires a C++ compiler with good C++11 support. It has been - tested with g++ 4.7, g++ 4.8, and clang 3.4. - -6. On x86-64, we by default use highly optimized assembly implementations for some - operations (see `USE_ASM` above). On other architectures we fall back to a - portable C++ implementation, which is slower. - -Tested configurations include: - -* Debian jessie with g++ 4.7 on x86-64 -* Debian jessie with clang 3.4 on x86-64 -* Fedora 20/21 with g++ 4.8.2/4.9.2 on x86-64 and i686 -* Ubuntu 14.04 LTS with g++ 4.8 on x86-64 -* Ubuntu 14.04 LTS with g++ 4.8 on x86-32, for EDWARDS and ALT_BN128 curve choices -* Debian wheezy with g++ 4.7 on ARM little endian (Debian armel port) inside QEMU, for EDWARDS and ALT_BN128 curve choices -* Windows 7 with g++ 4.8.3 under Cygwin 1.7.30 on x86-64 with NO_PROCPS=1, NO_GTEST=1 and NO_DOCS=1, for EDWARDS and ALT_BN128 curve choices -* Mac OS X 10.9.4 (Mavericks) with Apple LLVM version 5.1 (based on LLVM 3.4svn) on x86-64 with NO_PROCPS=1, NO_GTEST=1 and NO_DOCS=1 - - --------------------------------------------------------------------------------- -Directory structure --------------------------------------------------------------------------------- - -The directory structure of the libsnark library is as follows: - -* src/ --- main C++ source code, containing the following modules: - * algebra/ --- fields and elliptic curve groups - * common/ --- miscellaneous utilities - * gadgetlib1/ --- gadgetlib1, a library to construct R1CS instances - * gadgets/ --- basic gadgets for gadgetlib1 - * gadgetlib2/ --- gadgetlib2, a library to construct R1CS instances - * qap/ --- quadratic arithmetic program - * domains/ --- support for fast interpolation/evaluation, by providing - FFTs and Lagrange-coefficient computations for various domains - * relations/ --- interfaces for expressing statement (relations between instances and witnesses) as various NP-complete languages - * constraint_satisfaction_problems/ --- R1CS and USCS languages - * circuit_satisfaction_problems/ --- Boolean and arithmetic circuit satisfiability languages - * ram_computations/ --- RAM computation languages - * zk_proof_systems --- interfaces and implementations of the proof systems - * reductions --- reductions between languages (used internally, but contains many examples of building constraints) - - Some of these module directories have the following subdirectories: - - * ... - * examples/ --- example code and tutorials for this module - * tests/ --- unit tests for this module - - In particular, the top-level API examples are at `src/r1cs_ppzksnark/examples/` and `src/gadgetlib2/examples/`. - -* depsrc/ --- created by `prepare_depends.sh` for retrieved sourcecode and local builds of external code - (currently: \[ate-pairing], and its dependency xbyak). - -* depinst/ --- created by `prepare_depends.sh` and `Makefile` - for local installation of locally-compiled dependencies. - -* doxygen/ --- created by `make doxy` and contains a Doxygen summary of all files, classes etc. in libsnark. - - --------------------------------------------------------------------------------- -Further considerations --------------------------------------------------------------------------------- - -### Multiexponentiation window size - -The ppzkSNARK's generator has to solve a fixed-base multi-exponentiation -problem. We use a window-based method in which the optimal window size depends -on the size of the multiexponentiation instance *and* the platform. - -On our benchmarking platform (a 3.40 GHz Intel Core i7-4770 CPU), we have -computed for each curve optimal windows, provided as -"fixed_base_exp_window_table" initialization sequences, for each curve; see -`X_init.cpp` for X=edwards,bn128,alt_bn128. - -Performance on other platforms may not be optimal (but probably not be far off). -Future releases of the libsnark library will include a tool that generates -optimal window sizes. - - --------------------------------------------------------------------------------- -References --------------------------------------------------------------------------------- - -\[BBFR15] [ - _ADSNARK: nearly practical and privacy-preserving proofs on authenticated data_ -](https://eprint.iacr.org/2014/617), - Michael Backes, Manuel Barbosa, Dario Fiore, Raphael M. Reischuk, - IEEE Symposium on Security and Privacy (Oakland) 2015 - -\[BCCT12] [ - _From extractable collision resistance to succinct non-Interactive arguments of knowledge, and back again_ -](http://eprint.iacr.org/2011/443), - Nir Bitansky, Ran Canetti, Alessandro Chiesa, Eran Tromer, - Innovations in Computer Science (ITCS) 2012 - -\[BCCT13] [ - _Recursive composition and bootstrapping for SNARKs and proof-carrying data_ -](http://eprint.iacr.org/2012/095) - Nir Bitansky, Ran Canetti, Alessandro Chiesa, Eran Tromer, - Symposium on Theory of Computing (STOC) 13 - -\[BCGTV13] [ - _SNARKs for C: Verifying Program Executions Succinctly and in Zero Knowledge_ -](http://eprint.iacr.org/2013/507), - Eli Ben-Sasson, Alessandro Chiesa, Daniel Genkin, Eran Tromer, Madars Virza, - CRYPTO 2013 - -\[BCIOP13] [ - _Succinct Non-Interactive Arguments via Linear Interactive Proofs_ -](http://eprint.iacr.org/2012/718), - Nir Bitansky, Alessandro Chiesa, Yuval Ishai, Rafail Ostrovsky, Omer Paneth, - Theory of Cryptography Conference 2013 - -\[BCTV14a] [ - _Succinct Non-Interactive Zero Knowledge for a von Neumann Architecture_ -](http://eprint.iacr.org/2013/879), - Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza, - USENIX Security 2014 - -\[BCTV14b] [ - _Scalable succinct non-interactive arguments via cycles of elliptic curves_ -](https://eprint.iacr.org/2014/595), - Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza, - CRYPTO 2014 - -\[CTV15] [ - _Cluster computing in zero knowledge_ -](https://eprint.iacr.org/2015/377), - Alessandro Chiesa, Eran Tromer, Madars Virza, - Eurocrypt 2015 - -\[DFGK14] [ - Square span programs with applications to succinct NIZK arguments -](https://eprint.iacr.org/2014/718), - George Danezis, Cedric Fournet, Jens Groth, Markulf Kohlweiss, - ASIACCS 2014 - -\[GGPR13] [ - _Quadratic span programs and succinct NIZKs without PCPs_ -](http://eprint.iacr.org/2012/215), - Rosario Gennaro, Craig Gentry, Bryan Parno, Mariana Raykova, - EUROCRYPT 2013 - -\[ate-pairing] [ - _High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves_ -](https://github.com/herumi/ate-pairing), - MITSUNARI Shigeo, TERUYA Tadanori - -\[PGHR13] [ - _Pinocchio: Nearly Practical Verifiable Computation_ -](http://eprint.iacr.org/2013/279), - Bryan Parno, Craig Gentry, Jon Howell, Mariana Raykova, - IEEE Symposium on Security and Privacy (Oakland) 2013 - -[SCIPR Lab]: http://www.scipr-lab.org/ (Succinct Computational Integrity and Privacy Research Lab) - -[LICENSE]: LICENSE (LICENSE file in top directory of libsnark distribution) - -[AUTHORS]: AUTHORS (AUTHORS file in top directory of libsnark distribution) diff --git a/src/snark/doxygen.conf b/src/snark/doxygen.conf deleted file mode 100644 index 5fbe61681..000000000 --- a/src/snark/doxygen.conf +++ /dev/null @@ -1,1807 +0,0 @@ -# Doxyfile 1.8.2 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project -# -# All text after a hash (#) is considered a comment and will be ignored -# The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all -# text before the first occurrence of this tag. Doxygen uses libiconv (or the -# iconv built into libc) for the transcoding. See -# http://www.gnu.org/software/libiconv for the list of possible encodings. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or sequence of words) that should -# identify the project. Note that if you do not use Doxywizard you need -# to put quotes around the project name if it contains spaces. - -PROJECT_NAME = libsnark - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -PROJECT_NUMBER = - -# Using the PROJECT_BRIEF tag one can provide an optional one line description -# for a project that appears at the top of each page and should give viewer -# a quick idea about the purpose of the project. Keep the description short. - -PROJECT_BRIEF = - -# With the PROJECT_LOGO tag one can specify an logo or icon that is -# included in the documentation. The maximum height of the logo should not -# exceed 55 pixels and the maximum width should not exceed 200 pixels. -# Doxygen will copy the logo to the output directory. - -PROJECT_LOGO = - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - -OUTPUT_DIRECTORY = - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would -# otherwise cause performance problems for the file system. - -CREATE_SUBDIRS = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, -# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English -# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, -# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, -# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" - -ABBREVIATE_BRIEF = - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. - -FULL_PATH_NAMES = YES - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. Note that you specify absolute paths here, but also -# relative paths, which will be relative from the directory where doxygen is -# started. - -STRIP_FROM_PATH = src - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful if your file system -# doesn't support long names like on DOS, Mac, or CD-ROM. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like regular Qt-style comments -# (thus requiring an explicit @brief command for a brief description.) - -JAVADOC_AUTOBRIEF = YES - -# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -# interpret the first line (until the first dot) of a Qt-style -# comment as the brief description. If set to NO, the comments -# will behave just like regular Qt-style comments (thus requiring -# an explicit \brief command for a brief description.) - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. - -TAB_SIZE = 8 - -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. - -ALIASES = - -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding -# "class=itcl::class" will allow you to use the command class in the -# itcl::class meaning. - -TCL_SUBST = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. - -OPTIMIZE_OUTPUT_FOR_C = NO - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for -# Java. For instance, namespaces will be presented as packages, qualified -# scopes will look different, etc. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources only. Doxygen will then generate output that is more tailored for -# Fortran. - -OPTIMIZE_FOR_FORTRAN = NO - -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for -# VHDL. - -OPTIMIZE_OUTPUT_VHDL = NO - -# Doxygen selects the parser to use depending on the extension of the files it -# parses. With this tag you can assign which parser to use for a given -# extension. Doxygen has a built-in mapping, but you can override or extend it -# using this tag. The format is ext=language, where ext is a file extension, -# and language is one of the parsers supported by doxygen: IDL, Java, -# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, -# C++. For instance to make doxygen treat .inc files as Fortran files (default -# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note -# that for custom extensions you also need to set FILE_PATTERNS otherwise the -# files are not read by doxygen. - -EXTENSION_MAPPING = tcc=C++ - -# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all -# comments according to the Markdown format, which allows for more readable -# documentation. See http://daringfireball.net/projects/markdown/ for details. -# The output of markdown processing is further processed by doxygen, so you -# can mix doxygen, HTML, and XML commands with Markdown formatting. -# Disable only in case of backward compatibilities issues. - -MARKDOWN_SUPPORT = YES - -# When enabled doxygen tries to link words that correspond to documented classes, -# or namespaces to their corresponding documentation. Such a link can be -# prevented in individual cases by by putting a % sign in front of the word or -# globally by setting AUTOLINK_SUPPORT to NO. - -AUTOLINK_SUPPORT = YES - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also makes the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. - -BUILTIN_STL_SUPPORT = NO - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. - -CPP_CLI_SUPPORT = NO - -# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. -# Doxygen will parse them like normal C++ but will assume all classes use public -# instead of private inheritance when no explicit protection keyword is present. - -SIP_SUPPORT = NO - -# For Microsoft's IDL there are propget and propput attributes to indicate -# getter and setter methods for a property. Setting this option to YES (the -# default) will make doxygen replace the get and set methods by a property in -# the documentation. This will only work if the methods are indeed getting or -# setting a simple type. If this is not the case, or you want to show the -# methods anyway, you should set this option to NO. - -IDL_PROPERTY_SUPPORT = YES - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. - -DISTRIBUTE_GROUP_DOC = NO - -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. - -SUBGROUPING = YES - -# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and -# unions are shown inside the group in which they are included (e.g. using -# @ingroup) instead of on a separate page (for HTML and Man pages) or -# section (for LaTeX and RTF). - -INLINE_GROUPED_CLASSES = NO - -# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and -# unions with only public data fields will be shown inline in the documentation -# of the scope in which they are defined (i.e. file, namespace, or group -# documentation), provided this scope is documented. If set to NO (the default), -# structs, classes, and unions are shown on a separate page (for HTML and Man -# pages) or section (for LaTeX and RTF). - -INLINE_SIMPLE_STRUCTS = NO - -# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum -# is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically -# be useful for C code in case the coding convention dictates that all compound -# types are typedef'ed and only the typedef is referenced, never the tag name. - -TYPEDEF_HIDES_STRUCT = NO - -# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to -# determine which symbols to keep in memory and which to flush to disk. -# When the cache is full, less often used symbols will be written to disk. -# For small to medium size projects (<1000 input files) the default value is -# probably good enough. For larger projects a too small cache size can cause -# doxygen to be busy swapping symbols to and from disk most of the time -# causing a significant performance penalty. -# If the system has enough physical memory increasing the cache will improve the -# performance by keeping more symbols in memory. Note that the value works on -# a logarithmic scale so increasing the size by one will roughly double the -# memory usage. The cache size is given by this formula: -# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols. - -SYMBOL_CACHE_SIZE = 0 - -# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be -# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given -# their name and scope. Since this can be an expensive process and often the -# same symbol appear multiple times in the code, doxygen keeps a cache of -# pre-resolved symbols. If the cache is too small doxygen will become slower. -# If the cache is too large, memory is wasted. The cache size is given by this -# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols. - -LOOKUP_CACHE_SIZE = 0 - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES - -EXTRACT_ALL = YES - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - -EXTRACT_PRIVATE = YES - -# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal -# scope will be included in the documentation. - -EXTRACT_PACKAGE = NO - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. - -EXTRACT_STATIC = YES - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. - -EXTRACT_LOCAL_CLASSES = YES - -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. - -EXTRACT_LOCAL_METHODS = NO - -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base -# name of the file that contains the anonymous namespace. By default -# anonymous namespaces are hidden. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. - -INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. - -CASE_SENSE_NAMES = YES - -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. - -HIDE_SCOPE_NAMES = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. - -SHOW_INCLUDE_FILES = YES - -# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen -# will list include files with double quotes in the documentation -# rather than with sharp brackets. - -FORCE_LOCAL_INCLUDES = NO - -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. - -SORT_BRIEF_DOCS = NO - -# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen -# will sort the (brief and detailed) documentation of class members so that -# constructors and destructors are listed first. If set to NO (the default) -# the constructors will appear in the respective orders defined by -# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. -# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO -# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. - -SORT_MEMBERS_CTORS_1ST = NO - -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the -# hierarchy of group names into alphabetical order. If set to NO (the default) -# the group names will appear in their defined order. - -SORT_GROUP_NAMES = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. - -SORT_BY_SCOPE_NAME = NO - -# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to -# do proper type resolution of all parameters of a function it will reject a -# match between the prototype and the implementation of a member function even -# if there is only one candidate or it is obvious which candidate to choose -# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen -# will still accept a match between prototype and implementation in such cases. - -STRICT_PROTO_MATCHING = NO - -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting -# \deprecated commands in the documentation. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or macro consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and macros in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. - -SHOW_USED_FILES = YES - -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. -# This will remove the Files entry from the Quick Index and from the -# Folder Tree View (if specified). The default is YES. - -SHOW_FILES = YES - -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the -# Namespaces page. This will remove the Namespaces entry from the Quick Index -# and from the Folder Tree View (if specified). The default is YES. - -SHOW_NAMESPACES = YES - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command , where is the value of -# the FILE_VERSION_FILTER tag, and is the name of an input file -# provided by doxygen. Whatever the program writes to standard output -# is used as the file version. See the manual for examples. - -FILE_VERSION_FILTER = - -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed -# by doxygen. The layout file controls the global structure of the generated -# output files in an output format independent way. To create the layout file -# that represents doxygen's defaults, run doxygen with the -l option. -# You can optionally specify a file name after the option, if omitted -# DoxygenLayout.xml will be used as the name of the layout file. - -LAYOUT_FILE = - -# The CITE_BIB_FILES tag can be used to specify one or more bib files -# containing the references data. This must be a list of .bib files. The -# .bib extension is automatically appended if omitted. Using this command -# requires the bibtex tool to be installed. See also -# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style -# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this -# feature you need bibtex and perl available in the search path. - -CITE_BIB_FILES = - -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - -QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - -WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. - -WARN_IF_UNDOCUMENTED = YES - -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. - -WARN_IF_DOC_ERROR = YES - -# The WARN_NO_PARAMDOC option can be enabled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. - -WARN_NO_PARAMDOC = NO - -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -INPUT = src README.md - -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is -# also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for -# the list of possible encodings. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh -# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py -# *.f90 *.f *.for *.vhd *.vhdl - -FILE_PATTERNS = *.md *.c *.h *.cpp *.hpp *.tcc *.inc *.cc - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - -RECURSIVE = YES - -# The EXCLUDE tag can be used to specify files and/or directories that should be -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. -# Note that relative paths are relative to the directory from which doxygen is -# run. - -EXCLUDE = Debug \ - Release - -# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or -# directories that are symbolic links (a Unix file system feature) are excluded -# from the input. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories -# for example use the pattern */test/* - -EXCLUDE_PATTERNS = - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test - -EXCLUDE_SYMBOLS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -EXAMPLE_PATTERNS = - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. If FILTER_PATTERNS is specified, this tag will be -# ignored. - -INPUT_FILTER = "perl -pe 's/^(libsnark: .*)$/$1 {#mainpage}/ if $.==1; s!//+ *(TODO|FIXME|XXX)!/// \\todo!'" - # The 1st replacement marks README.md as the main page. - # The 2nd replacement identifies additional TODO notations. - # These should be done with FILTER_PATTERNS instead, but it looks like shell escaping is different there. - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty or if -# non of the patterns match the file name, INPUT_FILTER is applied. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). - -FILTER_SOURCE_FILES = NO - -# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file -# pattern. A pattern will override the setting for FILTER_PATTERN (if any) -# and it is also possible to disable source filtering for a specific pattern -# using *.ext= (so without naming a filter). This option only has effect when -# FILTER_SOURCE_FILES is enabled. - -FILTER_SOURCE_PATTERNS = - -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. - -SOURCE_BROWSER = YES - -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. - -INLINE_SOURCES = YES - -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C, C++ and Fortran comments will always remain visible. - -STRIP_CODE_COMMENTS = NO - -# If the REFERENCED_BY_RELATION tag is set to YES -# then for each documented function all documented -# functions referencing it will be listed. - -REFERENCED_BY_RELATION = NO - -# If the REFERENCES_RELATION tag is set to YES -# then for each documented function all documented entities -# called/used by that function will be listed. - -REFERENCES_RELATION = NO - -# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. Otherwise they will link to the documentation. - -REFERENCES_LINK_SOURCE = YES - -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You -# will need version 4.8.6 or higher. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - -VERBATIM_HEADERS = YES - -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - -ALPHABETICAL_INDEX = YES - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - -HTML_OUTPUT = doxygen - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. Note that when using a custom header you are responsible -# for the proper inclusion of any scripts and style sheets that doxygen -# needs, which is dependent on the configuration options used. -# It is advised to generate a default header using "doxygen -w html -# header.html footer.html stylesheet.css YourConfigFile" and then modify -# that header. Note that the header is subject to change so you typically -# have to redo this when upgrading to a newer version of doxygen or when -# changing the value of configuration settings such as GENERATE_TREEVIEW! - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If left blank doxygen will -# generate a default style sheet. Note that it is recommended to use -# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this -# tag will in the future become obsolete. - -HTML_STYLESHEET = - -# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional -# user-defined cascading style sheet that is included after the standard -# style sheets created by doxygen. Using this option one can overrule -# certain style aspects. This is preferred over using HTML_STYLESHEET -# since it does not replace the standard style sheet and is therefor more -# robust against future updates. Doxygen will copy the style sheet file to -# the output directory. - -HTML_EXTRA_STYLESHEET = - -# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or -# other source files which should be copied to the HTML output directory. Note -# that these files will be copied to the base HTML output directory. Use the -# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these -# files. In the HTML_STYLESHEET file, use the file name only. Also note that -# the files will be copied as-is; there are no commands or markers available. - -HTML_EXTRA_FILES = - -# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. -# Doxygen will adjust the colors in the style sheet and background images -# according to this color. Hue is specified as an angle on a colorwheel, -# see http://en.wikipedia.org/wiki/Hue for more information. -# For instance the value 0 represents red, 60 is yellow, 120 is green, -# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. -# The allowed range is 0 to 359. - -HTML_COLORSTYLE_HUE = 220 - -# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of -# the colors in the HTML output. For a value of 0 the output will use -# grayscales only. A value of 255 will produce the most vivid colors. - -HTML_COLORSTYLE_SAT = 100 - -# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to -# the luminance component of the colors in the HTML output. Values below -# 100 gradually make the output lighter, whereas values above 100 make -# the output darker. The value divided by 100 is the actual gamma applied, -# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, -# and 100 does not change the gamma. - -HTML_COLORSTYLE_GAMMA = 80 - -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting -# this to NO can help when comparing the output of multiple runs. - -HTML_TIMESTAMP = NO - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. - -HTML_DYNAMIC_SECTIONS = NO - -# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of -# entries shown in the various tree structured indices initially; the user -# can expand and collapse entries dynamically later on. Doxygen will expand -# the tree to such a level that at most the specified number of entries are -# visible (unless a fully collapsed tree already exceeds this amount). -# So setting the number of entries 1 will produce a full collapsed tree by -# default. 0 is a special value representing an infinite number of entries -# and will result in a full expanded tree by default. - -HTML_INDEX_NUM_ENTRIES = 0 - -# If the GENERATE_DOCSET tag is set to YES, additional index files -# will be generated that can be used as input for Apple's Xcode 3 -# integrated development environment, introduced with OSX 10.5 (Leopard). -# To create a documentation set, doxygen will generate a Makefile in the -# HTML output directory. Running make will produce the docset in that -# directory and running "make install" will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find -# it at startup. -# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html -# for more information. - -GENERATE_DOCSET = NO - -# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the -# feed. A documentation feed provides an umbrella under which multiple -# documentation sets from a single provider (such as a company or product suite) -# can be grouped. - -DOCSET_FEEDNAME = "Doxygen generated docs" - -# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that -# should uniquely identify the documentation set bundle. This should be a -# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen -# will append .docset to the name. - -DOCSET_BUNDLE_ID = org.doxygen.Project - -# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely -# identify the documentation publisher. This should be a reverse domain-name -# style string, e.g. com.mycompany.MyDocSet.documentation. - -DOCSET_PUBLISHER_ID = org.doxygen.Publisher - -# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. - -DOCSET_PUBLISHER_NAME = Publisher - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) -# of the generated HTML documentation. - -GENERATE_HTMLHELP = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be -# written to the html output directory. - -CHM_FILE = - -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. - -HHC_LOCATION = - -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). - -GENERATE_CHI = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING -# is used to encode HtmlHelp index (hhk), content (hhc) and project file -# content. - -CHM_INDEX_ENCODING = - -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. - -TOC_EXPAND = NO - -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and -# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated -# that can be used as input for Qt's qhelpgenerator to generate a -# Qt Compressed Help (.qch) of the generated HTML documentation. - -GENERATE_QHP = NO - -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can -# be used to specify the file name of the resulting .qch file. -# The path specified is relative to the HTML output folder. - -QCH_FILE = - -# The QHP_NAMESPACE tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#namespace - -QHP_NAMESPACE = org.doxygen.Project - -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating -# Qt Help Project output. For more information please see -# http://doc.trolltech.com/qthelpproject.html#virtual-folders - -QHP_VIRTUAL_FOLDER = doc - -# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to -# add. For more information please see -# http://doc.trolltech.com/qthelpproject.html#custom-filters - -QHP_CUST_FILTER_NAME = - -# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the -# custom filter to add. For more information please see -# -# Qt Help Project / Custom Filters. - -QHP_CUST_FILTER_ATTRS = - -# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this -# project's -# filter section matches. -# -# Qt Help Project / Filter Attributes. - -QHP_SECT_FILTER_ATTRS = - -# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can -# be used to specify the location of Qt's qhelpgenerator. -# If non-empty doxygen will try to run qhelpgenerator on the generated -# .qhp file. - -QHG_LOCATION = - -# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files -# will be generated, which together with the HTML files, form an Eclipse help -# plugin. To install this plugin and make it available under the help contents -# menu in Eclipse, the contents of the directory containing the HTML and XML -# files needs to be copied into the plugins directory of eclipse. The name of -# the directory within the plugins directory should be the same as -# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before -# the help appears. - -GENERATE_ECLIPSEHELP = NO - -# A unique identifier for the eclipse help plugin. When installing the plugin -# the directory name containing the HTML and XML files should also have -# this name. - -ECLIPSE_DOC_ID = org.doxygen.Project - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) -# at top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. Since the tabs have the same information as the -# navigation tree you can set this option to NO if you already set -# GENERATE_TREEVIEW to YES. - -DISABLE_INDEX = NO - -# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. -# If the tag value is set to YES, a side panel will be generated -# containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). -# Windows users are probably better off using the HTML help feature. -# Since the tree basically has the same information as the tab index you -# could consider to set DISABLE_INDEX to NO when enabling this option. - -GENERATE_TREEVIEW = YES - -# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values -# (range [0,1..20]) that doxygen will group on one line in the generated HTML -# documentation. Note that a value of 0 will completely suppress the enum -# values from appearing in the overview section. - -ENUM_VALUES_PER_LINE = 4 - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. - -TREEVIEW_WIDTH = 250 - -# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open -# links to external symbols imported via tag files in a separate window. - -EXT_LINKS_IN_WINDOW = NO - -# Use this tag to change the font size of Latex formulas included -# as images in the HTML documentation. The default is 10. Note that -# when you change the font size after a successful doxygen run you need -# to manually remove any form_*.png images from the HTML output directory -# to force them to be regenerated. - -FORMULA_FONTSIZE = 10 - -# Use the FORMULA_TRANPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are -# not supported properly for IE 6.0, but are supported on all modern browsers. -# Note that when changing this option you need to delete any form_*.png files -# in the HTML output before the changes have effect. - -FORMULA_TRANSPARENT = YES - -# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax -# (see http://www.mathjax.org) which uses client side Javascript for the -# rendering instead of using prerendered bitmaps. Use this if you do not -# have LaTeX installed or if you want to formulas look prettier in the HTML -# output. When enabled you may also need to install MathJax separately and -# configure the path to it using the MATHJAX_RELPATH option. - -USE_MATHJAX = YES - -# When MathJax is enabled you need to specify the location relative to the -# HTML output directory using the MATHJAX_RELPATH option. The destination -# directory should contain the MathJax.js script. For instance, if the mathjax -# directory is located at the same level as the HTML output directory, then -# MATHJAX_RELPATH should be ../mathjax. The default value points to -# the MathJax Content Delivery Network so you can quickly see the result without -# installing MathJax. However, it is strongly recommended to install a local -# copy of MathJax from http://www.mathjax.org before deployment. - -MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest - -# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension -# names that should be enabled during MathJax rendering. - -MATHJAX_EXTENSIONS = - -# When the SEARCHENGINE tag is enabled doxygen will generate a search box -# for the HTML output. The underlying search engine uses javascript -# and DHTML and should work on any modern browser. Note that when using -# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets -# (GENERATE_DOCSET) there is already a search function so this one should -# typically be disabled. For large projects the javascript based search engine -# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. - -SEARCHENGINE = YES - -# When the SERVER_BASED_SEARCH tag is enabled the search engine will be -# implemented using a PHP enabled web server instead of at the web client -# using Javascript. Doxygen will generate the search PHP script and index -# file to put on the web server. The advantage of the server -# based approach is that it scales better to large projects and allows -# full text search. The disadvantages are that it is more difficult to setup -# and does not have live searching capabilities. - -SERVER_BASED_SEARCH = NO - -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - -GENERATE_LATEX = NO - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - -LATEX_OUTPUT = latex - -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -# invoked. If left blank `latex' will be used as the default command name. -# Note that when enabling USE_PDFLATEX this option is only used for -# generating bitmaps for formulas in the HTML output, but not in the -# Makefile that is written to the output directory. - -LATEX_CMD_NAME = latex - -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the -# default command name. - -MAKEINDEX_CMD_NAME = makeindex - -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_LATEX = NO - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, letter, legal and -# executive. If left blank a4wide will be used. - -PAPER_TYPE = a4 - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - -EXTRA_PACKAGES = amsfonts - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - -LATEX_HEADER = - -# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for -# the generated latex document. The footer should contain everything after -# the last chapter. If it is left blank doxygen will generate a -# standard footer. Notice: only use this tag if you know what you are doing! - -LATEX_FOOTER = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - -PDF_HYPERLINKS = NO - -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a -# higher quality PDF documentation. - -USE_PDFLATEX = NO - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - -LATEX_BATCHMODE = NO - -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) -# in the output. - -LATEX_HIDE_INDICES = NO - -# If LATEX_SOURCE_CODE is set to YES then doxygen will include -# source code with syntax highlighting in the LaTeX output. -# Note that which sources are shown also depends on other settings -# such as SOURCE_BROWSER. - -LATEX_SOURCE_CODE = NO - -# The LATEX_BIB_STYLE tag can be used to specify the style to use for the -# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See -# http://en.wikipedia.org/wiki/BibTeX for more info. - -LATEX_BIB_STYLE = plain - -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- - -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with -# other RTF readers or editors. - -GENERATE_RTF = NO - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - -RTF_OUTPUT = rtf - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - -RTF_HYPERLINKS = NO - -# Load style sheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide -# replacements, missing definitions are set to their default value. - -RTF_STYLESHEET_FILE = - -# Set optional variables used in the generation of an rtf document. -# Syntax is similar to doxygen's config file. - -RTF_EXTENSIONS_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - -GENERATE_MAN = NO - -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `man' will be used as the default path. - -MAN_OUTPUT = man - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - -MAN_EXTENSION = .3 - -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command -# would be unable to find the correct page. The default is NO. - -MAN_LINKS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- - -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of -# the code including all documentation. - -GENERATE_XML = NO - -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `xml' will be used as the default path. - -XML_OUTPUT = xml - -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that -# enabling this will significantly increase the size of the XML output. - -XML_PROGRAMLISTING = YES - -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- - -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental -# and incomplete at the moment. - -GENERATE_AUTOGEN_DEF = NO - -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- - -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the -# moment. - -GENERATE_PERLMOD = NO - -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able -# to generate PDF and DVI output from the Perl module output. - -PERLMOD_LATEX = NO - -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. This is useful -# if you want to understand what is going on. On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller -# and Perl will parse it just the same. - -PERLMOD_PRETTY = YES - -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same -# Makefile don't overwrite each other's variables. - -PERLMOD_MAKEVAR_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = YES - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled -# way by setting EXPAND_ONLY_PREDEF to YES. - -MACRO_EXPANSION = NO - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_DEFINED tags. - -EXPAND_ONLY_PREDEF = NO - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# pointed to by INCLUDE_PATH will be searched when a #include is found. - -SEARCH_INCLUDES = YES - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - -INCLUDE_PATH = - -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will -# be used. - -INCLUDE_FILE_PATTERNS = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator -# instead of the = operator. - -PREDEFINED = - -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition that -# overrules the definition found in the source code. - -EXPAND_AS_DEFINED = - -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all references to function-like macros -# that are alone on a line, have an all uppercase name, and do not end with a -# semicolon, because these will confuse the parser if not removed. - -SKIP_FUNCTION_MACROS = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to external references -#--------------------------------------------------------------------------- - -# The TAGFILES option can be used to specify one or more tagfiles. For each -# tag file the location of the external documentation should be added. The -# format of a tag file without this location is as follows: -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths -# or URLs. Note that each tag file must have a unique name (where the name does -# NOT include the path). If a tag file is not located in the directory in which -# doxygen is run, you must also specify the path to the tagfile here. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - -GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - -ALLEXTERNALS = NO - -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will -# be listed. - -EXTERNAL_GROUPS = YES - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - -PERL_PATH = /usr/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- - -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option also works with HAVE_DOT disabled, but it is recommended to -# install and use dot, since it yields more powerful graphs. - -CLASS_DIAGRAMS = NO - -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see -# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented -# or is not a class. - -HIDE_UNDOC_RELATIONS = YES - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - -HAVE_DOT = YES - -# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is -# allowed to run in parallel. When set to 0 (the default) doxygen will -# base this on the number of processors available in the system. You can set it -# explicitly to a value larger than 0 to get control over the balance -# between CPU load and processing speed. - -DOT_NUM_THREADS = 0 - -# By default doxygen will use the Helvetica font for all dot files that -# doxygen generates. When you want a differently looking font you can specify -# the font name using DOT_FONTNAME. You need to make sure dot is able to find -# the font, which can be done by putting it in a standard location or by setting -# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the -# directory containing the font. - -DOT_FONTNAME = Helvetica - -# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. -# The default size is 10pt. - -DOT_FONTSIZE = 10 - -# By default doxygen will tell dot to use the Helvetica font. -# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to -# set the path where dot can find it. - -DOT_FONTPATH = - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# CLASS_DIAGRAMS tag to NO. - -CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -COLLABORATION_GRAPH = YES - -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for groups, showing the direct groups dependencies - -GROUP_GRAPHS = YES - -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling -# Language. - -UML_LOOK = NO - -# If the UML_LOOK tag is enabled, the fields and methods are shown inside -# the class node. If there are many fields or methods and many nodes the -# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS -# threshold limits the number of items for each type to make the size more -# managable. Set this to 0 for no limit. Note that the threshold may be -# exceeded by 50% before the limit is enforced. - -UML_LIMIT_NUM_FIELDS = 10 - -# If set to YES, the inheritance and collaboration graphs will show the -# relations between templates and their instances. - -TEMPLATE_RELATIONS = NO - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with -# other documented files. - -INCLUDE_GRAPH = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - -INCLUDED_BY_GRAPH = YES - -# If the CALL_GRAPH and HAVE_DOT options are set to YES then -# doxygen will generate a call dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable call graphs -# for selected functions only using the \callgraph command. - -CALL_GRAPH = YES - -# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then -# doxygen will generate a caller dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable caller -# graphs for selected functions only using the \callergraph command. - -CALLER_GRAPH = YES - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will generate a graphical hierarchy of all classes instead of a textual one. - -GRAPHICAL_HIERARCHY = YES - -# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include -# relations between the files in the directories. - -DIRECTORY_GRAPH = YES - -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are svg, png, jpg, or gif. -# If left blank png will be used. If you choose svg you need to set -# HTML_FILE_EXTENSION to xhtml in order to make the SVG files -# visible in IE 9+ (other browsers do not have this requirement). - -DOT_IMAGE_FORMAT = png - -# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to -# enable generation of interactive SVG images that allow zooming and panning. -# Note that this requires a modern browser other than Internet Explorer. -# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you -# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files -# visible. Older versions of IE do not have SVG support. - -INTERACTIVE_SVG = NO - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found in the path. - -DOT_PATH = - -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the -# \dotfile command). - -DOTFILE_DIRS = - -# The MSCFILE_DIRS tag can be used to specify one or more directories that -# contain msc files that are included in the documentation (see the -# \mscfile command). - -MSCFILE_DIRS = - -# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -# nodes that will be shown in the graph. If the number of nodes in a graph -# becomes larger than this value, doxygen will truncate the graph, which is -# visualized by representing a node as a red box. Note that doxygen if the -# number of direct children of the root node in a graph is already larger than -# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note -# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. - -DOT_GRAPH_MAX_NODES = 50 - -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that the size of a graph can be further restricted by -# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. - -MAX_DOT_GRAPH_DEPTH = 0 - -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not -# seem to support this out of the box. Warning: Depending on the platform used, -# enabling this option may lead to badly anti-aliased labels on the edges of -# a graph (i.e. they become hard to read). - -DOT_TRANSPARENT = NO - -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) -# support this, this feature is disabled by default. - -DOT_MULTI_TARGETS = NO - -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. - -GENERATE_LEGEND = YES - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate -# the various graphs. - -DOT_CLEANUP = YES diff --git a/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g1.cpp b/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g1.cpp deleted file mode 100644 index 7f329d659..000000000 --- a/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g1.cpp +++ /dev/null @@ -1,525 +0,0 @@ -/** @file - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#include "algebra/curves/alt_bn128/alt_bn128_g1.hpp" -#include "common/assert_except.hpp" - -namespace libsnark { - -#ifdef PROFILE_OP_COUNTS -int64_t alt_bn128_G1::add_cnt = 0; -int64_t alt_bn128_G1::dbl_cnt = 0; -#endif - -std::vector alt_bn128_G1::wnaf_window_table; -std::vector alt_bn128_G1::fixed_base_exp_window_table; -alt_bn128_G1 alt_bn128_G1::G1_zero; -alt_bn128_G1 alt_bn128_G1::G1_one; - -alt_bn128_G1::alt_bn128_G1() -{ - this->X = G1_zero.X; - this->Y = G1_zero.Y; - this->Z = G1_zero.Z; -} - -void alt_bn128_G1::print() const -{ - if (this->is_zero()) - { - printf("O\n"); - } - else - { - alt_bn128_G1 copy(*this); - copy.to_affine_coordinates(); - gmp_printf("(%Nd , %Nd)\n", - copy.X.as_bigint().data, alt_bn128_Fq::num_limbs, - copy.Y.as_bigint().data, alt_bn128_Fq::num_limbs); - } -} - -void alt_bn128_G1::print_coordinates() const -{ - if (this->is_zero()) - { - printf("O\n"); - } - else - { - gmp_printf("(%Nd : %Nd : %Nd)\n", - this->X.as_bigint().data, alt_bn128_Fq::num_limbs, - this->Y.as_bigint().data, alt_bn128_Fq::num_limbs, - this->Z.as_bigint().data, alt_bn128_Fq::num_limbs); - } -} - -void alt_bn128_G1::to_affine_coordinates() -{ - if (this->is_zero()) - { - this->X = alt_bn128_Fq::zero(); - this->Y = alt_bn128_Fq::one(); - this->Z = alt_bn128_Fq::zero(); - } - else - { - alt_bn128_Fq Z_inv = Z.inverse(); - alt_bn128_Fq Z2_inv = Z_inv.squared(); - alt_bn128_Fq Z3_inv = Z2_inv * Z_inv; - this->X = this->X * Z2_inv; - this->Y = this->Y * Z3_inv; - this->Z = alt_bn128_Fq::one(); - } -} - -void alt_bn128_G1::to_special() -{ - this->to_affine_coordinates(); -} - -bool alt_bn128_G1::is_special() const -{ - return (this->is_zero() || this->Z == alt_bn128_Fq::one()); -} - -bool alt_bn128_G1::is_zero() const -{ - return (this->Z.is_zero()); -} - -bool alt_bn128_G1::operator==(const alt_bn128_G1 &other) const -{ - if (this->is_zero()) - { - return other.is_zero(); - } - - if (other.is_zero()) - { - return false; - } - - /* now neither is O */ - - // using Jacobian coordinates so: - // (X1:Y1:Z1) = (X2:Y2:Z2) - // iff - // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3 - // iff - // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3 - - alt_bn128_Fq Z1_squared = (this->Z).squared(); - alt_bn128_Fq Z2_squared = (other.Z).squared(); - - if ((this->X * Z2_squared) != (other.X * Z1_squared)) - { - return false; - } - - alt_bn128_Fq Z1_cubed = (this->Z) * Z1_squared; - alt_bn128_Fq Z2_cubed = (other.Z) * Z2_squared; - - if ((this->Y * Z2_cubed) != (other.Y * Z1_cubed)) - { - return false; - } - - return true; -} - -bool alt_bn128_G1::operator!=(const alt_bn128_G1& other) const -{ - return !(operator==(other)); -} - -alt_bn128_G1 alt_bn128_G1::operator+(const alt_bn128_G1 &other) const -{ - // handle special cases having to do with O - if (this->is_zero()) - { - return other; - } - - if (other.is_zero()) - { - return *this; - } - - // no need to handle points of order 2,4 - // (they cannot exist in a prime-order subgroup) - - // check for doubling case - - // using Jacobian coordinates so: - // (X1:Y1:Z1) = (X2:Y2:Z2) - // iff - // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3 - // iff - // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3 - - alt_bn128_Fq Z1Z1 = (this->Z).squared(); - alt_bn128_Fq Z2Z2 = (other.Z).squared(); - - alt_bn128_Fq U1 = this->X * Z2Z2; - alt_bn128_Fq U2 = other.X * Z1Z1; - - alt_bn128_Fq Z1_cubed = (this->Z) * Z1Z1; - alt_bn128_Fq Z2_cubed = (other.Z) * Z2Z2; - - alt_bn128_Fq S1 = (this->Y) * Z2_cubed; // S1 = Y1 * Z2 * Z2Z2 - alt_bn128_Fq S2 = (other.Y) * Z1_cubed; // S2 = Y2 * Z1 * Z1Z1 - - if (U1 == U2 && S1 == S2) - { - // dbl case; nothing of above can be reused - return this->dbl(); - } - - // rest of add case - alt_bn128_Fq H = U2 - U1; // H = U2-U1 - alt_bn128_Fq S2_minus_S1 = S2-S1; - alt_bn128_Fq I = (H+H).squared(); // I = (2 * H)^2 - alt_bn128_Fq J = H * I; // J = H * I - alt_bn128_Fq r = S2_minus_S1 + S2_minus_S1; // r = 2 * (S2-S1) - alt_bn128_Fq V = U1 * I; // V = U1 * I - alt_bn128_Fq X3 = r.squared() - J - (V+V); // X3 = r^2 - J - 2 * V - alt_bn128_Fq S1_J = S1 * J; - alt_bn128_Fq Y3 = r * (V-X3) - (S1_J+S1_J); // Y3 = r * (V-X3)-2 S1 J - alt_bn128_Fq Z3 = ((this->Z+other.Z).squared()-Z1Z1-Z2Z2) * H; // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H - - return alt_bn128_G1(X3, Y3, Z3); -} - -alt_bn128_G1 alt_bn128_G1::operator-() const -{ - return alt_bn128_G1(this->X, -(this->Y), this->Z); -} - - -alt_bn128_G1 alt_bn128_G1::operator-(const alt_bn128_G1 &other) const -{ - return (*this) + (-other); -} - -alt_bn128_G1 alt_bn128_G1::add(const alt_bn128_G1 &other) const -{ - // handle special cases having to do with O - if (this->is_zero()) - { - return other; - } - - if (other.is_zero()) - { - return *this; - } - - // no need to handle points of order 2,4 - // (they cannot exist in a prime-order subgroup) - - // handle double case - if (this->operator==(other)) - { - return this->dbl(); - } - -#ifdef PROFILE_OP_COUNTS - this->add_cnt++; -#endif - // NOTE: does not handle O and pts of order 2,4 - // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl - - alt_bn128_Fq Z1Z1 = (this->Z).squared(); // Z1Z1 = Z1^2 - alt_bn128_Fq Z2Z2 = (other.Z).squared(); // Z2Z2 = Z2^2 - alt_bn128_Fq U1 = (this->X) * Z2Z2; // U1 = X1 * Z2Z2 - alt_bn128_Fq U2 = (other.X) * Z1Z1; // U2 = X2 * Z1Z1 - alt_bn128_Fq S1 = (this->Y) * (other.Z) * Z2Z2; // S1 = Y1 * Z2 * Z2Z2 - alt_bn128_Fq S2 = (other.Y) * (this->Z) * Z1Z1; // S2 = Y2 * Z1 * Z1Z1 - alt_bn128_Fq H = U2 - U1; // H = U2-U1 - alt_bn128_Fq S2_minus_S1 = S2-S1; - alt_bn128_Fq I = (H+H).squared(); // I = (2 * H)^2 - alt_bn128_Fq J = H * I; // J = H * I - alt_bn128_Fq r = S2_minus_S1 + S2_minus_S1; // r = 2 * (S2-S1) - alt_bn128_Fq V = U1 * I; // V = U1 * I - alt_bn128_Fq X3 = r.squared() - J - (V+V); // X3 = r^2 - J - 2 * V - alt_bn128_Fq S1_J = S1 * J; - alt_bn128_Fq Y3 = r * (V-X3) - (S1_J+S1_J); // Y3 = r * (V-X3)-2 S1 J - alt_bn128_Fq Z3 = ((this->Z+other.Z).squared()-Z1Z1-Z2Z2) * H; // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H - - return alt_bn128_G1(X3, Y3, Z3); -} - -alt_bn128_G1 alt_bn128_G1::mixed_add(const alt_bn128_G1 &other) const -{ -#ifdef DEBUG - assert_except(other.is_special()); -#endif - - // handle special cases having to do with O - if (this->is_zero()) - { - return other; - } - - if (other.is_zero()) - { - return *this; - } - - // no need to handle points of order 2,4 - // (they cannot exist in a prime-order subgroup) - - // check for doubling case - - // using Jacobian coordinates so: - // (X1:Y1:Z1) = (X2:Y2:Z2) - // iff - // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3 - // iff - // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3 - - // we know that Z2 = 1 - - const alt_bn128_Fq Z1Z1 = (this->Z).squared(); - - const alt_bn128_Fq &U1 = this->X; - const alt_bn128_Fq U2 = other.X * Z1Z1; - - const alt_bn128_Fq Z1_cubed = (this->Z) * Z1Z1; - - const alt_bn128_Fq &S1 = (this->Y); // S1 = Y1 * Z2 * Z2Z2 - const alt_bn128_Fq S2 = (other.Y) * Z1_cubed; // S2 = Y2 * Z1 * Z1Z1 - - if (U1 == U2 && S1 == S2) - { - // dbl case; nothing of above can be reused - return this->dbl(); - } - -#ifdef PROFILE_OP_COUNTS - this->add_cnt++; -#endif - - // NOTE: does not handle O and pts of order 2,4 - // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl - alt_bn128_Fq H = U2-(this->X); // H = U2-X1 - alt_bn128_Fq HH = H.squared() ; // HH = H&2 - alt_bn128_Fq I = HH+HH; // I = 4*HH - I = I + I; - alt_bn128_Fq J = H*I; // J = H*I - alt_bn128_Fq r = S2-(this->Y); // r = 2*(S2-Y1) - r = r + r; - alt_bn128_Fq V = (this->X) * I ; // V = X1*I - alt_bn128_Fq X3 = r.squared()-J-V-V; // X3 = r^2-J-2*V - alt_bn128_Fq Y3 = (this->Y)*J; // Y3 = r*(V-X3)-2*Y1*J - Y3 = r*(V-X3) - Y3 - Y3; - alt_bn128_Fq Z3 = ((this->Z)+H).squared() - Z1Z1 - HH; // Z3 = (Z1+H)^2-Z1Z1-HH - - return alt_bn128_G1(X3, Y3, Z3); -} - -alt_bn128_G1 alt_bn128_G1::dbl() const -{ -#ifdef PROFILE_OP_COUNTS - this->dbl_cnt++; -#endif - // handle point at infinity - if (this->is_zero()) - { - return (*this); - } - - // no need to handle points of order 2,4 - // (they cannot exist in a prime-order subgroup) - - // NOTE: does not handle O and pts of order 2,4 - // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l - - alt_bn128_Fq A = (this->X).squared(); // A = X1^2 - alt_bn128_Fq B = (this->Y).squared(); // B = Y1^2 - alt_bn128_Fq C = B.squared(); // C = B^2 - alt_bn128_Fq D = (this->X + B).squared() - A - C; - D = D+D; // D = 2 * ((X1 + B)^2 - A - C) - alt_bn128_Fq E = A + A + A; // E = 3 * A - alt_bn128_Fq F = E.squared(); // F = E^2 - alt_bn128_Fq X3 = F - (D+D); // X3 = F - 2 D - alt_bn128_Fq eightC = C+C; - eightC = eightC + eightC; - eightC = eightC + eightC; - alt_bn128_Fq Y3 = E * (D - X3) - eightC; // Y3 = E * (D - X3) - 8 * C - alt_bn128_Fq Y1Z1 = (this->Y)*(this->Z); - alt_bn128_Fq Z3 = Y1Z1 + Y1Z1; // Z3 = 2 * Y1 * Z1 - - return alt_bn128_G1(X3, Y3, Z3); -} - -bool alt_bn128_G1::is_well_formed() const -{ - if (this->is_zero()) - { - return true; - } - else - { - /* - y^2 = x^3 + b - - We are using Jacobian coordinates, so equation we need to check is actually - - (y/z^3)^2 = (x/z^2)^3 + b - y^2 / z^6 = x^3 / z^6 + b - y^2 = x^3 + b z^6 - */ - alt_bn128_Fq X2 = this->X.squared(); - alt_bn128_Fq Y2 = this->Y.squared(); - alt_bn128_Fq Z2 = this->Z.squared(); - - alt_bn128_Fq X3 = this->X * X2; - alt_bn128_Fq Z3 = this->Z * Z2; - alt_bn128_Fq Z6 = Z3.squared(); - - return (Y2 == X3 + alt_bn128_coeff_b * Z6); - } -} - -alt_bn128_G1 alt_bn128_G1::zero() -{ - return G1_zero; -} - -alt_bn128_G1 alt_bn128_G1::one() -{ - return G1_one; -} - -alt_bn128_G1 alt_bn128_G1::random_element() -{ - return (scalar_field::random_element().as_bigint()) * G1_one; -} - -std::ostream& operator<<(std::ostream &out, const alt_bn128_G1 &g) -{ - alt_bn128_G1 copy(g); - copy.to_affine_coordinates(); - - out << (copy.is_zero() ? 1 : 0) << OUTPUT_SEPARATOR; -#ifdef NO_PT_COMPRESSION - out << copy.X << OUTPUT_SEPARATOR << copy.Y; -#else - /* storing LSB of Y */ - out << copy.X << OUTPUT_SEPARATOR << (copy.Y.as_bigint().data[0] & 1); -#endif - - return out; -} - -std::istream& operator>>(std::istream &in, alt_bn128_G1 &g) -{ - char is_zero; - alt_bn128_Fq tX, tY; - -#ifdef NO_PT_COMPRESSION - in >> is_zero >> tX >> tY; - is_zero -= '0'; -#else - in.read((char*)&is_zero, 1); // this reads is_zero; - is_zero -= '0'; - consume_OUTPUT_SEPARATOR(in); - - unsigned char Y_lsb; - in >> tX; - consume_OUTPUT_SEPARATOR(in); - in.read((char*)&Y_lsb, 1); - Y_lsb -= '0'; - - // y = +/- sqrt(x^3 + b) - if (!is_zero) - { - alt_bn128_Fq tX2 = tX.squared(); - alt_bn128_Fq tY2 = tX2*tX + alt_bn128_coeff_b; - tY = tY2.sqrt(); - - if ((tY.as_bigint().data[0] & 1) != Y_lsb) - { - tY = -tY; - } - } -#endif - // using Jacobian coordinates - if (!is_zero) - { - g.X = tX; - g.Y = tY; - g.Z = alt_bn128_Fq::one(); - } - else - { - g = alt_bn128_G1::zero(); - } - - return in; -} - -std::ostream& operator<<(std::ostream& out, const std::vector &v) -{ - out << v.size() << "\n"; - for (const alt_bn128_G1& t : v) - { - out << t << OUTPUT_NEWLINE; - } - - return out; -} - -std::istream& operator>>(std::istream& in, std::vector &v) -{ - v.clear(); - - size_t s; - in >> s; - consume_newline(in); - - v.reserve(s); - - for (size_t i = 0; i < s; ++i) - { - alt_bn128_G1 g; - in >> g; - consume_OUTPUT_NEWLINE(in); - v.emplace_back(g); - } - - return in; -} - -template<> -void batch_to_special_all_non_zeros(std::vector &vec) -{ - std::vector Z_vec; - Z_vec.reserve(vec.size()); - - for (auto &el: vec) - { - Z_vec.emplace_back(el.Z); - } - batch_invert(Z_vec); - - const alt_bn128_Fq one = alt_bn128_Fq::one(); - - for (size_t i = 0; i < vec.size(); ++i) - { - alt_bn128_Fq Z2 = Z_vec[i].squared(); - alt_bn128_Fq Z3 = Z_vec[i] * Z2; - - vec[i].X = vec[i].X * Z2; - vec[i].Y = vec[i].Y * Z3; - vec[i].Z = one; - } -} - -} // libsnark diff --git a/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g1.hpp b/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g1.hpp deleted file mode 100644 index 567f2fa3f..000000000 --- a/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g1.hpp +++ /dev/null @@ -1,95 +0,0 @@ -/** @file - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef ALT_BN128_G1_HPP_ -#define ALT_BN128_G1_HPP_ -#include -#include "algebra/curves/alt_bn128/alt_bn128_init.hpp" -#include "algebra/curves/curve_utils.hpp" - -namespace libsnark { - -class alt_bn128_G1; -std::ostream& operator<<(std::ostream &, const alt_bn128_G1&); -std::istream& operator>>(std::istream &, alt_bn128_G1&); - -class alt_bn128_G1 { -public: -#ifdef PROFILE_OP_COUNTS - static int64_t add_cnt; - static int64_t dbl_cnt; -#endif - static std::vector wnaf_window_table; - static std::vector fixed_base_exp_window_table; - static alt_bn128_G1 G1_zero; - static alt_bn128_G1 G1_one; - - typedef alt_bn128_Fq base_field; - typedef alt_bn128_Fr scalar_field; - - alt_bn128_Fq X, Y, Z; - - // using Jacobian coordinates - alt_bn128_G1(); - alt_bn128_G1(const alt_bn128_Fq& X, const alt_bn128_Fq& Y, const alt_bn128_Fq& Z) : X(X), Y(Y), Z(Z) {}; - - void print() const; - void print_coordinates() const; - - void to_affine_coordinates(); - void to_special(); - bool is_special() const; - - bool is_zero() const; - - bool operator==(const alt_bn128_G1 &other) const; - bool operator!=(const alt_bn128_G1 &other) const; - - alt_bn128_G1 operator+(const alt_bn128_G1 &other) const; - alt_bn128_G1 operator-() const; - alt_bn128_G1 operator-(const alt_bn128_G1 &other) const; - - alt_bn128_G1 add(const alt_bn128_G1 &other) const; - alt_bn128_G1 mixed_add(const alt_bn128_G1 &other) const; - alt_bn128_G1 dbl() const; - - bool is_well_formed() const; - - static alt_bn128_G1 zero(); - static alt_bn128_G1 one(); - static alt_bn128_G1 random_element(); - - static size_t size_in_bits() { return base_field::size_in_bits() + 1; } - static bigint base_field_char() { return base_field::field_char(); } - static bigint order() { return scalar_field::field_char(); } - - friend std::ostream& operator<<(std::ostream &out, const alt_bn128_G1 &g); - friend std::istream& operator>>(std::istream &in, alt_bn128_G1 &g); -}; - -template -alt_bn128_G1 operator*(const bigint &lhs, const alt_bn128_G1 &rhs) -{ - return scalar_mul(rhs, lhs); -} - -template& modulus_p> -alt_bn128_G1 operator*(const Fp_model &lhs, const alt_bn128_G1 &rhs) -{ - return scalar_mul(rhs, lhs.as_bigint()); -} - -std::ostream& operator<<(std::ostream& out, const std::vector &v); -std::istream& operator>>(std::istream& in, std::vector &v); - -template -void batch_to_special_all_non_zeros(std::vector &vec); -template<> -void batch_to_special_all_non_zeros(std::vector &vec); - -} // libsnark -#endif // ALT_BN128_G1_HPP_ diff --git a/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g2.cpp b/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g2.cpp deleted file mode 100644 index 98f471044..000000000 --- a/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g2.cpp +++ /dev/null @@ -1,506 +0,0 @@ -/** @file - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#include "algebra/curves/alt_bn128/alt_bn128_g2.hpp" -#include "common/assert_except.hpp" - -namespace libsnark { - -#ifdef PROFILE_OP_COUNTS -int64_t alt_bn128_G2::add_cnt = 0; -int64_t alt_bn128_G2::dbl_cnt = 0; -#endif - -std::vector alt_bn128_G2::wnaf_window_table; -std::vector alt_bn128_G2::fixed_base_exp_window_table; -alt_bn128_G2 alt_bn128_G2::G2_zero; -alt_bn128_G2 alt_bn128_G2::G2_one; - -alt_bn128_G2::alt_bn128_G2() -{ - this->X = G2_zero.X; - this->Y = G2_zero.Y; - this->Z = G2_zero.Z; -} - -alt_bn128_Fq2 alt_bn128_G2::mul_by_b(const alt_bn128_Fq2 &elt) -{ - return alt_bn128_Fq2(alt_bn128_twist_mul_by_b_c0 * elt.c0, alt_bn128_twist_mul_by_b_c1 * elt.c1); -} - -void alt_bn128_G2::print() const -{ - if (this->is_zero()) - { - printf("O\n"); - } - else - { - alt_bn128_G2 copy(*this); - copy.to_affine_coordinates(); - gmp_printf("(%Nd*z + %Nd , %Nd*z + %Nd)\n", - copy.X.c1.as_bigint().data, alt_bn128_Fq::num_limbs, - copy.X.c0.as_bigint().data, alt_bn128_Fq::num_limbs, - copy.Y.c1.as_bigint().data, alt_bn128_Fq::num_limbs, - copy.Y.c0.as_bigint().data, alt_bn128_Fq::num_limbs); - } -} - -void alt_bn128_G2::print_coordinates() const -{ - if (this->is_zero()) - { - printf("O\n"); - } - else - { - gmp_printf("(%Nd*z + %Nd : %Nd*z + %Nd : %Nd*z + %Nd)\n", - this->X.c1.as_bigint().data, alt_bn128_Fq::num_limbs, - this->X.c0.as_bigint().data, alt_bn128_Fq::num_limbs, - this->Y.c1.as_bigint().data, alt_bn128_Fq::num_limbs, - this->Y.c0.as_bigint().data, alt_bn128_Fq::num_limbs, - this->Z.c1.as_bigint().data, alt_bn128_Fq::num_limbs, - this->Z.c0.as_bigint().data, alt_bn128_Fq::num_limbs); - } -} - -void alt_bn128_G2::to_affine_coordinates() -{ - if (this->is_zero()) - { - this->X = alt_bn128_Fq2::zero(); - this->Y = alt_bn128_Fq2::one(); - this->Z = alt_bn128_Fq2::zero(); - } - else - { - alt_bn128_Fq2 Z_inv = Z.inverse(); - alt_bn128_Fq2 Z2_inv = Z_inv.squared(); - alt_bn128_Fq2 Z3_inv = Z2_inv * Z_inv; - this->X = this->X * Z2_inv; - this->Y = this->Y * Z3_inv; - this->Z = alt_bn128_Fq2::one(); - } -} - -void alt_bn128_G2::to_special() -{ - this->to_affine_coordinates(); -} - -bool alt_bn128_G2::is_special() const -{ - return (this->is_zero() || this->Z == alt_bn128_Fq2::one()); -} - -bool alt_bn128_G2::is_zero() const -{ - return (this->Z.is_zero()); -} - -bool alt_bn128_G2::operator==(const alt_bn128_G2 &other) const -{ - if (this->is_zero()) - { - return other.is_zero(); - } - - if (other.is_zero()) - { - return false; - } - - /* now neither is O */ - - // using Jacobian coordinates so: - // (X1:Y1:Z1) = (X2:Y2:Z2) - // iff - // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3 - // iff - // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3 - - alt_bn128_Fq2 Z1_squared = (this->Z).squared(); - alt_bn128_Fq2 Z2_squared = (other.Z).squared(); - - if ((this->X * Z2_squared) != (other.X * Z1_squared)) - { - return false; - } - - alt_bn128_Fq2 Z1_cubed = (this->Z) * Z1_squared; - alt_bn128_Fq2 Z2_cubed = (other.Z) * Z2_squared; - - if ((this->Y * Z2_cubed) != (other.Y * Z1_cubed)) - { - return false; - } - - return true; -} - -bool alt_bn128_G2::operator!=(const alt_bn128_G2& other) const -{ - return !(operator==(other)); -} - -alt_bn128_G2 alt_bn128_G2::operator+(const alt_bn128_G2 &other) const -{ - // handle special cases having to do with O - if (this->is_zero()) - { - return other; - } - - if (other.is_zero()) - { - return *this; - } - - // no need to handle points of order 2,4 - // (they cannot exist in a prime-order subgroup) - - // check for doubling case - - // using Jacobian coordinates so: - // (X1:Y1:Z1) = (X2:Y2:Z2) - // iff - // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3 - // iff - // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3 - - alt_bn128_Fq2 Z1Z1 = (this->Z).squared(); - alt_bn128_Fq2 Z2Z2 = (other.Z).squared(); - - alt_bn128_Fq2 U1 = this->X * Z2Z2; - alt_bn128_Fq2 U2 = other.X * Z1Z1; - - alt_bn128_Fq2 Z1_cubed = (this->Z) * Z1Z1; - alt_bn128_Fq2 Z2_cubed = (other.Z) * Z2Z2; - - alt_bn128_Fq2 S1 = (this->Y) * Z2_cubed; // S1 = Y1 * Z2 * Z2Z2 - alt_bn128_Fq2 S2 = (other.Y) * Z1_cubed; // S2 = Y2 * Z1 * Z1Z1 - - if (U1 == U2 && S1 == S2) - { - // dbl case; nothing of above can be reused - return this->dbl(); - } - - // rest of add case - alt_bn128_Fq2 H = U2 - U1; // H = U2-U1 - alt_bn128_Fq2 S2_minus_S1 = S2-S1; - alt_bn128_Fq2 I = (H+H).squared(); // I = (2 * H)^2 - alt_bn128_Fq2 J = H * I; // J = H * I - alt_bn128_Fq2 r = S2_minus_S1 + S2_minus_S1; // r = 2 * (S2-S1) - alt_bn128_Fq2 V = U1 * I; // V = U1 * I - alt_bn128_Fq2 X3 = r.squared() - J - (V+V); // X3 = r^2 - J - 2 * V - alt_bn128_Fq2 S1_J = S1 * J; - alt_bn128_Fq2 Y3 = r * (V-X3) - (S1_J+S1_J); // Y3 = r * (V-X3)-2 S1 J - alt_bn128_Fq2 Z3 = ((this->Z+other.Z).squared()-Z1Z1-Z2Z2) * H; // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H - - return alt_bn128_G2(X3, Y3, Z3); -} - -alt_bn128_G2 alt_bn128_G2::operator-() const -{ - return alt_bn128_G2(this->X, -(this->Y), this->Z); -} - - -alt_bn128_G2 alt_bn128_G2::operator-(const alt_bn128_G2 &other) const -{ - return (*this) + (-other); -} - -alt_bn128_G2 alt_bn128_G2::add(const alt_bn128_G2 &other) const -{ - // handle special cases having to do with O - if (this->is_zero()) - { - return other; - } - - if (other.is_zero()) - { - return *this; - } - - // no need to handle points of order 2,4 - // (they cannot exist in a prime-order subgroup) - - // handle double case - if (this->operator==(other)) - { - return this->dbl(); - } - -#ifdef PROFILE_OP_COUNTS - this->add_cnt++; -#endif - // NOTE: does not handle O and pts of order 2,4 - // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#addition-add-1998-cmo-2 - - alt_bn128_Fq2 Z1Z1 = (this->Z).squared(); // Z1Z1 = Z1^2 - alt_bn128_Fq2 Z2Z2 = (other.Z).squared(); // Z2Z2 = Z2^2 - alt_bn128_Fq2 U1 = (this->X) * Z2Z2; // U1 = X1 * Z2Z2 - alt_bn128_Fq2 U2 = (other.X) * Z1Z1; // U2 = X2 * Z1Z1 - alt_bn128_Fq2 S1 = (this->Y) * (other.Z) * Z2Z2; // S1 = Y1 * Z2 * Z2Z2 - alt_bn128_Fq2 S2 = (other.Y) * (this->Z) * Z1Z1; // S2 = Y2 * Z1 * Z1Z1 - alt_bn128_Fq2 H = U2 - U1; // H = U2-U1 - alt_bn128_Fq2 S2_minus_S1 = S2-S1; - alt_bn128_Fq2 I = (H+H).squared(); // I = (2 * H)^2 - alt_bn128_Fq2 J = H * I; // J = H * I - alt_bn128_Fq2 r = S2_minus_S1 + S2_minus_S1; // r = 2 * (S2-S1) - alt_bn128_Fq2 V = U1 * I; // V = U1 * I - alt_bn128_Fq2 X3 = r.squared() - J - (V+V); // X3 = r^2 - J - 2 * V - alt_bn128_Fq2 S1_J = S1 * J; - alt_bn128_Fq2 Y3 = r * (V-X3) - (S1_J+S1_J); // Y3 = r * (V-X3)-2 S1 J - alt_bn128_Fq2 Z3 = ((this->Z+other.Z).squared()-Z1Z1-Z2Z2) * H; // Z3 = ((Z1+Z2)^2-Z1Z1-Z2Z2) * H - - return alt_bn128_G2(X3, Y3, Z3); -} - -alt_bn128_G2 alt_bn128_G2::mixed_add(const alt_bn128_G2 &other) const -{ -#ifdef DEBUG - assert_except(other.is_special()); -#endif - - // handle special cases having to do with O - if (this->is_zero()) - { - return other; - } - - if (other.is_zero()) - { - return *this; - } - - // no need to handle points of order 2,4 - // (they cannot exist in a prime-order subgroup) - - // check for doubling case - - // using Jacobian coordinates so: - // (X1:Y1:Z1) = (X2:Y2:Z2) - // iff - // X1/Z1^2 == X2/Z2^2 and Y1/Z1^3 == Y2/Z2^3 - // iff - // X1 * Z2^2 == X2 * Z1^2 and Y1 * Z2^3 == Y2 * Z1^3 - - // we know that Z2 = 1 - - const alt_bn128_Fq2 Z1Z1 = (this->Z).squared(); - - const alt_bn128_Fq2 &U1 = this->X; - const alt_bn128_Fq2 U2 = other.X * Z1Z1; - - const alt_bn128_Fq2 Z1_cubed = (this->Z) * Z1Z1; - - const alt_bn128_Fq2 &S1 = (this->Y); // S1 = Y1 * Z2 * Z2Z2 - const alt_bn128_Fq2 S2 = (other.Y) * Z1_cubed; // S2 = Y2 * Z1 * Z1Z1 - - if (U1 == U2 && S1 == S2) - { - // dbl case; nothing of above can be reused - return this->dbl(); - } - -#ifdef PROFILE_OP_COUNTS - this->add_cnt++; -#endif - - // NOTE: does not handle O and pts of order 2,4 - // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl - alt_bn128_Fq2 H = U2-(this->X); // H = U2-X1 - alt_bn128_Fq2 HH = H.squared() ; // HH = H&2 - alt_bn128_Fq2 I = HH+HH; // I = 4*HH - I = I + I; - alt_bn128_Fq2 J = H*I; // J = H*I - alt_bn128_Fq2 r = S2-(this->Y); // r = 2*(S2-Y1) - r = r + r; - alt_bn128_Fq2 V = (this->X) * I ; // V = X1*I - alt_bn128_Fq2 X3 = r.squared()-J-V-V; // X3 = r^2-J-2*V - alt_bn128_Fq2 Y3 = (this->Y)*J; // Y3 = r*(V-X3)-2*Y1*J - Y3 = r*(V-X3) - Y3 - Y3; - alt_bn128_Fq2 Z3 = ((this->Z)+H).squared() - Z1Z1 - HH; // Z3 = (Z1+H)^2-Z1Z1-HH - - return alt_bn128_G2(X3, Y3, Z3); -} - -alt_bn128_G2 alt_bn128_G2::dbl() const -{ -#ifdef PROFILE_OP_COUNTS - this->dbl_cnt++; -#endif - // handle point at infinity - if (this->is_zero()) - { - return (*this); - } - - // NOTE: does not handle O and pts of order 2,4 - // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective.html#doubling-dbl-2007-bl - - alt_bn128_Fq2 A = (this->X).squared(); // A = X1^2 - alt_bn128_Fq2 B = (this->Y).squared(); // B = Y1^2 - alt_bn128_Fq2 C = B.squared(); // C = B^2 - alt_bn128_Fq2 D = (this->X + B).squared() - A - C; - D = D+D; // D = 2 * ((X1 + B)^2 - A - C) - alt_bn128_Fq2 E = A + A + A; // E = 3 * A - alt_bn128_Fq2 F = E.squared(); // F = E^2 - alt_bn128_Fq2 X3 = F - (D+D); // X3 = F - 2 D - alt_bn128_Fq2 eightC = C+C; - eightC = eightC + eightC; - eightC = eightC + eightC; - alt_bn128_Fq2 Y3 = E * (D - X3) - eightC; // Y3 = E * (D - X3) - 8 * C - alt_bn128_Fq2 Y1Z1 = (this->Y)*(this->Z); - alt_bn128_Fq2 Z3 = Y1Z1 + Y1Z1; // Z3 = 2 * Y1 * Z1 - - return alt_bn128_G2(X3, Y3, Z3); -} - -alt_bn128_G2 alt_bn128_G2::mul_by_q() const -{ - return alt_bn128_G2(alt_bn128_twist_mul_by_q_X * (this->X).Frobenius_map(1), - alt_bn128_twist_mul_by_q_Y * (this->Y).Frobenius_map(1), - (this->Z).Frobenius_map(1)); -} - -bool alt_bn128_G2::is_well_formed() const -{ - if (this->is_zero()) - { - return true; - } - else - { - /* - y^2 = x^3 + b - - We are using Jacobian coordinates, so equation we need to check is actually - - (y/z^3)^2 = (x/z^2)^3 + b - y^2 / z^6 = x^3 / z^6 + b - y^2 = x^3 + b z^6 - */ - alt_bn128_Fq2 X2 = this->X.squared(); - alt_bn128_Fq2 Y2 = this->Y.squared(); - alt_bn128_Fq2 Z2 = this->Z.squared(); - - alt_bn128_Fq2 X3 = this->X * X2; - alt_bn128_Fq2 Z3 = this->Z * Z2; - alt_bn128_Fq2 Z6 = Z3.squared(); - - return (Y2 == X3 + alt_bn128_twist_coeff_b * Z6); - } -} - -alt_bn128_G2 alt_bn128_G2::zero() -{ - return G2_zero; -} - -alt_bn128_G2 alt_bn128_G2::one() -{ - return G2_one; -} - -alt_bn128_G2 alt_bn128_G2::random_element() -{ - return (alt_bn128_Fr::random_element().as_bigint()) * G2_one; -} - -std::ostream& operator<<(std::ostream &out, const alt_bn128_G2 &g) -{ - alt_bn128_G2 copy(g); - copy.to_affine_coordinates(); - out << (copy.is_zero() ? 1 : 0) << OUTPUT_SEPARATOR; -#ifdef NO_PT_COMPRESSION - out << copy.X << OUTPUT_SEPARATOR << copy.Y; -#else - /* storing LSB of Y */ - out << copy.X << OUTPUT_SEPARATOR << (copy.Y.c0.as_bigint().data[0] & 1); -#endif - - return out; -} - -std::istream& operator>>(std::istream &in, alt_bn128_G2 &g) -{ - char is_zero; - alt_bn128_Fq2 tX, tY; - -#ifdef NO_PT_COMPRESSION - in >> is_zero >> tX >> tY; - is_zero -= '0'; -#else - in.read((char*)&is_zero, 1); // this reads is_zero; - is_zero -= '0'; - consume_OUTPUT_SEPARATOR(in); - - unsigned char Y_lsb; - in >> tX; - consume_OUTPUT_SEPARATOR(in); - in.read((char*)&Y_lsb, 1); - Y_lsb -= '0'; - - // y = +/- sqrt(x^3 + b) - if (!is_zero) - { - alt_bn128_Fq2 tX2 = tX.squared(); - alt_bn128_Fq2 tY2 = tX2 * tX + alt_bn128_twist_coeff_b; - tY = tY2.sqrt(); - - if ((tY.c0.as_bigint().data[0] & 1) != Y_lsb) - { - tY = -tY; - } - } -#endif - // using projective coordinates - if (!is_zero) - { - g.X = tX; - g.Y = tY; - g.Z = alt_bn128_Fq2::one(); - } - else - { - g = alt_bn128_G2::zero(); - } - - return in; -} - -template<> -void batch_to_special_all_non_zeros(std::vector &vec) -{ - std::vector Z_vec; - Z_vec.reserve(vec.size()); - - for (auto &el: vec) - { - Z_vec.emplace_back(el.Z); - } - batch_invert(Z_vec); - - const alt_bn128_Fq2 one = alt_bn128_Fq2::one(); - - for (size_t i = 0; i < vec.size(); ++i) - { - alt_bn128_Fq2 Z2 = Z_vec[i].squared(); - alt_bn128_Fq2 Z3 = Z_vec[i] * Z2; - - vec[i].X = vec[i].X * Z2; - vec[i].Y = vec[i].Y * Z3; - vec[i].Z = one; - } -} - -} // libsnark diff --git a/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g2.hpp b/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g2.hpp deleted file mode 100644 index 57bad1a4b..000000000 --- a/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g2.hpp +++ /dev/null @@ -1,96 +0,0 @@ -/** @file - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef ALT_BN128_G2_HPP_ -#define ALT_BN128_G2_HPP_ -#include -#include "algebra/curves/alt_bn128/alt_bn128_init.hpp" -#include "algebra/curves/curve_utils.hpp" - -namespace libsnark { - -class alt_bn128_G2; -std::ostream& operator<<(std::ostream &, const alt_bn128_G2&); -std::istream& operator>>(std::istream &, alt_bn128_G2&); - -class alt_bn128_G2 { -public: -#ifdef PROFILE_OP_COUNTS - static int64_t add_cnt; - static int64_t dbl_cnt; -#endif - static std::vector wnaf_window_table; - static std::vector fixed_base_exp_window_table; - static alt_bn128_G2 G2_zero; - static alt_bn128_G2 G2_one; - - typedef alt_bn128_Fq base_field; - typedef alt_bn128_Fq2 twist_field; - typedef alt_bn128_Fr scalar_field; - - alt_bn128_Fq2 X, Y, Z; - - // using Jacobian coordinates - alt_bn128_G2(); - alt_bn128_G2(const alt_bn128_Fq2& X, const alt_bn128_Fq2& Y, const alt_bn128_Fq2& Z) : X(X), Y(Y), Z(Z) {}; - - static alt_bn128_Fq2 mul_by_b(const alt_bn128_Fq2 &elt); - - void print() const; - void print_coordinates() const; - - void to_affine_coordinates(); - void to_special(); - bool is_special() const; - - bool is_zero() const; - - bool operator==(const alt_bn128_G2 &other) const; - bool operator!=(const alt_bn128_G2 &other) const; - - alt_bn128_G2 operator+(const alt_bn128_G2 &other) const; - alt_bn128_G2 operator-() const; - alt_bn128_G2 operator-(const alt_bn128_G2 &other) const; - - alt_bn128_G2 add(const alt_bn128_G2 &other) const; - alt_bn128_G2 mixed_add(const alt_bn128_G2 &other) const; - alt_bn128_G2 dbl() const; - alt_bn128_G2 mul_by_q() const; - - bool is_well_formed() const; - - static alt_bn128_G2 zero(); - static alt_bn128_G2 one(); - static alt_bn128_G2 random_element(); - - static size_t size_in_bits() { return twist_field::size_in_bits() + 1; } - static bigint base_field_char() { return base_field::field_char(); } - static bigint order() { return scalar_field::field_char(); } - - friend std::ostream& operator<<(std::ostream &out, const alt_bn128_G2 &g); - friend std::istream& operator>>(std::istream &in, alt_bn128_G2 &g); -}; - -template -alt_bn128_G2 operator*(const bigint &lhs, const alt_bn128_G2 &rhs) -{ - return scalar_mul(rhs, lhs); -} - -template& modulus_p> -alt_bn128_G2 operator*(const Fp_model &lhs, const alt_bn128_G2 &rhs) -{ - return scalar_mul(rhs, lhs.as_bigint()); -} - -template -void batch_to_special_all_non_zeros(std::vector &vec); -template<> -void batch_to_special_all_non_zeros(std::vector &vec); - -} // libsnark -#endif // ALT_BN128_G2_HPP_ diff --git a/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_init.cpp b/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_init.cpp deleted file mode 100644 index 7c23773d6..000000000 --- a/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_init.cpp +++ /dev/null @@ -1,273 +0,0 @@ -/** @file - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#include "algebra/curves/alt_bn128/alt_bn128_init.hpp" -#include "algebra/curves/alt_bn128/alt_bn128_g1.hpp" -#include "algebra/curves/alt_bn128/alt_bn128_g2.hpp" - -namespace libsnark { - -bigint alt_bn128_modulus_r; -bigint alt_bn128_modulus_q; - -alt_bn128_Fq alt_bn128_coeff_b; -alt_bn128_Fq2 alt_bn128_twist; -alt_bn128_Fq2 alt_bn128_twist_coeff_b; -alt_bn128_Fq alt_bn128_twist_mul_by_b_c0; -alt_bn128_Fq alt_bn128_twist_mul_by_b_c1; -alt_bn128_Fq2 alt_bn128_twist_mul_by_q_X; -alt_bn128_Fq2 alt_bn128_twist_mul_by_q_Y; - -bigint alt_bn128_ate_loop_count; -bool alt_bn128_ate_is_loop_count_neg; -bigint<12*alt_bn128_q_limbs> alt_bn128_final_exponent; -bigint alt_bn128_final_exponent_z; -bool alt_bn128_final_exponent_is_z_neg; - -void init_alt_bn128_params() -{ - typedef bigint bigint_r; - typedef bigint bigint_q; - - assert(sizeof(mp_limb_t) == 8 || sizeof(mp_limb_t) == 4); // Montgomery assumes this - - /* parameters for scalar field Fr */ - - alt_bn128_modulus_r = bigint_r("21888242871839275222246405745257275088548364400416034343698204186575808495617"); - assert(alt_bn128_Fr::modulus_is_valid()); - if (sizeof(mp_limb_t) == 8) - { - alt_bn128_Fr::Rsquared = bigint_r("944936681149208446651664254269745548490766851729442924617792859073125903783"); - alt_bn128_Fr::Rcubed = bigint_r("5866548545943845227489894872040244720403868105578784105281690076696998248512"); - alt_bn128_Fr::inv = 0xc2e1f593efffffff; - } - if (sizeof(mp_limb_t) == 4) - { - alt_bn128_Fr::Rsquared = bigint_r("944936681149208446651664254269745548490766851729442924617792859073125903783"); - alt_bn128_Fr::Rcubed = bigint_r("5866548545943845227489894872040244720403868105578784105281690076696998248512"); - alt_bn128_Fr::inv = 0xefffffff; - } - alt_bn128_Fr::num_bits = 254; - alt_bn128_Fr::euler = bigint_r("10944121435919637611123202872628637544274182200208017171849102093287904247808"); - alt_bn128_Fr::s = 28; - alt_bn128_Fr::t = bigint_r("81540058820840996586704275553141814055101440848469862132140264610111"); - alt_bn128_Fr::t_minus_1_over_2 = bigint_r("40770029410420498293352137776570907027550720424234931066070132305055"); - alt_bn128_Fr::multiplicative_generator = alt_bn128_Fr("5"); - alt_bn128_Fr::root_of_unity = alt_bn128_Fr("19103219067921713944291392827692070036145651957329286315305642004821462161904"); - alt_bn128_Fr::nqr = alt_bn128_Fr("5"); - alt_bn128_Fr::nqr_to_t = alt_bn128_Fr("19103219067921713944291392827692070036145651957329286315305642004821462161904"); - - /* parameters for base field Fq */ - - alt_bn128_modulus_q = bigint_q("21888242871839275222246405745257275088696311157297823662689037894645226208583"); - assert(alt_bn128_Fq::modulus_is_valid()); - if (sizeof(mp_limb_t) == 8) - { - alt_bn128_Fq::Rsquared = bigint_q("3096616502983703923843567936837374451735540968419076528771170197431451843209"); - alt_bn128_Fq::Rcubed = bigint_q("14921786541159648185948152738563080959093619838510245177710943249661917737183"); - alt_bn128_Fq::inv = 0x87d20782e4866389; - } - if (sizeof(mp_limb_t) == 4) - { - alt_bn128_Fq::Rsquared = bigint_q("3096616502983703923843567936837374451735540968419076528771170197431451843209"); - alt_bn128_Fq::Rcubed = bigint_q("14921786541159648185948152738563080959093619838510245177710943249661917737183"); - alt_bn128_Fq::inv = 0xe4866389; - } - alt_bn128_Fq::num_bits = 254; - alt_bn128_Fq::euler = bigint_q("10944121435919637611123202872628637544348155578648911831344518947322613104291"); - alt_bn128_Fq::s = 1; - alt_bn128_Fq::t = bigint_q("10944121435919637611123202872628637544348155578648911831344518947322613104291"); - alt_bn128_Fq::t_minus_1_over_2 = bigint_q("5472060717959818805561601436314318772174077789324455915672259473661306552145"); - alt_bn128_Fq::multiplicative_generator = alt_bn128_Fq("3"); - alt_bn128_Fq::root_of_unity = alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); - alt_bn128_Fq::nqr = alt_bn128_Fq("3"); - alt_bn128_Fq::nqr_to_t = alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); - - /* parameters for twist field Fq2 */ - alt_bn128_Fq2::euler = bigint<2*alt_bn128_q_limbs>("239547588008311421220994022608339370399626158265550411218223901127035046843189118723920525909718935985594116157406550130918127817069793474323196511433944"); - alt_bn128_Fq2::s = 4; - alt_bn128_Fq2::t = bigint<2*alt_bn128_q_limbs>("29943448501038927652624252826042421299953269783193801402277987640879380855398639840490065738714866998199264519675818766364765977133724184290399563929243"); - alt_bn128_Fq2::t_minus_1_over_2 = bigint<2*alt_bn128_q_limbs>("14971724250519463826312126413021210649976634891596900701138993820439690427699319920245032869357433499099632259837909383182382988566862092145199781964621"); - alt_bn128_Fq2::non_residue = alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); - alt_bn128_Fq2::nqr = alt_bn128_Fq2(alt_bn128_Fq("2"),alt_bn128_Fq("1")); - alt_bn128_Fq2::nqr_to_t = alt_bn128_Fq2(alt_bn128_Fq("5033503716262624267312492558379982687175200734934877598599011485707452665730"),alt_bn128_Fq("314498342015008975724433667930697407966947188435857772134235984660852259084")); - alt_bn128_Fq2::Frobenius_coeffs_c1[0] = alt_bn128_Fq("1"); - alt_bn128_Fq2::Frobenius_coeffs_c1[1] = alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"); - - /* parameters for Fq6 */ - alt_bn128_Fq6::non_residue = alt_bn128_Fq2(alt_bn128_Fq("9"),alt_bn128_Fq("1")); - alt_bn128_Fq6::Frobenius_coeffs_c1[0] = alt_bn128_Fq2(alt_bn128_Fq("1"),alt_bn128_Fq("0")); - alt_bn128_Fq6::Frobenius_coeffs_c1[1] = alt_bn128_Fq2(alt_bn128_Fq("21575463638280843010398324269430826099269044274347216827212613867836435027261"),alt_bn128_Fq("10307601595873709700152284273816112264069230130616436755625194854815875713954")); - alt_bn128_Fq6::Frobenius_coeffs_c1[2] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275220042445260109153167277707414472061641714758635765020556616"),alt_bn128_Fq("0")); - alt_bn128_Fq6::Frobenius_coeffs_c1[3] = alt_bn128_Fq2(alt_bn128_Fq("3772000881919853776433695186713858239009073593817195771773381919316419345261"),alt_bn128_Fq("2236595495967245188281701248203181795121068902605861227855261137820944008926")); - alt_bn128_Fq6::Frobenius_coeffs_c1[4] = alt_bn128_Fq2(alt_bn128_Fq("2203960485148121921418603742825762020974279258880205651966"),alt_bn128_Fq("0")); - alt_bn128_Fq6::Frobenius_coeffs_c1[5] = alt_bn128_Fq2(alt_bn128_Fq("18429021223477853657660792034369865839114504446431234726392080002137598044644"),alt_bn128_Fq("9344045779998320333812420223237981029506012124075525679208581902008406485703")); - alt_bn128_Fq6::Frobenius_coeffs_c2[0] = alt_bn128_Fq2(alt_bn128_Fq("1"),alt_bn128_Fq("0")); - alt_bn128_Fq6::Frobenius_coeffs_c2[1] = alt_bn128_Fq2(alt_bn128_Fq("2581911344467009335267311115468803099551665605076196740867805258568234346338"),alt_bn128_Fq("19937756971775647987995932169929341994314640652964949448313374472400716661030")); - alt_bn128_Fq6::Frobenius_coeffs_c2[2] = alt_bn128_Fq2(alt_bn128_Fq("2203960485148121921418603742825762020974279258880205651966"),alt_bn128_Fq("0")); - alt_bn128_Fq6::Frobenius_coeffs_c2[3] = alt_bn128_Fq2(alt_bn128_Fq("5324479202449903542726783395506214481928257762400643279780343368557297135718"),alt_bn128_Fq("16208900380737693084919495127334387981393726419856888799917914180988844123039")); - alt_bn128_Fq6::Frobenius_coeffs_c2[4] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275220042445260109153167277707414472061641714758635765020556616"),alt_bn128_Fq("0")); - alt_bn128_Fq6::Frobenius_coeffs_c2[5] = alt_bn128_Fq2(alt_bn128_Fq("13981852324922362344252311234282257507216387789820983642040889267519694726527"),alt_bn128_Fq("7629828391165209371577384193250820201684255241773809077146787135900891633097")); - - /* parameters for Fq12 */ - - alt_bn128_Fq12::non_residue = alt_bn128_Fq2(alt_bn128_Fq("9"),alt_bn128_Fq("1")); - alt_bn128_Fq12::Frobenius_coeffs_c1[0] = alt_bn128_Fq2(alt_bn128_Fq("1"),alt_bn128_Fq("0")); - alt_bn128_Fq12::Frobenius_coeffs_c1[1] = alt_bn128_Fq2(alt_bn128_Fq("8376118865763821496583973867626364092589906065868298776909617916018768340080"),alt_bn128_Fq("16469823323077808223889137241176536799009286646108169935659301613961712198316")); - alt_bn128_Fq12::Frobenius_coeffs_c1[2] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275220042445260109153167277707414472061641714758635765020556617"),alt_bn128_Fq("0")); - alt_bn128_Fq12::Frobenius_coeffs_c1[3] = alt_bn128_Fq2(alt_bn128_Fq("11697423496358154304825782922584725312912383441159505038794027105778954184319"),alt_bn128_Fq("303847389135065887422783454877609941456349188919719272345083954437860409601")); - alt_bn128_Fq12::Frobenius_coeffs_c1[4] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275220042445260109153167277707414472061641714758635765020556616"),alt_bn128_Fq("0")); - alt_bn128_Fq12::Frobenius_coeffs_c1[5] = alt_bn128_Fq2(alt_bn128_Fq("3321304630594332808241809054958361220322477375291206261884409189760185844239"),alt_bn128_Fq("5722266937896532885780051958958348231143373700109372999374820235121374419868")); - alt_bn128_Fq12::Frobenius_coeffs_c1[6] = alt_bn128_Fq2(alt_bn128_Fq("21888242871839275222246405745257275088696311157297823662689037894645226208582"),alt_bn128_Fq("0")); - alt_bn128_Fq12::Frobenius_coeffs_c1[7] = alt_bn128_Fq2(alt_bn128_Fq("13512124006075453725662431877630910996106405091429524885779419978626457868503"),alt_bn128_Fq("5418419548761466998357268504080738289687024511189653727029736280683514010267")); - alt_bn128_Fq12::Frobenius_coeffs_c1[8] = alt_bn128_Fq2(alt_bn128_Fq("2203960485148121921418603742825762020974279258880205651966"),alt_bn128_Fq("0")); - alt_bn128_Fq12::Frobenius_coeffs_c1[9] = alt_bn128_Fq2(alt_bn128_Fq("10190819375481120917420622822672549775783927716138318623895010788866272024264"),alt_bn128_Fq("21584395482704209334823622290379665147239961968378104390343953940207365798982")); - alt_bn128_Fq12::Frobenius_coeffs_c1[10] = alt_bn128_Fq2(alt_bn128_Fq("2203960485148121921418603742825762020974279258880205651967"),alt_bn128_Fq("0")); - alt_bn128_Fq12::Frobenius_coeffs_c1[11] = alt_bn128_Fq2(alt_bn128_Fq("18566938241244942414004596690298913868373833782006617400804628704885040364344"),alt_bn128_Fq("16165975933942742336466353786298926857552937457188450663314217659523851788715")); - - /* choice of short Weierstrass curve and its twist */ - - alt_bn128_coeff_b = alt_bn128_Fq("3"); - alt_bn128_twist = alt_bn128_Fq2(alt_bn128_Fq("9"), alt_bn128_Fq("1")); - alt_bn128_twist_coeff_b = alt_bn128_coeff_b * alt_bn128_twist.inverse(); - alt_bn128_twist_mul_by_b_c0 = alt_bn128_coeff_b * alt_bn128_Fq2::non_residue; - alt_bn128_twist_mul_by_b_c1 = alt_bn128_coeff_b * alt_bn128_Fq2::non_residue; - alt_bn128_twist_mul_by_q_X = alt_bn128_Fq2(alt_bn128_Fq("21575463638280843010398324269430826099269044274347216827212613867836435027261"), - alt_bn128_Fq("10307601595873709700152284273816112264069230130616436755625194854815875713954")); - alt_bn128_twist_mul_by_q_Y = alt_bn128_Fq2(alt_bn128_Fq("2821565182194536844548159561693502659359617185244120367078079554186484126554"), - alt_bn128_Fq("3505843767911556378687030309984248845540243509899259641013678093033130930403")); - - /* choice of group G1 */ - alt_bn128_G1::G1_zero = alt_bn128_G1(alt_bn128_Fq::zero(), - alt_bn128_Fq::one(), - alt_bn128_Fq::zero()); - alt_bn128_G1::G1_one = alt_bn128_G1(alt_bn128_Fq("1"), - alt_bn128_Fq("2"), - alt_bn128_Fq::one()); - alt_bn128_G1::wnaf_window_table.push_back(11); - alt_bn128_G1::wnaf_window_table.push_back(24); - alt_bn128_G1::wnaf_window_table.push_back(60); - alt_bn128_G1::wnaf_window_table.push_back(127); - - alt_bn128_G1::fixed_base_exp_window_table.resize(0); - // window 1 is unbeaten in [-inf, 4.99] - alt_bn128_G1::fixed_base_exp_window_table.push_back(1); - // window 2 is unbeaten in [4.99, 10.99] - alt_bn128_G1::fixed_base_exp_window_table.push_back(5); - // window 3 is unbeaten in [10.99, 32.29] - alt_bn128_G1::fixed_base_exp_window_table.push_back(11); - // window 4 is unbeaten in [32.29, 55.23] - alt_bn128_G1::fixed_base_exp_window_table.push_back(32); - // window 5 is unbeaten in [55.23, 162.03] - alt_bn128_G1::fixed_base_exp_window_table.push_back(55); - // window 6 is unbeaten in [162.03, 360.15] - alt_bn128_G1::fixed_base_exp_window_table.push_back(162); - // window 7 is unbeaten in [360.15, 815.44] - alt_bn128_G1::fixed_base_exp_window_table.push_back(360); - // window 8 is unbeaten in [815.44, 2373.07] - alt_bn128_G1::fixed_base_exp_window_table.push_back(815); - // window 9 is unbeaten in [2373.07, 6977.75] - alt_bn128_G1::fixed_base_exp_window_table.push_back(2373); - // window 10 is unbeaten in [6977.75, 7122.23] - alt_bn128_G1::fixed_base_exp_window_table.push_back(6978); - // window 11 is unbeaten in [7122.23, 57818.46] - alt_bn128_G1::fixed_base_exp_window_table.push_back(7122); - // window 12 is never the best - alt_bn128_G1::fixed_base_exp_window_table.push_back(0); - // window 13 is unbeaten in [57818.46, 169679.14] - alt_bn128_G1::fixed_base_exp_window_table.push_back(57818); - // window 14 is never the best - alt_bn128_G1::fixed_base_exp_window_table.push_back(0); - // window 15 is unbeaten in [169679.14, 439758.91] - alt_bn128_G1::fixed_base_exp_window_table.push_back(169679); - // window 16 is unbeaten in [439758.91, 936073.41] - alt_bn128_G1::fixed_base_exp_window_table.push_back(439759); - // window 17 is unbeaten in [936073.41, 4666554.74] - alt_bn128_G1::fixed_base_exp_window_table.push_back(936073); - // window 18 is never the best - alt_bn128_G1::fixed_base_exp_window_table.push_back(0); - // window 19 is unbeaten in [4666554.74, 7580404.42] - alt_bn128_G1::fixed_base_exp_window_table.push_back(4666555); - // window 20 is unbeaten in [7580404.42, 34552892.20] - alt_bn128_G1::fixed_base_exp_window_table.push_back(7580404); - // window 21 is never the best - alt_bn128_G1::fixed_base_exp_window_table.push_back(0); - // window 22 is unbeaten in [34552892.20, inf] - alt_bn128_G1::fixed_base_exp_window_table.push_back(34552892); - - /* choice of group G2 */ - - alt_bn128_G2::G2_zero = alt_bn128_G2(alt_bn128_Fq2::zero(), - alt_bn128_Fq2::one(), - alt_bn128_Fq2::zero()); - - alt_bn128_G2::G2_one = alt_bn128_G2(alt_bn128_Fq2(alt_bn128_Fq("10857046999023057135944570762232829481370756359578518086990519993285655852781"), - alt_bn128_Fq("11559732032986387107991004021392285783925812861821192530917403151452391805634")), - alt_bn128_Fq2(alt_bn128_Fq("8495653923123431417604973247489272438418190587263600148770280649306958101930"), - alt_bn128_Fq("4082367875863433681332203403145435568316851327593401208105741076214120093531")), - alt_bn128_Fq2::one()); - alt_bn128_G2::wnaf_window_table.push_back(5); - alt_bn128_G2::wnaf_window_table.push_back(15); - alt_bn128_G2::wnaf_window_table.push_back(39); - alt_bn128_G2::wnaf_window_table.push_back(109); - - alt_bn128_G2::fixed_base_exp_window_table.resize(0); - // window 1 is unbeaten in [-inf, 5.10] - alt_bn128_G2::fixed_base_exp_window_table.push_back(1); - // window 2 is unbeaten in [5.10, 10.43] - alt_bn128_G2::fixed_base_exp_window_table.push_back(5); - // window 3 is unbeaten in [10.43, 25.28] - alt_bn128_G2::fixed_base_exp_window_table.push_back(10); - // window 4 is unbeaten in [25.28, 59.00] - alt_bn128_G2::fixed_base_exp_window_table.push_back(25); - // window 5 is unbeaten in [59.00, 154.03] - alt_bn128_G2::fixed_base_exp_window_table.push_back(59); - // window 6 is unbeaten in [154.03, 334.25] - alt_bn128_G2::fixed_base_exp_window_table.push_back(154); - // window 7 is unbeaten in [334.25, 742.58] - alt_bn128_G2::fixed_base_exp_window_table.push_back(334); - // window 8 is unbeaten in [742.58, 2034.40] - alt_bn128_G2::fixed_base_exp_window_table.push_back(743); - // window 9 is unbeaten in [2034.40, 4987.56] - alt_bn128_G2::fixed_base_exp_window_table.push_back(2034); - // window 10 is unbeaten in [4987.56, 8888.27] - alt_bn128_G2::fixed_base_exp_window_table.push_back(4988); - // window 11 is unbeaten in [8888.27, 26271.13] - alt_bn128_G2::fixed_base_exp_window_table.push_back(8888); - // window 12 is unbeaten in [26271.13, 39768.20] - alt_bn128_G2::fixed_base_exp_window_table.push_back(26271); - // window 13 is unbeaten in [39768.20, 106275.75] - alt_bn128_G2::fixed_base_exp_window_table.push_back(39768); - // window 14 is unbeaten in [106275.75, 141703.40] - alt_bn128_G2::fixed_base_exp_window_table.push_back(106276); - // window 15 is unbeaten in [141703.40, 462422.97] - alt_bn128_G2::fixed_base_exp_window_table.push_back(141703); - // window 16 is unbeaten in [462422.97, 926871.84] - alt_bn128_G2::fixed_base_exp_window_table.push_back(462423); - // window 17 is unbeaten in [926871.84, 4873049.17] - alt_bn128_G2::fixed_base_exp_window_table.push_back(926872); - // window 18 is never the best - alt_bn128_G2::fixed_base_exp_window_table.push_back(0); - // window 19 is unbeaten in [4873049.17, 5706707.88] - alt_bn128_G2::fixed_base_exp_window_table.push_back(4873049); - // window 20 is unbeaten in [5706707.88, 31673814.95] - alt_bn128_G2::fixed_base_exp_window_table.push_back(5706708); - // window 21 is never the best - alt_bn128_G2::fixed_base_exp_window_table.push_back(0); - // window 22 is unbeaten in [31673814.95, inf] - alt_bn128_G2::fixed_base_exp_window_table.push_back(31673815); - - /* pairing parameters */ - - alt_bn128_ate_loop_count = bigint_q("29793968203157093288"); - alt_bn128_ate_is_loop_count_neg = false; - alt_bn128_final_exponent = bigint<12*alt_bn128_q_limbs>("552484233613224096312617126783173147097382103762957654188882734314196910839907541213974502761540629817009608548654680343627701153829446747810907373256841551006201639677726139946029199968412598804882391702273019083653272047566316584365559776493027495458238373902875937659943504873220554161550525926302303331747463515644711876653177129578303191095900909191624817826566688241804408081892785725967931714097716709526092261278071952560171111444072049229123565057483750161460024353346284167282452756217662335528813519139808291170539072125381230815729071544861602750936964829313608137325426383735122175229541155376346436093930287402089517426973178917569713384748081827255472576937471496195752727188261435633271238710131736096299798168852925540549342330775279877006784354801422249722573783561685179618816480037695005515426162362431072245638324744480"); - alt_bn128_final_exponent_z = bigint_q("4965661367192848881"); - alt_bn128_final_exponent_is_z_neg = false; - -} -} // libsnark diff --git a/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_init.hpp b/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_init.hpp deleted file mode 100644 index c3bea7673..000000000 --- a/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_init.hpp +++ /dev/null @@ -1,57 +0,0 @@ -/** @file - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef ALT_BN128_INIT_HPP_ -#define ALT_BN128_INIT_HPP_ -#include "algebra/curves/public_params.hpp" -#include "algebra/fields/fp.hpp" -#include "algebra/fields/fp2.hpp" -#include "algebra/fields/fp6_3over2.hpp" -#include "algebra/fields/fp12_2over3over2.hpp" - -namespace libsnark { - -const mp_size_t alt_bn128_r_bitcount = 254; -const mp_size_t alt_bn128_q_bitcount = 254; - -const mp_size_t alt_bn128_r_limbs = (alt_bn128_r_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; -const mp_size_t alt_bn128_q_limbs = (alt_bn128_q_bitcount+GMP_NUMB_BITS-1)/GMP_NUMB_BITS; - -extern bigint alt_bn128_modulus_r; -extern bigint alt_bn128_modulus_q; - -typedef Fp_model alt_bn128_Fr; -typedef Fp_model alt_bn128_Fq; -typedef Fp2_model alt_bn128_Fq2; -typedef Fp6_3over2_model alt_bn128_Fq6; -typedef Fp12_2over3over2_model alt_bn128_Fq12; -typedef alt_bn128_Fq12 alt_bn128_GT; - -// parameters for Barreto--Naehrig curve E/Fq : y^2 = x^3 + b -extern alt_bn128_Fq alt_bn128_coeff_b; -// parameters for twisted Barreto--Naehrig curve E'/Fq2 : y^2 = x^3 + b/xi -extern alt_bn128_Fq2 alt_bn128_twist; -extern alt_bn128_Fq2 alt_bn128_twist_coeff_b; -extern alt_bn128_Fq alt_bn128_twist_mul_by_b_c0; -extern alt_bn128_Fq alt_bn128_twist_mul_by_b_c1; -extern alt_bn128_Fq2 alt_bn128_twist_mul_by_q_X; -extern alt_bn128_Fq2 alt_bn128_twist_mul_by_q_Y; - -// parameters for pairing -extern bigint alt_bn128_ate_loop_count; -extern bool alt_bn128_ate_is_loop_count_neg; -extern bigint<12*alt_bn128_q_limbs> alt_bn128_final_exponent; -extern bigint alt_bn128_final_exponent_z; -extern bool alt_bn128_final_exponent_is_z_neg; - -void init_alt_bn128_params(); - -class alt_bn128_G1; -class alt_bn128_G2; - -} // libsnark -#endif // ALT_BN128_INIT_HPP_ diff --git a/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pairing.cpp b/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pairing.cpp deleted file mode 100644 index 07b6a8c71..000000000 --- a/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pairing.cpp +++ /dev/null @@ -1,547 +0,0 @@ -/** @file - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#include "algebra/curves/alt_bn128/alt_bn128_pairing.hpp" -#include "algebra/curves/alt_bn128/alt_bn128_init.hpp" -#include "algebra/curves/alt_bn128/alt_bn128_g1.hpp" -#include "algebra/curves/alt_bn128/alt_bn128_g2.hpp" -#include -#include "common/profiling.hpp" -#include "common/assert_except.hpp" - -namespace libsnark { - -bool alt_bn128_ate_G1_precomp::operator==(const alt_bn128_ate_G1_precomp &other) const -{ - return (this->PX == other.PX && - this->PY == other.PY); -} - -std::ostream& operator<<(std::ostream &out, const alt_bn128_ate_G1_precomp &prec_P) -{ - out << prec_P.PX << OUTPUT_SEPARATOR << prec_P.PY; - - return out; -} - -std::istream& operator>>(std::istream &in, alt_bn128_ate_G1_precomp &prec_P) -{ - in >> prec_P.PX; - consume_OUTPUT_SEPARATOR(in); - in >> prec_P.PY; - - return in; -} - -bool alt_bn128_ate_ell_coeffs::operator==(const alt_bn128_ate_ell_coeffs &other) const -{ - return (this->ell_0 == other.ell_0 && - this->ell_VW == other.ell_VW && - this->ell_VV == other.ell_VV); -} - -std::ostream& operator<<(std::ostream &out, const alt_bn128_ate_ell_coeffs &c) -{ - out << c.ell_0 << OUTPUT_SEPARATOR << c.ell_VW << OUTPUT_SEPARATOR << c.ell_VV; - return out; -} - -std::istream& operator>>(std::istream &in, alt_bn128_ate_ell_coeffs &c) -{ - in >> c.ell_0; - consume_OUTPUT_SEPARATOR(in); - in >> c.ell_VW; - consume_OUTPUT_SEPARATOR(in); - in >> c.ell_VV; - - return in; -} - -bool alt_bn128_ate_G2_precomp::operator==(const alt_bn128_ate_G2_precomp &other) const -{ - return (this->QX == other.QX && - this->QY == other.QY && - this->coeffs == other.coeffs); -} - -std::ostream& operator<<(std::ostream& out, const alt_bn128_ate_G2_precomp &prec_Q) -{ - out << prec_Q.QX << OUTPUT_SEPARATOR << prec_Q.QY << "\n"; - out << prec_Q.coeffs.size() << "\n"; - for (const alt_bn128_ate_ell_coeffs &c : prec_Q.coeffs) - { - out << c << OUTPUT_NEWLINE; - } - return out; -} - -std::istream& operator>>(std::istream& in, alt_bn128_ate_G2_precomp &prec_Q) -{ - in >> prec_Q.QX; - consume_OUTPUT_SEPARATOR(in); - in >> prec_Q.QY; - consume_newline(in); - - prec_Q.coeffs.clear(); - size_t s; - in >> s; - - consume_newline(in); - - prec_Q.coeffs.reserve(s); - - for (size_t i = 0; i < s; ++i) - { - alt_bn128_ate_ell_coeffs c; - in >> c; - consume_OUTPUT_NEWLINE(in); - prec_Q.coeffs.emplace_back(c); - } - - return in; -} - -/* final exponentiations */ - -alt_bn128_Fq12 alt_bn128_final_exponentiation_first_chunk(const alt_bn128_Fq12 &elt) -{ - enter_block("Call to alt_bn128_final_exponentiation_first_chunk"); - - /* - Computes result = elt^((q^6-1)*(q^2+1)). - Follows, e.g., Beuchat et al page 9, by computing result as follows: - elt^((q^6-1)*(q^2+1)) = (conj(elt) * elt^(-1))^(q^2+1) - More precisely: - A = conj(elt) - B = elt.inverse() - C = A * B - D = C.Frobenius_map(2) - result = D * C - */ - - const alt_bn128_Fq12 A = alt_bn128_Fq12(elt.c0,-elt.c1); - const alt_bn128_Fq12 B = elt.inverse(); - const alt_bn128_Fq12 C = A * B; - const alt_bn128_Fq12 D = C.Frobenius_map(2); - const alt_bn128_Fq12 result = D * C; - - leave_block("Call to alt_bn128_final_exponentiation_first_chunk"); - - return result; -} - -alt_bn128_Fq12 alt_bn128_exp_by_neg_z(const alt_bn128_Fq12 &elt) -{ - enter_block("Call to alt_bn128_exp_by_neg_z"); - - alt_bn128_Fq12 result = elt.cyclotomic_exp(alt_bn128_final_exponent_z); - if (!alt_bn128_final_exponent_is_z_neg) - { - result = result.unitary_inverse(); - } - - leave_block("Call to alt_bn128_exp_by_neg_z"); - - return result; -} - -alt_bn128_Fq12 alt_bn128_final_exponentiation_last_chunk(const alt_bn128_Fq12 &elt) -{ - enter_block("Call to alt_bn128_final_exponentiation_last_chunk"); - - /* - Follows Laura Fuentes-Castaneda et al. "Faster hashing to G2" - by computing: - - result = elt^(q^3 * (12*z^3 + 6z^2 + 4z - 1) + - q^2 * (12*z^3 + 6z^2 + 6z) + - q * (12*z^3 + 6z^2 + 4z) + - 1 * (12*z^3 + 12z^2 + 6z + 1)) - which equals - - result = elt^( 2z * ( 6z^2 + 3z + 1 ) * (q^4 - q^2 + 1)/r ). - - Using the following addition chain: - - A = exp_by_neg_z(elt) // = elt^(-z) - B = A^2 // = elt^(-2*z) - C = B^2 // = elt^(-4*z) - D = C * B // = elt^(-6*z) - E = exp_by_neg_z(D) // = elt^(6*z^2) - F = E^2 // = elt^(12*z^2) - G = epx_by_neg_z(F) // = elt^(-12*z^3) - H = conj(D) // = elt^(6*z) - I = conj(G) // = elt^(12*z^3) - J = I * E // = elt^(12*z^3 + 6*z^2) - K = J * H // = elt^(12*z^3 + 6*z^2 + 6*z) - L = K * B // = elt^(12*z^3 + 6*z^2 + 4*z) - M = K * E // = elt^(12*z^3 + 12*z^2 + 6*z) - N = M * elt // = elt^(12*z^3 + 12*z^2 + 6*z + 1) - O = L.Frobenius_map(1) // = elt^(q*(12*z^3 + 6*z^2 + 4*z)) - P = O * N // = elt^(q*(12*z^3 + 6*z^2 + 4*z) * (12*z^3 + 12*z^2 + 6*z + 1)) - Q = K.Frobenius_map(2) // = elt^(q^2 * (12*z^3 + 6*z^2 + 6*z)) - R = Q * P // = elt^(q^2 * (12*z^3 + 6*z^2 + 6*z) + q*(12*z^3 + 6*z^2 + 4*z) * (12*z^3 + 12*z^2 + 6*z + 1)) - S = conj(elt) // = elt^(-1) - T = S * L // = elt^(12*z^3 + 6*z^2 + 4*z - 1) - U = T.Frobenius_map(3) // = elt^(q^3(12*z^3 + 6*z^2 + 4*z - 1)) - V = U * R // = elt^(q^3(12*z^3 + 6*z^2 + 4*z - 1) + q^2 * (12*z^3 + 6*z^2 + 6*z) + q*(12*z^3 + 6*z^2 + 4*z) * (12*z^3 + 12*z^2 + 6*z + 1)) - result = V - - */ - - const alt_bn128_Fq12 A = alt_bn128_exp_by_neg_z(elt); - const alt_bn128_Fq12 B = A.cyclotomic_squared(); - const alt_bn128_Fq12 C = B.cyclotomic_squared(); - const alt_bn128_Fq12 D = C * B; - const alt_bn128_Fq12 E = alt_bn128_exp_by_neg_z(D); - const alt_bn128_Fq12 F = E.cyclotomic_squared(); - const alt_bn128_Fq12 G = alt_bn128_exp_by_neg_z(F); - const alt_bn128_Fq12 H = D.unitary_inverse(); - const alt_bn128_Fq12 I = G.unitary_inverse(); - const alt_bn128_Fq12 J = I * E; - const alt_bn128_Fq12 K = J * H; - const alt_bn128_Fq12 L = K * B; - const alt_bn128_Fq12 M = K * E; - const alt_bn128_Fq12 N = M * elt; - const alt_bn128_Fq12 O = L.Frobenius_map(1); - const alt_bn128_Fq12 P = O * N; - const alt_bn128_Fq12 Q = K.Frobenius_map(2); - const alt_bn128_Fq12 R = Q * P; - const alt_bn128_Fq12 S = elt.unitary_inverse(); - const alt_bn128_Fq12 T = S * L; - const alt_bn128_Fq12 U = T.Frobenius_map(3); - const alt_bn128_Fq12 V = U * R; - - const alt_bn128_Fq12 result = V; - - leave_block("Call to alt_bn128_final_exponentiation_last_chunk"); - - return result; -} - -alt_bn128_GT alt_bn128_final_exponentiation(const alt_bn128_Fq12 &elt) -{ - enter_block("Call to alt_bn128_final_exponentiation"); - /* OLD naive version: - alt_bn128_GT result = elt^alt_bn128_final_exponent; - */ - alt_bn128_Fq12 A = alt_bn128_final_exponentiation_first_chunk(elt); - alt_bn128_GT result = alt_bn128_final_exponentiation_last_chunk(A); - - leave_block("Call to alt_bn128_final_exponentiation"); - return result; -} - -/* ate pairing */ - -void doubling_step_for_flipped_miller_loop(const alt_bn128_Fq two_inv, - alt_bn128_G2 ¤t, - alt_bn128_ate_ell_coeffs &c) -{ - const alt_bn128_Fq2 X = current.X, Y = current.Y, Z = current.Z; - - const alt_bn128_Fq2 A = two_inv * (X * Y); // A = X1 * Y1 / 2 - const alt_bn128_Fq2 B = Y.squared(); // B = Y1^2 - const alt_bn128_Fq2 C = Z.squared(); // C = Z1^2 - const alt_bn128_Fq2 D = C+C+C; // D = 3 * C - const alt_bn128_Fq2 E = alt_bn128_twist_coeff_b * D; // E = twist_b * D - const alt_bn128_Fq2 F = E+E+E; // F = 3 * E - const alt_bn128_Fq2 G = two_inv * (B+F); // G = (B+F)/2 - const alt_bn128_Fq2 H = (Y+Z).squared() - (B+C); // H = (Y1+Z1)^2-(B+C) - const alt_bn128_Fq2 I = E-B; // I = E-B - const alt_bn128_Fq2 J = X.squared(); // J = X1^2 - const alt_bn128_Fq2 E_squared = E.squared(); // E_squared = E^2 - - current.X = A * (B-F); // X3 = A * (B-F) - current.Y = G.squared() - (E_squared+E_squared+E_squared); // Y3 = G^2 - 3*E^2 - current.Z = B * H; // Z3 = B * H - c.ell_0 = alt_bn128_twist * I; // ell_0 = xi * I - c.ell_VW = -H; // ell_VW = - H (later: * yP) - c.ell_VV = J+J+J; // ell_VV = 3*J (later: * xP) -} - -void mixed_addition_step_for_flipped_miller_loop(const alt_bn128_G2 base, - alt_bn128_G2 ¤t, - alt_bn128_ate_ell_coeffs &c) -{ - const alt_bn128_Fq2 X1 = current.X, Y1 = current.Y, Z1 = current.Z; - const alt_bn128_Fq2 &x2 = base.X, &y2 = base.Y; - - const alt_bn128_Fq2 D = X1 - x2 * Z1; // D = X1 - X2*Z1 - const alt_bn128_Fq2 E = Y1 - y2 * Z1; // E = Y1 - Y2*Z1 - const alt_bn128_Fq2 F = D.squared(); // F = D^2 - const alt_bn128_Fq2 G = E.squared(); // G = E^2 - const alt_bn128_Fq2 H = D*F; // H = D*F - const alt_bn128_Fq2 I = X1 * F; // I = X1 * F - const alt_bn128_Fq2 J = H + Z1*G - (I+I); // J = H + Z1*G - (I+I) - - current.X = D * J; // X3 = D*J - current.Y = E * (I-J)-(H * Y1); // Y3 = E*(I-J)-(H*Y1) - current.Z = Z1 * H; // Z3 = Z1*H - c.ell_0 = alt_bn128_twist * (E * x2 - D * y2); // ell_0 = xi * (E * X2 - D * Y2) - c.ell_VV = - E; // ell_VV = - E (later: * xP) - c.ell_VW = D; // ell_VW = D (later: * yP ) -} - -alt_bn128_ate_G1_precomp alt_bn128_ate_precompute_G1(const alt_bn128_G1& P) -{ - enter_block("Call to alt_bn128_ate_precompute_G1"); - - alt_bn128_G1 Pcopy = P; - Pcopy.to_affine_coordinates(); - - alt_bn128_ate_G1_precomp result; - result.PX = Pcopy.X; - result.PY = Pcopy.Y; - - leave_block("Call to alt_bn128_ate_precompute_G1"); - return result; -} - -alt_bn128_ate_G2_precomp alt_bn128_ate_precompute_G2(const alt_bn128_G2& Q) -{ - enter_block("Call to alt_bn128_ate_precompute_G2"); - - alt_bn128_G2 Qcopy(Q); - Qcopy.to_affine_coordinates(); - - alt_bn128_Fq two_inv = (alt_bn128_Fq("2").inverse()); // could add to global params if needed - - alt_bn128_ate_G2_precomp result; - result.QX = Qcopy.X; - result.QY = Qcopy.Y; - - alt_bn128_G2 R; - R.X = Qcopy.X; - R.Y = Qcopy.Y; - R.Z = alt_bn128_Fq2::one(); - - const bigint &loop_count = alt_bn128_ate_loop_count; - bool found_one = false; - alt_bn128_ate_ell_coeffs c; - - for (int64_t i = loop_count.max_bits(); i >= 0; --i) - { - const bool bit = loop_count.test_bit(i); - if (!found_one) - { - /* this skips the MSB itself */ - found_one |= bit; - continue; - } - - doubling_step_for_flipped_miller_loop(two_inv, R, c); - result.coeffs.push_back(c); - - if (bit) - { - mixed_addition_step_for_flipped_miller_loop(Qcopy, R, c); - result.coeffs.push_back(c); - } - } - - alt_bn128_G2 Q1 = Qcopy.mul_by_q(); - assert_except(Q1.Z == alt_bn128_Fq2::one()); - alt_bn128_G2 Q2 = Q1.mul_by_q(); - assert_except(Q2.Z == alt_bn128_Fq2::one()); - - if (alt_bn128_ate_is_loop_count_neg) - { - R.Y = - R.Y; - } - Q2.Y = - Q2.Y; - - mixed_addition_step_for_flipped_miller_loop(Q1, R, c); - result.coeffs.push_back(c); - - mixed_addition_step_for_flipped_miller_loop(Q2, R, c); - result.coeffs.push_back(c); - - leave_block("Call to alt_bn128_ate_precompute_G2"); - return result; -} - -alt_bn128_Fq12 alt_bn128_ate_miller_loop(const alt_bn128_ate_G1_precomp &prec_P, - const alt_bn128_ate_G2_precomp &prec_Q) -{ - enter_block("Call to alt_bn128_ate_miller_loop"); - - alt_bn128_Fq12 f = alt_bn128_Fq12::one(); - - bool found_one = false; - size_t idx = 0; - - const bigint &loop_count = alt_bn128_ate_loop_count; - alt_bn128_ate_ell_coeffs c; - - for (int64_t i = loop_count.max_bits(); i >= 0; --i) - { - const bool bit = loop_count.test_bit(i); - if (!found_one) - { - /* this skips the MSB itself */ - found_one |= bit; - continue; - } - - /* code below gets executed for all bits (EXCEPT the MSB itself) of - alt_bn128_param_p (skipping leading zeros) in MSB to LSB - order */ - - c = prec_Q.coeffs[idx++]; - f = f.squared(); - f = f.mul_by_024(c.ell_0, prec_P.PY * c.ell_VW, prec_P.PX * c.ell_VV); - - if (bit) - { - c = prec_Q.coeffs[idx++]; - f = f.mul_by_024(c.ell_0, prec_P.PY * c.ell_VW, prec_P.PX * c.ell_VV); - } - - } - - if (alt_bn128_ate_is_loop_count_neg) - { - f = f.inverse(); - } - - c = prec_Q.coeffs[idx++]; - f = f.mul_by_024(c.ell_0,prec_P.PY * c.ell_VW,prec_P.PX * c.ell_VV); - - c = prec_Q.coeffs[idx++]; - f = f.mul_by_024(c.ell_0,prec_P.PY * c.ell_VW,prec_P.PX * c.ell_VV); - - leave_block("Call to alt_bn128_ate_miller_loop"); - return f; -} - -alt_bn128_Fq12 alt_bn128_ate_double_miller_loop(const alt_bn128_ate_G1_precomp &prec_P1, - const alt_bn128_ate_G2_precomp &prec_Q1, - const alt_bn128_ate_G1_precomp &prec_P2, - const alt_bn128_ate_G2_precomp &prec_Q2) -{ - enter_block("Call to alt_bn128_ate_double_miller_loop"); - - alt_bn128_Fq12 f = alt_bn128_Fq12::one(); - - bool found_one = false; - size_t idx = 0; - - const bigint &loop_count = alt_bn128_ate_loop_count; - for (int64_t i = loop_count.max_bits(); i >= 0; --i) - { - const bool bit = loop_count.test_bit(i); - if (!found_one) - { - /* this skips the MSB itself */ - found_one |= bit; - continue; - } - - /* code below gets executed for all bits (EXCEPT the MSB itself) of - alt_bn128_param_p (skipping leading zeros) in MSB to LSB - order */ - - alt_bn128_ate_ell_coeffs c1 = prec_Q1.coeffs[idx]; - alt_bn128_ate_ell_coeffs c2 = prec_Q2.coeffs[idx]; - ++idx; - - f = f.squared(); - - f = f.mul_by_024(c1.ell_0, prec_P1.PY * c1.ell_VW, prec_P1.PX * c1.ell_VV); - f = f.mul_by_024(c2.ell_0, prec_P2.PY * c2.ell_VW, prec_P2.PX * c2.ell_VV); - - if (bit) - { - alt_bn128_ate_ell_coeffs c1 = prec_Q1.coeffs[idx]; - alt_bn128_ate_ell_coeffs c2 = prec_Q2.coeffs[idx]; - ++idx; - - f = f.mul_by_024(c1.ell_0, prec_P1.PY * c1.ell_VW, prec_P1.PX * c1.ell_VV); - f = f.mul_by_024(c2.ell_0, prec_P2.PY * c2.ell_VW, prec_P2.PX * c2.ell_VV); - } - } - - if (alt_bn128_ate_is_loop_count_neg) - { - f = f.inverse(); - } - - alt_bn128_ate_ell_coeffs c1 = prec_Q1.coeffs[idx]; - alt_bn128_ate_ell_coeffs c2 = prec_Q2.coeffs[idx]; - ++idx; - f = f.mul_by_024(c1.ell_0, prec_P1.PY * c1.ell_VW, prec_P1.PX * c1.ell_VV); - f = f.mul_by_024(c2.ell_0, prec_P2.PY * c2.ell_VW, prec_P2.PX * c2.ell_VV); - - c1 = prec_Q1.coeffs[idx]; - c2 = prec_Q2.coeffs[idx]; - ++idx; - f = f.mul_by_024(c1.ell_0, prec_P1.PY * c1.ell_VW, prec_P1.PX * c1.ell_VV); - f = f.mul_by_024(c2.ell_0, prec_P2.PY * c2.ell_VW, prec_P2.PX * c2.ell_VV); - - leave_block("Call to alt_bn128_ate_double_miller_loop"); - - return f; -} - -alt_bn128_Fq12 alt_bn128_ate_pairing(const alt_bn128_G1& P, const alt_bn128_G2 &Q) -{ - enter_block("Call to alt_bn128_ate_pairing"); - alt_bn128_ate_G1_precomp prec_P = alt_bn128_ate_precompute_G1(P); - alt_bn128_ate_G2_precomp prec_Q = alt_bn128_ate_precompute_G2(Q); - alt_bn128_Fq12 result = alt_bn128_ate_miller_loop(prec_P, prec_Q); - leave_block("Call to alt_bn128_ate_pairing"); - return result; -} - -alt_bn128_GT alt_bn128_ate_reduced_pairing(const alt_bn128_G1 &P, const alt_bn128_G2 &Q) -{ - enter_block("Call to alt_bn128_ate_reduced_pairing"); - const alt_bn128_Fq12 f = alt_bn128_ate_pairing(P, Q); - const alt_bn128_GT result = alt_bn128_final_exponentiation(f); - leave_block("Call to alt_bn128_ate_reduced_pairing"); - return result; -} - -/* choice of pairing */ - -alt_bn128_G1_precomp alt_bn128_precompute_G1(const alt_bn128_G1& P) -{ - return alt_bn128_ate_precompute_G1(P); -} - -alt_bn128_G2_precomp alt_bn128_precompute_G2(const alt_bn128_G2& Q) -{ - return alt_bn128_ate_precompute_G2(Q); -} - -alt_bn128_Fq12 alt_bn128_miller_loop(const alt_bn128_G1_precomp &prec_P, - const alt_bn128_G2_precomp &prec_Q) -{ - return alt_bn128_ate_miller_loop(prec_P, prec_Q); -} - -alt_bn128_Fq12 alt_bn128_double_miller_loop(const alt_bn128_G1_precomp &prec_P1, - const alt_bn128_G2_precomp &prec_Q1, - const alt_bn128_G1_precomp &prec_P2, - const alt_bn128_G2_precomp &prec_Q2) -{ - return alt_bn128_ate_double_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2); -} - -alt_bn128_Fq12 alt_bn128_pairing(const alt_bn128_G1& P, - const alt_bn128_G2 &Q) -{ - return alt_bn128_ate_pairing(P, Q); -} - -alt_bn128_GT alt_bn128_reduced_pairing(const alt_bn128_G1 &P, - const alt_bn128_G2 &Q) -{ - return alt_bn128_ate_reduced_pairing(P, Q); -} -} // libsnark diff --git a/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pairing.hpp b/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pairing.hpp deleted file mode 100644 index 15d325485..000000000 --- a/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pairing.hpp +++ /dev/null @@ -1,92 +0,0 @@ -/** @file - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef ALT_BN128_PAIRING_HPP_ -#define ALT_BN128_PAIRING_HPP_ -#include -#include "algebra/curves/alt_bn128/alt_bn128_init.hpp" - -namespace libsnark { - -/* final exponentiation */ - -alt_bn128_GT alt_bn128_final_exponentiation(const alt_bn128_Fq12 &elt); - -/* ate pairing */ - -struct alt_bn128_ate_G1_precomp { - alt_bn128_Fq PX; - alt_bn128_Fq PY; - - bool operator==(const alt_bn128_ate_G1_precomp &other) const; - friend std::ostream& operator<<(std::ostream &out, const alt_bn128_ate_G1_precomp &prec_P); - friend std::istream& operator>>(std::istream &in, alt_bn128_ate_G1_precomp &prec_P); -}; - -struct alt_bn128_ate_ell_coeffs { - alt_bn128_Fq2 ell_0; - alt_bn128_Fq2 ell_VW; - alt_bn128_Fq2 ell_VV; - - bool operator==(const alt_bn128_ate_ell_coeffs &other) const; - friend std::ostream& operator<<(std::ostream &out, const alt_bn128_ate_ell_coeffs &dc); - friend std::istream& operator>>(std::istream &in, alt_bn128_ate_ell_coeffs &dc); -}; - -struct alt_bn128_ate_G2_precomp { - alt_bn128_Fq2 QX; - alt_bn128_Fq2 QY; - std::vector coeffs; - - bool operator==(const alt_bn128_ate_G2_precomp &other) const; - friend std::ostream& operator<<(std::ostream &out, const alt_bn128_ate_G2_precomp &prec_Q); - friend std::istream& operator>>(std::istream &in, alt_bn128_ate_G2_precomp &prec_Q); -}; - -alt_bn128_ate_G1_precomp alt_bn128_ate_precompute_G1(const alt_bn128_G1& P); -alt_bn128_ate_G2_precomp alt_bn128_ate_precompute_G2(const alt_bn128_G2& Q); - -alt_bn128_Fq12 alt_bn128_ate_miller_loop(const alt_bn128_ate_G1_precomp &prec_P, - const alt_bn128_ate_G2_precomp &prec_Q); -alt_bn128_Fq12 alt_bn128_ate_double_miller_loop(const alt_bn128_ate_G1_precomp &prec_P1, - const alt_bn128_ate_G2_precomp &prec_Q1, - const alt_bn128_ate_G1_precomp &prec_P2, - const alt_bn128_ate_G2_precomp &prec_Q2); - -alt_bn128_Fq12 alt_bn128_ate_pairing(const alt_bn128_G1& P, - const alt_bn128_G2 &Q); -alt_bn128_GT alt_bn128_ate_reduced_pairing(const alt_bn128_G1 &P, - const alt_bn128_G2 &Q); - -/* choice of pairing */ - -typedef alt_bn128_ate_G1_precomp alt_bn128_G1_precomp; -typedef alt_bn128_ate_G2_precomp alt_bn128_G2_precomp; - -alt_bn128_G1_precomp alt_bn128_precompute_G1(const alt_bn128_G1& P); - -alt_bn128_G2_precomp alt_bn128_precompute_G2(const alt_bn128_G2& Q); - -alt_bn128_Fq12 alt_bn128_miller_loop(const alt_bn128_G1_precomp &prec_P, - const alt_bn128_G2_precomp &prec_Q); - -alt_bn128_Fq12 alt_bn128_double_miller_loop(const alt_bn128_G1_precomp &prec_P1, - const alt_bn128_G2_precomp &prec_Q1, - const alt_bn128_G1_precomp &prec_P2, - const alt_bn128_G2_precomp &prec_Q2); - -alt_bn128_Fq12 alt_bn128_pairing(const alt_bn128_G1& P, - const alt_bn128_G2 &Q); - -alt_bn128_GT alt_bn128_reduced_pairing(const alt_bn128_G1 &P, - const alt_bn128_G2 &Q); - -alt_bn128_GT alt_bn128_affine_reduced_pairing(const alt_bn128_G1 &P, - const alt_bn128_G2 &Q); - -} // libsnark -#endif // ALT_BN128_PAIRING_HPP_ diff --git a/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pp.cpp b/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pp.cpp deleted file mode 100644 index 25ea924d8..000000000 --- a/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pp.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/** @file - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp" - -namespace libsnark { - -void alt_bn128_pp::init_public_params() -{ - init_alt_bn128_params(); -} - -alt_bn128_GT alt_bn128_pp::final_exponentiation(const alt_bn128_Fq12 &elt) -{ - return alt_bn128_final_exponentiation(elt); -} - -alt_bn128_G1_precomp alt_bn128_pp::precompute_G1(const alt_bn128_G1 &P) -{ - return alt_bn128_precompute_G1(P); -} - -alt_bn128_G2_precomp alt_bn128_pp::precompute_G2(const alt_bn128_G2 &Q) -{ - return alt_bn128_precompute_G2(Q); -} - -alt_bn128_Fq12 alt_bn128_pp::miller_loop(const alt_bn128_G1_precomp &prec_P, - const alt_bn128_G2_precomp &prec_Q) -{ - return alt_bn128_miller_loop(prec_P, prec_Q); -} - -alt_bn128_Fq12 alt_bn128_pp::double_miller_loop(const alt_bn128_G1_precomp &prec_P1, - const alt_bn128_G2_precomp &prec_Q1, - const alt_bn128_G1_precomp &prec_P2, - const alt_bn128_G2_precomp &prec_Q2) -{ - return alt_bn128_double_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2); -} - -alt_bn128_Fq12 alt_bn128_pp::pairing(const alt_bn128_G1 &P, - const alt_bn128_G2 &Q) -{ - return alt_bn128_pairing(P, Q); -} - -alt_bn128_Fq12 alt_bn128_pp::reduced_pairing(const alt_bn128_G1 &P, - const alt_bn128_G2 &Q) -{ - return alt_bn128_reduced_pairing(P, Q); -} - -} // libsnark diff --git a/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pp.hpp b/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pp.hpp deleted file mode 100644 index ec8059dcb..000000000 --- a/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_pp.hpp +++ /dev/null @@ -1,50 +0,0 @@ -/** @file -***************************************************************************** -* @author This file is part of libsnark, developed by SCIPR Lab -* and contributors (see AUTHORS). -* @copyright MIT license (see LICENSE file) -*****************************************************************************/ - -#ifndef ALT_BN128_PP_HPP_ -#define ALT_BN128_PP_HPP_ -#include "algebra/curves/public_params.hpp" -#include "algebra/curves/alt_bn128/alt_bn128_init.hpp" -#include "algebra/curves/alt_bn128/alt_bn128_g1.hpp" -#include "algebra/curves/alt_bn128/alt_bn128_g2.hpp" -#include "algebra/curves/alt_bn128/alt_bn128_pairing.hpp" - -namespace libsnark { - -class alt_bn128_pp { -public: - typedef alt_bn128_Fr Fp_type; - typedef alt_bn128_G1 G1_type; - typedef alt_bn128_G2 G2_type; - typedef alt_bn128_G1_precomp G1_precomp_type; - typedef alt_bn128_G2_precomp G2_precomp_type; - typedef alt_bn128_Fq Fq_type; - typedef alt_bn128_Fq2 Fqe_type; - typedef alt_bn128_Fq12 Fqk_type; - typedef alt_bn128_GT GT_type; - - static const bool has_affine_pairing = false; - - static void init_public_params(); - static alt_bn128_GT final_exponentiation(const alt_bn128_Fq12 &elt); - static alt_bn128_G1_precomp precompute_G1(const alt_bn128_G1 &P); - static alt_bn128_G2_precomp precompute_G2(const alt_bn128_G2 &Q); - static alt_bn128_Fq12 miller_loop(const alt_bn128_G1_precomp &prec_P, - const alt_bn128_G2_precomp &prec_Q); - static alt_bn128_Fq12 double_miller_loop(const alt_bn128_G1_precomp &prec_P1, - const alt_bn128_G2_precomp &prec_Q1, - const alt_bn128_G1_precomp &prec_P2, - const alt_bn128_G2_precomp &prec_Q2); - static alt_bn128_Fq12 pairing(const alt_bn128_G1 &P, - const alt_bn128_G2 &Q); - static alt_bn128_Fq12 reduced_pairing(const alt_bn128_G1 &P, - const alt_bn128_G2 &Q); -}; - -} // libsnark - -#endif // ALT_BN128_PP_HPP_ diff --git a/src/snark/libsnark/algebra/curves/curve_utils.hpp b/src/snark/libsnark/algebra/curves/curve_utils.hpp deleted file mode 100644 index 33a8e1e17..000000000 --- a/src/snark/libsnark/algebra/curves/curve_utils.hpp +++ /dev/null @@ -1,22 +0,0 @@ -/** @file - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef CURVE_UTILS_HPP_ -#define CURVE_UTILS_HPP_ -#include - -#include "algebra/fields/bigint.hpp" - -namespace libsnark { - -template -GroupT scalar_mul(const GroupT &base, const bigint &scalar); - -} // libsnark -#include "algebra/curves/curve_utils.tcc" - -#endif // CURVE_UTILS_HPP_ diff --git a/src/snark/libsnark/algebra/curves/curve_utils.tcc b/src/snark/libsnark/algebra/curves/curve_utils.tcc deleted file mode 100644 index 38140cd48..000000000 --- a/src/snark/libsnark/algebra/curves/curve_utils.tcc +++ /dev/null @@ -1,37 +0,0 @@ -/** @file - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef CURVE_UTILS_TCC_ -#define CURVE_UTILS_TCC_ - -namespace libsnark { - -template -GroupT scalar_mul(const GroupT &base, const bigint &scalar) -{ - GroupT result = GroupT::zero(); - - bool found_one = false; - for (int64_t i = scalar.max_bits() - 1; i >= 0; --i) - { - if (found_one) - { - result = result.dbl(); - } - - if (scalar.test_bit(i)) - { - found_one = true; - result = result + base; - } - } - - return result; -} - -} // libsnark -#endif // CURVE_UTILS_TCC_ diff --git a/src/snark/libsnark/algebra/curves/public_params.hpp b/src/snark/libsnark/algebra/curves/public_params.hpp deleted file mode 100644 index 07e047560..000000000 --- a/src/snark/libsnark/algebra/curves/public_params.hpp +++ /dev/null @@ -1,103 +0,0 @@ -/** @file - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef PUBLIC_PARAMS_HPP_ -#define PUBLIC_PARAMS_HPP_ -#include - -namespace libsnark { - -/* - for every curve the user should define corresponding - public_params with the following typedefs: - - Fp_type - G1_type - G2_type - G1_precomp_type - G2_precomp_type - affine_ate_G1_precomp_type - affine_ate_G2_precomp_type - Fq_type - Fqe_type - Fqk_type - GT_type - - one should also define the following static methods: - - void init_public_params(); - - GT final_exponentiation(const Fqk &elt); - - G1_precomp precompute_G1(const G1 &P); - G2_precomp precompute_G2(const G2 &Q); - - Fqk miller_loop(const G1_precomp &prec_P, - const G2_precomp &prec_Q); - - affine_ate_G1_precomp affine_ate_precompute_G1(const G1 &P); - affine_ate_G2_precomp affine_ate_precompute_G2(const G2 &Q); - - - Fqk affine_ate_miller_loop(const affine_ate_G1_precomp &prec_P, - const affine_ate_G2_precomp &prec_Q); - Fqk affine_ate_e_over_e_miller_loop(const affine_ate_G1_precomp &prec_P1, - const affine_ate_G2_precomp &prec_Q1, - const affine_ate_G1_precomp &prec_P2, - const affine_ate_G2_precomp &prec_Q2); - Fqk affine_ate_e_times_e_over_e_miller_loop(const affine_ate_G1_precomp &prec_P1, - const affine_ate_G2_precomp &prec_Q1, - const affine_ate_G1_precomp &prec_P2, - const affine_ate_G2_precomp &prec_Q2, - const affine_ate_G1_precomp &prec_P3, - const affine_ate_G2_precomp &prec_Q3); - Fqk double_miller_loop(const G1_precomp &prec_P1, - const G2_precomp &prec_Q1, - const G1_precomp &prec_P2, - const G2_precomp &prec_Q2); - - Fqk pairing(const G1 &P, - const G2 &Q); - GT reduced_pairing(const G1 &P, - const G2 &Q); - GT affine_reduced_pairing(const G1 &P, - const G2 &Q); -*/ - -template -using Fr = typename EC_ppT::Fp_type; -template -using G1 = typename EC_ppT::G1_type; -template -using G2 = typename EC_ppT::G2_type; -template -using G1_precomp = typename EC_ppT::G1_precomp_type; -template -using G2_precomp = typename EC_ppT::G2_precomp_type; -template -using affine_ate_G1_precomp = typename EC_ppT::affine_ate_G1_precomp_type; -template -using affine_ate_G2_precomp = typename EC_ppT::affine_ate_G2_precomp_type; -template -using Fq = typename EC_ppT::Fq_type; -template -using Fqe = typename EC_ppT::Fqe_type; -template -using Fqk = typename EC_ppT::Fqk_type; -template -using GT = typename EC_ppT::GT_type; - -template -using Fr_vector = std::vector >; -template -using G1_vector = std::vector >; -template -using G2_vector = std::vector >; - -} // libsnark - -#endif // PUBLIC_PARAMS_HPP_ diff --git a/src/snark/libsnark/algebra/curves/tests/test_bilinearity.cpp b/src/snark/libsnark/algebra/curves/tests/test_bilinearity.cpp deleted file mode 100644 index 18e68f7bb..000000000 --- a/src/snark/libsnark/algebra/curves/tests/test_bilinearity.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/** - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ -#include -#include "common/profiling.hpp" -//#include "algebra/curves/edwards/edwards_pp.hpp" -#ifdef CURVE_BN128 -#include "algebra/curves/bn128/bn128_pp.hpp" -#endif -#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp" -//#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" -//#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" -#include "algebra/curves/alt_bn128/alt_bn128_pairing.hpp" -#include "algebra/curves/alt_bn128/alt_bn128_pairing.cpp" - -using namespace libsnark; - -template -void pairing_test() -{ - GT GT_one = GT::one(); - - printf("Running bilinearity tests:\n"); - G1 P = (Fr::random_element()) * G1::one(); - //G1 P = Fr("2") * G1::one(); - G2 Q = (Fr::random_element()) * G2::one(); - //G2 Q = Fr("3") * G2::one(); - - printf("P:\n"); - P.print(); - P.print_coordinates(); - printf("Q:\n"); - Q.print(); - Q.print_coordinates(); - printf("\n\n"); - - Fr s = Fr::random_element(); - //Fr s = Fr("2"); - G1 sP = s * P; - G2 sQ = s * Q; - - printf("Pairing bilinearity tests (three must match):\n"); - GT ans1 = ppT::reduced_pairing(sP, Q); - GT ans2 = ppT::reduced_pairing(P, sQ); - GT ans3 = ppT::reduced_pairing(P, Q)^s; - ans1.print(); - ans2.print(); - ans3.print(); - assert(ans1 == ans2); - assert(ans2 == ans3); - - assert(ans1 != GT_one); - assert((ans1^Fr::field_char()) == GT_one); - printf("\n\n"); -} - -template -void double_miller_loop_test() -{ - const G1 P1 = (Fr::random_element()) * G1::one(); - const G1 P2 = (Fr::random_element()) * G1::one(); - const G2 Q1 = (Fr::random_element()) * G2::one(); - const G2 Q2 = (Fr::random_element()) * G2::one(); - - const G1_precomp prec_P1 = ppT::precompute_G1(P1); - const G1_precomp prec_P2 = ppT::precompute_G1(P2); - const G2_precomp prec_Q1 = ppT::precompute_G2(Q1); - const G2_precomp prec_Q2 = ppT::precompute_G2(Q2); - - const Fqk ans_1 = ppT::miller_loop(prec_P1, prec_Q1); - const Fqk ans_2 = ppT::miller_loop(prec_P2, prec_Q2); - const Fqk ans_12 = ppT::double_miller_loop(prec_P1, prec_Q1, prec_P2, prec_Q2); - assert(ans_1 * ans_2 == ans_12); -} - -template -void affine_pairing_test() -{ - GT GT_one = GT::one(); - - printf("Running bilinearity tests:\n"); - G1 P = (Fr::random_element()) * G1::one(); - G2 Q = (Fr::random_element()) * G2::one(); - - printf("P:\n"); - P.print(); - printf("Q:\n"); - Q.print(); - printf("\n\n"); - - Fr s = Fr::random_element(); - G1 sP = s * P; - G2 sQ = s * Q; - - printf("Pairing bilinearity tests (three must match):\n"); - GT ans1 = ppT::affine_reduced_pairing(sP, Q); - GT ans2 = ppT::affine_reduced_pairing(P, sQ); - GT ans3 = ppT::affine_reduced_pairing(P, Q)^s; - ans1.print(); - ans2.print(); - ans3.print(); - assert(ans1 == ans2); - assert(ans2 == ans3); - - assert(ans1 != GT_one); - assert((ans1^Fr::field_char()) == GT_one); - printf("\n\n"); -} - -int main(void) -{ - start_profiling(); - edwards_pp::init_public_params(); - pairing_test(); - double_miller_loop_test(); - - mnt6_pp::init_public_params(); - pairing_test(); - double_miller_loop_test(); - affine_pairing_test(); - - mnt4_pp::init_public_params(); - pairing_test(); - double_miller_loop_test(); - affine_pairing_test(); - - alt_bn128_pp::init_public_params(); - pairing_test(); - double_miller_loop_test(); - -#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled - bn128_pp::init_public_params(); - pairing_test(); - double_miller_loop_test(); -#endif -} diff --git a/src/snark/libsnark/algebra/curves/tests/test_groups.cpp b/src/snark/libsnark/algebra/curves/tests/test_groups.cpp deleted file mode 100644 index 4f64334ba..000000000 --- a/src/snark/libsnark/algebra/curves/tests/test_groups.cpp +++ /dev/null @@ -1,176 +0,0 @@ -/** - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ -#include "common/profiling.hpp" -//#include "algebra/curves/edwards/edwards_pp.hpp" -//#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" -//#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" -#ifdef CURVE_BN128 -#include "algebra/curves/bn128/bn128_pp.hpp" -#endif -#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp" -#include - -using namespace libsnark; - -template -void test_mixed_add() -{ - GroupT base, el, result; - - base = GroupT::zero(); - el = GroupT::zero(); - el.to_special(); - result = base.mixed_add(el); - assert(result == base + el); - - base = GroupT::zero(); - el = GroupT::random_element(); - el.to_special(); - result = base.mixed_add(el); - assert(result == base + el); - - base = GroupT::random_element(); - el = GroupT::zero(); - el.to_special(); - result = base.mixed_add(el); - assert(result == base + el); - - base = GroupT::random_element(); - el = GroupT::random_element(); - el.to_special(); - result = base.mixed_add(el); - assert(result == base + el); - - base = GroupT::random_element(); - el = base; - el.to_special(); - result = base.mixed_add(el); - assert(result == base.dbl()); -} - -template -void test_group() -{ - bigint<1> rand1 = bigint<1>("76749407"); - bigint<1> rand2 = bigint<1>("44410867"); - bigint<1> randsum = bigint<1>("121160274"); - - GroupT zero = GroupT::zero(); - assert(zero == zero); - GroupT one = GroupT::one(); - assert(one == one); - GroupT two = bigint<1>(2l) * GroupT::one(); - assert(two == two); - GroupT five = bigint<1>(5l) * GroupT::one(); - - GroupT three = bigint<1>(3l) * GroupT::one(); - GroupT four = bigint<1>(4l) * GroupT::one(); - - assert(two+five == three+four); - - GroupT a = GroupT::random_element(); - GroupT b = GroupT::random_element(); - - assert(one != zero); - assert(a != zero); - assert(a != one); - - assert(b != zero); - assert(b != one); - - assert(a.dbl() == a + a); - assert(b.dbl() == b + b); - assert(one.add(two) == three); - assert(two.add(one) == three); - assert(a + b == b + a); - assert(a - a == zero); - assert(a - b == a + (-b)); - assert(a - b == (-b) + a); - - // handle special cases - assert(zero + (-a) == -a); - assert(zero - a == -a); - assert(a - zero == a); - assert(a + zero == a); - assert(zero + a == a); - - assert((a + b).dbl() == (a + b) + (b + a)); - assert(bigint<1>("2") * (a + b) == (a + b) + (b + a)); - - assert((rand1 * a) + (rand2 * a) == (randsum * a)); - - assert(GroupT::order() * a == zero); - assert(GroupT::order() * one == zero); - assert((GroupT::order() * a) - a != zero); - assert((GroupT::order() * one) - one != zero); - - test_mixed_add(); -} - -template -void test_mul_by_q() -{ - GroupT a = GroupT::random_element(); - assert((GroupT::base_field_char()*a) == a.mul_by_q()); -} - -template -void test_output() -{ - GroupT g = GroupT::zero(); - - for (size_t i = 0; i < 1000; ++i) - { - std::stringstream ss; - ss << g; - GroupT gg; - ss >> gg; - assert(g == gg); - /* use a random point in next iteration */ - g = GroupT::random_element(); - } -} - -int main(void) -{ -/* - edwards_pp::init_public_params(); - test_group >(); - test_output >(); - test_group >(); - test_output >(); - test_mul_by_q >(); - - mnt4_pp::init_public_params(); - test_group >(); - test_output >(); - test_group >(); - test_output >(); - test_mul_by_q >(); - - mnt6_pp::init_public_params(); - test_group >(); - test_output >(); - test_group >(); - test_output >(); - test_mul_by_q >(); -*/ - alt_bn128_pp::init_public_params(); - test_group >(); - test_output >(); - test_group >(); - test_output >(); - test_mul_by_q >(); - -#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled - bn128_pp::init_public_params(); - test_group >(); - test_output >(); - test_group >(); - test_output >(); -#endif -} diff --git a/src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain.hpp b/src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain.hpp deleted file mode 100644 index 3e127a063..000000000 --- a/src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain.hpp +++ /dev/null @@ -1,45 +0,0 @@ -/** @file - ***************************************************************************** - - Declaration of interfaces for the "basic radix-2" evaluation domain. - - Roughly, the domain has size m = 2^k and consists of the m-th roots of unity. - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef BASIC_RADIX2_DOMAIN_HPP_ -#define BASIC_RADIX2_DOMAIN_HPP_ - -#include "algebra/evaluation_domain/evaluation_domain.hpp" - -namespace libsnark { - -template -class basic_radix2_domain : public evaluation_domain { -public: - - FieldT omega; - - basic_radix2_domain(const size_t m); - - void FFT(std::vector &a); - void iFFT(std::vector &a); - void cosetFFT(std::vector &a, const FieldT &g); - void icosetFFT(std::vector &a, const FieldT &g); - std::vector lagrange_coeffs(const FieldT &t); - FieldT get_element(const size_t idx); - FieldT compute_Z(const FieldT &t); - void add_poly_Z(const FieldT &coeff, std::vector &H); - void divide_by_Z_on_coset(std::vector &P); - -}; - -} // libsnark - -#include "algebra/evaluation_domain/domains/basic_radix2_domain.tcc" - -#endif // BASIC_RADIX2_DOMAIN_HPP_ diff --git a/src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain.tcc b/src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain.tcc deleted file mode 100644 index 16dcd54fc..000000000 --- a/src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain.tcc +++ /dev/null @@ -1,113 +0,0 @@ -/** @file - ***************************************************************************** - - Implementation of interfaces for the "basic radix-2" evaluation domain. - - See basic_radix2_domain.hpp . - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef BASIC_RADIX2_DOMAIN_TCC_ -#define BASIC_RADIX2_DOMAIN_TCC_ - -#include "algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp" -#include "common/assert_except.hpp" - -namespace libsnark { - -template -basic_radix2_domain::basic_radix2_domain(const size_t m) : evaluation_domain(m) -{ - assert_except(m > 1); - const size_t logm = log2(m); - assert_except(logm <= (FieldT::s)); - - omega = get_root_of_unity(m); -} - -template -void basic_radix2_domain::FFT(std::vector &a) -{ - enter_block("Execute FFT"); - assert_except(a.size() == this->m); - _basic_radix2_FFT(a, omega); - leave_block("Execute FFT"); -} - -template -void basic_radix2_domain::iFFT(std::vector &a) -{ - enter_block("Execute inverse FFT"); - assert_except(a.size() == this->m); - _basic_radix2_FFT(a, omega.inverse()); - - const FieldT sconst = FieldT(a.size()).inverse(); - for (size_t i = 0; i < a.size(); ++i) - { - a[i] *= sconst; - } - leave_block("Execute inverse FFT"); -} - -template -void basic_radix2_domain::cosetFFT(std::vector &a, const FieldT &g) -{ - enter_block("Execute coset FFT"); - _multiply_by_coset(a, g); - FFT(a); - leave_block("Execute coset FFT"); -} - -template -void basic_radix2_domain::icosetFFT(std::vector &a, const FieldT &g) -{ - enter_block("Execute inverse coset IFFT"); - iFFT(a); - _multiply_by_coset(a, g.inverse()); - leave_block("Execute inverse coset IFFT"); -} - -template -std::vector basic_radix2_domain::lagrange_coeffs(const FieldT &t) -{ - return _basic_radix2_lagrange_coeffs(this->m, t); -} - -template -FieldT basic_radix2_domain::get_element(const size_t idx) -{ - return omega^idx; -} - -template -FieldT basic_radix2_domain::compute_Z(const FieldT &t) -{ - return (t^this->m) - FieldT::one(); -} - -template -void basic_radix2_domain::add_poly_Z(const FieldT &coeff, std::vector &H) -{ - assert_except(H.size() == this->m+1); - H[this->m] += coeff; - H[0] -= coeff; -} - -template -void basic_radix2_domain::divide_by_Z_on_coset(std::vector &P) -{ - const FieldT coset = FieldT::multiplicative_generator; - const FieldT Z_inverse_at_coset = this->compute_Z(coset).inverse(); - for (size_t i = 0; i < this->m; ++i) - { - P[i] *= Z_inverse_at_coset; - } -} - -} // libsnark - -#endif // BASIC_RADIX2_DOMAIN_TCC_ diff --git a/src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp b/src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp deleted file mode 100644 index c42ab2f6f..000000000 --- a/src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain_aux.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/** @file - ***************************************************************************** - - Declaration of interfaces for auxiliary functions for the "basic radix-2" evaluation domain. - - These functions compute the radix-2 FFT (in single- or multi-thread mode) and, - also compute Lagrange coefficients. - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef BASIC_RADIX2_DOMAIN_AUX_HPP_ -#define BASIC_RADIX2_DOMAIN_AUX_HPP_ - -namespace libsnark { - -/** - * Compute the radix-2 FFT of the vector a over the set S={omega^{0},...,omega^{m-1}}. - */ -template -void _basic_radix2_FFT(std::vector &a, const FieldT &omega); - -/** - * A multi-thread version of _basic_radix2_FFT. - */ -template -void _parallel_basic_radix2_FFT(std::vector &a, const FieldT &omega); - -/** - * Translate the vector a to a coset defined by g. - */ -template -void _multiply_by_coset(std::vector &a, const FieldT &g); - -/** - * Compute the m Lagrange coefficients, relative to the set S={omega^{0},...,omega^{m-1}}, at the field element t. - */ -template -std::vector _basic_radix2_lagrange_coeffs(const size_t m, const FieldT &t); - -} // libsnark - -#include "algebra/evaluation_domain/domains/basic_radix2_domain_aux.tcc" - -#endif // BASIC_RADIX2_DOMAIN_AUX_HPP_ diff --git a/src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain_aux.tcc b/src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain_aux.tcc deleted file mode 100644 index 4b03b1f9b..000000000 --- a/src/snark/libsnark/algebra/evaluation_domain/domains/basic_radix2_domain_aux.tcc +++ /dev/null @@ -1,243 +0,0 @@ -/** @file - ***************************************************************************** - - Implementation of interfaces for auxiliary functions for the "basic radix-2" evaluation domain. - - See basic_radix2_domain_aux.hpp . - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef BASIC_RADIX2_DOMAIN_AUX_TCC_ -#define BASIC_RADIX2_DOMAIN_AUX_TCC_ - -#include -#ifdef MULTICORE -#include -#endif -#include "algebra/fields/field_utils.hpp" -#include "common/profiling.hpp" -#include "common/utils.hpp" -#include "common/assert_except.hpp" - -namespace libsnark { - -#ifdef MULTICORE -#define _basic_radix2_FFT _basic_parallel_radix2_FFT -#else -#define _basic_radix2_FFT _basic_serial_radix2_FFT -#endif - -/* - Below we make use of pseudocode from [CLRS 2n Ed, pp. 864]. - Also, note that it's the caller's responsibility to multiply by 1/N. - */ -template -void _basic_serial_radix2_FFT(std::vector &a, const FieldT &omega) -{ - const size_t n = a.size(), logn = log2(n); - assert_except(n == (1u << logn)); - - /* swapping in place (from Storer's book) */ - for (size_t k = 0; k < n; ++k) - { - const size_t rk = bitreverse(k, logn); - if (k < rk) - std::swap(a[k], a[rk]); - } - - size_t m = 1; // invariant: m = 2^{s-1} - for (size_t s = 1; s <= logn; ++s) - { - // w_m is 2^s-th root of unity now - const FieldT w_m = omega^(n/(2*m)); - - asm volatile ("/* pre-inner */"); - for (size_t k = 0; k < n; k += 2*m) - { - FieldT w = FieldT::one(); - for (size_t j = 0; j < m; ++j) - { - const FieldT t = w * a[k+j+m]; - a[k+j+m] = a[k+j] - t; - a[k+j] += t; - w *= w_m; - } - } - asm volatile ("/* post-inner */"); - m *= 2; - } -} - -template -void _basic_parallel_radix2_FFT_inner(std::vector &a, const FieldT &omega, const size_t log_cpus) -{ - const size_t num_cpus = UINT64_C(1)< > tmp(num_cpus); - for (size_t j = 0; j < num_cpus; ++j) - { - tmp[j].resize(UINT64_C(1)<<(log_m-log_cpus), FieldT::zero()); - } - -#ifdef MULTICORE - #pragma omp parallel for -#endif - for (size_t j = 0; j < num_cpus; ++j) - { - const FieldT omega_j = omega^j; - const FieldT omega_step = omega^(j<<(log_m - log_cpus)); - - FieldT elt = FieldT::one(); - for (size_t i = 0; i < UINT64_C(1)<<(log_m - log_cpus); ++i) - { - for (size_t s = 0; s < num_cpus; ++s) - { - // invariant: elt is omega^(j*idx) - const size_t idx = (i + (s<<(log_m - log_cpus))) % (1u << log_m); - tmp[j][i] += a[idx] * elt; - elt *= omega_step; - } - elt *= omega_j; - } - } - leave_block("Shuffle inputs"); - - enter_block("Execute sub-FFTs"); - const FieldT omega_num_cpus = omega^num_cpus; - -#ifdef MULTICORE - #pragma omp parallel for -#endif - for (size_t j = 0; j < num_cpus; ++j) - { - _basic_serial_radix2_FFT(tmp[j], omega_num_cpus); - } - leave_block("Execute sub-FFTs"); - - enter_block("Re-shuffle outputs"); - -#ifdef MULTICORE - #pragma omp parallel for -#endif - for (size_t i = 0; i < num_cpus; ++i) - { - for (size_t j = 0; j < UINT64_C(1)<<(log_m - log_cpus); ++j) - { - // now: i = idx >> (log_m - log_cpus) and j = idx % (1u << (log_m - log_cpus)), for idx = ((i<<(log_m-log_cpus))+j) % (1u << log_m) - a[(j< -void _basic_parallel_radix2_FFT(std::vector &a, const FieldT &omega) -{ -#ifdef MULTICORE - const size_t num_cpus = omp_get_max_threads(); -#else - const size_t num_cpus = 1; -#endif - const size_t log_cpus = ((num_cpus & (num_cpus - 1)) == 0 ? log2(num_cpus) : log2(num_cpus) - 1); - -#ifdef DEBUG - print_indent(); printf("* Invoking parallel FFT on 2^%zu CPUs (omp_get_max_threads = %zu)\n", log_cpus, num_cpus); -#endif - - if (log_cpus == 0) - { - _basic_serial_radix2_FFT(a, omega); - } - else - { - _basic_parallel_radix2_FFT_inner(a, omega, log_cpus); - } -} - -template -void _multiply_by_coset(std::vector &a, const FieldT &g) -{ - //enter_block("Multiply by coset"); - FieldT u = g; - for (size_t i = 1; i < a.size(); ++i) - { - a[i] *= u; - u *= g; - } - //leave_block("Multiply by coset"); -} - -template -std::vector _basic_radix2_lagrange_coeffs(const size_t m, const FieldT &t) -{ - if (m == 1) - { - return std::vector(1, FieldT::one()); - } - - assert_except(m == (1u << log2(m))); - - const FieldT omega = get_root_of_unity(m); - - std::vector u(m, FieldT::zero()); - - /* - If t equals one of the roots of unity in S={omega^{0},...,omega^{m-1}} - then output 1 at the right place, and 0 elsewhere - */ - - if ((t^m) == (FieldT::one())) - { - FieldT omega_i = FieldT::one(); - for (size_t i = 0; i < m; ++i) - { - if (omega_i == t) // i.e., t equals omega^i - { - u[i] = FieldT::one(); - return u; - } - - omega_i *= omega; - } - } - - /* - Otherwise, if t does not equal any of the roots of unity in S, - then compute each L_{i,S}(t) as Z_{S}(t) * v_i / (t-\omega^i) - where: - - Z_{S}(t) = \prod_{j} (t-\omega^j) = (t^m-1), and - - v_{i} = 1 / \prod_{j \neq i} (\omega^i-\omega^j). - Below we use the fact that v_{0} = 1/m and v_{i+1} = \omega * v_{i}. - */ - - const FieldT Z = (t^m)-FieldT::one(); - FieldT l = Z * FieldT(m).inverse(); - FieldT r = FieldT::one(); - for (size_t i = 0; i < m; ++i) - { - u[i] = l * (t - r).inverse(); - l *= omega; - r *= omega; - } - - return u; -} - -} // libsnark - -#endif // BASIC_RADIX2_DOMAIN_AUX_TCC_ diff --git a/src/snark/libsnark/algebra/evaluation_domain/evaluation_domain.hpp b/src/snark/libsnark/algebra/evaluation_domain/evaluation_domain.hpp deleted file mode 100644 index 358db9798..000000000 --- a/src/snark/libsnark/algebra/evaluation_domain/evaluation_domain.hpp +++ /dev/null @@ -1,125 +0,0 @@ -/** @file - ***************************************************************************** - - Declaration of interfaces for evaluation domains. - - Roughly, given a desired size m for the domain, the constructor selects - a choice of domain S with size ~m that has been selected so to optimize - - computations of Lagrange polynomials, and - - FFT/iFFT computations. - An evaluation domain also provides other other functions, e.g., accessing - individual elements in S or evaluating its vanishing polynomial. - - The descriptions below make use of the definition of a *Lagrange polynomial*, - which we recall. Given a field F, a subset S=(a_i)_i of F, and an index idx - in {0,...,|S-1|}, the idx-th Lagrange polynomial (wrt to subset S) is defined to be - \f[ L_{idx,S}(z) := prod_{k \neq idx} (z - a_k) / prod_{k \neq idx} (a_{idx} - a_k) \f] - Note that, by construction: - \f[ \forall j \neq idx: L_{idx,S}(a_{idx}) = 1 \text{ and } L_{idx,S}(a_j) = 0 \f] - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef EVALUATION_DOMAIN_HPP_ -#define EVALUATION_DOMAIN_HPP_ - -#include - -namespace libsnark { - -/** - * An evaluation domain. - */ -template -class evaluation_domain { -public: - - const size_t m; - - /** - * Construct an evaluation domain S of size m, if possible. - * - * (See the function get_evaluation_domain below.) - */ - evaluation_domain(const size_t m) : m(m) {}; - - /** - * Get the idx-th element in S. - */ - virtual FieldT get_element(const size_t idx) = 0; - - /** - * Compute the FFT, over the domain S, of the vector a. - */ - virtual void FFT(std::vector &a) = 0; - - /** - * Compute the inverse FFT, over the domain S, of the vector a. - */ - virtual void iFFT(std::vector &a) = 0; - - /** - * Compute the FFT, over the domain g*S, of the vector a. - */ - virtual void cosetFFT(std::vector &a, const FieldT &g) = 0; - - /** - * Compute the inverse FFT, over the domain g*S, of the vector a. - */ - virtual void icosetFFT(std::vector &a, const FieldT &g) = 0; - - /** - * Evaluate all Lagrange polynomials. - * - * The inputs are: - * - an integer m - * - an element t - * The output is a vector (b_{0},...,b_{m-1}) - * where b_{i} is the evaluation of L_{i,S}(z) at z = t. - */ - virtual std::vector lagrange_coeffs(const FieldT &t) = 0; - - /** - * Evaluate the vanishing polynomial of S at the field element t. - */ - virtual FieldT compute_Z(const FieldT &t) = 0; - - /** - * Add the coefficients of the vanishing polynomial of S to the coefficients of the polynomial H. - */ - virtual void add_poly_Z(const FieldT &coeff, std::vector &H) = 0; - - /** - * Multiply by the evaluation, on a coset of S, of the inverse of the vanishing polynomial of S. - */ - virtual void divide_by_Z_on_coset(std::vector &P) = 0; -}; - -/** - * Return an evaluation domain object in which the domain S has size |S| >= min_size. - * The function chooses from different supported domains, depending on min_size. - */ -template -std::shared_ptr > get_evaluation_domain(const size_t min_size); - -/** - * Naive evaluation of a *single* Lagrange polynomial, used for testing purposes. - * - * The inputs are: - * - an integer m - * - a domain S = (a_{0},...,a_{m-1}) of size m - * - a field element element t - * - an index idx in {0,...,m-1} - * The output is the polynomial L_{idx,S}(z) evaluated at z = t. - */ -template -FieldT lagrange_eval(const size_t m, const std::vector &domain, const FieldT &t, const size_t idx); - -} // libsnark - -#include "algebra/evaluation_domain/evaluation_domain.tcc" - -#endif // EVALUATION_DOMAIN_HPP_ diff --git a/src/snark/libsnark/algebra/evaluation_domain/evaluation_domain.tcc b/src/snark/libsnark/algebra/evaluation_domain/evaluation_domain.tcc deleted file mode 100644 index d0e28c8ce..000000000 --- a/src/snark/libsnark/algebra/evaluation_domain/evaluation_domain.tcc +++ /dev/null @@ -1,118 +0,0 @@ -/** @file - ***************************************************************************** - - Imeplementation of interfaces for evaluation domains. - - See evaluation_domain.hpp . - - We currently implement, and select among, three types of domains: - - "basic radix-2": the domain has size m = 2^k and consists of the m-th roots of unity - - "extended radix-2": the domain has size m = 2^{k+1} and consists of "the m-th roots of unity" union "a coset" - - "step radix-2": the domain has size m = 2^k + 2^r and consists of "the 2^k-th roots of unity" union "a coset of 2^r-th roots of unity" - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef EVALUATION_DOMAIN_TCC_ -#define EVALUATION_DOMAIN_TCC_ - -#include -#include "algebra/fields/field_utils.hpp" -#include "algebra/evaluation_domain/domains/basic_radix2_domain.hpp" -#include "common/assert_except.hpp" - -namespace libsnark { - -template -std::shared_ptr > get_evaluation_domain(const size_t min_size) -{ - assert_except(min_size > 1); - const size_t log_min_size = log2(min_size); - assert_except(log_min_size <= (FieldT::s+1)); - - std::shared_ptr > result; - if (min_size == (1u << log_min_size)) - { - if (log_min_size == FieldT::s+1) - { - if (!inhibit_profiling_info) - { - print_indent(); printf("* Selected domain: extended_radix2\n"); - } - assert_except(0); - } - else - { - if (!inhibit_profiling_info) - { - print_indent(); printf("* Selected domain: basic_radix2\n"); - } - result.reset(new basic_radix2_domain(min_size)); - } - } - else - { - const size_t big = UINT64_C(1)<<(log2(min_size)-1); - const size_t small = min_size - big; - const size_t rounded_small = (UINT64_C(1)<(big + rounded_small)); - } - else - { - if (!inhibit_profiling_info) - { - print_indent(); printf("* Selected domain: extended_radix2\n"); - } - assert_except(0); - } - } - else - { - if (!inhibit_profiling_info) - { - print_indent(); printf("* Selected domain: step_radix2\n"); - } - assert_except(0); - } - } - - return result; -} - -template -FieldT lagrange_eval(const size_t m, const std::vector &domain, const FieldT &t, const size_t idx) -{ - assert_except(m == domain.size()); - assert_except(idx < m); - - FieldT num = FieldT::one(); - FieldT denom = FieldT::one(); - - for (size_t k = 0; k < m; ++k) - { - if (k == idx) - { - continue; - } - - num *= t - domain[k]; - denom *= domain[idx] - domain[k]; - } - - return num * denom.inverse(); -} - -} // libsnark - -#endif // EVALUATION_DOMAIN_TCC_ diff --git a/src/snark/libsnark/algebra/exponentiation/exponentiation.hpp b/src/snark/libsnark/algebra/exponentiation/exponentiation.hpp deleted file mode 100644 index 836ebf002..000000000 --- a/src/snark/libsnark/algebra/exponentiation/exponentiation.hpp +++ /dev/null @@ -1,31 +0,0 @@ -/** @file - ***************************************************************************** - - Declaration of interfaces for (square-and-multiply) exponentiation. - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef EXPONENTIATION_HPP_ -#define EXPONENTIATION_HPP_ - -#include - -#include "algebra/fields/bigint.hpp" - -namespace libsnark { - -template -FieldT power(const FieldT &base, const bigint &exponent); - -template -FieldT power(const FieldT &base, const uint64_t exponent); - -} // libsnark - -#include "algebra/exponentiation/exponentiation.tcc" - -#endif // EXPONENTIATION_HPP_ diff --git a/src/snark/libsnark/algebra/exponentiation/exponentiation.tcc b/src/snark/libsnark/algebra/exponentiation/exponentiation.tcc deleted file mode 100644 index 7ac3bf5d3..000000000 --- a/src/snark/libsnark/algebra/exponentiation/exponentiation.tcc +++ /dev/null @@ -1,53 +0,0 @@ -/** @file - ***************************************************************************** - - Implementation of interfaces for (square-and-multiply) exponentiation. - - See exponentiation.hpp . - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef EXPONENTIATION_TCC_ -#define EXPONENTIATION_TCC_ - -#include "common/utils.hpp" - -namespace libsnark { - -template -FieldT power(const FieldT &base, const bigint &exponent) -{ - FieldT result = FieldT::one(); - - bool found_one = false; - - for (int64_t i = exponent.max_bits() - 1; i >= 0; --i) - { - if (found_one) - { - result = result * result; - } - - if (exponent.test_bit(i)) - { - found_one = true; - result = result * base; - } - } - - return result; -} - -template -FieldT power(const FieldT &base, const uint64_t exponent) -{ - return power(base, bigint<1>(exponent)); -} - -} // libsnark - -#endif // EXPONENTIATION_TCC_ diff --git a/src/snark/libsnark/algebra/fields/bigint.hpp b/src/snark/libsnark/algebra/fields/bigint.hpp deleted file mode 100644 index d17e9a7bb..000000000 --- a/src/snark/libsnark/algebra/fields/bigint.hpp +++ /dev/null @@ -1,70 +0,0 @@ -/** @file - ***************************************************************************** - Declaration of bigint wrapper class around GMP's MPZ long integers. - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef BIGINT_HPP_ -#define BIGINT_HPP_ -#include -#include -#include -#include "common/serialization.hpp" - -namespace libsnark { - -template class bigint; -template std::ostream& operator<<(std::ostream &, const bigint&); -template std::istream& operator>>(std::istream &, bigint&); - -/** - * Wrapper class around GMP's MPZ long integers. It supports arithmetic operations, - * serialization and randomization. Serialization is fragile, see common/serialization.hpp. - */ - -template -class bigint { -public: - static const mp_size_t N = n; - - mp_limb_t data[n] = {0}; - - bigint() = default; - bigint(const uint64_t x); /// Initalize from a small integer - bigint(const char* s); /// Initialize from a string containing an integer in decimal notation - bigint(const mpz_t r); /// Initialize from MPZ element - - void print() const; - void print_hex() const; - bool operator==(const bigint& other) const; - bool operator!=(const bigint& other) const; - void clear(); - bool is_zero() const; - size_t max_bits() const { return n * GMP_NUMB_BITS; } - size_t num_bits() const; - - uint64_t as_uint64() const; /* return the last limb of the integer */ - void to_mpz(mpz_t r) const; - bool test_bit(const std::size_t bitno) const; - - template inline void operator+=(const bigint& other); - template inline bigint operator*(const bigint& other) const; - template static inline void div_qr(bigint& quotient, bigint& remainder, - const bigint& dividend, const bigint& divisor); - template inline bigint shorten(const bigint& q, const char *msg) const; - - inline void limit(const bigint& q, const char *msg) const; - bool operator>(const bigint& other) const; - - bigint& randomize(); - - friend std::ostream& operator<< (std::ostream &out, const bigint &b); - friend std::istream& operator>> (std::istream &in, bigint &b); -}; - -} // libsnark -#include "algebra/fields/bigint.tcc" -#endif diff --git a/src/snark/libsnark/algebra/fields/bigint.tcc b/src/snark/libsnark/algebra/fields/bigint.tcc deleted file mode 100644 index fada2d06b..000000000 --- a/src/snark/libsnark/algebra/fields/bigint.tcc +++ /dev/null @@ -1,280 +0,0 @@ -/** @file - ***************************************************************************** - Implementation of bigint wrapper class around GMP's MPZ long integers. - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef BIGINT_TCC_ -#define BIGINT_TCC_ -#include -#include -#include -#include "sodium.h" -#include "common/assert_except.hpp" - -namespace libsnark { - -template -bigint::bigint(const uint64_t x) /// Initialize from a small integer -{ - static_assert(UINT64_MAX <= GMP_NUMB_MAX, "uint64_t does not fit in a GMP limb"); - this->data[0] = x; -} - -template -bigint::bigint(const char* s) /// Initialize from a string containing an integer in decimal notation -{ - size_t l = strlen(s); - unsigned char* s_copy = new unsigned char[l]; - - for (size_t i = 0; i < l; ++i) - { - assert_except(s[i] >= '0' && s[i] <= '9'); - s_copy[i] = s[i] - '0'; - } - - mp_size_t limbs_written = mpn_set_str(this->data, s_copy, l, 10); - assert_except(limbs_written <= n); - - delete[] s_copy; -} - -template -bigint::bigint(const mpz_t r) /// Initialize from MPZ element -{ - mpz_t k; - mpz_init_set(k, r); - - for (size_t i = 0; i < n; ++i) - { - data[i] = mpz_get_ui(k); - mpz_fdiv_q_2exp(k, k, GMP_NUMB_BITS); - } - - assert_except(mpz_sgn(k) == 0); - mpz_clear(k); -} - -template -void bigint::print() const -{ - gmp_printf("%Nd\n", this->data, n); -} - -template -void bigint::print_hex() const -{ - gmp_printf("%Nx\n", this->data, n); -} - -template -bool bigint::operator==(const bigint& other) const -{ - return (mpn_cmp(this->data, other.data, n) == 0); -} - -template -bool bigint::operator!=(const bigint& other) const -{ - return !(operator==(other)); -} - -template -void bigint::clear() -{ - mpn_zero(this->data, n); -} - -template -bool bigint::is_zero() const -{ - for (mp_size_t i = 0; i < n; ++i) - { - if (this->data[i]) - { - return false; - } - } - - return true; -} - -template -size_t bigint::num_bits() const -{ -/* - for (int64_t i = max_bits(); i >= 0; --i) - { - if (this->test_bit(i)) - { - return i+1; - } - } - - return 0; -*/ - for (int64_t i = n-1; i >= 0; --i) - { - mp_limb_t x = this->data[i]; - if (x == 0) - { - continue; - } - else - { - static_assert(GMP_NUMB_MAX <= ULLONG_MAX, "coercing limb to unsigned long long might truncate"); - return ((i+1) * GMP_NUMB_BITS) - __builtin_clzll(x); - } - } - return 0; -} - -template -uint64_t bigint::as_uint64() const -{ - return this->data[0]; -} - -template -void bigint::to_mpz(mpz_t r) const -{ - mpz_set_ui(r, 0); - - for (int i = n-1; i >= 0; --i) - { - mpz_mul_2exp(r, r, GMP_NUMB_BITS); - mpz_add_ui(r, r, this->data[i]); - } -} - -template -bool bigint::test_bit(const std::size_t bitno) const -{ - if (bitno >= n * GMP_NUMB_BITS) - { - return false; - } - else - { - const std::size_t part = bitno/GMP_NUMB_BITS; - const std::size_t bit = bitno - (GMP_NUMB_BITS*part); - const mp_limb_t one = 1; - return (this->data[part] & (one< template -inline void bigint::operator+=(const bigint& other) -{ - static_assert(n >= m, "first arg must not be smaller than second arg for bigint in-place add"); - mpn_add(data, data, n, other.data, m); -} - -template template -inline bigint bigint::operator*(const bigint& other) const -{ - static_assert(n >= m, "first arg must not be smaller than second arg for bigint mul"); - bigint res; - mpn_mul(res.data, data, n, other.data, m); - return res; -} - -template template -inline void bigint::div_qr(bigint& quotient, bigint& remainder, - const bigint& dividend, const bigint& divisor) -{ - static_assert(n >= d, "dividend must not be smaller than divisor for bigint::div_qr"); - assert_except(divisor.data[d-1] != 0); - mpn_tdiv_qr(quotient.data, remainder.data, 0, dividend.data, n, divisor.data, d); -} - -// Return a copy shortened to m limbs provided it is less than limit, throwing std::domain_error if not in range. -template template -inline bigint bigint::shorten(const bigint& q, const char *msg) const -{ - static_assert(m <= n, "number of limbs must not increase for bigint::shorten"); - for (mp_size_t i = m; i < n; i++) { // high-order limbs - if (data[i] != 0) { - throw std::domain_error(msg); - } - } - bigint res; - mpn_copyi(res.data, data, m); - res.limit(q, msg); - return res; -} - -template -inline void bigint::limit(const bigint& q, const char *msg) const -{ - if (!(q > *this)) { - throw std::domain_error(msg); - } -} - -template -inline bool bigint::operator>(const bigint& other) const -{ - return mpn_cmp(this->data, other.data, n) > 0; -} - -template -bigint& bigint::randomize() -{ - assert_except(GMP_NUMB_BITS == sizeof(mp_limb_t) * 8); - - randombytes_buf(this->data, sizeof(mp_limb_t) * n); - - return (*this); -} - - -template -std::ostream& operator<<(std::ostream &out, const bigint &b) -{ -#ifdef BINARY_OUTPUT - out.write((char*)b.data, sizeof(b.data[0]) * n); -#else - mpz_t t; - mpz_init(t); - b.to_mpz(t); - - out << t; - - mpz_clear(t); -#endif - return out; -} - -template -std::istream& operator>>(std::istream &in, bigint &b) -{ -#ifdef BINARY_OUTPUT - in.read((char*)b.data, sizeof(b.data[0]) * n); -#else - std::string s; - in >> s; - - size_t l = s.size(); - unsigned char* s_copy = new unsigned char[l]; - - for (size_t i = 0; i < l; ++i) - { - assert_except(s[i] >= '0' && s[i] <= '9'); - s_copy[i] = s[i] - '0'; - } - - mp_size_t limbs_written = mpn_set_str(b.data, s_copy, l, 10); - assert_except(limbs_written <= n); - - delete[] s_copy; -#endif - return in; -} - -} // libsnark -#endif // BIGINT_TCC_ diff --git a/src/snark/libsnark/algebra/fields/field_utils.hpp b/src/snark/libsnark/algebra/fields/field_utils.hpp deleted file mode 100644 index 8358e48b3..000000000 --- a/src/snark/libsnark/algebra/fields/field_utils.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/** @file - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef FIELD_UTILS_HPP_ -#define FIELD_UTILS_HPP_ -#include - -#include "common/utils.hpp" -#include "algebra/fields/bigint.hpp" - -namespace libsnark { - -// returns root of unity of order n (for n a power of 2), if one exists -template -FieldT get_root_of_unity(const uint64_t n); - -template -std::vector pack_int_vector_into_field_element_vector(const std::vector &v, const uint64_t w); - -template -std::vector pack_bit_vector_into_field_element_vector(const bit_vector &v, const uint64_t chunk_bits); - -template -std::vector pack_bit_vector_into_field_element_vector(const bit_vector &v); - -template -std::vector convert_bit_vector_to_field_element_vector(const bit_vector &v); - -template -bit_vector convert_field_element_vector_to_bit_vector(const std::vector &v); - -template -bit_vector convert_field_element_to_bit_vector(const FieldT &el); - -template -bit_vector convert_field_element_to_bit_vector(const FieldT &el, const uint64_t bitcount); - -template -FieldT convert_bit_vector_to_field_element(const bit_vector &v); - -template -void batch_invert(std::vector &vec); - -} // libsnark -#include "algebra/fields/field_utils.tcc" - -#endif // FIELD_UTILS_HPP_ diff --git a/src/snark/libsnark/algebra/fields/field_utils.tcc b/src/snark/libsnark/algebra/fields/field_utils.tcc deleted file mode 100644 index a0928605d..000000000 --- a/src/snark/libsnark/algebra/fields/field_utils.tcc +++ /dev/null @@ -1,184 +0,0 @@ -/** @file - ***************************************************************************** - Implementation of misc. math and serialization utility functions - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef FIELD_UTILS_TCC_ -#define FIELD_UTILS_TCC_ - -#include "common/utils.hpp" -#include "common/assert_except.hpp" - -namespace libsnark { - -template -FieldT coset_shift() -{ - return FieldT::multiplicative_generator.squared(); -} - -template -FieldT get_root_of_unity(const uint64_t n) -{ - const uint64_t logn = log2(n); - assert_except(n == (1u << logn)); - assert_except(logn <= FieldT::s); - - FieldT omega = FieldT::root_of_unity; - for (uint64_t i = FieldT::s; i > logn; --i) - { - omega *= omega; - } - - return omega; -} - -template -std::vector pack_int_vector_into_field_element_vector(const std::vector &v, const uint64_t w) -{ - const uint64_t chunk_bits = FieldT::capacity(); - const uint64_t repacked_size = div_ceil(v.size() * w, chunk_bits); - std::vector result(repacked_size); - - for (uint64_t i = 0; i < repacked_size; ++i) - { - bigint b; - for (uint64_t j = 0; j < chunk_bits; ++j) - { - const uint64_t word_index = (i * chunk_bits + j) / w; - const uint64_t pos_in_word = (i * chunk_bits + j) % w; - const uint64_t word_or_0 = (word_index < v.size() ? v[word_index] : 0); - const uint64_t bit = (word_or_0 >> pos_in_word) & 1; - - b.data[j / GMP_NUMB_BITS] |= bit << (j % GMP_NUMB_BITS); - } - result[i] = FieldT(b); - } - - return result; -} - -template -std::vector pack_bit_vector_into_field_element_vector(const bit_vector &v, const uint64_t chunk_bits) -{ - assert_except(chunk_bits <= FieldT::capacity()); - - const uint64_t repacked_size = div_ceil(v.size(), chunk_bits); - std::vector result(repacked_size); - - for (size_t i = 0; i < repacked_size; ++i) - { - bigint b; - for (size_t j = 0; j < chunk_bits; ++j) - { - b.data[j / GMP_NUMB_BITS] |= ((i * chunk_bits + j) < v.size() && v[i * chunk_bits + j] ? 1ll : 0ll) << (j % GMP_NUMB_BITS); - } - result[i] = FieldT(b); - } - - return result; -} - -template -std::vector pack_bit_vector_into_field_element_vector(const bit_vector &v) -{ - return pack_bit_vector_into_field_element_vector(v, FieldT::capacity()); -} - -template -std::vector convert_bit_vector_to_field_element_vector(const bit_vector &v) -{ - std::vector result; - result.reserve(v.size()); - - for (const bool b : v) - { - result.emplace_back(b ? FieldT::one() : FieldT::zero()); - } - - return result; -} - -template -bit_vector convert_field_element_vector_to_bit_vector(const std::vector &v) -{ - bit_vector result; - - for (const FieldT &el : v) - { - const bit_vector el_bits = convert_field_element_to_bit_vector(el); - result.insert(result.end(), el_bits.begin(), el_bits.end()); - } - - return result; -} - -template -bit_vector convert_field_element_to_bit_vector(const FieldT &el) -{ - bit_vector result; - - bigint b = el.as_bigint(); - for (size_t i = 0; i < FieldT::size_in_bits(); ++i) - { - result.push_back(b.test_bit(i)); - } - - return result; -} - -template -bit_vector convert_field_element_to_bit_vector(const FieldT &el, const uint64_t bitcount) -{ - bit_vector result = convert_field_element_to_bit_vector(el); - result.resize(bitcount); - - return result; -} - -template -FieldT convert_bit_vector_to_field_element(const bit_vector &v) -{ - assert_except(v.size() <= FieldT::size_in_bits()); - - FieldT res = FieldT::zero(); - FieldT c = FieldT::one(); - for (bool b : v) - { - res += b ? c : FieldT::zero(); - c += c; - } - return res; -} - -template -void batch_invert(std::vector &vec) -{ - std::vector prod; - prod.reserve(vec.size()); - - FieldT acc = FieldT::one(); - - for (auto el : vec) - { - assert_except(!el.is_zero()); - prod.emplace_back(acc); - acc = acc * el; - } - - FieldT acc_inverse = acc.inverse(); - - for (int64_t i = vec.size()-1; i >= 0; --i) - { - const FieldT old_el = vec[i]; - vec[i] = acc_inverse * prod[i]; - acc_inverse = acc_inverse * old_el; - } -} - -} // libsnark -#endif // FIELD_UTILS_TCC_ diff --git a/src/snark/libsnark/algebra/fields/fp.hpp b/src/snark/libsnark/algebra/fields/fp.hpp deleted file mode 100644 index eae4634b6..000000000 --- a/src/snark/libsnark/algebra/fields/fp.hpp +++ /dev/null @@ -1,182 +0,0 @@ -/** @file - ***************************************************************************** - Declaration of arithmetic in the finite field F[p], for prime p of fixed length. - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef FP_HPP_ -#define FP_HPP_ - -#include "algebra/fields/bigint.hpp" -#include "algebra/exponentiation/exponentiation.hpp" - -namespace libsnark { - -template& modulus> -class Fp_model; - -template& modulus> -std::ostream& operator<<(std::ostream &, const Fp_model&); - -template& modulus> -std::istream& operator>>(std::istream &, Fp_model &); - -/** - * Arithmetic in the finite field F[p], for prime p of fixed length. - * - * This class implements Fp-arithmetic, for a large prime p, using a fixed number - * of words. It is optimized for tight memory consumption, so the modulus p is - * passed as a template parameter, to avoid per-element overheads. - * - * The implementation is mostly a wrapper around GMP's MPN (constant-size integers). - * But for the integer sizes of interest for libsnark (3 to 5 limbs of 64 bits each), - * we implement performance-critical routines, like addition and multiplication, - * using hand-optimzied assembly code. -*/ -template& modulus> -class Fp_model { -public: - bigint mont_repr; -public: - static const mp_size_t num_limbs = n; - static const constexpr bigint& mod = modulus; -#ifdef PROFILE_OP_COUNTS - static int64_t add_cnt; - static int64_t sub_cnt; - static int64_t mul_cnt; - static int64_t sqr_cnt; - static int64_t inv_cnt; -#endif - static uint64_t num_bits; - static bigint euler; // (modulus-1)/2 - static uint64_t s; // modulus = 2^s * t + 1 - static bigint t; // with t odd - static bigint t_minus_1_over_2; // (t-1)/2 - static Fp_model nqr; // a quadratic nonresidue - static Fp_model nqr_to_t; // nqr^t - static Fp_model multiplicative_generator; // generator of Fp^* - static Fp_model root_of_unity; // generator^((modulus-1)/2^s) - static mp_limb_t inv; // modulus^(-1) mod W, where W = 2^(word size) - static bigint Rsquared; // R^2, where R = W^k, where k = ?? - static bigint Rcubed; // R^3 - - static bool modulus_is_valid() { return modulus.data[n-1] != 0; } // mpn inverse assumes that highest limb is non-zero - - Fp_model() {}; - Fp_model(const bigint &b); - Fp_model(const int64_t x, const bool is_unsigned=false); - - void set_uint64(const uint64_t x); - - void mul_reduce(const bigint &other); - - void clear(); - - /* Return the standard (not Montgomery) representation of the - Field element's requivalence class. I.e. Fp(2).as_bigint() - would return bigint(2) */ - bigint as_bigint() const; - /* Return the last limb of the standard representation of the - field element. E.g. on 64-bit architectures Fp(123).as_uint64() - and Fp(2^64+123).as_uint64() would both return 123. */ - uint64_t as_uint64() const; - - bool operator==(const Fp_model& other) const; - bool operator!=(const Fp_model& other) const; - bool is_zero() const; - - void print() const; - - Fp_model& operator+=(const Fp_model& other); - Fp_model& operator-=(const Fp_model& other); - Fp_model& operator*=(const Fp_model& other); - Fp_model& operator^=(const uint64_t pow); - - template - Fp_model& operator^=(const bigint &pow); - - Fp_model operator+(const Fp_model& other) const; - Fp_model operator-(const Fp_model& other) const; - Fp_model operator*(const Fp_model& other) const; - Fp_model operator-() const; - Fp_model squared() const; - Fp_model& invert(); - Fp_model inverse() const; - Fp_model sqrt() const; // HAS TO BE A SQUARE (else does not terminate) - - Fp_model operator^(const uint64_t pow) const; - template - Fp_model operator^(const bigint &pow) const; - - static uint64_t size_in_bits() { return num_bits; } - static uint64_t capacity() { return num_bits - 1; } - static bigint field_char() { return modulus; } - - static Fp_model zero(); - static Fp_model one(); - static Fp_model random_element(); - - friend std::ostream& operator<< (std::ostream &out, const Fp_model &p); - friend std::istream& operator>> (std::istream &in, Fp_model &p); -}; - -#ifdef PROFILE_OP_COUNTS -template& modulus> -int64_t Fp_model::add_cnt = 0; - -template& modulus> -int64_t Fp_model::sub_cnt = 0; - -template& modulus> -int64_t Fp_model::mul_cnt = 0; - -template& modulus> -int64_t Fp_model::sqr_cnt = 0; - -template& modulus> -int64_t Fp_model::inv_cnt = 0; -#endif - -template& modulus> -uint64_t Fp_model::num_bits; - -template& modulus> -bigint Fp_model::euler; - -template& modulus> -uint64_t Fp_model::s; - -template& modulus> -bigint Fp_model::t; - -template& modulus> -bigint Fp_model::t_minus_1_over_2; - -template& modulus> -Fp_model Fp_model::nqr; - -template& modulus> -Fp_model Fp_model::nqr_to_t; - -template& modulus> -Fp_model Fp_model::multiplicative_generator; - -template& modulus> -Fp_model Fp_model::root_of_unity; - -template& modulus> -mp_limb_t Fp_model::inv; - -template& modulus> -bigint Fp_model::Rsquared; - -template& modulus> -bigint Fp_model::Rcubed; - -} // libsnark -#include "algebra/fields/fp.tcc" - -#endif // FP_HPP_ diff --git a/src/snark/libsnark/algebra/fields/fp.tcc b/src/snark/libsnark/algebra/fields/fp.tcc deleted file mode 100644 index f1d97153f..000000000 --- a/src/snark/libsnark/algebra/fields/fp.tcc +++ /dev/null @@ -1,790 +0,0 @@ -/** @file - ***************************************************************************** - Implementation of arithmetic in the finite field F[p], for prime p of fixed length. - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef FP_TCC_ -#define FP_TCC_ -#include -#include -#include - -#include "algebra/fields/fp_aux.tcc" -#include "algebra/fields/field_utils.hpp" -#include "common/assert_except.hpp" - -namespace libsnark { - -template& modulus> -void Fp_model::mul_reduce(const bigint &other) -{ - /* stupid pre-processor tricks; beware */ -#if defined(__x86_64__) && defined(USE_ASM) - if (n == 3) - { // Use asm-optimized Comba multiplication and reduction - mp_limb_t res[2*n]; - mp_limb_t c0, c1, c2; - COMBA_3_BY_3_MUL(c0, c1, c2, res, this->mont_repr.data, other.data); - - mp_limb_t k; - mp_limb_t tmp1, tmp2, tmp3; - REDUCE_6_LIMB_PRODUCT(k, tmp1, tmp2, tmp3, inv, res, modulus.data); - - /* subtract t > mod */ - __asm__ - ("/* check for overflow */ \n\t" - MONT_CMP(16) - MONT_CMP(8) - MONT_CMP(0) - - "/* subtract mod if overflow */ \n\t" - "subtract%=: \n\t" - MONT_FIRSTSUB - MONT_NEXTSUB(8) - MONT_NEXTSUB(16) - "done%=: \n\t" - : - : [tmp] "r" (res+n), [M] "r" (modulus.data) - : "cc", "memory", "%rax"); - mpn_copyi(this->mont_repr.data, res+n, n); - } - else if (n == 4) - { // use asm-optimized "CIOS method" - - mp_limb_t tmp[n+1]; - mp_limb_t T0=0, T1=1, cy=2, u=3; // TODO: fix this - - __asm__ (MONT_PRECOMPUTE - MONT_FIRSTITER(1) - MONT_FIRSTITER(2) - MONT_FIRSTITER(3) - MONT_FINALIZE(3) - MONT_ITERFIRST(1) - MONT_ITERITER(1, 1) - MONT_ITERITER(1, 2) - MONT_ITERITER(1, 3) - MONT_FINALIZE(3) - MONT_ITERFIRST(2) - MONT_ITERITER(2, 1) - MONT_ITERITER(2, 2) - MONT_ITERITER(2, 3) - MONT_FINALIZE(3) - MONT_ITERFIRST(3) - MONT_ITERITER(3, 1) - MONT_ITERITER(3, 2) - MONT_ITERITER(3, 3) - MONT_FINALIZE(3) - "/* check for overflow */ \n\t" - MONT_CMP(24) - MONT_CMP(16) - MONT_CMP(8) - MONT_CMP(0) - - "/* subtract mod if overflow */ \n\t" - "subtract%=: \n\t" - MONT_FIRSTSUB - MONT_NEXTSUB(8) - MONT_NEXTSUB(16) - MONT_NEXTSUB(24) - "done%=: \n\t" - : - : [tmp] "r" (tmp), [A] "r" (this->mont_repr.data), [B] "r" (other.data), [inv] "r" (inv), [M] "r" (modulus.data), - [T0] "r" (T0), [T1] "r" (T1), [cy] "r" (cy), [u] "r" (u) - : "cc", "memory", "%rax", "%rdx" - ); - mpn_copyi(this->mont_repr.data, tmp, n); - } - else if (n == 5) - { // use asm-optimized "CIOS method" - - mp_limb_t tmp[n+1]; - mp_limb_t T0=0, T1=1, cy=2, u=3; // TODO: fix this - - __asm__ (MONT_PRECOMPUTE - MONT_FIRSTITER(1) - MONT_FIRSTITER(2) - MONT_FIRSTITER(3) - MONT_FIRSTITER(4) - MONT_FINALIZE(4) - MONT_ITERFIRST(1) - MONT_ITERITER(1, 1) - MONT_ITERITER(1, 2) - MONT_ITERITER(1, 3) - MONT_ITERITER(1, 4) - MONT_FINALIZE(4) - MONT_ITERFIRST(2) - MONT_ITERITER(2, 1) - MONT_ITERITER(2, 2) - MONT_ITERITER(2, 3) - MONT_ITERITER(2, 4) - MONT_FINALIZE(4) - MONT_ITERFIRST(3) - MONT_ITERITER(3, 1) - MONT_ITERITER(3, 2) - MONT_ITERITER(3, 3) - MONT_ITERITER(3, 4) - MONT_FINALIZE(4) - MONT_ITERFIRST(4) - MONT_ITERITER(4, 1) - MONT_ITERITER(4, 2) - MONT_ITERITER(4, 3) - MONT_ITERITER(4, 4) - MONT_FINALIZE(4) - "/* check for overflow */ \n\t" - MONT_CMP(32) - MONT_CMP(24) - MONT_CMP(16) - MONT_CMP(8) - MONT_CMP(0) - - "/* subtract mod if overflow */ \n\t" - "subtract%=: \n\t" - MONT_FIRSTSUB - MONT_NEXTSUB(8) - MONT_NEXTSUB(16) - MONT_NEXTSUB(24) - MONT_NEXTSUB(32) - "done%=: \n\t" - : - : [tmp] "r" (tmp), [A] "r" (this->mont_repr.data), [B] "r" (other.data), [inv] "r" (inv), [M] "r" (modulus.data), - [T0] "r" (T0), [T1] "r" (T1), [cy] "r" (cy), [u] "r" (u) - : "cc", "memory", "%rax", "%rdx" - ); - mpn_copyi(this->mont_repr.data, tmp, n); - } - else -#endif - { - mp_limb_t res[2*n]; - mpn_mul_n(res, this->mont_repr.data, other.data, n); - - /* - The Montgomery reduction here is based on Algorithm 14.32 in - Handbook of Applied Cryptography - . - */ - for (size_t i = 0; i < n; ++i) - { - mp_limb_t k = inv * res[i]; - /* calculate res = res + k * mod * b^i */ - mp_limb_t carryout = mpn_addmul_1(res+i, modulus.data, n, k); - carryout = mpn_add_1(res+n+i, res+n+i, n-i, carryout); - assert_except(carryout == 0); - } - - if (mpn_cmp(res+n, modulus.data, n) >= 0) - { - const mp_limb_t borrow = mpn_sub(res+n, res+n, n, modulus.data, n); - assert_except(borrow == 0); - } - - mpn_copyi(this->mont_repr.data, res+n, n); - } -} - -template& modulus> -Fp_model::Fp_model(const bigint &b) -{ - mpn_copyi(this->mont_repr.data, Rsquared.data, n); - mul_reduce(b); -} - -template& modulus> -Fp_model::Fp_model(const int64_t x, const bool is_unsigned) -{ - if (is_unsigned || x >= 0) - { - this->mont_repr.data[0] = x; - } - else - { - const mp_limb_t borrow = mpn_sub_1(this->mont_repr.data, modulus.data, n, -x); - assert_except(borrow == 0); - } - - mul_reduce(Rsquared); -} - -template& modulus> -void Fp_model::set_uint64(const uint64_t x) -{ - this->mont_repr.clear(); - this->mont_repr.data[0] = x; - mul_reduce(Rsquared); -} - -template& modulus> -void Fp_model::clear() -{ - this->mont_repr.clear(); -} - -template& modulus> -bigint Fp_model::as_bigint() const -{ - bigint one; - one.clear(); - one.data[0] = 1; - - Fp_model res(*this); - res.mul_reduce(one); - - return (res.mont_repr); -} - -template& modulus> -uint64_t Fp_model::as_uint64() const -{ - return this->as_bigint().as_uint64(); -} - -template& modulus> -bool Fp_model::operator==(const Fp_model& other) const -{ - return (this->mont_repr == other.mont_repr); -} - -template& modulus> -bool Fp_model::operator!=(const Fp_model& other) const -{ - return (this->mont_repr != other.mont_repr); -} - -template& modulus> -bool Fp_model::is_zero() const -{ - return (this->mont_repr.is_zero()); // zero maps to zero -} - -template& modulus> -void Fp_model::print() const -{ - Fp_model tmp; - tmp.mont_repr.data[0] = 1; - tmp.mul_reduce(this->mont_repr); - - tmp.mont_repr.print(); -} - -template& modulus> -Fp_model Fp_model::zero() -{ - Fp_model res; - res.mont_repr.clear(); - return res; -} - -template& modulus> -Fp_model Fp_model::one() -{ - Fp_model res; - res.mont_repr.data[0] = 1; - res.mul_reduce(Rsquared); - return res; -} - -template& modulus> -Fp_model& Fp_model::operator+=(const Fp_model& other) -{ -#ifdef PROFILE_OP_COUNTS - this->add_cnt++; -#endif -#if defined(__x86_64__) && defined(USE_ASM) - if (n == 3) - { - __asm__ - ("/* perform bignum addition */ \n\t" - ADD_FIRSTADD - ADD_NEXTADD(8) - ADD_NEXTADD(16) - "/* if overflow: subtract */ \n\t" - "/* (tricky point: if A and B are in the range we do not need to do anything special for the possible carry flag) */ \n\t" - "jc subtract%= \n\t" - - "/* check for overflow */ \n\t" - ADD_CMP(16) - ADD_CMP(8) - ADD_CMP(0) - - "/* subtract mod if overflow */ \n\t" - "subtract%=: \n\t" - ADD_FIRSTSUB - ADD_NEXTSUB(8) - ADD_NEXTSUB(16) - "done%=: \n\t" - : - : [A] "r" (this->mont_repr.data), [B] "r" (other.mont_repr.data), [mod] "r" (modulus.data) - : "cc", "memory", "%rax"); - } - else if (n == 4) - { - __asm__ - ("/* perform bignum addition */ \n\t" - ADD_FIRSTADD - ADD_NEXTADD(8) - ADD_NEXTADD(16) - ADD_NEXTADD(24) - "/* if overflow: subtract */ \n\t" - "/* (tricky point: if A and B are in the range we do not need to do anything special for the possible carry flag) */ \n\t" - "jc subtract%= \n\t" - - "/* check for overflow */ \n\t" - ADD_CMP(24) - ADD_CMP(16) - ADD_CMP(8) - ADD_CMP(0) - - "/* subtract mod if overflow */ \n\t" - "subtract%=: \n\t" - ADD_FIRSTSUB - ADD_NEXTSUB(8) - ADD_NEXTSUB(16) - ADD_NEXTSUB(24) - "done%=: \n\t" - : - : [A] "r" (this->mont_repr.data), [B] "r" (other.mont_repr.data), [mod] "r" (modulus.data) - : "cc", "memory", "%rax"); - } - else if (n == 5) - { - __asm__ - ("/* perform bignum addition */ \n\t" - ADD_FIRSTADD - ADD_NEXTADD(8) - ADD_NEXTADD(16) - ADD_NEXTADD(24) - ADD_NEXTADD(32) - "/* if overflow: subtract */ \n\t" - "/* (tricky point: if A and B are in the range we do not need to do anything special for the possible carry flag) */ \n\t" - "jc subtract%= \n\t" - - "/* check for overflow */ \n\t" - ADD_CMP(32) - ADD_CMP(24) - ADD_CMP(16) - ADD_CMP(8) - ADD_CMP(0) - - "/* subtract mod if overflow */ \n\t" - "subtract%=: \n\t" - ADD_FIRSTSUB - ADD_NEXTSUB(8) - ADD_NEXTSUB(16) - ADD_NEXTSUB(24) - ADD_NEXTSUB(32) - "done%=: \n\t" - : - : [A] "r" (this->mont_repr.data), [B] "r" (other.mont_repr.data), [mod] "r" (modulus.data) - : "cc", "memory", "%rax"); - } - else -#endif - { - mp_limb_t scratch[n+1]; - const mp_limb_t carry = mpn_add_n(scratch, this->mont_repr.data, other.mont_repr.data, n); - scratch[n] = carry; - - if (carry || mpn_cmp(scratch, modulus.data, n) >= 0) - { - const mp_limb_t borrow = mpn_sub(scratch, scratch, n+1, modulus.data, n); - assert_except(borrow == 0); - } - - mpn_copyi(this->mont_repr.data, scratch, n); - } - - return *this; -} - -template& modulus> -Fp_model& Fp_model::operator-=(const Fp_model& other) -{ -#ifdef PROFILE_OP_COUNTS - this->sub_cnt++; -#endif -#if defined(__x86_64__) && defined(USE_ASM) - if (n == 3) - { - __asm__ - (SUB_FIRSTSUB - SUB_NEXTSUB(8) - SUB_NEXTSUB(16) - - "jnc done%=\n\t" - - SUB_FIRSTADD - SUB_NEXTADD(8) - SUB_NEXTADD(16) - - "done%=:\n\t" - : - : [A] "r" (this->mont_repr.data), [B] "r" (other.mont_repr.data), [mod] "r" (modulus.data) - : "cc", "memory", "%rax"); - } - else if (n == 4) - { - __asm__ - (SUB_FIRSTSUB - SUB_NEXTSUB(8) - SUB_NEXTSUB(16) - SUB_NEXTSUB(24) - - "jnc done%=\n\t" - - SUB_FIRSTADD - SUB_NEXTADD(8) - SUB_NEXTADD(16) - SUB_NEXTADD(24) - - "done%=:\n\t" - : - : [A] "r" (this->mont_repr.data), [B] "r" (other.mont_repr.data), [mod] "r" (modulus.data) - : "cc", "memory", "%rax"); - } - else if (n == 5) - { - __asm__ - (SUB_FIRSTSUB - SUB_NEXTSUB(8) - SUB_NEXTSUB(16) - SUB_NEXTSUB(24) - SUB_NEXTSUB(32) - - "jnc done%=\n\t" - - SUB_FIRSTADD - SUB_NEXTADD(8) - SUB_NEXTADD(16) - SUB_NEXTADD(24) - SUB_NEXTADD(32) - - "done%=:\n\t" - : - : [A] "r" (this->mont_repr.data), [B] "r" (other.mont_repr.data), [mod] "r" (modulus.data) - : "cc", "memory", "%rax"); - } - else -#endif - { - mp_limb_t scratch[n+1]; - if (mpn_cmp(this->mont_repr.data, other.mont_repr.data, n) < 0) - { - const mp_limb_t carry = mpn_add_n(scratch, this->mont_repr.data, modulus.data, n); - scratch[n] = carry; - } - else - { - mpn_copyi(scratch, this->mont_repr.data, n); - scratch[n] = 0; - } - - const mp_limb_t borrow = mpn_sub(scratch, scratch, n+1, other.mont_repr.data, n); - assert_except(borrow == 0); - - mpn_copyi(this->mont_repr.data, scratch, n); - } - return *this; -} - -template& modulus> -Fp_model& Fp_model::operator*=(const Fp_model& other) -{ -#ifdef PROFILE_OP_COUNTS - this->mul_cnt++; -#endif - - mul_reduce(other.mont_repr); - return *this; -} - -template& modulus> -Fp_model& Fp_model::operator^=(const uint64_t pow) -{ - (*this) = power >(*this, pow); - return (*this); -} - -template& modulus> -template -Fp_model& Fp_model::operator^=(const bigint &pow) -{ - (*this) = power, m>(*this, pow); - return (*this); -} - -template& modulus> -Fp_model Fp_model::operator+(const Fp_model& other) const -{ - Fp_model r(*this); - return (r += other); -} - -template& modulus> -Fp_model Fp_model::operator-(const Fp_model& other) const -{ - Fp_model r(*this); - return (r -= other); -} - -template& modulus> -Fp_model Fp_model::operator*(const Fp_model& other) const -{ - Fp_model r(*this); - return (r *= other); -} - -template& modulus> -Fp_model Fp_model::operator^(const uint64_t pow) const -{ - Fp_model r(*this); - return (r ^= pow); -} - -template& modulus> -template -Fp_model Fp_model::operator^(const bigint &pow) const -{ - Fp_model r(*this); - return (r ^= pow); -} - -template& modulus> -Fp_model Fp_model::operator-() const -{ -#ifdef PROFILE_OP_COUNTS - this->sub_cnt++; -#endif - - if (this->is_zero()) - { - return (*this); - } - else - { - Fp_model r; - mpn_sub_n(r.mont_repr.data, modulus.data, this->mont_repr.data, n); - return r; - } -} - -template& modulus> -Fp_model Fp_model::squared() const -{ -#ifdef PROFILE_OP_COUNTS - this->sqr_cnt++; - this->mul_cnt--; // zero out the upcoming mul -#endif - /* stupid pre-processor tricks; beware */ -#if defined(__x86_64__) && defined(USE_ASM) - if (n == 3) - { // use asm-optimized Comba squaring - mp_limb_t res[2*n]; - mp_limb_t c0, c1, c2; - COMBA_3_BY_3_SQR(c0, c1, c2, res, this->mont_repr.data); - - mp_limb_t k; - mp_limb_t tmp1, tmp2, tmp3; - REDUCE_6_LIMB_PRODUCT(k, tmp1, tmp2, tmp3, inv, res, modulus.data); - - /* subtract t > mod */ - __asm__ volatile - ("/* check for overflow */ \n\t" - MONT_CMP(16) - MONT_CMP(8) - MONT_CMP(0) - - "/* subtract mod if overflow */ \n\t" - "subtract%=: \n\t" - MONT_FIRSTSUB - MONT_NEXTSUB(8) - MONT_NEXTSUB(16) - "done%=: \n\t" - : - : [tmp] "r" (res+n), [M] "r" (modulus.data) - : "cc", "memory", "%rax"); - - Fp_model r; - mpn_copyi(r.mont_repr.data, res+n, n); - return r; - } - else -#endif - { - Fp_model r(*this); - return (r *= r); - } -} - -template& modulus> -Fp_model& Fp_model::invert() -{ -#ifdef PROFILE_OP_COUNTS - this->inv_cnt++; -#endif - - assert_except(!this->is_zero()); - - bigint g; /* gp should have room for vn = n limbs */ - - mp_limb_t s[n+1]; /* sp should have room for vn+1 limbs */ - mp_size_t sn; - - bigint v = modulus; // both source operands are destroyed by mpn_gcdext - - /* computes gcd(u, v) = g = u*s + v*t, so s*u will be 1 (mod v) */ - const mp_size_t gn = mpn_gcdext(g.data, s, &sn, this->mont_repr.data, n, v.data, n); - assert_except(gn == 1 && g.data[0] == 1); /* inverse exists */ - - mp_limb_t q; /* division result fits into q, as sn <= n+1 */ - /* sn < 0 indicates negative sn; will fix up later */ - - if (std::abs(sn) >= n) - { - /* if sn could require modulus reduction, do it here */ - mpn_tdiv_qr(&q, this->mont_repr.data, 0, s, std::abs(sn), modulus.data, n); - } - else - { - /* otherwise just copy it over */ - mpn_zero(this->mont_repr.data, n); - mpn_copyi(this->mont_repr.data, s, std::abs(sn)); - } - - /* fix up the negative sn */ - if (sn < 0) - { - const mp_limb_t borrow = mpn_sub_n(this->mont_repr.data, modulus.data, this->mont_repr.data, n); - assert_except(borrow == 0); - } - - mul_reduce(Rcubed); - return *this; -} - -template& modulus> -Fp_model Fp_model::inverse() const -{ - Fp_model r(*this); - return (r.invert()); -} - -template& modulus> -Fp_model Fp_model::random_element() /// returns random element of Fp_model -{ - /* note that as Montgomery representation is a bijection then - selecting a random element of {xR} is the same as selecting a - random element of {x} */ - Fp_model r; - do - { - r.mont_repr.randomize(); - - /* clear all bits higher than MSB of modulus */ - uint64_t bitno = GMP_NUMB_BITS * n - 1; - while (modulus.test_bit(bitno) == false) - { - const uint64_t part = bitno/GMP_NUMB_BITS; - const uint64_t bit = bitno - (GMP_NUMB_BITS*part); - - r.mont_repr.data[part] &= ~(UINT64_C(1)<= modulus -- repeat (rejection sampling) */ - while (mpn_cmp(r.mont_repr.data, modulus.data, n) >= 0); - - return r; -} - -template& modulus> -Fp_model Fp_model::sqrt() const -{ - if (is_zero()) { - return *this; - } - - Fp_model one = Fp_model::one(); - - uint64_t v = Fp_model::s; - Fp_model z = Fp_model::nqr_to_t; - Fp_model w = (*this)^Fp_model::t_minus_1_over_2; - Fp_model x = (*this) * w; - Fp_model b = x * w; // b = (*this)^t - - - // check if square with euler's criterion - Fp_model check = b; - for (size_t i = 0; i < v-1; ++i) - { - check = check.squared(); - } - if (check != one) - { - assert_except(0); - } - - - // compute square root with Tonelli--Shanks - // (does not terminate if not a square!) - - while (b != one) - { - uint64_t m = 0; - Fp_model b2m = b; - while (b2m != one) - { - /* invariant: b2m = b^(2^m) after entering this loop */ - b2m = b2m.squared(); - m += 1; - } - - int j = v-m-1; - w = z; - while (j > 0) - { - w = w.squared(); - --j; - } // w = z^2^(v-m-1) - - z = w.squared(); - b = b * z; - x = x * w; - v = m; - } - - return x; -} - -template& modulus> -std::ostream& operator<<(std::ostream &out, const Fp_model &p) -{ -#ifndef MONTGOMERY_OUTPUT - Fp_model tmp; - tmp.mont_repr.data[0] = 1; - tmp.mul_reduce(p.mont_repr); - out << tmp.mont_repr; -#else - out << p.mont_repr; -#endif - return out; -} - -template& modulus> -std::istream& operator>>(std::istream &in, Fp_model &p) -{ -#ifndef MONTGOMERY_OUTPUT - in >> p.mont_repr; - p.mul_reduce(Fp_model::Rsquared); -#else - in >> p.mont_repr; -#endif - return in; -} - -} // libsnark -#endif // FP_TCC_ diff --git a/src/snark/libsnark/algebra/fields/fp12_2over3over2.hpp b/src/snark/libsnark/algebra/fields/fp12_2over3over2.hpp deleted file mode 100644 index 69d057a05..000000000 --- a/src/snark/libsnark/algebra/fields/fp12_2over3over2.hpp +++ /dev/null @@ -1,116 +0,0 @@ -/** @file - ***************************************************************************** - Declaration of arithmetic in the finite field F[((p^2)^3)^2]. - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef FP12_2OVER3OVER2_HPP_ -#define FP12_2OVER3OVER2_HPP_ -#include "algebra/fields/fp.hpp" -#include "algebra/fields/fp2.hpp" -#include "algebra/fields/fp6_3over2.hpp" -#include - -namespace libsnark { - -template& modulus> -class Fp12_2over3over2_model; - -template& modulus> -std::ostream& operator<<(std::ostream &, const Fp12_2over3over2_model &); - -template& modulus> -std::istream& operator>>(std::istream &, Fp12_2over3over2_model &); - -/** - * Arithmetic in the finite field F[((p^2)^3)^2]. - * - * Let p := modulus. This interface provides arithmetic for the extension field - * Fp12 = Fp6[W]/(W^2-V) where Fp6 = Fp2[V]/(V^3-non_residue) and non_residue is in Fp2 - * - * ASSUMPTION: p = 1 (mod 6) - */ -template& modulus> -class Fp12_2over3over2_model { -public: - typedef Fp_model my_Fp; - typedef Fp2_model my_Fp2; - typedef Fp6_3over2_model my_Fp6; - - static Fp2_model non_residue; - static Fp2_model Frobenius_coeffs_c1[12]; // non_residue^((modulus^i-1)/6) for i=0,...,11 - - my_Fp6 c0, c1; - Fp12_2over3over2_model() {}; - Fp12_2over3over2_model(const my_Fp6& c0, const my_Fp6& c1) : c0(c0), c1(c1) {}; - - void clear() { c0.clear(); c1.clear(); } - void print() const { printf("c0/c1:\n"); c0.print(); c1.print(); } - - static Fp12_2over3over2_model zero(); - static Fp12_2over3over2_model one(); - static Fp12_2over3over2_model random_element(); - - bool is_zero() const { return c0.is_zero() && c1.is_zero(); } - bool operator==(const Fp12_2over3over2_model &other) const; - bool operator!=(const Fp12_2over3over2_model &other) const; - - Fp12_2over3over2_model operator+(const Fp12_2over3over2_model &other) const; - Fp12_2over3over2_model operator-(const Fp12_2over3over2_model &other) const; - Fp12_2over3over2_model operator*(const Fp12_2over3over2_model &other) const; - Fp12_2over3over2_model operator-() const; - Fp12_2over3over2_model squared() const; // default is squared_complex - Fp12_2over3over2_model squared_karatsuba() const; - Fp12_2over3over2_model squared_complex() const; - Fp12_2over3over2_model inverse() const; - Fp12_2over3over2_model Frobenius_map(uint64_t power) const; - Fp12_2over3over2_model unitary_inverse() const; - Fp12_2over3over2_model cyclotomic_squared() const; - - Fp12_2over3over2_model mul_by_024(const my_Fp2 &ell_0, const my_Fp2 &ell_VW, const my_Fp2 &ell_VV) const; - - static my_Fp6 mul_by_non_residue(const my_Fp6 &elt); - - template - Fp12_2over3over2_model cyclotomic_exp(const bigint &exponent) const; - - static bigint base_field_char() { return modulus; } - static uint64_t extension_degree() { return 12; } - - friend std::ostream& operator<< (std::ostream &out, const Fp12_2over3over2_model &el); - friend std::istream& operator>> (std::istream &in, Fp12_2over3over2_model &el); -}; - -template& modulus> -std::ostream& operator<<(std::ostream& out, const std::vector > &v); - -template& modulus> -std::istream& operator>>(std::istream& in, std::vector > &v); - -template& modulus> -Fp12_2over3over2_model operator*(const Fp_model &lhs, const Fp12_2over3over2_model &rhs); - -template& modulus> -Fp12_2over3over2_model operator*(const Fp2_model &lhs, const Fp12_2over3over2_model &rhs); - -template& modulus> -Fp12_2over3over2_model operator*(const Fp6_3over2_model &lhs, const Fp12_2over3over2_model &rhs); - -template& modulus, mp_size_t m> -Fp12_2over3over2_model operator^(const Fp12_2over3over2_model &self, const bigint &exponent); - -template& modulus, mp_size_t m, const bigint& exp_modulus> -Fp12_2over3over2_model operator^(const Fp12_2over3over2_model &self, const Fp_model &exponent); - -template& modulus> -Fp2_model Fp12_2over3over2_model::non_residue; - -template& modulus> -Fp2_model Fp12_2over3over2_model::Frobenius_coeffs_c1[12]; - -} // libsnark -#include "algebra/fields/fp12_2over3over2.tcc" -#endif // FP12_2OVER3OVER2_HPP_ diff --git a/src/snark/libsnark/algebra/fields/fp12_2over3over2.tcc b/src/snark/libsnark/algebra/fields/fp12_2over3over2.tcc deleted file mode 100644 index 64d2cf97c..000000000 --- a/src/snark/libsnark/algebra/fields/fp12_2over3over2.tcc +++ /dev/null @@ -1,412 +0,0 @@ -/** @file - ***************************************************************************** - Implementation of arithmetic in the finite field F[((p^2)^3)^2]. - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef FP12_2OVER3OVER2_TCC_ -#define FP12_2OVER3OVER2_TCC_ - -namespace libsnark { - -template& modulus> -Fp6_3over2_model Fp12_2over3over2_model::mul_by_non_residue(const Fp6_3over2_model &elt) -{ - return Fp6_3over2_model(non_residue * elt.c2, elt.c0, elt.c1); -} - -template& modulus> -Fp12_2over3over2_model Fp12_2over3over2_model::zero() -{ - return Fp12_2over3over2_model(my_Fp6::zero(), my_Fp6::zero()); -} - -template& modulus> -Fp12_2over3over2_model Fp12_2over3over2_model::one() -{ - return Fp12_2over3over2_model(my_Fp6::one(), my_Fp6::zero()); -} - -template& modulus> -Fp12_2over3over2_model Fp12_2over3over2_model::random_element() -{ - Fp12_2over3over2_model r; - r.c0 = my_Fp6::random_element(); - r.c1 = my_Fp6::random_element(); - - return r; -} - -template& modulus> -bool Fp12_2over3over2_model::operator==(const Fp12_2over3over2_model &other) const -{ - return (this->c0 == other.c0 && this->c1 == other.c1); -} - -template& modulus> -bool Fp12_2over3over2_model::operator!=(const Fp12_2over3over2_model &other) const -{ - return !(operator==(other)); -} - -template& modulus> -Fp12_2over3over2_model Fp12_2over3over2_model::operator+(const Fp12_2over3over2_model &other) const -{ - return Fp12_2over3over2_model(this->c0 + other.c0, - this->c1 + other.c1); -} - -template& modulus> -Fp12_2over3over2_model Fp12_2over3over2_model::operator-(const Fp12_2over3over2_model &other) const -{ - return Fp12_2over3over2_model(this->c0 - other.c0, - this->c1 - other.c1); -} - -template& modulus> -Fp12_2over3over2_model operator*(const Fp_model &lhs, const Fp12_2over3over2_model &rhs) -{ - return Fp12_2over3over2_model(lhs*rhs.c0, - lhs*rhs.c1); -} - -template& modulus> -Fp12_2over3over2_model operator*(const Fp2_model &lhs, const Fp12_2over3over2_model &rhs) -{ - return Fp12_2over3over2_model(lhs*rhs.c0, - lhs*rhs.c1); -} - -template& modulus> -Fp12_2over3over2_model operator*(const Fp6_3over2_model &lhs, const Fp12_2over3over2_model &rhs) -{ - return Fp12_2over3over2_model(lhs*rhs.c0, - lhs*rhs.c1); -} - -template& modulus> -Fp12_2over3over2_model Fp12_2over3over2_model::operator*(const Fp12_2over3over2_model &other) const -{ - /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba) */ - - const my_Fp6 &A = other.c0, &B = other.c1, - &a = this->c0, &b = this->c1; - const my_Fp6 aA = a * A; - const my_Fp6 bB = b * B; - - return Fp12_2over3over2_model(aA + Fp12_2over3over2_model::mul_by_non_residue(bB), - (a + b)*(A+B) - aA - bB); -} - -template& modulus> -Fp12_2over3over2_model Fp12_2over3over2_model::operator-() const -{ - return Fp12_2over3over2_model(-this->c0, - -this->c1); -} - -template& modulus> -Fp12_2over3over2_model Fp12_2over3over2_model::squared() const -{ - return squared_complex(); -} - -template& modulus> -Fp12_2over3over2_model Fp12_2over3over2_model::squared_karatsuba() const -{ - /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba squaring) */ - - const my_Fp6 &a = this->c0, &b = this->c1; - const my_Fp6 asq = a.squared(); - const my_Fp6 bsq = b.squared(); - - return Fp12_2over3over2_model(asq + Fp12_2over3over2_model::mul_by_non_residue(bsq), - (a + b).squared() - asq - bsq); -} - -template& modulus> -Fp12_2over3over2_model Fp12_2over3over2_model::squared_complex() const -{ - /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Complex squaring) */ - - const my_Fp6 &a = this->c0, &b = this->c1; - const my_Fp6 ab = a * b; - - return Fp12_2over3over2_model((a + b) * (a + Fp12_2over3over2_model::mul_by_non_residue(b)) - ab - Fp12_2over3over2_model::mul_by_non_residue(ab), - ab + ab); -} - -template& modulus> -Fp12_2over3over2_model Fp12_2over3over2_model::inverse() const -{ - /* From "High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves"; Algorithm 8 */ - - const my_Fp6 &a = this->c0, &b = this->c1; - const my_Fp6 t0 = a.squared(); - const my_Fp6 t1 = b.squared(); - const my_Fp6 t2 = t0 - Fp12_2over3over2_model::mul_by_non_residue(t1); - const my_Fp6 t3 = t2.inverse(); - const my_Fp6 c0 = a * t3; - const my_Fp6 c1 = - (b * t3); - - return Fp12_2over3over2_model(c0, c1); -} - -template& modulus> -Fp12_2over3over2_model Fp12_2over3over2_model::Frobenius_map(uint64_t power) const -{ - return Fp12_2over3over2_model(c0.Frobenius_map(power), - Frobenius_coeffs_c1[power % 12] * c1.Frobenius_map(power)); -} - -template& modulus> -Fp12_2over3over2_model Fp12_2over3over2_model::unitary_inverse() const -{ - return Fp12_2over3over2_model(this->c0, - -this->c1); -} - -template& modulus> -Fp12_2over3over2_model Fp12_2over3over2_model::cyclotomic_squared() const -{ - /* OLD: naive implementation - return (*this).squared(); - */ - my_Fp2 z0 = this->c0.c0; - my_Fp2 z4 = this->c0.c1; - my_Fp2 z3 = this->c0.c2; - my_Fp2 z2 = this->c1.c0; - my_Fp2 z1 = this->c1.c1; - my_Fp2 z5 = this->c1.c2; - - my_Fp2 t0, t1, t2, t3, t4, t5, tmp; - - // t0 + t1*y = (z0 + z1*y)^2 = a^2 - tmp = z0 * z1; - t0 = (z0 + z1) * (z0 + my_Fp6::non_residue * z1) - tmp - my_Fp6::non_residue * tmp; - t1 = tmp + tmp; - // t2 + t3*y = (z2 + z3*y)^2 = b^2 - tmp = z2 * z3; - t2 = (z2 + z3) * (z2 + my_Fp6::non_residue * z3) - tmp - my_Fp6::non_residue * tmp; - t3 = tmp + tmp; - // t4 + t5*y = (z4 + z5*y)^2 = c^2 - tmp = z4 * z5; - t4 = (z4 + z5) * (z4 + my_Fp6::non_residue * z5) - tmp - my_Fp6::non_residue * tmp; - t5 = tmp + tmp; - - // for A - - // z0 = 3 * t0 - 2 * z0 - z0 = t0 - z0; - z0 = z0 + z0; - z0 = z0 + t0; - // z1 = 3 * t1 + 2 * z1 - z1 = t1 + z1; - z1 = z1 + z1; - z1 = z1 + t1; - - // for B - - // z2 = 3 * (xi * t5) + 2 * z2 - tmp = my_Fp6::non_residue * t5; - z2 = tmp + z2; - z2 = z2 + z2; - z2 = z2 + tmp; - - // z3 = 3 * t4 - 2 * z3 - z3 = t4 - z3; - z3 = z3 + z3; - z3 = z3 + t4; - - // for C - - // z4 = 3 * t2 - 2 * z4 - z4 = t2 - z4; - z4 = z4 + z4; - z4 = z4 + t2; - - // z5 = 3 * t3 + 2 * z5 - z5 = t3 + z5; - z5 = z5 + z5; - z5 = z5 + t3; - - return Fp12_2over3over2_model(my_Fp6(z0,z4,z3),my_Fp6(z2,z1,z5)); -} - -template& modulus> -Fp12_2over3over2_model Fp12_2over3over2_model::mul_by_024(const Fp2_model &ell_0, - const Fp2_model &ell_VW, - const Fp2_model &ell_VV) const -{ - /* OLD: naive implementation - Fp12_2over3over2_model a(my_Fp6(ell_0, my_Fp2::zero(), ell_VV), - my_Fp6(my_Fp2::zero(), ell_VW, my_Fp2::zero())); - - return (*this) * a; - */ - my_Fp2 z0 = this->c0.c0; - my_Fp2 z1 = this->c0.c1; - my_Fp2 z2 = this->c0.c2; - my_Fp2 z3 = this->c1.c0; - my_Fp2 z4 = this->c1.c1; - my_Fp2 z5 = this->c1.c2; - - my_Fp2 x0 = ell_0; - my_Fp2 x2 = ell_VV; - my_Fp2 x4 = ell_VW; - - my_Fp2 t0, t1, t2, s0, T3, T4, D0, D2, D4, S1; - - D0 = z0 * x0; - D2 = z2 * x2; - D4 = z4 * x4; - t2 = z0 + z4; - t1 = z0 + z2; - s0 = z1 + z3 + z5; - - // For z.a_.a_ = z0. - S1 = z1 * x2; - T3 = S1 + D4; - T4 = my_Fp6::non_residue * T3 + D0; - z0 = T4; - - // For z.a_.b_ = z1 - T3 = z5 * x4; - S1 = S1 + T3; - T3 = T3 + D2; - T4 = my_Fp6::non_residue * T3; - T3 = z1 * x0; - S1 = S1 + T3; - T4 = T4 + T3; - z1 = T4; - - // For z.a_.c_ = z2 - t0 = x0 + x2; - T3 = t1 * t0 - D0 - D2; - T4 = z3 * x4; - S1 = S1 + T4; - T3 = T3 + T4; - - // For z.b_.a_ = z3 (z3 needs z2) - t0 = z2 + z4; - z2 = T3; - t1 = x2 + x4; - T3 = t0 * t1 - D2 - D4; - T4 = my_Fp6::non_residue * T3; - T3 = z3 * x0; - S1 = S1 + T3; - T4 = T4 + T3; - z3 = T4; - - // For z.b_.b_ = z4 - T3 = z5 * x2; - S1 = S1 + T3; - T4 = my_Fp6::non_residue * T3; - t0 = x0 + x4; - T3 = t2 * t0 - D0 - D4; - T4 = T4 + T3; - z4 = T4; - - // For z.b_.c_ = z5. - t0 = x0 + x2 + x4; - T3 = s0 * t0 - S1; - z5 = T3; - - return Fp12_2over3over2_model(my_Fp6(z0,z1,z2),my_Fp6(z3,z4,z5)); - -} - -template& modulus, mp_size_t m> -Fp12_2over3over2_model operator^(const Fp12_2over3over2_model &self, const bigint &exponent) -{ - return power >(self, exponent); -} - -template& modulus, mp_size_t m, const bigint& exp_modulus> -Fp12_2over3over2_model operator^(const Fp12_2over3over2_model &self, const Fp_model &exponent) -{ - return self^(exponent.as_bigint()); -} - - -template& modulus> -template -Fp12_2over3over2_model Fp12_2over3over2_model::cyclotomic_exp(const bigint &exponent) const -{ - Fp12_2over3over2_model res = Fp12_2over3over2_model::one(); - - bool found_one = false; - for (int64_t i = m-1; i >= 0; --i) - { - for (int64_t j = GMP_NUMB_BITS - 1; j >= 0; --j) - { - if (found_one) - { - res = res.cyclotomic_squared(); - } - - if (exponent.data[i] & (((mp_limb_t) 1)<& modulus> -std::ostream& operator<<(std::ostream &out, const Fp12_2over3over2_model &el) -{ - out << el.c0 << OUTPUT_SEPARATOR << el.c1; - return out; -} - -template& modulus> -std::istream& operator>>(std::istream &in, Fp12_2over3over2_model &el) -{ - in >> el.c0 >> el.c1; - return in; -} - -template& modulus> -std::ostream& operator<<(std::ostream& out, const std::vector > &v) -{ - out << v.size() << "\n"; - for (const Fp12_2over3over2_model& t : v) - { - out << t << OUTPUT_NEWLINE; - } - - return out; -} - -template& modulus> -std::istream& operator>>(std::istream& in, std::vector > &v) -{ - v.clear(); - - uint64_t s; - in >> s; - - char b; - in.read(&b, 1); - - v.reserve(s); - - for (size_t i = 0; i < s; ++i) - { - Fp12_2over3over2_model el; - in >> el; - v.emplace_back(el); - } - - return in; -} - -} // libsnark -#endif // FP12_2OVER3OVER2_TCC_ diff --git a/src/snark/libsnark/algebra/fields/fp2.hpp b/src/snark/libsnark/algebra/fields/fp2.hpp deleted file mode 100644 index f194f5ec5..000000000 --- a/src/snark/libsnark/algebra/fields/fp2.hpp +++ /dev/null @@ -1,120 +0,0 @@ -/** @file - ***************************************************************************** - Implementation of arithmetic in the finite field F[p^2]. - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef FP2_HPP_ -#define FP2_HPP_ -#include "algebra/fields/fp.hpp" -#include - -namespace libsnark { - -template& modulus> -class Fp2_model; - -template& modulus> -std::ostream& operator<<(std::ostream &, const Fp2_model &); - -template& modulus> -std::istream& operator>>(std::istream &, Fp2_model &); - -/** - * Arithmetic in the field F[p^3]. - * - * Let p := modulus. This interface provides arithmetic for the extension field - * Fp2 = Fp[U]/(U^2-non_residue), where non_residue is in Fp. - * - * ASSUMPTION: p = 1 (mod 6) - */ -template& modulus> -class Fp2_model { -public: - typedef Fp_model my_Fp; - - static bigint<2*n> euler; // (modulus^2-1)/2 - static uint64_t s; // modulus^2 = 2^s * t + 1 - static bigint<2*n> t; // with t odd - static bigint<2*n> t_minus_1_over_2; // (t-1)/2 - static my_Fp non_residue; // X^4-non_residue irreducible over Fp; used for constructing Fp2 = Fp[X] / (X^2 - non_residue) - static Fp2_model nqr; // a quadratic nonresidue in Fp2 - static Fp2_model nqr_to_t; // nqr^t - static my_Fp Frobenius_coeffs_c1[2]; // non_residue^((modulus^i-1)/2) for i=0,1 - - my_Fp c0, c1; - Fp2_model() {}; - Fp2_model(const my_Fp& c0, const my_Fp& c1) : c0(c0), c1(c1) {}; - - void clear() { c0.clear(); c1.clear(); } - void print() const { printf("c0/c1:\n"); c0.print(); c1.print(); } - - static Fp2_model zero(); - static Fp2_model one(); - static Fp2_model random_element(); - - bool is_zero() const { return c0.is_zero() && c1.is_zero(); } - bool operator==(const Fp2_model &other) const; - bool operator!=(const Fp2_model &other) const; - - Fp2_model operator+(const Fp2_model &other) const; - Fp2_model operator-(const Fp2_model &other) const; - Fp2_model operator*(const Fp2_model &other) const; - Fp2_model operator-() const; - Fp2_model squared() const; // default is squared_complex - Fp2_model inverse() const; - Fp2_model Frobenius_map(uint64_t power) const; - Fp2_model sqrt() const; // HAS TO BE A SQUARE (else does not terminate) - Fp2_model squared_karatsuba() const; - Fp2_model squared_complex() const; - - template - Fp2_model operator^(const bigint &other) const; - - static uint64_t size_in_bits() { return 2*my_Fp::size_in_bits(); } - static bigint base_field_char() { return modulus; } - - friend std::ostream& operator<< (std::ostream &out, const Fp2_model &el); - friend std::istream& operator>> (std::istream &in, Fp2_model &el); -}; - -template& modulus> -std::ostream& operator<<(std::ostream& out, const std::vector > &v); - -template& modulus> -std::istream& operator>>(std::istream& in, std::vector > &v); - -template& modulus> -Fp2_model operator*(const Fp_model &lhs, const Fp2_model &rhs); - -template& modulus> -bigint<2*n> Fp2_model::euler; - -template& modulus> -uint64_t Fp2_model::s; - -template& modulus> -bigint<2*n> Fp2_model::t; - -template& modulus> -bigint<2*n> Fp2_model::t_minus_1_over_2; - -template& modulus> -Fp_model Fp2_model::non_residue; - -template& modulus> -Fp2_model Fp2_model::nqr; - -template& modulus> -Fp2_model Fp2_model::nqr_to_t; - -template& modulus> -Fp_model Fp2_model::Frobenius_coeffs_c1[2]; - -} // libsnark -#include "algebra/fields/fp2.tcc" - -#endif // FP2_HPP_ diff --git a/src/snark/libsnark/algebra/fields/fp2.tcc b/src/snark/libsnark/algebra/fields/fp2.tcc deleted file mode 100644 index 84aa3035c..000000000 --- a/src/snark/libsnark/algebra/fields/fp2.tcc +++ /dev/null @@ -1,261 +0,0 @@ -/** @file - ***************************************************************************** - Implementation of arithmetic in the finite field F[p^2]. - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef FP2_TCC_ -#define FP2_TCC_ - -#include "algebra/fields/field_utils.hpp" - -namespace libsnark { - -template& modulus> -Fp2_model Fp2_model::zero() -{ - return Fp2_model(my_Fp::zero(), my_Fp::zero()); -} - -template& modulus> -Fp2_model Fp2_model::one() -{ - return Fp2_model(my_Fp::one(), my_Fp::zero()); -} - -template& modulus> -Fp2_model Fp2_model::random_element() -{ - Fp2_model r; - r.c0 = my_Fp::random_element(); - r.c1 = my_Fp::random_element(); - - return r; -} - -template& modulus> -bool Fp2_model::operator==(const Fp2_model &other) const -{ - return (this->c0 == other.c0 && this->c1 == other.c1); -} - -template& modulus> -bool Fp2_model::operator!=(const Fp2_model &other) const -{ - return !(operator==(other)); -} - -template& modulus> -Fp2_model Fp2_model::operator+(const Fp2_model &other) const -{ - return Fp2_model(this->c0 + other.c0, - this->c1 + other.c1); -} - -template& modulus> -Fp2_model Fp2_model::operator-(const Fp2_model &other) const -{ - return Fp2_model(this->c0 - other.c0, - this->c1 - other.c1); -} - -template& modulus> -Fp2_model operator*(const Fp_model &lhs, const Fp2_model &rhs) -{ - return Fp2_model(lhs*rhs.c0, - lhs*rhs.c1); -} - -template& modulus> -Fp2_model Fp2_model::operator*(const Fp2_model &other) const -{ - /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba) */ - const my_Fp - &A = other.c0, &B = other.c1, - &a = this->c0, &b = this->c1; - const my_Fp aA = a * A; - const my_Fp bB = b * B; - - return Fp2_model(aA + non_residue * bB, - (a + b)*(A+B) - aA - bB); -} - -template& modulus> -Fp2_model Fp2_model::operator-() const -{ - return Fp2_model(-this->c0, - -this->c1); -} - -template& modulus> -Fp2_model Fp2_model::squared() const -{ - return squared_complex(); -} - -template& modulus> -Fp2_model Fp2_model::squared_karatsuba() const -{ - /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Karatsuba squaring) */ - const my_Fp &a = this->c0, &b = this->c1; - const my_Fp asq = a.squared(); - const my_Fp bsq = b.squared(); - - return Fp2_model(asq + non_residue * bsq, - (a + b).squared() - asq - bsq); -} - -template& modulus> -Fp2_model Fp2_model::squared_complex() const -{ - /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 3 (Complex squaring) */ - const my_Fp &a = this->c0, &b = this->c1; - const my_Fp ab = a * b; - - return Fp2_model((a + b) * (a + non_residue * b) - ab - non_residue * ab, - ab + ab); -} - -template& modulus> -Fp2_model Fp2_model::inverse() const -{ - const my_Fp &a = this->c0, &b = this->c1; - - /* From "High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves"; Algorithm 8 */ - const my_Fp t0 = a.squared(); - const my_Fp t1 = b.squared(); - const my_Fp t2 = t0 - non_residue * t1; - const my_Fp t3 = t2.inverse(); - const my_Fp c0 = a * t3; - const my_Fp c1 = - (b * t3); - - return Fp2_model(c0, c1); -} - -template& modulus> -Fp2_model Fp2_model::Frobenius_map(uint64_t power) const -{ - return Fp2_model(c0, - Frobenius_coeffs_c1[power % 2] * c1); -} - -template& modulus> -Fp2_model Fp2_model::sqrt() const -{ - if (is_zero()) { - return *this; - } - - Fp2_model one = Fp2_model::one(); - - unsigned long long v = Fp2_model::s; - Fp2_model z = Fp2_model::nqr_to_t; - Fp2_model w = (*this)^Fp2_model::t_minus_1_over_2; - Fp2_model x = (*this) * w; - Fp2_model b = x * w; // b = (*this)^t - - - // check if square with euler's criterion - Fp2_model check = b; - for (size_t i = 0; i < v-1; ++i) - { - check = check.squared(); - } - if (check != one) - { - assert_except(0); - } - - - // compute square root with Tonelli--Shanks - // (does not terminate if not a square!) - - while (b != one) - { - unsigned long long m = 0; - Fp2_model b2m = b; - while (b2m != one) - { - /* invariant: b2m = b^(2^m) after entering this loop */ - b2m = b2m.squared(); - m += 1; - } - - int j = v-m-1; - w = z; - while (j > 0) - { - w = w.squared(); - --j; - } // w = z^2^(v-m-1) - - z = w.squared(); - b = b * z; - x = x * w; - v = m; - } - - return x; -} - -template& modulus> -template -Fp2_model Fp2_model::operator^(const bigint &pow) const -{ - return power, m>(*this, pow); -} - -template& modulus> -std::ostream& operator<<(std::ostream &out, const Fp2_model &el) -{ - out << el.c0 << OUTPUT_SEPARATOR << el.c1; - return out; -} - -template& modulus> -std::istream& operator>>(std::istream &in, Fp2_model &el) -{ - in >> el.c0 >> el.c1; - return in; -} - -template& modulus> -std::ostream& operator<<(std::ostream& out, const std::vector > &v) -{ - out << v.size() << "\n"; - for (const Fp2_model& t : v) - { - out << t << OUTPUT_NEWLINE; - } - - return out; -} - -template& modulus> -std::istream& operator>>(std::istream& in, std::vector > &v) -{ - v.clear(); - - unsigned long long s; - in >> s; - - char b; - in.read(&b, 1); - - v.reserve(s); - - for (size_t i = 0; i < s; ++i) - { - Fp2_model el; - in >> el; - v.emplace_back(el); - } - - return in; -} - -} // libsnark -#endif // FP2_TCC_ diff --git a/src/snark/libsnark/algebra/fields/fp6_3over2.hpp b/src/snark/libsnark/algebra/fields/fp6_3over2.hpp deleted file mode 100644 index 8a888f0cf..000000000 --- a/src/snark/libsnark/algebra/fields/fp6_3over2.hpp +++ /dev/null @@ -1,104 +0,0 @@ -/** @file - ***************************************************************************** - Declaration of arithmetic in the finite field F[(p^2)^3] - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef FP6_3OVER2_HPP_ -#define FP6_3OVER2_HPP_ -#include "algebra/fields/fp.hpp" -#include "algebra/fields/fp2.hpp" -#include - -namespace libsnark { - -template& modulus> -class Fp6_3over2_model; - -template& modulus> -std::ostream& operator<<(std::ostream &, const Fp6_3over2_model &); - -template& modulus> -std::istream& operator>>(std::istream &, Fp6_3over2_model &); - -/** - * Arithmetic in the finite field F[(p^2)^3]. - * - * Let p := modulus. This interface provides arithmetic for the extension field - * Fp6 = Fp2[V]/(V^3-non_residue) where non_residue is in Fp. - * - * ASSUMPTION: p = 1 (mod 6) - */ -template& modulus> -class Fp6_3over2_model { -public: - typedef Fp_model my_Fp; - typedef Fp2_model my_Fp2; - - static my_Fp2 non_residue; - static my_Fp2 Frobenius_coeffs_c1[6]; // non_residue^((modulus^i-1)/3) for i=0,1,2,3,4,5 - static my_Fp2 Frobenius_coeffs_c2[6]; // non_residue^((2*modulus^i-2)/3) for i=0,1,2,3,4,5 - - my_Fp2 c0, c1, c2; - Fp6_3over2_model() {}; - Fp6_3over2_model(const my_Fp2& c0, const my_Fp2& c1, const my_Fp2& c2) : c0(c0), c1(c1), c2(c2) {}; - - void clear() { c0.clear(); c1.clear(); c2.clear(); } - void print() const { printf("c0/c1/c2:\n"); c0.print(); c1.print(); c2.print(); } - - static Fp6_3over2_model zero(); - static Fp6_3over2_model one(); - static Fp6_3over2_model random_element(); - - bool is_zero() const { return c0.is_zero() && c1.is_zero() && c2.is_zero(); } - bool operator==(const Fp6_3over2_model &other) const; - bool operator!=(const Fp6_3over2_model &other) const; - - Fp6_3over2_model operator+(const Fp6_3over2_model &other) const; - Fp6_3over2_model operator-(const Fp6_3over2_model &other) const; - Fp6_3over2_model operator*(const Fp6_3over2_model &other) const; - Fp6_3over2_model operator-() const; - Fp6_3over2_model squared() const; - Fp6_3over2_model inverse() const; - Fp6_3over2_model Frobenius_map(uint64_t power) const; - - static my_Fp2 mul_by_non_residue(const my_Fp2 &elt); - - template - Fp6_3over2_model operator^(const bigint &other) const; - - static bigint base_field_char() { return modulus; } - static uint64_t extension_degree() { return 6; } - - friend std::ostream& operator<< (std::ostream &out, const Fp6_3over2_model &el); - friend std::istream& operator>> (std::istream &in, Fp6_3over2_model &el); -}; - -template& modulus> -std::ostream& operator<<(std::ostream& out, const std::vector > &v); - -template& modulus> -std::istream& operator>>(std::istream& in, std::vector > &v); - -template& modulus> -Fp6_3over2_model operator*(const Fp_model &lhs, const Fp6_3over2_model &rhs); - -template& modulus> -Fp6_3over2_model operator*(const Fp2_model &lhs, const Fp6_3over2_model &rhs); - -template& modulus> -Fp2_model Fp6_3over2_model::non_residue; - -template& modulus> -Fp2_model Fp6_3over2_model::Frobenius_coeffs_c1[6]; - -template& modulus> -Fp2_model Fp6_3over2_model::Frobenius_coeffs_c2[6]; - -} // libsnark -#include "algebra/fields/fp6_3over2.tcc" - -#endif // FP6_3OVER2_HPP_ diff --git a/src/snark/libsnark/algebra/fields/fp6_3over2.tcc b/src/snark/libsnark/algebra/fields/fp6_3over2.tcc deleted file mode 100644 index de9b83d11..000000000 --- a/src/snark/libsnark/algebra/fields/fp6_3over2.tcc +++ /dev/null @@ -1,216 +0,0 @@ -/** @file - ***************************************************************************** - Implementation of arithmetic in the finite field F[(p^2)^3]. - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef FP6_3OVER2_TCC_ -#define FP6_3OVER2_TCC_ -#include "algebra/fields/field_utils.hpp" - -namespace libsnark { - -template& modulus> -Fp2_model Fp6_3over2_model::mul_by_non_residue(const Fp2_model &elt) -{ - return Fp2_model(non_residue * elt); -} - -template& modulus> -Fp6_3over2_model Fp6_3over2_model::zero() -{ - return Fp6_3over2_model(my_Fp2::zero(), my_Fp2::zero(), my_Fp2::zero()); -} - -template& modulus> -Fp6_3over2_model Fp6_3over2_model::one() -{ - return Fp6_3over2_model(my_Fp2::one(), my_Fp2::zero(), my_Fp2::zero()); -} - -template& modulus> -Fp6_3over2_model Fp6_3over2_model::random_element() -{ - Fp6_3over2_model r; - r.c0 = my_Fp2::random_element(); - r.c1 = my_Fp2::random_element(); - r.c2 = my_Fp2::random_element(); - - return r; -} - -template& modulus> -bool Fp6_3over2_model::operator==(const Fp6_3over2_model &other) const -{ - return (this->c0 == other.c0 && this->c1 == other.c1 && this->c2 == other.c2); -} - -template& modulus> -bool Fp6_3over2_model::operator!=(const Fp6_3over2_model &other) const -{ - return !(operator==(other)); -} - -template& modulus> -Fp6_3over2_model Fp6_3over2_model::operator+(const Fp6_3over2_model &other) const -{ - return Fp6_3over2_model(this->c0 + other.c0, - this->c1 + other.c1, - this->c2 + other.c2); -} - -template& modulus> -Fp6_3over2_model Fp6_3over2_model::operator-(const Fp6_3over2_model &other) const -{ - return Fp6_3over2_model(this->c0 - other.c0, - this->c1 - other.c1, - this->c2 - other.c2); -} - -template& modulus> -Fp6_3over2_model operator*(const Fp_model &lhs, const Fp6_3over2_model &rhs) -{ - return Fp6_3over2_model(lhs*rhs.c0, - lhs*rhs.c1, - lhs*rhs.c2); -} - -template& modulus> -Fp6_3over2_model operator*(const Fp2_model &lhs, const Fp6_3over2_model &rhs) -{ - return Fp6_3over2_model(lhs*rhs.c0, - lhs*rhs.c1, - lhs*rhs.c2); -} - -template& modulus> -Fp6_3over2_model Fp6_3over2_model::operator*(const Fp6_3over2_model &other) const -{ - /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 4 (Karatsuba) */ - - const my_Fp2 &A = other.c0, &B = other.c1, &C = other.c2, - &a = this->c0, &b = this->c1, &c = this->c2; - const my_Fp2 aA = a*A; - const my_Fp2 bB = b*B; - const my_Fp2 cC = c*C; - - return Fp6_3over2_model(aA + Fp6_3over2_model::mul_by_non_residue((b+c)*(B+C)-bB-cC), - (a+b)*(A+B)-aA-bB+Fp6_3over2_model::mul_by_non_residue(cC), - (a+c)*(A+C)-aA+bB-cC); -} - -template& modulus> -Fp6_3over2_model Fp6_3over2_model::operator-() const -{ - return Fp6_3over2_model(-this->c0, - -this->c1, - -this->c2); -} - -template& modulus> -Fp6_3over2_model Fp6_3over2_model::squared() const -{ - /* Devegili OhEig Scott Dahab --- Multiplication and Squaring on Pairing-Friendly Fields.pdf; Section 4 (CH-SQR2) */ - - const my_Fp2 &a = this->c0, &b = this->c1, &c = this->c2; - const my_Fp2 s0 = a.squared(); - const my_Fp2 ab = a*b; - const my_Fp2 s1 = ab + ab; - const my_Fp2 s2 = (a - b + c).squared(); - const my_Fp2 bc = b*c; - const my_Fp2 s3 = bc + bc; - const my_Fp2 s4 = c.squared(); - - return Fp6_3over2_model(s0 + Fp6_3over2_model::mul_by_non_residue(s3), - s1 + Fp6_3over2_model::mul_by_non_residue(s4), - s1 + s2 + s3 - s0 - s4); -} - -template& modulus> -Fp6_3over2_model Fp6_3over2_model::inverse() const -{ - /* From "High-Speed Software Implementation of the Optimal Ate Pairing over Barreto-Naehrig Curves"; Algorithm 17 */ - - const my_Fp2 &a = this->c0, &b = this->c1, &c = this->c2; - const my_Fp2 t0 = a.squared(); - const my_Fp2 t1 = b.squared(); - const my_Fp2 t2 = c.squared(); - const my_Fp2 t3 = a*b; - const my_Fp2 t4 = a*c; - const my_Fp2 t5 = b*c; - const my_Fp2 c0 = t0 - Fp6_3over2_model::mul_by_non_residue(t5); - const my_Fp2 c1 = Fp6_3over2_model::mul_by_non_residue(t2) - t3; - const my_Fp2 c2 = t1 - t4; // typo in paper referenced above. should be "-" as per Scott, but is "*" - const my_Fp2 t6 = (a * c0 + Fp6_3over2_model::mul_by_non_residue((c * c1 + b * c2))).inverse(); - return Fp6_3over2_model(t6 * c0, t6 * c1, t6 * c2); -} - -template& modulus> -Fp6_3over2_model Fp6_3over2_model::Frobenius_map(uint64_t power) const -{ - return Fp6_3over2_model(c0.Frobenius_map(power), - Frobenius_coeffs_c1[power % 6] * c1.Frobenius_map(power), - Frobenius_coeffs_c2[power % 6] * c2.Frobenius_map(power)); -} - -template& modulus> -template -Fp6_3over2_model Fp6_3over2_model::operator^(const bigint &pow) const -{ - return power, m>(*this, pow); -} - -template& modulus> -std::ostream& operator<<(std::ostream &out, const Fp6_3over2_model &el) -{ - out << el.c0 << OUTPUT_SEPARATOR << el.c1 << OUTPUT_SEPARATOR << el.c2; - return out; -} - -template& modulus> -std::istream& operator>>(std::istream &in, Fp6_3over2_model &el) -{ - in >> el.c0 >> el.c1 >> el.c2; - return in; -} - -template& modulus> -std::ostream& operator<<(std::ostream& out, const std::vector > &v) -{ - out << v.size() << "\n"; - for (const Fp6_3over2_model& t : v) - { - out << t << OUTPUT_NEWLINE; - } - - return out; -} - -template& modulus> -std::istream& operator>>(std::istream& in, std::vector > &v) -{ - v.clear(); - - uint64_t s; - in >> s; - - char b; - in.read(&b, 1); - - v.reserve(s); - - for (size_t i = 0; i < s; ++i) - { - Fp6_3over2_model el; - in >> el; - v.emplace_back(el); - } - - return in; -} - -} // libsnark -#endif // FP6_3_OVER_2_TCC_ diff --git a/src/snark/libsnark/algebra/fields/fp_aux.tcc b/src/snark/libsnark/algebra/fields/fp_aux.tcc deleted file mode 100644 index 7f8a3eadf..000000000 --- a/src/snark/libsnark/algebra/fields/fp_aux.tcc +++ /dev/null @@ -1,389 +0,0 @@ -/** @file - ***************************************************************************** - Assembly code snippets for F[p] finite field arithmetic, used by fp.tcc . - Specific to x86-64, and used only if USE_ASM is defined. - On other architectures or without USE_ASM, fp.tcc uses a portable - C++ implementation instead. - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef FP_AUX_TCC_ -#define FP_AUX_TCC_ - -namespace libsnark { - -#define STR_HELPER(x) #x -#define STR(x) STR_HELPER(x) - -/* addq is faster than adcq, even if preceded by clc */ -#define ADD_FIRSTADD \ - "movq (%[B]), %%rax \n\t" \ - "addq %%rax, (%[A]) \n\t" - -#define ADD_NEXTADD(ofs) \ - "movq " STR(ofs) "(%[B]), %%rax \n\t" \ - "adcq %%rax, " STR(ofs) "(%[A]) \n\t" - -#define ADD_CMP(ofs) \ - "movq " STR(ofs) "(%[mod]), %%rax \n\t" \ - "cmpq %%rax, " STR(ofs) "(%[A]) \n\t" \ - "jb done%= \n\t" \ - "ja subtract%= \n\t" - -#define ADD_FIRSTSUB \ - "movq (%[mod]), %%rax \n\t" \ - "subq %%rax, (%[A]) \n\t" - -#define ADD_FIRSTSUB \ - "movq (%[mod]), %%rax \n\t" \ - "subq %%rax, (%[A]) \n\t" - -#define ADD_NEXTSUB(ofs) \ - "movq " STR(ofs) "(%[mod]), %%rax \n\t" \ - "sbbq %%rax, " STR(ofs) "(%[A]) \n\t" - -#define SUB_FIRSTSUB \ - "movq (%[B]), %%rax\n\t" \ - "subq %%rax, (%[A])\n\t" - -#define SUB_NEXTSUB(ofs) \ - "movq " STR(ofs) "(%[B]), %%rax\n\t" \ - "sbbq %%rax, " STR(ofs) "(%[A])\n\t" - -#define SUB_FIRSTADD \ - "movq (%[mod]), %%rax\n\t" \ - "addq %%rax, (%[A])\n\t" - -#define SUB_NEXTADD(ofs) \ - "movq " STR(ofs) "(%[mod]), %%rax\n\t" \ - "adcq %%rax, " STR(ofs) "(%[A])\n\t" - -#define MONT_CMP(ofs) \ - "movq " STR(ofs) "(%[M]), %%rax \n\t" \ - "cmpq %%rax, " STR(ofs) "(%[tmp]) \n\t" \ - "jb done%= \n\t" \ - "ja subtract%= \n\t" - -#define MONT_FIRSTSUB \ - "movq (%[M]), %%rax \n\t" \ - "subq %%rax, (%[tmp]) \n\t" - -#define MONT_NEXTSUB(ofs) \ - "movq " STR(ofs) "(%[M]), %%rax \n\t" \ - "sbbq %%rax, " STR(ofs) "(%[tmp]) \n\t" - -/* - The x86-64 Montgomery multiplication here is similar - to Algorithm 2 (CIOS method) in http://eprint.iacr.org/2012/140.pdf - and the PowerPC pseudocode of gmp-ecm library (c) Paul Zimmermann and Alexander Kruppa - (see comments on top of powerpc64/mulredc.m4). -*/ - -#define MONT_PRECOMPUTE \ - "xorq %[cy], %[cy] \n\t" \ - "movq 0(%[A]), %%rax \n\t" \ - "mulq 0(%[B]) \n\t" \ - "movq %%rax, %[T0] \n\t" \ - "movq %%rdx, %[T1] # T1:T0 <- A[0] * B[0] \n\t" \ - "mulq %[inv] \n\t" \ - "movq %%rax, %[u] # u <- T0 * inv \n\t" \ - "mulq 0(%[M]) \n\t" \ - "addq %[T0], %%rax \n\t" \ - "adcq %%rdx, %[T1] \n\t" \ - "adcq $0, %[cy] # cy:T1 <- (M[0]*u + T1 * b + T0) / b\n\t" - -#define MONT_FIRSTITER(j) \ - "xorq %[T0], %[T0] \n\t" \ - "movq 0(%[A]), %%rax \n\t" \ - "mulq " STR((j*8)) "(%[B]) \n\t" \ - "addq %[T1], %%rax \n\t" \ - "movq %%rax, " STR(((j-1)*8)) "(%[tmp]) \n\t" \ - "adcq $0, %%rdx \n\t" \ - "movq %%rdx, %[T1] # now T1:tmp[j-1] <-- X[0] * Y[j] + T1\n\t" \ - "movq " STR((j*8)) "(%[M]), %%rax \n\t" \ - "mulq %[u] \n\t" \ - "addq %%rax, " STR(((j-1)*8)) "(%[tmp]) \n\t" \ - "adcq %[cy], %%rdx \n\t" \ - "adcq $0, %[T0] \n\t" \ - "xorq %[cy], %[cy] \n\t" \ - "addq %%rdx, %[T1] \n\t" \ - "adcq %[T0], %[cy] # cy:T1:tmp[j-1] <---- (X[0] * Y[j] + T1) + (M[j] * u + cy * b) \n\t" - -#define MONT_ITERFIRST(i) \ - "xorq %[cy], %[cy] \n\t" \ - "movq " STR((i*8)) "(%[A]), %%rax \n\t" \ - "mulq 0(%[B]) \n\t" \ - "addq 0(%[tmp]), %%rax \n\t" \ - "adcq 8(%[tmp]), %%rdx \n\t" \ - "adcq $0, %[cy] \n\t" \ - "movq %%rax, %[T0] \n\t" \ - "movq %%rdx, %[T1] # cy:T1:T0 <- A[i] * B[0] + tmp[1] * b + tmp[0]\n\t" \ - "mulq %[inv] \n\t" \ - "movq %%rax, %[u] # u <- T0 * inv\n\t" \ - "mulq 0(%[M]) \n\t" \ - "addq %[T0], %%rax \n\t" \ - "adcq %%rdx, %[T1] \n\t" \ - "adcq $0, %[cy] # cy:T1 <- (M[0]*u + cy * b * b + T1 * b + T0) / b\n\t" - -#define MONT_ITERITER(i, j) \ - "xorq %[T0], %[T0] \n\t" \ - "movq " STR((i*8)) "(%[A]), %%rax \n\t" \ - "mulq " STR((j*8)) "(%[B]) \n\t" \ - "addq %[T1], %%rax \n\t" \ - "movq %%rax, " STR(((j-1)*8)) "(%[tmp]) \n\t" \ - "adcq $0, %%rdx \n\t" \ - "movq %%rdx, %[T1] # now T1:tmp[j-1] <-- X[i] * Y[j] + T1 \n\t" \ - "movq " STR((j*8)) "(%[M]), %%rax \n\t" \ - "mulq %[u] \n\t" \ - "addq %%rax, " STR(((j-1)*8)) "(%[tmp]) \n\t" \ - "adcq %[cy], %%rdx \n\t" \ - "adcq $0, %[T0] \n\t" \ - "xorq %[cy], %[cy] \n\t" \ - "addq %%rdx, %[T1] \n\t" \ - "adcq %[T0], %[cy] # cy:T1:tmp[j-1] <-- (X[i] * Y[j] + T1) + M[j] * u + cy * b \n\t" \ - "addq " STR(((j+1)*8)) "(%[tmp]), %[T1] \n\t" \ - "adcq $0, %[cy] # cy:T1:tmp[j-1] <-- (X[i] * Y[j] + T1) + M[j] * u + (tmp[j+1] + cy) * b \n\t" - -#define MONT_FINALIZE(j) \ - "movq %[T1], " STR((j*8)) "(%[tmp]) \n\t" \ - "movq %[cy], " STR(((j+1)*8)) "(%[tmp]) \n\t" - -/* - Comba multiplication and squaring routines are based on the - public-domain tomsfastmath library by Tom St Denis - - - - Compared to the above, we save 5-20% of cycles by using careful register - renaming to implement Comba forward operation. - */ - -#define COMBA_3_BY_3_MUL(c0_, c1_, c2_, res_, A_, B_) \ - asm volatile ( \ - "movq 0(%[A]), %%rax \n\t" \ - "mulq 0(%[B]) \n\t" \ - "movq %%rax, 0(%[res]) \n\t" \ - "movq %%rdx, %[c0] \n\t" \ - \ - "xorq %[c1], %[c1] \n\t" \ - "movq 0(%[A]), %%rax \n\t" \ - "mulq 8(%[B]) \n\t" \ - "addq %%rax, %[c0] \n\t" \ - "adcq %%rdx, %[c1] \n\t" \ - \ - "xorq %[c2], %[c2] \n\t" \ - "movq 8(%[A]), %%rax \n\t" \ - "mulq 0(%[B]) \n\t" \ - "addq %%rax, %[c0] \n\t" \ - "movq %[c0], 8(%[res]) \n\t" \ - "adcq %%rdx, %[c1] \n\t" \ - "adcq $0, %[c2] \n\t" \ - \ - "// register renaming (c1, c2, c0)\n\t" \ - "xorq %[c0], %[c0] \n\t" \ - "movq 0(%[A]), %%rax \n\t" \ - "mulq 16(%[B]) \n\t" \ - "addq %%rax, %[c1] \n\t" \ - "adcq %%rdx, %[c2] \n\t" \ - "adcq $0, %[c0] \n\t" \ - \ - "movq 8(%[A]), %%rax \n\t" \ - "mulq 8(%[B]) \n\t" \ - "addq %%rax, %[c1] \n\t" \ - "adcq %%rdx, %[c2] \n\t" \ - "adcq $0, %[c0] \n\t" \ - \ - "movq 16(%[A]), %%rax \n\t" \ - "mulq 0(%[B]) \n\t" \ - "addq %%rax, %[c1] \n\t" \ - "movq %[c1], 16(%[res]) \n\t" \ - "adcq %%rdx, %[c2] \n\t" \ - "adcq $0, %[c0] \n\t" \ - \ - "// register renaming (c2, c0, c1)\n\t" \ - "xorq %[c1], %[c1] \n\t" \ - "movq 8(%[A]), %%rax \n\t" \ - "mulq 16(%[B]) \n\t" \ - "addq %%rax, %[c2] \n\t" \ - "adcq %%rdx, %[c0] \n\t" \ - "adcq $0, %[c1] \n\t" \ - \ - "movq 16(%[A]), %%rax \n\t" \ - "mulq 8(%[B]) \n\t" \ - "addq %%rax, %[c2] \n\t" \ - "movq %[c2], 24(%[res]) \n\t" \ - "adcq %%rdx, %[c0] \n\t" \ - "adcq $0, %[c1] \n\t" \ - \ - "// register renaming (c0, c1, c2)\n\t" \ - "xorq %[c2], %[c2] \n\t" \ - "movq 16(%[A]), %%rax \n\t" \ - "mulq 16(%[B]) \n\t" \ - "addq %%rax, %[c0] \n\t" \ - "movq %[c0], 32(%[res]) \n\t" \ - "adcq %%rdx, %[c1] \n\t" \ - "movq %[c1], 40(%[res]) \n\t" \ - : [c0] "=&r" (c0_), [c1] "=&r" (c1_), [c2] "=&r" (c2_) \ - : [res] "r" (res_), [A] "r" (A_), [B] "r" (B_) \ - : "%rax", "%rdx", "cc", "memory") - -#define COMBA_3_BY_3_SQR(c0_, c1_, c2_, res_, A_) \ - asm volatile ( \ - "xorq %[c1], %[c1] \n\t" \ - "xorq %[c2], %[c2] \n\t" \ - "movq 0(%[A]), %%rax \n\t" \ - "mulq %%rax \n\t" \ - "movq %%rax, 0(%[res]) \n\t" \ - "movq %%rdx, %[c0] \n\t" \ - \ - "movq 0(%[A]), %%rax \n\t" \ - "mulq 8(%[A]) \n\t" \ - "addq %%rax, %[c0] \n\t" \ - "adcq %%rdx, %[c1] \n\t" \ - "addq %%rax, %[c0] \n\t" \ - "movq %[c0], 8(%[res]) \n\t" \ - "adcq %%rdx, %[c1] \n\t" \ - "adcq $0, %[c2] \n\t" \ - \ - "// register renaming (c1, c2, c0)\n\t" \ - "movq 0(%[A]), %%rax \n\t" \ - "xorq %[c0], %[c0] \n\t" \ - "mulq 16(%[A]) \n\t" \ - "addq %%rax, %[c1] \n\t" \ - "adcq %%rdx, %[c2] \n\t" \ - "adcq $0, %[c0] \n\t" \ - "addq %%rax, %[c1] \n\t" \ - "adcq %%rdx, %[c2] \n\t" \ - "adcq $0, %[c0] \n\t" \ - \ - "movq 8(%[A]), %%rax \n\t" \ - "mulq %%rax \n\t" \ - "addq %%rax, %[c1] \n\t" \ - "movq %[c1], 16(%[res]) \n\t" \ - "adcq %%rdx, %[c2] \n\t" \ - "adcq $0, %[c0] \n\t" \ - \ - "// register renaming (c2, c0, c1)\n\t" \ - "movq 8(%[A]), %%rax \n\t" \ - "xorq %[c1], %[c1] \n\t" \ - "mulq 16(%[A]) \n\t" \ - "addq %%rax, %[c2] \n\t" \ - "adcq %%rdx, %[c0] \n\t" \ - "adcq $0, %[c1] \n\t" \ - "addq %%rax, %[c2] \n\t" \ - "movq %[c2], 24(%[res]) \n\t" \ - "adcq %%rdx, %[c0] \n\t" \ - "adcq $0, %[c1] \n\t" \ - \ - "// register renaming (c0, c1, c2)\n\t" \ - "movq 16(%[A]), %%rax \n\t" \ - "mulq %%rax \n\t" \ - "addq %%rax, %[c0] \n\t" \ - "movq %[c0], 32(%[res]) \n\t" \ - "adcq %%rdx, %[c1] \n\t" \ - "movq %[c1], 40(%[res]) \n\t" \ - \ - : [c0] "=&r" (c0_), [c1] "=&r" (c1_), [c2] "=&r" (c2_) \ - : [res] "r" (res_), [A] "r" (A_) \ - : "%rax", "%rdx", "cc", "memory") - -/* - The Montgomery reduction here is based on Algorithm 14.32 in - Handbook of Applied Cryptography - . - */ -#define REDUCE_6_LIMB_PRODUCT(k_, tmp1_, tmp2_, tmp3_, inv_, res_, mod_) \ - __asm__ volatile \ - ("///////////////////////////////////\n\t" \ - "movq 0(%[res]), %%rax \n\t" \ - "mulq %[modprime] \n\t" \ - "movq %%rax, %[k] \n\t" \ - \ - "movq (%[mod]), %%rax \n\t" \ - "mulq %[k] \n\t" \ - "movq %%rax, %[tmp1] \n\t" \ - "movq %%rdx, %[tmp2] \n\t" \ - \ - "xorq %[tmp3], %[tmp3] \n\t" \ - "movq 8(%[mod]), %%rax \n\t" \ - "mulq %[k] \n\t" \ - "addq %[tmp1], 0(%[res]) \n\t" \ - "adcq %%rax, %[tmp2] \n\t" \ - "adcq %%rdx, %[tmp3] \n\t" \ - \ - "xorq %[tmp1], %[tmp1] \n\t" \ - "movq 16(%[mod]), %%rax \n\t" \ - "mulq %[k] \n\t" \ - "addq %[tmp2], 8(%[res]) \n\t" \ - "adcq %%rax, %[tmp3] \n\t" \ - "adcq %%rdx, %[tmp1] \n\t" \ - \ - "addq %[tmp3], 16(%[res]) \n\t" \ - "adcq %[tmp1], 24(%[res]) \n\t" \ - "adcq $0, 32(%[res]) \n\t" \ - "adcq $0, 40(%[res]) \n\t" \ - \ - "///////////////////////////////////\n\t" \ - "movq 8(%[res]), %%rax \n\t" \ - "mulq %[modprime] \n\t" \ - "movq %%rax, %[k] \n\t" \ - \ - "movq (%[mod]), %%rax \n\t" \ - "mulq %[k] \n\t" \ - "movq %%rax, %[tmp1] \n\t" \ - "movq %%rdx, %[tmp2] \n\t" \ - \ - "xorq %[tmp3], %[tmp3] \n\t" \ - "movq 8(%[mod]), %%rax \n\t" \ - "mulq %[k] \n\t" \ - "addq %[tmp1], 8(%[res]) \n\t" \ - "adcq %%rax, %[tmp2] \n\t" \ - "adcq %%rdx, %[tmp3] \n\t" \ - \ - "xorq %[tmp1], %[tmp1] \n\t" \ - "movq 16(%[mod]), %%rax \n\t" \ - "mulq %[k] \n\t" \ - "addq %[tmp2], 16(%[res]) \n\t" \ - "adcq %%rax, %[tmp3] \n\t" \ - "adcq %%rdx, %[tmp1] \n\t" \ - \ - "addq %[tmp3], 24(%[res]) \n\t" \ - "adcq %[tmp1], 32(%[res]) \n\t" \ - "adcq $0, 40(%[res]) \n\t" \ - \ - "///////////////////////////////////\n\t" \ - "movq 16(%[res]), %%rax \n\t" \ - "mulq %[modprime] \n\t" \ - "movq %%rax, %[k] \n\t" \ - \ - "movq (%[mod]), %%rax \n\t" \ - "mulq %[k] \n\t" \ - "movq %%rax, %[tmp1] \n\t" \ - "movq %%rdx, %[tmp2] \n\t" \ - \ - "xorq %[tmp3], %[tmp3] \n\t" \ - "movq 8(%[mod]), %%rax \n\t" \ - "mulq %[k] \n\t" \ - "addq %[tmp1], 16(%[res]) \n\t" \ - "adcq %%rax, %[tmp2] \n\t" \ - "adcq %%rdx, %[tmp3] \n\t" \ - \ - "xorq %[tmp1], %[tmp1] \n\t" \ - "movq 16(%[mod]), %%rax \n\t" \ - "mulq %[k] \n\t" \ - "addq %[tmp2], 24(%[res]) \n\t" \ - "adcq %%rax, %[tmp3] \n\t" \ - "adcq %%rdx, %[tmp1] \n\t" \ - \ - "addq %[tmp3], 32(%[res]) \n\t" \ - "adcq %[tmp1], 40(%[res]) \n\t" \ - : [k] "=&r" (k_), [tmp1] "=&r" (tmp1_), [tmp2] "=&r" (tmp2_), [tmp3] "=&r" (tmp3_) \ - : [modprime] "r" (inv_), [res] "r" (res_), [mod] "r" (mod_) \ - : "%rax", "%rdx", "cc", "memory") - -} // libsnark -#endif // FP_AUX_TCC_ diff --git a/src/snark/libsnark/algebra/fields/tests/test_bigint.cpp b/src/snark/libsnark/algebra/fields/tests/test_bigint.cpp deleted file mode 100644 index a735c3436..000000000 --- a/src/snark/libsnark/algebra/fields/tests/test_bigint.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/** - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#include "algebra/fields/bigint.hpp" - -using namespace libsnark; - -void test_bigint() -{ - static_assert(GMP_NUMB_BITS == 64, "GMP limb not 64-bit"); - - const char *b1_decimal = "76749407"; - const char *b2_decimal = "435020359732196472065729437602"; - const char *b3_decimal = "33387554642372758038536799358397002014"; - const char *b2_binary = "0000000000000000000000000000010101111101101000000110100001011010" - "1101101010001001000001101000101000100110011001110001111110100010"; - - bigint<1> b0 = bigint<1>(UINT64_C(0)); - bigint<1> b1 = bigint<1>(b1_decimal); - bigint<2> b2 = bigint<2>(b2_decimal); - - EXPECT_EQ(b0.as_uint64(), UINT64_C(0)); - EXPECT_TRUE(b0.is_zero()); - EXPECT_EQ(b1.as_uint64(), UINT64_C(76749407)); - EXPECT_FALSE(b1.is_zero()); - EXPECT_EQ(b2.as_uint64(), UINT64_C(15747124762497195938)); - EXPECT_FALSE(b2.is_zero()); - EXPECT_NE(b0, b1); - EXPECT_FALSE(b0 == b1); - - EXPECT_EQ(b2.max_bits(), 128u); - EXPECT_EQ(b2.num_bits(), 99u); - for (size_t i = 0; i < 128; i++) { - assert(b2.test_bit(i) == (b2_binary[127-i] == '1')); - } - - bigint<3> b3 = b2 * b1; - - assert(b3 == bigint<3>(b3_decimal)); - assert(!(b3.is_zero())); - - bigint<3> b3a { b3 }; - assert(b3a == bigint<3>(b3_decimal)); - assert(b3a == b3); - assert(!(b3a.is_zero())); - - mpz_t m3; - mpz_init(m3); - b3.to_mpz(m3); - bigint<3> b3b { m3 }; - assert(b3b == b3); - - bigint<2> quotient; - bigint<2> remainder; - bigint<3>::div_qr(quotient, remainder, b3, b2); - EXPECT_LT(quotient.num_bits(), static_cast(GMP_NUMB_BITS)); - EXPECT_EQ(quotient.as_uint64(), b1.as_uint64()); - bigint<1> b1inc = bigint<1>("76749408"); - bigint<1> b1a = quotient.shorten(b1inc, "test"); - assert(b1a == b1); - assert(remainder.is_zero()); - remainder.limit(b2, "test"); - - try { - (void)(quotient.shorten(b1, "test")); - assert(false); - } catch (std::domain_error) {} - try { - remainder.limit(remainder, "test"); - assert(false); - } catch (std::domain_error) {} - - bigint<1> br = bigint<1>("42"); - b3 += br; - assert(b3 != b3a); - assert(b3 > b3a); - assert(!(b3a > b3)); - - bigint<3>::div_qr(quotient, remainder, b3, b2); - EXPECT_LT(quotient.num_bits(), static_cast(GMP_NUMB_BITS)); - EXPECT_EQ(quotient.as_uint64(), b1.as_uint64()); - EXPECT_LT(remainder.num_bits(), static_cast(GMP_NUMB_BITS)); - EXPECT_EQ(remainder.as_uint64(), 42u); - - b3a.clear(); - EXPECT_TRUE(b3a.is_zero()); - EXPECT_EQ(b3a.num_bits(), 0u); - EXPECT_FALSE(b3.is_zero()); - - bigint<4> bx = bigint<4>().randomize(); - bigint<4> by = bigint<4>().randomize(); - assert(!(bx == by)); - - // TODO: test serialization -} - -int main(void) -{ - test_bigint(); - return 0; -} - diff --git a/src/snark/libsnark/algebra/fields/tests/test_fields.cpp b/src/snark/libsnark/algebra/fields/tests/test_fields.cpp deleted file mode 100644 index 8f62ceef9..000000000 --- a/src/snark/libsnark/algebra/fields/tests/test_fields.cpp +++ /dev/null @@ -1,245 +0,0 @@ -/** - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ -#include "common/profiling.hpp" -#include "algebra/curves/edwards/edwards_pp.hpp" -#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" -#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" -#ifdef CURVE_BN128 -#include "algebra/curves/bn128/bn128_pp.hpp" -#endif -#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp" -#include "algebra/fields/fp6_3over2.hpp" -#include "algebra/fields/fp12_2over3over2.hpp" - -using namespace libsnark; - -template -void test_field() -{ - bigint<1> rand1 = bigint<1>("76749407"); - bigint<1> rand2 = bigint<1>("44410867"); - bigint<1> randsum = bigint<1>("121160274"); - - FieldT zero = FieldT::zero(); - FieldT one = FieldT::one(); - FieldT a = FieldT::random_element(); - FieldT a_ser; - a_ser = reserialize(a); - assert(a_ser == a); - - FieldT b = FieldT::random_element(); - FieldT c = FieldT::random_element(); - FieldT d = FieldT::random_element(); - - assert(a != zero); - assert(a != one); - - assert(a * a == a.squared()); - assert((a + b).squared() == a.squared() + a*b + b*a + b.squared()); - assert((a + b)*(c + d) == a*c + a*d + b*c + b*d); - assert(a - b == a + (-b)); - assert(a - b == (-b) + a); - - assert((a ^ rand1) * (a ^ rand2) == (a^randsum)); - - assert(a * a.inverse() == one); - assert((a + b) * c.inverse() == a * c.inverse() + (b.inverse() * c).inverse()); - -} - -template -void test_sqrt() -{ - for (size_t i = 0; i < 100; ++i) - { - FieldT a = FieldT::random_element(); - FieldT asq = a.squared(); - assert(asq.sqrt() == a || asq.sqrt() == -a); - } -} - -template -void test_two_squarings() -{ - FieldT a = FieldT::random_element(); - assert(a.squared() == a * a); - assert(a.squared() == a.squared_complex()); - assert(a.squared() == a.squared_karatsuba()); -} - -template -void test_Frobenius() -{ - FieldT a = FieldT::random_element(); - assert(a.Frobenius_map(0) == a); - FieldT a_q = a ^ FieldT::base_field_char(); - for (size_t power = 1; power < 10; ++power) - { - const FieldT a_qi = a.Frobenius_map(power); - assert(a_qi == a_q); - - a_q = a_q ^ FieldT::base_field_char(); - } -} - -template -void test_unitary_inverse() -{ - EXPECT_EQ(FieldT::extension_degree() % 2, 0u); - FieldT a = FieldT::random_element(); - FieldT aqcubed_minus1 = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse(); - assert(aqcubed_minus1.inverse() == aqcubed_minus1.unitary_inverse()); -} - -template -void test_cyclotomic_squaring(); - -template<> -void test_cyclotomic_squaring >() -{ - typedef Fqk FieldT; - assert(FieldT::extension_degree() % 2 == 0); - FieldT a = FieldT::random_element(); - FieldT a_unitary = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse(); - // beta = a^((q^(k/2)-1)*(q+1)) - FieldT beta = a_unitary.Frobenius_map(1) * a_unitary; - assert(beta.cyclotomic_squared() == beta.squared()); -} - -template<> -void test_cyclotomic_squaring >() -{ - typedef Fqk FieldT; - assert(FieldT::extension_degree() % 2 == 0); - FieldT a = FieldT::random_element(); - FieldT a_unitary = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse(); - // beta = a^(q^(k/2)-1) - FieldT beta = a_unitary; - assert(beta.cyclotomic_squared() == beta.squared()); -} - -template<> -void test_cyclotomic_squaring >() -{ - typedef Fqk FieldT; - assert(FieldT::extension_degree() % 2 == 0); - FieldT a = FieldT::random_element(); - FieldT a_unitary = a.Frobenius_map(FieldT::extension_degree()/2) * a.inverse(); - // beta = a^((q^(k/2)-1)*(q+1)) - FieldT beta = a_unitary.Frobenius_map(1) * a_unitary; - assert(beta.cyclotomic_squared() == beta.squared()); -} - -template -void test_all_fields() -{ - test_field >(); - test_field >(); - test_field >(); - test_field >(); - - test_sqrt >(); - test_sqrt >(); - test_sqrt >(); - - test_Frobenius >(); - test_Frobenius >(); - - test_unitary_inverse >(); -} - -template -void test_Fp4_tom_cook() -{ - typedef typename Fp4T::my_Fp FieldT; - for (size_t i = 0; i < 100; ++i) - { - const Fp4T a = Fp4T::random_element(); - const Fp4T b = Fp4T::random_element(); - const Fp4T correct_res = a * b; - - Fp4T res; - - const FieldT - &a0 = a.c0.c0, - &a1 = a.c1.c0, - &a2 = a.c0.c1, - &a3 = a.c1.c1; - - const FieldT - &b0 = b.c0.c0, - &b1 = b.c1.c0, - &b2 = b.c0.c1, - &b3 = b.c1.c1; - - FieldT - &c0 = res.c0.c0, - &c1 = res.c1.c0, - &c2 = res.c0.c1, - &c3 = res.c1.c1; - - const FieldT v0 = a0 * b0; - const FieldT v1 = (a0 + a1 + a2 + a3) * (b0 + b1 + b2 + b3); - const FieldT v2 = (a0 - a1 + a2 - a3) * (b0 - b1 + b2 - b3); - const FieldT v3 = (a0 + FieldT(2)*a1 + FieldT(4)*a2 + FieldT(8)*a3) * (b0 + FieldT(2)*b1 + FieldT(4)*b2 + FieldT(8)*b3); - const FieldT v4 = (a0 - FieldT(2)*a1 + FieldT(4)*a2 - FieldT(8)*a3) * (b0 - FieldT(2)*b1 + FieldT(4)*b2 - FieldT(8)*b3); - const FieldT v5 = (a0 + FieldT(3)*a1 + FieldT(9)*a2 + FieldT(27)*a3) * (b0 + FieldT(3)*b1 + FieldT(9)*b2 + FieldT(27)*b3); - const FieldT v6 = a3 * b3; - - const FieldT beta = Fp4T::non_residue; - - c0 = v0 + beta*(FieldT(4).inverse()*v0 - FieldT(6).inverse()*(v1 + v2) + FieldT(24).inverse() * (v3 + v4) - FieldT(5) * v6); - c1 = - FieldT(3).inverse()*v0 + v1 - FieldT(2).inverse()*v2 - FieldT(4).inverse()*v3 + FieldT(20).inverse() * v4 + FieldT(30).inverse() * v5 - FieldT(12) * v6 + beta * ( - FieldT(12).inverse() * (v0 - v1) + FieldT(24).inverse()*(v2 - v3) - FieldT(120).inverse() * (v4 - v5) - FieldT(3) * v6); - c2 = - (FieldT(5)*(FieldT(4).inverse()))* v0 + (FieldT(2)*(FieldT(3).inverse()))*(v1 + v2) - FieldT(24).inverse()*(v3 + v4) + FieldT(4)*v6 + beta*v6; - c3 = FieldT(12).inverse() * (FieldT(5)*v0 - FieldT(7)*v1) - FieldT(24).inverse()*(v2 - FieldT(7)*v3 + v4 + v5) + FieldT(15)*v6; - - assert(res == correct_res); - - // {v0, v3, v4, v5} - const FieldT u = (FieldT::one() - beta).inverse(); - assert(v0 == u * c0 + beta * u * c2 - beta * u * FieldT(2).inverse() * v1 - beta * u * FieldT(2).inverse() * v2 + beta * v6); - assert(v3 == - FieldT(15) * u * c0 - FieldT(30) * u * c1 - FieldT(3) * (FieldT(4) + beta) * u * c2 - FieldT(6) * (FieldT(4) + beta) * u * c3 + (FieldT(24) - FieldT(3) * beta * FieldT(2).inverse()) * u * v1 + (-FieldT(8) + beta * FieldT(2).inverse()) * u * v2 - - FieldT(3) * (-FieldT(16) + beta) * v6); - assert(v4 == - FieldT(15) * u * c0 + FieldT(30) * u * c1 - FieldT(3) * (FieldT(4) + beta) * u * c2 + FieldT(6) * (FieldT(4) + beta) * u * c3 + (FieldT(24) - FieldT(3) * beta * FieldT(2).inverse()) * u * v2 + (-FieldT(8) + beta * FieldT(2).inverse()) * u * v1 - - FieldT(3) * (-FieldT(16) + beta) * v6); - assert(v5 == - FieldT(80) * u * c0 - FieldT(240) * u * c1 - FieldT(8) * (FieldT(9) + beta) * u * c2 - FieldT(24) * (FieldT(9) + beta) * u * c3 - FieldT(2) * (-FieldT(81) + beta) * u * v1 + (-FieldT(81) + beta) * u * v2 - - FieldT(8) * (-FieldT(81) + beta) * v6); - - // c0 + beta c2 - (beta v1)/2 - (beta v2)/ 2 - (-1 + beta) beta v6, - // -15 c0 - 30 c1 - 3 (4 + beta) c2 - 6 (4 + beta) c3 + (24 - (3 beta)/2) v1 + (-8 + beta/2) v2 + 3 (-16 + beta) (-1 + beta) v6, - // -15 c0 + 30 c1 - 3 (4 + beta) c2 + 6 (4 + beta) c3 + (-8 + beta/2) v1 + (24 - (3 beta)/2) v2 + 3 (-16 + beta) (-1 + beta) v6, - // -80 c0 - 240 c1 - 8 (9 + beta) c2 - 24 (9 + beta) c3 - 2 (-81 + beta) v1 + (-81 + beta) v2 + 8 (-81 + beta) (-1 + beta) v6 - } -} - -int main(void) -{ - edwards_pp::init_public_params(); - test_all_fields(); - test_cyclotomic_squaring >(); - - mnt4_pp::init_public_params(); - test_all_fields(); - test_Fp4_tom_cook(); - test_two_squarings >(); - test_cyclotomic_squaring >(); - - mnt6_pp::init_public_params(); - test_all_fields(); - test_cyclotomic_squaring >(); - - alt_bn128_pp::init_public_params(); - test_field(); - test_Frobenius(); - test_all_fields(); - -#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled - bn128_pp::init_public_params(); - test_field >(); - test_field >(); -#endif -} diff --git a/src/snark/libsnark/algebra/knowledge_commitment/knowledge_commitment.hpp b/src/snark/libsnark/algebra/knowledge_commitment/knowledge_commitment.hpp deleted file mode 100644 index 902423134..000000000 --- a/src/snark/libsnark/algebra/knowledge_commitment/knowledge_commitment.hpp +++ /dev/null @@ -1,84 +0,0 @@ -/** @file - ***************************************************************************** - - Declaration of interfaces for: - - a knowledge commitment, and - - a knowledge commitment vector. - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef KNOWLEDGE_COMMITMENT_HPP_ -#define KNOWLEDGE_COMMITMENT_HPP_ - -#include "algebra/fields/fp.hpp" -#include "common/data_structures/sparse_vector.hpp" - -namespace libsnark { - -/********************** Knowledge commitment *********************************/ - -/** - * A knowledge commitment is a pair (g,h) where g is in T1 and h in T2, - * and T1 and T2 are groups (written additively). - * - * Such pairs form a group by defining: - * - "zero" = (0,0) - * - "one" = (1,1) - * - a * (g,h) + b * (g',h') := ( a * g + b * g', a * h + b * h'). - */ -template -struct knowledge_commitment { - - T1 g; - T2 h; - - knowledge_commitment() = default; - knowledge_commitment(const knowledge_commitment &other) = default; - knowledge_commitment(knowledge_commitment &&other) = default; - knowledge_commitment(const T1 &g, const T2 &h); - - knowledge_commitment& operator=(const knowledge_commitment &other) = default; - knowledge_commitment& operator=(knowledge_commitment &&other) = default; - knowledge_commitment operator+(const knowledge_commitment &other) const; - - bool is_zero() const; - bool operator==(const knowledge_commitment &other) const; - bool operator!=(const knowledge_commitment &other) const; - - static knowledge_commitment zero(); - static knowledge_commitment one(); - - void print() const; - - static size_t size_in_bits(); -}; - -template -knowledge_commitment operator*(const bigint &lhs, const knowledge_commitment &rhs); - -template &modulus_p> -knowledge_commitment operator*(const Fp_model &lhs, const knowledge_commitment &rhs); - -template -std::ostream& operator<<(std::ostream& out, const knowledge_commitment &kc); - -template -std::istream& operator>>(std::istream& in, knowledge_commitment &kc); - -/******************** Knowledge commitment vector ****************************/ - -/** - * A knowledge commitment vector is a sparse vector of knowledge commitments. - */ -template -using knowledge_commitment_vector = sparse_vector >; - -} // libsnark - -#include "algebra/knowledge_commitment/knowledge_commitment.tcc" - -#endif // KNOWLEDGE_COMMITMENT_HPP_ diff --git a/src/snark/libsnark/algebra/knowledge_commitment/knowledge_commitment.tcc b/src/snark/libsnark/algebra/knowledge_commitment/knowledge_commitment.tcc deleted file mode 100644 index 15b2926c8..000000000 --- a/src/snark/libsnark/algebra/knowledge_commitment/knowledge_commitment.tcc +++ /dev/null @@ -1,111 +0,0 @@ -/** @file - ***************************************************************************** - - Implementation of interfaces for: - - a knowledge commitment, and - - a knowledge commitment vector. - - See knowledge_commitment.hpp . - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef KNOWLEDGE_COMMITMENT_TCC_ -#define KNOWLEDGE_COMMITMENT_TCC_ - -namespace libsnark { - -template -knowledge_commitment::knowledge_commitment(const T1 &g, const T2 &h) : - g(g), h(h) -{ -} - -template -knowledge_commitment knowledge_commitment::zero() -{ - return knowledge_commitment(T1::zero(), T2::zero()); -} - -template -knowledge_commitment knowledge_commitment::one() -{ - return knowledge_commitment(T1::one(), T2::one()); -} - -template -knowledge_commitment knowledge_commitment::operator+(const knowledge_commitment &other) const -{ - return knowledge_commitment(this->g + other.g, - this->h + other.h); -} - -template -bool knowledge_commitment::is_zero() const -{ - return (g.is_zero() && h.is_zero()); -} - -template -bool knowledge_commitment::operator==(const knowledge_commitment &other) const -{ - return (this->g == other.g && - this->h == other.h); -} - -template -bool knowledge_commitment::operator!=(const knowledge_commitment &other) const -{ - return !((*this) == other); -} - -template -knowledge_commitment operator*(const bigint &lhs, const knowledge_commitment &rhs) -{ - return knowledge_commitment(lhs * rhs.g, - lhs * rhs.h); -} - -template &modulus_p> -knowledge_commitment operator*(const Fp_model &lhs, const knowledge_commitment &rhs) -{ - return (lhs.as_bigint()) * rhs; -} - -template -void knowledge_commitment::print() const -{ - printf("knowledge_commitment.g:\n"); - g.print(); - printf("knowledge_commitment.h:\n"); - h.print(); -} - -template -size_t knowledge_commitment::size_in_bits() -{ - return T1::size_in_bits() + T2::size_in_bits(); -} - -template -std::ostream& operator<<(std::ostream& out, const knowledge_commitment &kc) -{ - out << kc.g << OUTPUT_SEPARATOR << kc.h; - return out; -} - -template -std::istream& operator>>(std::istream& in, knowledge_commitment &kc) -{ - in >> kc.g; - consume_OUTPUT_SEPARATOR(in); - in >> kc.h; - return in; -} - -} // libsnark - -#endif // KNOWLEDGE_COMMITMENT_TCC_ diff --git a/src/snark/libsnark/algebra/scalar_multiplication/kc_multiexp.hpp b/src/snark/libsnark/algebra/scalar_multiplication/kc_multiexp.hpp deleted file mode 100644 index 4e8b55667..000000000 --- a/src/snark/libsnark/algebra/scalar_multiplication/kc_multiexp.hpp +++ /dev/null @@ -1,55 +0,0 @@ -/** @file - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef KC_MULTIEXP_HPP_ -#define KC_MULTIEXP_HPP_ - -/* - Split out from multiexp to prevent cyclical - dependencies. I.e. previously multiexp dependend on - knowledge_commitment, which dependend on sparse_vector, which - dependend on multiexp (to do accumulate). - - Will probably go away in more general exp refactoring. -*/ - -#include "algebra/knowledge_commitment/knowledge_commitment.hpp" - -namespace libsnark { - -template -knowledge_commitment opt_window_wnaf_exp(const knowledge_commitment &base, - const bigint &scalar, const size_t scalar_bits); - -template -knowledge_commitment kc_multi_exp_with_mixed_addition(const knowledge_commitment_vector &vec, - const size_t min_idx, - const size_t max_idx, - typename std::vector::const_iterator scalar_start, - typename std::vector::const_iterator scalar_end, - const size_t chunks, - const bool use_multiexp=false); - -template -void kc_batch_to_special(std::vector > &vec); - -template -knowledge_commitment_vector kc_batch_exp(const size_t scalar_size, - const size_t T1_window, - const size_t T2_window, - const window_table &T1_table, - const window_table &T2_table, - const FieldT &T1_coeff, - const FieldT &T2_coeff, - const std::vector &v, - const size_t suggested_num_chunks); - -} // libsnark - -#include "algebra/scalar_multiplication/kc_multiexp.tcc" - -#endif // KC_MULTIEXP_HPP_ diff --git a/src/snark/libsnark/algebra/scalar_multiplication/kc_multiexp.tcc b/src/snark/libsnark/algebra/scalar_multiplication/kc_multiexp.tcc deleted file mode 100644 index 605203347..000000000 --- a/src/snark/libsnark/algebra/scalar_multiplication/kc_multiexp.tcc +++ /dev/null @@ -1,276 +0,0 @@ -/** @file - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef KC_MULTIEXP_TCC_ -#define KC_MULTIEXP_TCC_ - -#include "common/assert_except.hpp" - -namespace libsnark { - -template -knowledge_commitment opt_window_wnaf_exp(const knowledge_commitment &base, - const bigint &scalar, const size_t scalar_bits) -{ - return knowledge_commitment(opt_window_wnaf_exp(base.g, scalar, scalar_bits), - opt_window_wnaf_exp(base.h, scalar, scalar_bits)); -} - -template -knowledge_commitment kc_multi_exp_with_mixed_addition(const knowledge_commitment_vector &vec, - const size_t min_idx, - const size_t max_idx, - typename std::vector::const_iterator scalar_start, - typename std::vector::const_iterator scalar_end, - const size_t chunks, - const bool use_multiexp) -{ - enter_block("Process scalar vector"); - auto index_it = std::lower_bound(vec.indices.begin(), vec.indices.end(), min_idx); - const size_t offset = index_it - vec.indices.begin(); - - auto value_it = vec.values.begin() + offset; - - const FieldT zero = FieldT::zero(); - const FieldT one = FieldT::one(); - - std::vector p; - std::vector > g; - - knowledge_commitment acc = knowledge_commitment::zero(); - - size_t num_skip = 0; - size_t num_add = 0; - size_t num_other = 0; - - const size_t scalar_length = std::distance(scalar_start, scalar_end); - - while (index_it != vec.indices.end() && *index_it < max_idx) - { - const size_t scalar_position = (*index_it) - min_idx; - assert_except(scalar_position < scalar_length); - - const FieldT scalar = *(scalar_start + scalar_position); - - if (scalar == zero) - { - // do nothing - ++num_skip; - } - else if (scalar == one) - { -#ifdef USE_MIXED_ADDITION - acc.g = acc.g.mixed_add(value_it->g); - acc.h = acc.h.mixed_add(value_it->h); -#else - acc.g = acc.g + value_it->g; - acc.h = acc.h + value_it->h; -#endif - ++num_add; - } - else - { - p.emplace_back(scalar); - g.emplace_back(*value_it); - ++num_other; - } - - ++index_it; - ++value_it; - } - - //print_indent(); printf("* Elements of w skipped: %zu (%0.2f%%)\n", num_skip, 100.*num_skip/(num_skip+num_add+num_other)); - //print_indent(); printf("* Elements of w processed with special addition: %zu (%0.2f%%)\n", num_add, 100.*num_add/(num_skip+num_add+num_other)); - //print_indent(); printf("* Elements of w remaining: %zu (%0.2f%%)\n", num_other, 100.*num_other/(num_skip+num_add+num_other)); - leave_block("Process scalar vector"); - - return acc + multi_exp, FieldT>(g.begin(), g.end(), p.begin(), p.end(), chunks, use_multiexp); -} - -template -void kc_batch_to_special(std::vector > &vec) -{ - enter_block("Batch-convert knowledge-commitments to special form"); - - std::vector g_vec; - g_vec.reserve(vec.size()); - - for (size_t i = 0; i < vec.size(); ++i) - { - if (!vec[i].g.is_zero()) - { - g_vec.emplace_back(vec[i].g); - } - } - - batch_to_special_all_non_zeros(g_vec); - auto g_it = g_vec.begin(); - T1 T1_zero_special = T1::zero(); - T1_zero_special.to_special(); - - for (size_t i = 0; i < vec.size(); ++i) - { - if (!vec[i].g.is_zero()) - { - vec[i].g = *g_it; - ++g_it; - } - else - { - vec[i].g = T1_zero_special; - } - } - - g_vec.clear(); - - std::vector h_vec; - h_vec.reserve(vec.size()); - - for (size_t i = 0; i < vec.size(); ++i) - { - if (!vec[i].h.is_zero()) - { - h_vec.emplace_back(vec[i].h); - } - } - - batch_to_special_all_non_zeros(h_vec); - auto h_it = h_vec.begin(); - T2 T2_zero_special = T2::zero(); - T2_zero_special.to_special(); - - for (size_t i = 0; i < vec.size(); ++i) - { - if (!vec[i].h.is_zero()) - { - vec[i].h = *h_it; - ++h_it; - } - else - { - vec[i].h = T2_zero_special; - } - } - - g_vec.clear(); - - leave_block("Batch-convert knowledge-commitments to special form"); -} - -template -knowledge_commitment_vector kc_batch_exp_internal(const size_t scalar_size, - const size_t T1_window, - const size_t T2_window, - const window_table &T1_table, - const window_table &T2_table, - const FieldT &T1_coeff, - const FieldT &T2_coeff, - const std::vector &v, - const size_t start_pos, - const size_t end_pos, - const size_t expected_size) -{ - knowledge_commitment_vector res; - - res.values.reserve(expected_size); - res.indices.reserve(expected_size); - - for (size_t pos = start_pos; pos != end_pos; ++pos) - { - if (!v[pos].is_zero()) - { - res.values.emplace_back(knowledge_commitment(windowed_exp(scalar_size, T1_window, T1_table, T1_coeff * v[pos]), - windowed_exp(scalar_size, T2_window, T2_table, T2_coeff * v[pos]))); - res.indices.emplace_back(pos); - } - } - - return res; -} - -template -knowledge_commitment_vector kc_batch_exp(const size_t scalar_size, - const size_t T1_window, - const size_t T2_window, - const window_table &T1_table, - const window_table &T2_table, - const FieldT &T1_coeff, - const FieldT &T2_coeff, - const std::vector &v, - const size_t suggested_num_chunks) -{ - knowledge_commitment_vector res; - res.domain_size_ = v.size(); - - size_t nonzero = 0; - for (size_t i = 0; i < v.size(); ++i) - { - nonzero += (v[i].is_zero() ? 0 : 1); - } - - const size_t num_chunks = std::max((size_t)1, std::min(nonzero, suggested_num_chunks)); - - if (!inhibit_profiling_info) - { - print_indent(); printf("Non-zero coordinate count: %zu/%zu (%0.2f%%)\n", nonzero, v.size(), 100.*nonzero/v.size()); - } - - std::vector > tmp(num_chunks); - std::vector chunk_pos(num_chunks+1); - - const size_t chunk_size = nonzero / num_chunks; - const size_t last_chunk = nonzero - chunk_size * (num_chunks - 1); - - chunk_pos[0] = 0; - - size_t cnt = 0; - size_t chunkno = 1; - - for (size_t i = 0; i < v.size(); ++i) - { - cnt += (v[i].is_zero() ? 0 : 1); - if (cnt == chunk_size && chunkno < num_chunks) - { - chunk_pos[chunkno] = i; - cnt = 0; - ++chunkno; - } - } - - chunk_pos[num_chunks] = v.size(); - -#ifdef MULTICORE -#pragma omp parallel for -#endif - for (size_t i = 0; i < num_chunks; ++i) - { - tmp[i] = kc_batch_exp_internal(scalar_size, T1_window, T2_window, T1_table, T2_table, T1_coeff, T2_coeff, v, - chunk_pos[i], chunk_pos[i+1], i == num_chunks - 1 ? last_chunk : chunk_size); -#ifdef USE_MIXED_ADDITION - kc_batch_to_special(tmp[i].values); -#endif - } - - if (num_chunks == 1) - { - tmp[0].domain_size_ = v.size(); - return tmp[0]; - } - else - { - for (size_t i = 0; i < num_chunks; ++i) - { - res.values.insert(res.values.end(), tmp[i].values.begin(), tmp[i].values.end()); - res.indices.insert(res.indices.end(), tmp[i].indices.begin(), tmp[i].indices.end()); - } - return res; - } -} - -} // libsnark - -#endif // KC_MULTIEXP_TCC_ diff --git a/src/snark/libsnark/algebra/scalar_multiplication/multiexp.hpp b/src/snark/libsnark/algebra/scalar_multiplication/multiexp.hpp deleted file mode 100644 index eaf72d61f..000000000 --- a/src/snark/libsnark/algebra/scalar_multiplication/multiexp.hpp +++ /dev/null @@ -1,110 +0,0 @@ -/** @file - ***************************************************************************** - - Declaration of interfaces for multi-exponentiation routines. - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef MULTIEXP_HPP_ -#define MULTIEXP_HPP_ - -namespace libsnark { - -/** - * Naive multi-exponentiation individually multiplies each base by the - * corresponding scalar and adds up the results. - */ -template -T naive_exp(typename std::vector::const_iterator vec_start, - typename std::vector::const_iterator vec_end, - typename std::vector::const_iterator scalar_start, - typename std::vector::const_iterator scalar_end); - -template -T naive_plain_exp(typename std::vector::const_iterator vec_start, - typename std::vector::const_iterator vec_end, - typename std::vector::const_iterator scalar_start, - typename std::vector::const_iterator scalar_end); - -/** - * Naive multi-exponentiation uses a variant of the Bos-Coster algorithm [1], - * and implementation suggestions from [2]. - * - * [1] = Bos and Coster, "Addition chain heuristics", CRYPTO '89 - * [2] = Bernstein, Duif, Lange, Schwabe, and Yang, "High-speed high-security signatures", CHES '11 - */ -template -T multi_exp(typename std::vector::const_iterator vec_start, - typename std::vector::const_iterator vec_end, - typename std::vector::const_iterator scalar_start, - typename std::vector::const_iterator scalar_end, - const size_t chunks, - const bool use_multiexp=false); - - -/** - * A variant of multi_exp that takes advantage of the method mixed_add (instead of the operator '+'). - */ -template -T multi_exp_with_mixed_addition(typename std::vector::const_iterator vec_start, - typename std::vector::const_iterator vec_end, - typename std::vector::const_iterator scalar_start, - typename std::vector::const_iterator scalar_end, - const size_t chunks, - const bool use_multiexp); - -/** - * A window table stores window sizes for different instance sizes for fixed-base multi-scalar multiplications. - */ -template -using window_table = std::vector >; - -/** - * Compute window size for the given number of scalars. - */ -template -size_t get_exp_window_size(const size_t num_scalars); - -/** - * Compute table of window sizes. - */ -template -window_table get_window_table(const size_t scalar_size, - const size_t window, - const T &g); - -template -T windowed_exp(const size_t scalar_size, - const size_t window, - const window_table &powers_of_g, - const FieldT &pow); - -template -std::vector batch_exp(const size_t scalar_size, - const size_t window, - const window_table &table, - const std::vector &v); - -template -std::vector batch_exp_with_coeff(const size_t scalar_size, - const size_t window, - const window_table &table, - const FieldT &coeff, - const std::vector &v); - -// defined in every curve -template -void batch_to_special_all_non_zeros(std::vector &vec); - -template -void batch_to_special(std::vector &vec); - -} // libsnark - -#include "algebra/scalar_multiplication/multiexp.tcc" - -#endif // MULTIEXP_HPP_ diff --git a/src/snark/libsnark/algebra/scalar_multiplication/multiexp.tcc b/src/snark/libsnark/algebra/scalar_multiplication/multiexp.tcc deleted file mode 100644 index 5dd19a651..000000000 --- a/src/snark/libsnark/algebra/scalar_multiplication/multiexp.tcc +++ /dev/null @@ -1,591 +0,0 @@ -/** @file - ***************************************************************************** - - Implementation of interfaces for multi-exponentiation routines. - - See multiexp.hpp . - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef MULTIEXP_TCC_ -#define MULTIEXP_TCC_ - -#include "algebra/fields/fp_aux.tcc" - -#include -#include -#include - -#include "common/profiling.hpp" -#include "common/utils.hpp" -#include "common/assert_except.hpp" -#include "algebra/scalar_multiplication/wnaf.hpp" - -namespace libsnark { - -template -class ordered_exponent { -// to use std::push_heap and friends later -public: - size_t idx; - bigint r; - - ordered_exponent(const size_t idx, const bigint &r) : idx(idx), r(r) {}; - - bool operator<(const ordered_exponent &other) const - { -#if defined(__x86_64__) && defined(USE_ASM) - if (n == 3) - { - int64_t res; - __asm__ - ("// check for overflow \n\t" - "mov $0, %[res] \n\t" - ADD_CMP(16) - ADD_CMP(8) - ADD_CMP(0) - "jmp done%= \n\t" - "subtract%=: \n\t" - "mov $1, %[res] \n\t" - "done%=: \n\t" - : [res] "=&r" (res) - : [A] "r" (other.r.data), [mod] "r" (this->r.data) - : "cc", "%rax"); - return res; - } - else if (n == 4) - { - int64_t res; - __asm__ - ("// check for overflow \n\t" - "mov $0, %[res] \n\t" - ADD_CMP(24) - ADD_CMP(16) - ADD_CMP(8) - ADD_CMP(0) - "jmp done%= \n\t" - "subtract%=: \n\t" - "mov $1, %[res] \n\t" - "done%=: \n\t" - : [res] "=&r" (res) - : [A] "r" (other.r.data), [mod] "r" (this->r.data) - : "cc", "%rax"); - return res; - } - else if (n == 5) - { - int64_t res; - __asm__ - ("// check for overflow \n\t" - "mov $0, %[res] \n\t" - ADD_CMP(32) - ADD_CMP(24) - ADD_CMP(16) - ADD_CMP(8) - ADD_CMP(0) - "jmp done%= \n\t" - "subtract%=: \n\t" - "mov $1, %[res] \n\t" - "done%=: \n\t" - : [res] "=&r" (res) - : [A] "r" (other.r.data), [mod] "r" (this->r.data) - : "cc", "%rax"); - return res; - } - else -#endif - { - return (mpn_cmp(this->r.data, other.r.data, n) < 0); - } - } -}; - -template -T naive_exp(typename std::vector::const_iterator vec_start, - typename std::vector::const_iterator vec_end, - typename std::vector::const_iterator scalar_start, - typename std::vector::const_iterator scalar_end) -{ - T result(T::zero()); - - typename std::vector::const_iterator vec_it; - typename std::vector::const_iterator scalar_it; - - for (vec_it = vec_start, scalar_it = scalar_start; vec_it != vec_end; ++vec_it, ++scalar_it) - { - bigint scalar_bigint = scalar_it->as_bigint(); - result = result + opt_window_wnaf_exp(*vec_it, scalar_bigint, scalar_bigint.num_bits()); - } - assert_except(scalar_it == scalar_end); - - return result; -} - -template -T naive_plain_exp(typename std::vector::const_iterator vec_start, - typename std::vector::const_iterator vec_end, - typename std::vector::const_iterator scalar_start, - typename std::vector::const_iterator scalar_end) -{ - T result(T::zero()); - - typename std::vector::const_iterator vec_it; - typename std::vector::const_iterator scalar_it; - - for (vec_it = vec_start, scalar_it = scalar_start; vec_it != vec_end; ++vec_it, ++scalar_it) - { - result = result + (*scalar_it) * (*vec_it); - } - assert_except(scalar_it == scalar_end); - - return result; -} - -/* - The multi-exponentiation algorithm below is a variant of the Bos-Coster algorithm - [Bos and Coster, "Addition chain heuristics", CRYPTO '89]. - The implementation uses suggestions from - [Bernstein, Duif, Lange, Schwabe, and Yang, "High-speed high-security signatures", CHES '11]. -*/ -template -T multi_exp_inner(typename std::vector::const_iterator vec_start, - typename std::vector::const_iterator vec_end, - typename std::vector::const_iterator scalar_start, - typename std::vector::const_iterator scalar_end) -{ - const mp_size_t n = std::remove_reference::type::num_limbs; - - if (vec_start == vec_end) - { - return T::zero(); - } - - if (vec_start + 1 == vec_end) - { - return (*scalar_start)*(*vec_start); - } - - std::vector > opt_q; - const size_t vec_len = scalar_end - scalar_start; - const size_t odd_vec_len = (vec_len % 2 == 1 ? vec_len : vec_len + 1); - opt_q.reserve(odd_vec_len); - std::vector g; - g.reserve(odd_vec_len); - - typename std::vector::const_iterator vec_it; - typename std::vector::const_iterator scalar_it; - size_t i; - for (i=0, vec_it = vec_start, scalar_it = scalar_start; vec_it != vec_end; ++vec_it, ++scalar_it, ++i) - { - g.emplace_back(*vec_it); - - opt_q.emplace_back(ordered_exponent(i, scalar_it->as_bigint())); - } - std::make_heap(opt_q.begin(),opt_q.end()); - assert_except(scalar_it == scalar_end); - - if (vec_len != odd_vec_len) - { - g.emplace_back(T::zero()); - opt_q.emplace_back(ordered_exponent(odd_vec_len - 1, bigint(UINT64_C(0)))); - } - assert_except(g.size() % 2 == 1); - assert_except(opt_q.size() == g.size()); - - T opt_result = T::zero(); - - while (true) - { - ordered_exponent &a = opt_q[0]; - ordered_exponent &b = (opt_q[1] < opt_q[2] ? opt_q[2] : opt_q[1]); - - const size_t abits = a.r.num_bits(); - - if (b.r.is_zero()) - { - // opt_result = opt_result + (a.r * g[a.idx]); - opt_result = opt_result + opt_window_wnaf_exp(g[a.idx], a.r, abits); - break; - } - - const size_t bbits = b.r.num_bits(); - const size_t limit = (abits-bbits >= 20 ? 20 : abits-bbits); - - if (bbits < UINT64_C(1)< (x-y) A + y (B+A) - mpn_sub_n(a.r.data, a.r.data, b.r.data, n); - g[b.idx] = g[b.idx] + g[a.idx]; - } - - // regardless of whether a was cleared or subtracted from we push it down, then take back up - - /* heapify A down */ - size_t a_pos = 0; - while (2*a_pos + 2< odd_vec_len) - { - // this is a max-heap so to maintain a heap property we swap with the largest of the two - if (opt_q[2*a_pos+1] < opt_q[2*a_pos+2]) - { - std::swap(opt_q[a_pos], opt_q[2*a_pos+2]); - a_pos = 2*a_pos+2; - } - else - { - std::swap(opt_q[a_pos], opt_q[2*a_pos+1]); - a_pos = 2*a_pos+1; - } - } - - /* now heapify A up appropriate amount of times */ - while (a_pos > 0 && opt_q[(a_pos-1)/2] < opt_q[a_pos]) - { - std::swap(opt_q[a_pos], opt_q[(a_pos-1)/2]); - a_pos = (a_pos-1) / 2; - } - } - - return opt_result; -} - -template -T multi_exp(typename std::vector::const_iterator vec_start, - typename std::vector::const_iterator vec_end, - typename std::vector::const_iterator scalar_start, - typename std::vector::const_iterator scalar_end, - const size_t chunks, - const bool use_multiexp) -{ - const size_t total = vec_end - vec_start; - if (total < chunks) - { - return naive_exp(vec_start, vec_end, scalar_start, scalar_end); - } - - const size_t one = total/chunks; - - std::vector partial(chunks, T::zero()); - - if (use_multiexp) - { -#ifdef MULTICORE -#pragma omp parallel for -#endif - for (size_t i = 0; i < chunks; ++i) - { - partial[i] = multi_exp_inner(vec_start + i*one, - (i == chunks-1 ? vec_end : vec_start + (i+1)*one), - scalar_start + i*one, - (i == chunks-1 ? scalar_end : scalar_start + (i+1)*one)); - } - } - else - { -#ifdef MULTICORE -#pragma omp parallel for -#endif - for (size_t i = 0; i < chunks; ++i) - { - partial[i] = naive_exp(vec_start + i*one, - (i == chunks-1 ? vec_end : vec_start + (i+1)*one), - scalar_start + i*one, - (i == chunks-1 ? scalar_end : scalar_start + (i+1)*one)); - } - } - - T final = T::zero(); - - for (size_t i = 0; i < chunks; ++i) - { - final = final + partial[i]; - } - - return final; -} - -template -T multi_exp_with_mixed_addition(typename std::vector::const_iterator vec_start, - typename std::vector::const_iterator vec_end, - typename std::vector::const_iterator scalar_start, - typename std::vector::const_iterator scalar_end, - const size_t chunks, - const bool use_multiexp) -{ - assert_except(std::distance(vec_start, vec_end) == std::distance(scalar_start, scalar_end)); - enter_block("Process scalar vector"); - auto value_it = vec_start; - auto scalar_it = scalar_start; - - const FieldT zero = FieldT::zero(); - const FieldT one = FieldT::one(); - std::vector p; - std::vector g; - - T acc = T::zero(); - - size_t num_skip = 0; - size_t num_add = 0; - size_t num_other = 0; - - for (; scalar_it != scalar_end; ++scalar_it, ++value_it) - { - if (*scalar_it == zero) - { - // do nothing - ++num_skip; - } - else if (*scalar_it == one) - { -#ifdef USE_MIXED_ADDITION - acc = acc.mixed_add(*value_it); -#else - acc = acc + (*value_it); -#endif - ++num_add; - } - else - { - p.emplace_back(*scalar_it); - g.emplace_back(*value_it); - ++num_other; - } - } - //print_indent(); printf("* Elements of w skipped: %zu (%0.2f%%)\n", num_skip, 100.*num_skip/(num_skip+num_add+num_other)); - //print_indent(); printf("* Elements of w processed with special addition: %zu (%0.2f%%)\n", num_add, 100.*num_add/(num_skip+num_add+num_other)); - //print_indent(); printf("* Elements of w remaining: %zu (%0.2f%%)\n", num_other, 100.*num_other/(num_skip+num_add+num_other)); - - leave_block("Process scalar vector"); - - return acc + multi_exp(g.begin(), g.end(), p.begin(), p.end(), chunks, use_multiexp); -} - -template -size_t get_exp_window_size(const size_t num_scalars) -{ - if (T::fixed_base_exp_window_table.empty()) - { -#ifdef LOWMEM - return 14; -#else - return 17; -#endif - } - size_t window = 1; - for (int64_t i = T::fixed_base_exp_window_table.size()-1; i >= 0; --i) - { -#ifdef DEBUG - if (!inhibit_profiling_info) - { - printf("%ld %zu %zu\n", i, num_scalars, T::fixed_base_exp_window_table[i]); - } -#endif - if (T::fixed_base_exp_window_table[i] != 0 && num_scalars >= T::fixed_base_exp_window_table[i]) - { - window = i+1; - break; - } - } - - if (!inhibit_profiling_info) - { - print_indent(); printf("Choosing window size %zu for %zu elements\n", window, num_scalars); - } - -#ifdef LOWMEM - window = std::min((size_t)14, window); -#endif - return window; -} - -template -window_table get_window_table(const size_t scalar_size, - const size_t window, - const T &g) -{ - const size_t in_window = UINT64_C(1)< powers_of_g(outerc, std::vector(in_window, T::zero())); - - T gouter = g; - - for (size_t outer = 0; outer < outerc; ++outer) - { - T ginner = T::zero(); - size_t cur_in_window = outer == outerc-1 ? last_in_window : in_window; - for (size_t inner = 0; inner < cur_in_window; ++inner) - { - powers_of_g[outer][inner] = ginner; - ginner = ginner + gouter; - } - - for (size_t i = 0; i < window; ++i) - { - gouter = gouter + gouter; - } - } - - return powers_of_g; -} - -template -T windowed_exp(const size_t scalar_size, - const size_t window, - const window_table &powers_of_g, - const FieldT &pow) -{ - const size_t outerc = (scalar_size+window-1)/window; - const bigint pow_val = pow.as_bigint(); - - /* exp */ - T res = powers_of_g[0][0]; - - for (size_t outer = 0; outer < outerc; ++outer) - { - size_t inner = 0; - for (size_t i = 0; i < window; ++i) - { - if (pow_val.test_bit(outer*window + i)) - { - inner |= 1u << i; - } - } - - res = res + powers_of_g[outer][inner]; - } - - return res; -} - -template -std::vector batch_exp(const size_t scalar_size, - const size_t window, - const window_table &table, - const std::vector &v) -{ - if (!inhibit_profiling_info) - { - print_indent(); - } - std::vector res(v.size(), table[0][0]); - -#ifdef MULTICORE -#pragma omp parallel for -#endif - for (size_t i = 0; i < v.size(); ++i) - { - res[i] = windowed_exp(scalar_size, window, table, v[i]); - - if (!inhibit_profiling_info && (i % 10000 == 0)) - { - printf("."); - fflush(stdout); - } - } - - if (!inhibit_profiling_info) - { - printf(" DONE!\n"); - } - - return res; -} - -template -std::vector batch_exp_with_coeff(const size_t scalar_size, - const size_t window, - const window_table &table, - const FieldT &coeff, - const std::vector &v) -{ - if (!inhibit_profiling_info) - { - print_indent(); - } - std::vector res(v.size(), table[0][0]); - -#ifdef MULTICORE -#pragma omp parallel for -#endif - for (size_t i = 0; i < v.size(); ++i) - { - res[i] = windowed_exp(scalar_size, window, table, coeff * v[i]); - - if (!inhibit_profiling_info && (i % 10000 == 0)) - { - printf("."); - fflush(stdout); - } - } - - if (!inhibit_profiling_info) - { - printf(" DONE!\n"); - } - - return res; -} - -template -void batch_to_special(std::vector &vec) -{ - enter_block("Batch-convert elements to special form"); - - std::vector non_zero_vec; - for (size_t i = 0; i < vec.size(); ++i) - { - if (!vec[i].is_zero()) - { - non_zero_vec.emplace_back(vec[i]); - } - } - - batch_to_special_all_non_zeros(non_zero_vec); - auto it = non_zero_vec.begin(); - T zero_special = T::zero(); - zero_special.to_special(); - - for (size_t i = 0; i < vec.size(); ++i) - { - if (!vec[i].is_zero()) - { - vec[i] = *it; - ++it; - } - else - { - vec[i] = zero_special; - } - } - leave_block("Batch-convert elements to special form"); -} - -} // libsnark - -#endif // MULTIEXP_TCC_ diff --git a/src/snark/libsnark/algebra/scalar_multiplication/wnaf.hpp b/src/snark/libsnark/algebra/scalar_multiplication/wnaf.hpp deleted file mode 100644 index d6c43267e..000000000 --- a/src/snark/libsnark/algebra/scalar_multiplication/wnaf.hpp +++ /dev/null @@ -1,39 +0,0 @@ -/** @file - ***************************************************************************** - - Declaration of interfaces for wNAF ("width-w Non-Adjacent Form") exponentiation routines. - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef WNAF_HPP_ -#define WNAF_HPP_ - -namespace libsnark { - -/** - * Find the wNAF representation of the given scalar relative to the given window size. - */ -template -std::vector find_wnaf(const size_t window_size, const bigint &scalar); - -/** - * In additive notation, use wNAF exponentiation (with the given window size) to compute scalar * base. - */ -template -T fixed_window_wnaf_exp(const size_t window_size, const T &base, const bigint &scalar); - -/** - * In additive notation, use wNAF exponentiation (with the window size determined by T) to compute scalar * base. - */ -template -T opt_window_wnaf_exp(const T &base, const bigint &scalar, const size_t scalar_bits); - -} // libsnark - -#include "algebra/scalar_multiplication/wnaf.tcc" - -#endif // WNAF_HPP_ diff --git a/src/snark/libsnark/algebra/scalar_multiplication/wnaf.tcc b/src/snark/libsnark/algebra/scalar_multiplication/wnaf.tcc deleted file mode 100644 index 4f2e4072c..000000000 --- a/src/snark/libsnark/algebra/scalar_multiplication/wnaf.tcc +++ /dev/null @@ -1,123 +0,0 @@ -/** @file - ***************************************************************************** - - Implementation of interfaces for wNAF ("weighted Non-Adjacent Form") exponentiation routines. - - See wnaf.hpp . - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef WNAF_TCC_ -#define WNAF_TCC_ - -namespace libsnark { - -template -std::vector find_wnaf(const size_t window_size, const bigint &scalar) -{ - const size_t length = scalar.max_bits(); // upper bound - std::vector res(length+1); - bigint c = scalar; - int64_t j = 0; - while (!c.is_zero()) - { - int64_t u; - if ((c.data[0] & 1) == 1) - { - u = c.data[0] % (1u << (window_size+1)); - if (u > (1 << window_size)) - { - u = u - (1 << (window_size+1)); - } - - if (u > 0) - { - mpn_sub_1(c.data, c.data, n, u); - } - else - { - mpn_add_1(c.data, c.data, n, -u); - } - } - else - { - u = 0; - } - res[j] = u; - ++j; - - mpn_rshift(c.data, c.data, n, 1); // c = c/2 - } - - return res; -} - -template -T fixed_window_wnaf_exp(const size_t window_size, const T &base, const bigint &scalar) -{ - std::vector naf = find_wnaf(window_size, scalar); - std::vector table(UINT64_C(1)<<(window_size-1)); - T tmp = base; - T dbl = base.dbl(); - for (size_t i = 0; i < UINT64_C(1)<<(window_size-1); ++i) - { - table[i] = tmp; - tmp = tmp + dbl; - } - - T res = T::zero(); - bool found_nonzero = false; - for (int64_t i = naf.size()-1; i >= 0; --i) - { - if (found_nonzero) - { - res = res.dbl(); - } - - if (naf[i] != 0) - { - found_nonzero = true; - if (naf[i] > 0) - { - res = res + table[naf[i]/2]; - } - else - { - res = res - table[(-naf[i])/2]; - } - } - } - - return res; -} - -template -T opt_window_wnaf_exp(const T &base, const bigint &scalar, const size_t scalar_bits) -{ - size_t best = 0; - for (int64_t i = T::wnaf_window_table.size() - 1; i >= 0; --i) - { - if (scalar_bits >= T::wnaf_window_table[i]) - { - best = i+1; - break; - } - } - - if (best > 0) - { - return fixed_window_wnaf_exp(best, base, scalar); - } - else - { - return scalar * base; - } -} - -} // libsnark - -#endif // WNAF_TCC_ diff --git a/src/snark/libsnark/common/assert_except.hpp b/src/snark/libsnark/common/assert_except.hpp deleted file mode 100644 index 781923044..000000000 --- a/src/snark/libsnark/common/assert_except.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef ASSERT_except_H -#define ASSERT_except_H - -#include - -inline void assert_except(bool condition) { - if (!condition) { - throw std::runtime_error("Assertion failed."); - } -} - -#endif diff --git a/src/snark/libsnark/common/data_structures/accumulation_vector.hpp b/src/snark/libsnark/common/data_structures/accumulation_vector.hpp deleted file mode 100644 index 37e0c9841..000000000 --- a/src/snark/libsnark/common/data_structures/accumulation_vector.hpp +++ /dev/null @@ -1,74 +0,0 @@ -/** @file - ***************************************************************************** - - Declaration of interfaces for an accumulation vector. - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef ACCUMULATION_VECTOR_HPP_ -#define ACCUMULATION_VECTOR_HPP_ - -#include "common/data_structures/sparse_vector.hpp" - -namespace libsnark { - -template -class accumulation_vector; - -template -std::ostream& operator<<(std::ostream &out, const accumulation_vector &v); - -template -std::istream& operator>>(std::istream &in, accumulation_vector &v); - -/** - * An accumulation vector comprises an accumulation value and a sparse vector. - * The method "accumulate_chunk" allows one to accumlate portions of the sparse - * vector into the accumualation value. - */ -template -class accumulation_vector { -public: - T first; - sparse_vector rest; - - accumulation_vector() = default; - accumulation_vector(const accumulation_vector &other) = default; - accumulation_vector(accumulation_vector &&other) = default; - accumulation_vector(T &&first, sparse_vector &&rest) : first(std::move(first)), rest(std::move(rest)) {}; - accumulation_vector(T &&first, std::vector &&v) : first(std::move(first)), rest(std::move(v)) {} - accumulation_vector(std::vector &&v) : first(T::zero()), rest(std::move(v)) {}; - - accumulation_vector& operator=(const accumulation_vector &other) = default; - accumulation_vector& operator=(accumulation_vector &&other) = default; - - bool operator==(const accumulation_vector &other) const; - - bool is_fully_accumulated() const; - - size_t domain_size() const; - size_t size() const; - size_t size_in_bits() const; - - template - accumulation_vector accumulate_chunk(const typename std::vector::const_iterator &it_begin, - const typename std::vector::const_iterator &it_end, - const size_t offset) const; - -}; - -template -std::ostream& operator<<(std::ostream &out, const accumulation_vector &v); - -template -std::istream& operator>>(std::istream &in, accumulation_vector &v); - -} // libsnark - -#include "common/data_structures/accumulation_vector.tcc" - -#endif // ACCUMULATION_VECTOR_HPP_ diff --git a/src/snark/libsnark/common/data_structures/accumulation_vector.tcc b/src/snark/libsnark/common/data_structures/accumulation_vector.tcc deleted file mode 100644 index 9e524aba7..000000000 --- a/src/snark/libsnark/common/data_structures/accumulation_vector.tcc +++ /dev/null @@ -1,84 +0,0 @@ -/** @file - ***************************************************************************** - - Implementation of interfaces for an accumulation vector. - - See accumulation_vector.hpp . - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef ACCUMULATION_VECTOR_TCC_ -#define ACCUMULATION_VECTOR_TCC_ - -namespace libsnark { - -template -bool accumulation_vector::operator==(const accumulation_vector &other) const -{ - return (this->first == other.first && this->rest == other.rest); -} - -template -bool accumulation_vector::is_fully_accumulated() const -{ - return rest.empty(); -} - -template -size_t accumulation_vector::domain_size() const -{ - return rest.domain_size(); -} - -template -size_t accumulation_vector::size() const -{ - return rest.domain_size(); -} - -template -size_t accumulation_vector::size_in_bits() const -{ - const size_t first_size_in_bits = T::size_in_bits(); - const size_t rest_size_in_bits = rest.size_in_bits(); - return first_size_in_bits + rest_size_in_bits; -} - -template -template -accumulation_vector accumulation_vector::accumulate_chunk(const typename std::vector::const_iterator &it_begin, - const typename std::vector::const_iterator &it_end, - const size_t offset) const -{ - std::pair > acc_result = rest.template accumulate(it_begin, it_end, offset); - T new_first = first + acc_result.first; - return accumulation_vector(std::move(new_first), std::move(acc_result.second)); -} - -template -std::ostream& operator<<(std::ostream& out, const accumulation_vector &v) -{ - out << v.first << OUTPUT_NEWLINE; - out << v.rest << OUTPUT_NEWLINE; - - return out; -} - -template -std::istream& operator>>(std::istream& in, accumulation_vector &v) -{ - in >> v.first; - consume_OUTPUT_NEWLINE(in); - in >> v.rest; - consume_OUTPUT_NEWLINE(in); - - return in; -} - -} // libsnark - -#endif // ACCUMULATION_VECTOR_TCC_ diff --git a/src/snark/libsnark/common/data_structures/merkle_tree.hpp b/src/snark/libsnark/common/data_structures/merkle_tree.hpp deleted file mode 100644 index 6f0c851ba..000000000 --- a/src/snark/libsnark/common/data_structures/merkle_tree.hpp +++ /dev/null @@ -1,71 +0,0 @@ -/** @file - ***************************************************************************** - - Declaration of interfaces for a Merkle tree. - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef MERKLE_TREE_HPP_ -#define MERKLE_TREE_HPP_ - -#include -#include -#include "common/utils.hpp" - -namespace libsnark { - -/** - * A Merkle tree is maintained as two maps: - * - a map from addresses to values, and - * - a map from addresses to hashes. - * - * The second map maintains the intermediate hashes of a Merkle tree - * built atop the values currently stored in the tree (the - * implementation admits a very efficient support for sparse - * trees). Besides offering methods to load and store values, the - * class offers methods to retrieve the root of the Merkle tree and to - * obtain the authentication paths for (the value at) a given address. - */ - -typedef bit_vector merkle_authentication_node; -typedef std::vector merkle_authentication_path; - -template -class merkle_tree { -private: - - typedef typename HashT::hash_value_type hash_value_type; - typedef typename HashT::merkle_authentication_path_type merkle_authentication_path_type; - -public: - - std::vector hash_defaults; - std::map values; - std::map hashes; - - size_t depth; - size_t value_size; - size_t digest_size; - - merkle_tree(const size_t depth, const size_t value_size); - merkle_tree(const size_t depth, const size_t value_size, const std::vector &contents_as_vector); - merkle_tree(const size_t depth, const size_t value_size, const std::map &contents); - - bit_vector get_value(const size_t address) const; - void set_value(const size_t address, const bit_vector &value); - - hash_value_type get_root() const; - merkle_authentication_path_type get_path(const size_t address) const; - - void dump() const; -}; - -} // libsnark - -#include "common/data_structures/merkle_tree.tcc" - -#endif // MERKLE_TREE_HPP_ diff --git a/src/snark/libsnark/common/data_structures/merkle_tree.tcc b/src/snark/libsnark/common/data_structures/merkle_tree.tcc deleted file mode 100644 index ce28b124f..000000000 --- a/src/snark/libsnark/common/data_structures/merkle_tree.tcc +++ /dev/null @@ -1,246 +0,0 @@ -/** @file - ***************************************************************************** - - Implementation of interfaces for Merkle tree. - - See merkle_tree.hpp . - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef MERKLE_TREE_TCC -#define MERKLE_TREE_TCC - -#include - -#include "common/profiling.hpp" -#include "common/utils.hpp" - -namespace libsnark { - -template -typename HashT::hash_value_type two_to_one_CRH(const typename HashT::hash_value_type &l, - const typename HashT::hash_value_type &r) -{ - typename HashT::hash_value_type new_input; - new_input.insert(new_input.end(), l.begin(), l.end()); - new_input.insert(new_input.end(), r.begin(), r.end()); - - const size_t digest_size = HashT::get_digest_len(); - assert(l.size() == digest_size); - assert(r.size() == digest_size); - - return HashT::get_hash(new_input); -} - -template -merkle_tree::merkle_tree(const size_t depth, const size_t value_size) : - depth(depth), value_size(value_size) -{ - assert(depth < sizeof(size_t) * 8); - - digest_size = HashT::get_digest_len(); - assert(value_size <= digest_size); - - hash_value_type last(digest_size); - hash_defaults.reserve(depth+1); - hash_defaults.emplace_back(last); - for (size_t i = 0; i < depth; ++i) - { - last = two_to_one_CRH(last, last); - hash_defaults.emplace_back(last); - } - - std::reverse(hash_defaults.begin(), hash_defaults.end()); -} - -template -merkle_tree::merkle_tree(const size_t depth, - const size_t value_size, - const std::vector &contents_as_vector) : - merkle_tree(depth, value_size) -{ - assert(log2(contents_as_vector.size()) <= depth); - for (size_t address = 0; address < contents_as_vector.size(); ++address) - { - const size_t idx = address + (UINT64_C(1)< 0; --layer) - { - for (size_t idx = idx_begin; idx < idx_end; idx += 2) - { - hash_value_type l = hashes[idx]; // this is sound, because idx_begin is always a left child - hash_value_type r = (idx + 1 < idx_end ? hashes[idx+1] : hash_defaults[layer]); - - hash_value_type h = two_to_one_CRH(l, r); - hashes[(idx-1)/2] = h; - } - - idx_begin = (idx_begin-1)/2; - idx_end = (idx_end-1)/2; - } -} - -template -merkle_tree::merkle_tree(const size_t depth, - const size_t value_size, - const std::map &contents) : - merkle_tree(depth, value_size) -{ - - if (!contents.empty()) - { - assert(contents.rbegin()->first < UINT64_C(1)<first; - const bit_vector value = it->second; - const size_t idx = address + (UINT64_C(1)< 0; --layer) - { - auto next_last_it = hashes.begin(); - - for (auto it = hashes.begin(); it != last_it; ++it) - { - const size_t idx = it->first; - const hash_value_type hash = it->second; - - if (idx % 2 == 0) - { - // this is the right child of its parent and by invariant we are missing the left child - hashes[(idx-1)/2] = two_to_one_CRH(hash_defaults[layer], hash); - } - else - { - if (std::next(it) == last_it || std::next(it)->first != idx + 1) - { - // this is the left child of its parent and is missing its right child - hashes[(idx-1)/2] = two_to_one_CRH(hash, hash_defaults[layer]); - } - else - { - // typical case: this is the left child of the parent and adjecent to it there is a right child - hashes[(idx-1)/2] = two_to_one_CRH(hash, std::next(it)->second); - ++it; - } - } - } - - last_it = next_last_it; - } - } -} - -template -bit_vector merkle_tree::get_value(const size_t address) const -{ - assert(log2(address) <= depth); - - auto it = values.find(address); - bit_vector padded_result = (it == values.end() ? bit_vector(digest_size) : it->second); - padded_result.resize(value_size); - - return padded_result; -} - -template -void merkle_tree::set_value(const size_t address, - const bit_vector &value) -{ - assert(log2(address) <= depth); - size_t idx = address + (UINT64_C(1)<=0; --layer) - { - idx = (idx-1)/2; - - auto it = hashes.find(2*idx+1); - hash_value_type l = (it == hashes.end() ? hash_defaults[layer+1] : it->second); - - it = hashes.find(2*idx+2); - hash_value_type r = (it == hashes.end() ? hash_defaults[layer+1] : it->second); - - hash_value_type h = two_to_one_CRH(l, r); - hashes[idx] = h; - } -} - -template -typename HashT::hash_value_type merkle_tree::get_root() const -{ - auto it = hashes.find(0); - return (it == hashes.end() ? hash_defaults[0] : it->second); -} - -template -typename HashT::merkle_authentication_path_type merkle_tree::get_path(const size_t address) const -{ - typename HashT::merkle_authentication_path_type result(depth); - assert(log2(address) <= depth); - size_t idx = address + (UINT64_C(1)< 0; --layer) - { - size_t sibling_idx = ((idx + 1) ^ 1) - 1; - auto it = hashes.find(sibling_idx); - if (layer == depth) - { - auto it2 = values.find(sibling_idx - ((UINT64_C(1)<second); - result[layer-1].resize(digest_size); - } - else - { - result[layer-1] = (it == hashes.end() ? hash_defaults[layer] : it->second); - } - - idx = (idx-1)/2; - } - - return result; -} - -template -void merkle_tree::dump() const -{ - for (size_t i = 0; i < UINT64_C(1)< ", i); - const bit_vector value = (it == values.end() ? bit_vector(value_size) : it->second); - for (bool b : value) - { - printf("%d", b ? 1 : 0); - } - printf("\n"); - } - printf("\n"); -} - -} // libsnark - -#endif // MERKLE_TREE_TCC diff --git a/src/snark/libsnark/common/data_structures/sparse_vector.hpp b/src/snark/libsnark/common/data_structures/sparse_vector.hpp deleted file mode 100644 index 20f1bc267..000000000 --- a/src/snark/libsnark/common/data_structures/sparse_vector.hpp +++ /dev/null @@ -1,79 +0,0 @@ -/** @file - ***************************************************************************** - - Declaration of interfaces for a sparse vector. - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef SPARSE_VECTOR_HPP_ -#define SPARSE_VECTOR_HPP_ - -#include - -namespace libsnark { - -template -struct sparse_vector; - -template -std::ostream& operator<<(std::ostream &out, const sparse_vector &v); - -template -std::istream& operator>>(std::istream &in, sparse_vector &v); - -/** - * A sparse vector is a list of indices along with corresponding values. - * The indices are selected from the set {0,1,...,domain_size-1}. - */ -template -struct sparse_vector { - - std::vector indices; - std::vector values; - uint64_t domain_size_ = 0; - - sparse_vector() = default; - sparse_vector(const sparse_vector &other) = default; - sparse_vector(sparse_vector &&other) = default; - sparse_vector(std::vector &&v); /* constructor from std::vector */ - - sparse_vector& operator=(const sparse_vector &other) = default; - sparse_vector& operator=(sparse_vector &&other) = default; - - T operator[](const uint64_t idx) const; - - bool operator==(const sparse_vector &other) const; - bool operator==(const std::vector &other) const; - - bool is_valid() const; - bool empty() const; - - uint64_t domain_size() const; // return domain_size_ - uint64_t size() const; // return the number of indices (representing the number of non-zero entries) - uint64_t size_in_bits() const; // return the number bits needed to store the sparse vector - - /* return a pair consisting of the accumulated value and the sparse vector of non-accumuated values */ - template - std::pair > accumulate(const typename std::vector::const_iterator &it_begin, - const typename std::vector::const_iterator &it_end, - const uint64_t offset) const; - - friend std::ostream& operator<< (std::ostream &out, const sparse_vector &v); - friend std::istream& operator>> (std::istream &in, sparse_vector &v); -}; - -template -std::ostream& operator<<(std::ostream& out, const sparse_vector &v); - -template -std::istream& operator>>(std::istream& in, sparse_vector &v); - -} // libsnark - -#include "common/data_structures/sparse_vector.tcc" - -#endif // SPARSE_VECTOR_HPP_ diff --git a/src/snark/libsnark/common/data_structures/sparse_vector.tcc b/src/snark/libsnark/common/data_structures/sparse_vector.tcc deleted file mode 100644 index 906ed16d9..000000000 --- a/src/snark/libsnark/common/data_structures/sparse_vector.tcc +++ /dev/null @@ -1,316 +0,0 @@ -/** @file - ***************************************************************************** - - Implementation of interfaces for a sparse vector. - - See sparse_vector.hpp . - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef SPARSE_VECTOR_TCC_ -#define SPARSE_VECTOR_TCC_ - -#include "algebra/scalar_multiplication/multiexp.hpp" - -#include - -namespace libsnark { - -template -sparse_vector::sparse_vector(std::vector &&v) : - values(std::move(v)), domain_size_(values.size()) -{ - indices.resize(domain_size_); - std::iota(indices.begin(), indices.end(), 0); -} - -template -T sparse_vector::operator[](const uint64_t idx) const -{ - auto it = std::lower_bound(indices.begin(), indices.end(), idx); - return (it != indices.end() && *it == idx) ? values[it - indices.begin()] : T(); -} - -template -bool sparse_vector::operator==(const sparse_vector &other) const -{ - if (this->domain_size_ != other.domain_size_) - { - return false; - } - - uint64_t this_pos = 0, other_pos = 0; - while (this_pos < this->indices.size() && other_pos < other.indices.size()) - { - if (this->indices[this_pos] == other.indices[other_pos]) - { - if (this->values[this_pos] != other.values[other_pos]) - { - return false; - } - ++this_pos; - ++other_pos; - } - else if (this->indices[this_pos] < other.indices[other_pos]) - { - if (!this->values[this_pos].is_zero()) - { - return false; - } - ++this_pos; - } - else - { - if (!other.values[other_pos].is_zero()) - { - return false; - } - ++other_pos; - } - } - - /* at least one of the vectors has been exhausted, so other must be empty */ - while (this_pos < this->indices.size()) - { - if (!this->values[this_pos].is_zero()) - { - return false; - } - ++this_pos; - } - - while (other_pos < other.indices.size()) - { - if (!other.values[other_pos].is_zero()) - { - return false; - } - ++other_pos; - } - - return true; -} - -template -bool sparse_vector::operator==(const std::vector &other) const -{ - if (this->domain_size_ < other.size()) - { - return false; - } - - uint64_t j = 0; - for (uint64_t i = 0; i < other.size(); ++i) - { - if (this->indices[j] == i) - { - if (this->values[j] != other[j]) - { - return false; - } - ++j; - } - else - { - if (!other[j].is_zero()) - { - return false; - } - } - } - - return true; -} - -template -bool sparse_vector::is_valid() const -{ - if (values.size() == indices.size() && values.size() <= domain_size_) - { - return false; - } - - for (uint64_t i = 0; i + 1 < indices.size(); ++i) - { - if (indices[i] >= indices[i+1]) - { - return false; - } - } - - if (!indices.empty() && indices[indices.size()-1] >= domain_size_) - { - return false; - } - - return true; -} - -template -bool sparse_vector::empty() const -{ - return indices.empty(); -} - -template -uint64_t sparse_vector::domain_size() const -{ - return domain_size_; -} - -template -uint64_t sparse_vector::size() const -{ - return indices.size(); -} - -template -uint64_t sparse_vector::size_in_bits() const -{ - return indices.size() * (sizeof(uint64_t) * 8 + T::size_in_bits()); -} - -template -template -std::pair > sparse_vector::accumulate(const typename std::vector::const_iterator &it_begin, - const typename std::vector::const_iterator &it_end, - const uint64_t offset) const -{ - // TODO: does not really belong here. - const uint64_t chunks = 1; - const bool use_multiexp = true; - - T accumulated_value = T::zero(); - sparse_vector resulting_vector; - resulting_vector.domain_size_ = domain_size_; - - const uint64_t range_len = it_end - it_begin; - bool in_block = false; - uint64_t first_pos = -1, last_pos = -1; // g++ -flto emits unitialized warning, even though in_block guards for such cases. - - for (uint64_t i = 0; i < indices.size(); ++i) - { - const bool matching_pos = (offset <= indices[i] && indices[i] < offset + range_len); - // printf("i = %zu, pos[i] = %zu, offset = %zu, w_size = %zu\n", i, indices[i], offset, w_size); - bool copy_over; - - if (in_block) - { - if (matching_pos && last_pos == i-1) - { - // block can be extended, do it - last_pos = i; - copy_over = false; - } - else - { - // block has ended here - in_block = false; - copy_over = true; - -#ifdef DEBUG - print_indent(); printf("doing multiexp for w_%zu ... w_%zu\n", indices[first_pos], indices[last_pos]); -#endif - accumulated_value = accumulated_value + multi_exp(values.begin() + first_pos, - values.begin() + last_pos + 1, - it_begin + (indices[first_pos] - offset), - it_begin + (indices[last_pos] - offset) + 1, - chunks, use_multiexp); - } - } - else - { - if (matching_pos) - { - // block can be started - first_pos = i; - last_pos = i; - in_block = true; - copy_over = false; - } - else - { - copy_over = true; - } - } - - if (copy_over) - { - resulting_vector.indices.emplace_back(indices[i]); - resulting_vector.values.emplace_back(values[i]); - } - } - - if (in_block) - { -#ifdef DEBUG - print_indent(); printf("doing multiexp for w_%zu ... w_%zu\n", indices[first_pos], indices[last_pos]); -#endif - accumulated_value = accumulated_value + multi_exp(values.begin() + first_pos, - values.begin() + last_pos + 1, - it_begin + (indices[first_pos] - offset), - it_begin + (indices[last_pos] - offset) + 1, - chunks, use_multiexp); - } - - return std::make_pair(accumulated_value, resulting_vector); -} - -template -std::ostream& operator<<(std::ostream& out, const sparse_vector &v) -{ - out << v.domain_size_ << "\n"; - out << v.indices.size() << "\n"; - for (const uint64_t& i : v.indices) - { - out << i << "\n"; - } - - out << v.values.size() << "\n"; - for (const T& t : v.values) - { - out << t << OUTPUT_NEWLINE; - } - - return out; -} - -template -std::istream& operator>>(std::istream& in, sparse_vector &v) -{ - in >> v.domain_size_; - consume_newline(in); - - uint64_t s; - in >> s; - consume_newline(in); - v.indices.resize(s); - for (uint64_t i = 0; i < s; ++i) - { - in >> v.indices[i]; - consume_newline(in); - } - - v.values.clear(); - in >> s; - consume_newline(in); - v.values.reserve(s); - - for (uint64_t i = 0; i < s; ++i) - { - T t; - in >> t; - consume_OUTPUT_NEWLINE(in); - v.values.emplace_back(t); - } - - return in; -} - -} // libsnark - -#endif // SPARSE_VECTOR_TCC_ diff --git a/src/snark/libsnark/common/default_types/ec_pp.hpp b/src/snark/libsnark/common/default_types/ec_pp.hpp deleted file mode 100644 index b08c2da88..000000000 --- a/src/snark/libsnark/common/default_types/ec_pp.hpp +++ /dev/null @@ -1,53 +0,0 @@ -/** @file - ***************************************************************************** - - This file defines default_ec_pp based on the CURVE=... make flag, which selects - which elliptic curve is used to implement group arithmetic and pairings. - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef EC_PP_HPP_ -#define EC_PP_HPP_ - -/************************ Pick the elliptic curve ****************************/ - -#ifdef CURVE_ALT_BN128 -#include "algebra/curves/alt_bn128/alt_bn128_pp.hpp" -namespace libsnark { -typedef alt_bn128_pp default_ec_pp; -} // libsnark -#endif - -#ifdef CURVE_BN128 -#include "algebra/curves/bn128/bn128_pp.hpp" -namespace libsnark { -typedef bn128_pp default_ec_pp; -} // libsnark -#endif - -#ifdef CURVE_EDWARDS -#include "algebra/curves/edwards/edwards_pp.hpp" -namespace libsnark { -typedef edwards_pp default_ec_pp; -} // libsnark -#endif - -#ifdef CURVE_MNT4 -#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" -namespace libsnark { -typedef mnt4_pp default_ec_pp; -} // libsnark -#endif - -#ifdef CURVE_MNT6 -#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" -namespace libsnark { -typedef mnt6_pp default_ec_pp; -} // libsnark -#endif - -#endif // EC_PP_HPP_ diff --git a/src/snark/libsnark/common/default_types/r1cs_ppzksnark_pp.hpp b/src/snark/libsnark/common/default_types/r1cs_ppzksnark_pp.hpp deleted file mode 100644 index c819b4a85..000000000 --- a/src/snark/libsnark/common/default_types/r1cs_ppzksnark_pp.hpp +++ /dev/null @@ -1,22 +0,0 @@ -/** @file - ***************************************************************************** - - This file defines default_r1cs_ppzksnark_pp based on the elliptic curve - choice selected in ec_pp.hpp. - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef R1CS_PPZKSNARK_PP_HPP_ -#define R1CS_PPZKSNARK_PP_HPP_ - -#include "common/default_types/ec_pp.hpp" - -namespace libsnark { -typedef default_ec_pp default_r1cs_ppzksnark_pp; -} // libsnark - -#endif // R1CS_PPZKSNARK_PP_HPP_ diff --git a/src/snark/libsnark/common/profiling.cpp b/src/snark/libsnark/common/profiling.cpp deleted file mode 100644 index 38b387d97..000000000 --- a/src/snark/libsnark/common/profiling.cpp +++ /dev/null @@ -1,399 +0,0 @@ -/** @file - ***************************************************************************** - - Implementation of functions for profiling code blocks. - - See profiling.hpp . - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#include "common/profiling.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include "common/default_types/ec_pp.hpp" -#include "common/utils.hpp" - -#ifndef NO_PROCPS -#include -#endif - -#ifdef __MACH__ // required to build on MacOS -#include -#include -#include -#include -#endif - -namespace libsnark { - -int64_t get_nsec_time() -{ - auto timepoint = std::chrono::high_resolution_clock::now(); - return std::chrono::duration_cast(timepoint.time_since_epoch()).count(); -} - -/* Return total CPU time consumed by all threads of the process, in nanoseconds. */ -int64_t get_nsec_cpu_time() -{ - ::timespec ts; - #ifdef __MACH__ - clock_serv_t cclock; - mach_timespec_t mts; - host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); - clock_get_time(cclock, &mts); - mach_port_deallocate(mach_task_self(), cclock); - ts.tv_sec = mts.tv_sec; - ts.tv_nsec = mts.tv_nsec; - #else - if ( ::clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts) ) - throw ::std::runtime_error("clock_gettime(CLOCK_PROCESS_CPUTIME_ID) failed"); - // If we expected this to work, don't silently ignore failures, because that would hide the problem and incur an unnecessarily system-call overhead. So if we ever observe this exception, we should probably add a suitable #ifdef . - //TODO: clock_gettime(CLOCK_PROCESS_CPUTIME_ID) is not supported by native Windows. What about Cygwin? Should we #ifdef on CLOCK_PROCESS_CPUTIME_ID or on __linux__? - #endif - return ts.tv_sec * 1000000000ll + ts.tv_nsec; -} - -static int64_t start_time; -static int64_t last_time; -static int64_t start_cpu_time; -static int64_t last_cpu_time; - -void start_profiling() -{ - printf("Reset time counters for profiling\n"); - - last_time = start_time = get_nsec_time(); - last_cpu_time = start_cpu_time = get_nsec_cpu_time(); -} - -std::map invocation_counts; -static std::map enter_times; -std::map last_times; -std::map cumulative_times; -//TODO: Instead of analogous maps for time and cpu_time, use a single struct-valued map -static std::map enter_cpu_times; -static std::map last_cpu_times; -static std::map, int64_t> op_counts; -static std::map, int64_t> cumulative_op_counts; // ((msg, data_point), value) - // TODO: Convert op_counts and cumulative_op_counts from pair to structs -static size_t indentation = 0; - -static std::vector block_names; - -static std::list > op_data_points = { -#ifdef PROFILE_OP_COUNTS - std::make_pair("Fradd", &Fr::add_cnt), - std::make_pair("Frsub", &Fr::sub_cnt), - std::make_pair("Frmul", &Fr::mul_cnt), - std::make_pair("Frinv", &Fr::inv_cnt), - std::make_pair("Fqadd", &Fq::add_cnt), - std::make_pair("Fqsub", &Fq::sub_cnt), - std::make_pair("Fqmul", &Fq::mul_cnt), - std::make_pair("Fqinv", &Fq::inv_cnt), - std::make_pair("G1add", &G1::add_cnt), - std::make_pair("G1dbl", &G1::dbl_cnt), - std::make_pair("G2add", &G2::add_cnt), - std::make_pair("G2dbl", &G2::dbl_cnt) -#endif -}; - -bool inhibit_profiling_info = true; -bool inhibit_profiling_counters = false; - -void clear_profiling_counters() -{ - invocation_counts.clear(); - last_times.clear(); - last_cpu_times.clear(); - cumulative_times.clear(); -} - -void print_cumulative_time_entry(const std::string &key, const int64_t factor) -{ - const double total_ms = (cumulative_times.at(key) * 1e-6); - const size_t cnt = invocation_counts.at(key); - const double avg_ms = total_ms / cnt; - printf(" %-45s: %12.5fms = %" PRId64 " * %0.5fms (%zu invocations, %0.5fms = %" PRId64 " * %0.5fms per invocation)\n", key.c_str(), total_ms, factor, total_ms/factor, cnt, avg_ms, factor, avg_ms/factor); -} - -void print_cumulative_times(const int64_t factor) -{ - printf("Dumping times:\n"); - for (auto& kv : cumulative_times) - { - print_cumulative_time_entry(kv.first, factor); - } -} - -void print_cumulative_op_counts(const bool only_fq) -{ -#ifdef PROFILE_OP_COUNTS - printf("Dumping operation counts:\n"); - for (auto& msg : invocation_counts) - { - printf(" %-45s: ", msg.first.c_str()); - bool first = true; - for (auto& data_point : op_data_points) - { - if (only_fq && data_point.first.compare(0, 2, "Fq") != 0) - { - continue; - } - - if (!first) - { - printf(", "); - } - printf("%-5s = %7.0f (%3zu)", - data_point.first.c_str(), - 1. * cumulative_op_counts[std::make_pair(msg.first, data_point.first)] / msg.second, - msg.second); - first = false; - } - printf("\n"); - } -#else - UNUSED(only_fq); -#endif -} - -void print_op_profiling(const std::string &msg) -{ -#ifdef PROFILE_OP_COUNTS - printf("\n"); - print_indent(); - - printf("(opcounts) = ("); - bool first = true; - for (std::pair p : op_data_points) - { - if (!first) - { - printf(", "); - } - - printf("%s=%lld", p.first.c_str(), *(p.second)-op_counts[std::make_pair(msg, p.first)]); - first = false; - } - printf(")"); -#else - UNUSED(msg); -#endif -} - -static void print_times_from_last_and_start(int64_t now, int64_t last, - int64_t cpu_now, int64_t cpu_last) -{ - int64_t time_from_start = now - start_time; - int64_t time_from_last = now - last; - - int64_t cpu_time_from_start = cpu_now - start_cpu_time; - int64_t cpu_time_from_last = cpu_now - cpu_last; - - if (time_from_last != 0) { - double parallelism_from_last = 1.0 * cpu_time_from_last / time_from_last; - printf("[%0.4fs x%0.2f]", time_from_last * 1e-9, parallelism_from_last); - } else { - printf("[ ]"); - } - if (time_from_start != 0) { - double parallelism_from_start = 1.0 * cpu_time_from_start / time_from_start; - printf("\t(%0.4fs x%0.2f from start)", time_from_start * 1e-9, parallelism_from_start); - } -} - -void print_time(const char* msg) -{ - if (inhibit_profiling_info) - { - return; - } - - int64_t now = get_nsec_time(); - int64_t cpu_now = get_nsec_cpu_time(); - - printf("%-35s\t", msg); - print_times_from_last_and_start(now, last_time, cpu_now, last_cpu_time); -#ifdef PROFILE_OP_COUNTS - print_op_profiling(msg); -#endif - printf("\n"); - - fflush(stdout); - last_time = now; - last_cpu_time = cpu_now; -} - -void print_header(const char *msg) -{ - printf("\n================================================================================\n"); - printf("%s\n", msg); - printf("================================================================================\n\n"); -} - -void print_indent() -{ - for (size_t i = 0; i < indentation; ++i) - { - printf(" "); - } -} - -void op_profiling_enter(const std::string &msg) -{ - for (std::pair p : op_data_points) - { - op_counts[std::make_pair(msg, p.first)] = *(p.second); - } -} - -void enter_block(const std::string &msg, const bool indent) -{ - if (inhibit_profiling_counters) - { - return; - } - - block_names.emplace_back(msg); - int64_t t = get_nsec_time(); - enter_times[msg] = t; - int64_t cpu_t = get_nsec_cpu_time(); - enter_cpu_times[msg] = cpu_t; - - if (inhibit_profiling_info) - { - return; - } - -#ifdef MULTICORE -#pragma omp critical -#endif - { - op_profiling_enter(msg); - - print_indent(); - printf("(enter) %-35s\t", msg.c_str()); - print_times_from_last_and_start(t, t, cpu_t, cpu_t); - printf("\n"); - fflush(stdout); - - if (indent) - { - ++indentation; - } - } -} - -void leave_block(const std::string &msg, const bool indent) -{ - if (inhibit_profiling_counters) - { - return; - } - -#ifndef MULTICORE - assert(*(--block_names.end()) == msg); -#endif - block_names.pop_back(); - - ++invocation_counts[msg]; - - int64_t t = get_nsec_time(); - last_times[msg] = (t - enter_times[msg]); - cumulative_times[msg] += (t - enter_times[msg]); - - int64_t cpu_t = get_nsec_cpu_time(); - last_cpu_times[msg] = (cpu_t - enter_cpu_times[msg]); - -#ifdef PROFILE_OP_COUNTS - for (std::pair p : op_data_points) - { - cumulative_op_counts[std::make_pair(msg, p.first)] += *(p.second)-op_counts[std::make_pair(msg, p.first)]; - } -#endif - - if (inhibit_profiling_info) - { - return; - } - -#ifdef MULTICORE -#pragma omp critical -#endif - { - if (indent) - { - --indentation; - } - - print_indent(); - printf("(leave) %-35s\t", msg.c_str()); - print_times_from_last_and_start(t, enter_times[msg], cpu_t, enter_cpu_times[msg]); - print_op_profiling(msg); - printf("\n"); - fflush(stdout); - } -} - -void print_mem(const std::string &s) -{ -#ifndef NO_PROCPS - struct proc_t usage; - look_up_our_self(&usage); - if (s.empty()) - { - printf("* Peak vsize (physical memory+swap) in mebibytes: %lu\n", usage.vsize >> 20); - } - else - { - printf("* Peak vsize (physical memory+swap) in mebibytes (%s): %lu\n", s.c_str(), usage.vsize >> 20); - } -#else - printf("* Memory profiling not supported in NO_PROCPS mode\n"); -#endif -} - -void print_compilation_info() -{ -#ifdef __GNUC__ - printf("g++ version: %s\n", __VERSION__); - //printf("Compiled on %s %s\n", __DATE__, __TIME__); -#endif -#ifdef STATIC - printf("STATIC: yes\n"); -#else - printf("STATIC: no\n"); -#endif -#ifdef MULTICORE - printf("MULTICORE: yes\n"); -#else - printf("MULTICORE: no\n"); -#endif -#ifdef DEBUG - printf("DEBUG: yes\n"); -#else - printf("DEBUG: no\n"); -#endif -#ifdef PROFILE_OP_COUNTS - printf("PROFILE_OP_COUNTS: yes\n"); -#else - printf("PROFILE_OP_COUNTS: no\n"); -#endif -#ifdef _GLIBCXX_DEBUG - printf("_GLIBCXX_DEBUG: yes\n"); -#else - printf("_GLIBCXX_DEBUG: no\n"); -#endif -} - -} // libsnark diff --git a/src/snark/libsnark/common/profiling.hpp b/src/snark/libsnark/common/profiling.hpp deleted file mode 100644 index 4a496107b..000000000 --- a/src/snark/libsnark/common/profiling.hpp +++ /dev/null @@ -1,51 +0,0 @@ -/** @file - ***************************************************************************** - - Declaration of functions for profiling code blocks. - - Reports time, operation counts, memory usage, and others. - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef PROFILING_HPP_ -#define PROFILING_HPP_ - -#include -#include -#include -#include - -namespace libsnark { - -void start_profiling(); -int64_t get_nsec_time(); -void print_time(const char* msg); -void print_header(const char* msg); - -void print_indent(); - -extern bool inhibit_profiling_info; -extern bool inhibit_profiling_counters; -extern std::map invocation_counts; -extern std::map last_times; -extern std::map cumulative_times; - -void clear_profiling_counters(); - -void print_cumulative_time_entry(const std::string &key, const int64_t factor=1); -void print_cumulative_times(const int64_t factor=1); -void print_cumulative_op_counts(const bool only_fq=false); - -void enter_block(const std::string &msg, const bool indent=true); -void leave_block(const std::string &msg, const bool indent=true); - -void print_mem(const std::string &s = ""); -void print_compilation_info(); - -} // libsnark - -#endif // PROFILING_HPP_ diff --git a/src/snark/libsnark/common/serialization.hpp b/src/snark/libsnark/common/serialization.hpp deleted file mode 100644 index c931c65b2..000000000 --- a/src/snark/libsnark/common/serialization.hpp +++ /dev/null @@ -1,104 +0,0 @@ -/** @file - ***************************************************************************** - - Declaration of serialization routines and constants. - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef SERIALIZATION_HPP_ -#define SERIALIZATION_HPP_ - -#include -#include -#include -#include -#include - -namespace libsnark { - -/* - * @todo - * The serialization is fragile. Shoud be rewritten using a standard, portable-format - * library like boost::serialize. - * - * However, for now the following conventions are used within the code. - * - * All algebraic objects support either binary or decimal output using - * the standard C++ stream operators (operator<<, operator>>). - * - * The binary mode is activated by defining a BINARY_OUTPUT - * preprocessor macro (e.g. g++ -DBINARY_OUTPUT ...). - * - * Binary output assumes that the stream is to be binary read at its - * current position so any white space should be consumed beforehand. - * - * Consecutive algebraic objects are separated by OUTPUT_NEWLINE and - * within themselves (e.g. X and Y coordinates for field elements) with - * OUTPUT_SEPARATOR (as defined below). - * - * Therefore to dump two integers, two Fp elements and another integer - * one would: - * - * out << 3 << "\n"; - * out << 4 << "\n"; - * out << FieldT(56) << OUTPUT_NEWLINE; - * out << FieldT(78) << OUTPUT_NEWLINE; - * out << 9 << "\n"; - * - * Then reading back it its reader's responsibility (!) to consume "\n" - * after 4, but Fp::operator<< will correctly consume OUTPUT_NEWLINE. - * - * The reader should also consume "\n" after 9, so that another field - * element can be properly chained. This is especially important for - * binary output. - * - * The binary serialization of algebraic objects is currently *not* - * portable between machines of different word sizes. - */ - -#ifdef BINARY_OUTPUT -#define OUTPUT_NEWLINE "" -#define OUTPUT_SEPARATOR "" -#else -#define OUTPUT_NEWLINE "\n" -#define OUTPUT_SEPARATOR " " -#endif - -inline void consume_newline(std::istream &in); -inline void consume_OUTPUT_NEWLINE(std::istream &in); -inline void consume_OUTPUT_SEPARATOR(std::istream &in); - -inline void output_bool(std::ostream &out, const bool b); - -inline void output_bool_vector(std::ostream &out, const std::vector &v); - -template -T reserialize(const T &obj); - -template -std::ostream& operator<<(std::ostream& out, const std::vector &v); - -template -std::istream& operator>>(std::ostream& out, std::vector &v); - -template -std::ostream& operator<<(std::ostream& out, const std::map &m); - -template -std::istream& operator>>(std::istream& in, std::map &m); - -template -std::ostream& operator<<(std::ostream& out, const std::set &s); - -template -std::istream& operator>>(std::istream& in, std::set &s); - -} // libsnark - -#include "common/serialization.tcc" - -#endif // SERIALIZATION_HPP_ diff --git a/src/snark/libsnark/common/serialization.tcc b/src/snark/libsnark/common/serialization.tcc deleted file mode 100644 index 7983c9f25..000000000 --- a/src/snark/libsnark/common/serialization.tcc +++ /dev/null @@ -1,181 +0,0 @@ -/** @file - ***************************************************************************** - - Implementation of serialization routines. - - See serialization.hpp . - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef SERIALIZATION_TCC_ -#define SERIALIZATION_TCC_ - -#include -#include -#include "common/utils.hpp" -#include "common/assert_except.hpp" - -namespace libsnark { - -inline void consume_newline(std::istream &in) -{ - char c; - in.read(&c, 1); -} - -inline void consume_OUTPUT_NEWLINE(std::istream &in) -{ -#ifdef BINARY_OUTPUT - // nothing to consume - UNUSED(in); -#else - char c; - in.read(&c, 1); -#endif -} - -inline void consume_OUTPUT_SEPARATOR(std::istream &in) -{ -#ifdef BINARY_OUTPUT - // nothing to consume - UNUSED(in); -#else - char c; - in.read(&c, 1); -#endif -} - -inline void output_bool(std::ostream &out, const bool b) -{ - out << (b ? 1 : 0) << "\n"; -} - -inline void output_bool_vector(std::ostream &out, const std::vector &v) -{ - out << v.size() << "\n"; - for (const bool b : v) - { - output_bool(out, b); - } -} - -template -T reserialize(const T &obj) -{ - std::stringstream ss; - ss << obj; - T tmp; - ss >> tmp; - assert_except(obj == tmp); - return tmp; -} - -template -std::ostream& operator<<(std::ostream& out, const std::vector &v) -{ - static_assert(!std::is_same::value, "this does not work for std::vector"); - out << v.size() << "\n"; - for (const T& t : v) - { - out << t << OUTPUT_NEWLINE; - } - - return out; -} - -template -std::istream& operator>>(std::istream& in, std::vector &v) -{ - static_assert(!std::is_same::value, "this does not work for std::vector"); - size_t size; - in >> size; - consume_newline(in); - - v.resize(0); - for (size_t i = 0; i < size; ++i) - { - T elt; - in >> elt; - consume_OUTPUT_NEWLINE(in); - v.push_back(elt); - } - - return in; -} - -template -std::ostream& operator<<(std::ostream& out, const std::map &m) -{ - out << m.size() << "\n"; - - for (auto &it : m) - { - out << it.first << "\n"; - out << it.second << "\n"; - } - - return out; -} - -template -std::istream& operator>>(std::istream& in, std::map &m) -{ - m.clear(); - size_t size; - in >> size; - consume_newline(in); - - for (size_t i = 0; i < size; ++i) - { - T1 k; - T2 v; - in >> k; - consume_newline(in); - in >> v; - consume_newline(in); - m[k] = v; - } - - return in; -} - -template -std::ostream& operator<<(std::ostream& out, const std::set &s) -{ - out << s.size() << "\n"; - - for (auto &el : s) - { - out << el << "\n"; - } - - return out; -} - - -template -std::istream& operator>>(std::istream& in, std::set &s) -{ - s.clear(); - size_t size; - in >> size; - consume_newline(in); - - for (size_t i = 0; i < size; ++i) - { - T el; - in >> el; - consume_newline(in); - s.insert(el); - } - - return in; -} - -} - -#endif // SERIALIZATION_TCC_ diff --git a/src/snark/libsnark/common/template_utils.hpp b/src/snark/libsnark/common/template_utils.hpp deleted file mode 100644 index 8dbfd261d..000000000 --- a/src/snark/libsnark/common/template_utils.hpp +++ /dev/null @@ -1,26 +0,0 @@ -/** @file - ***************************************************************************** - - Declaration of functions for supporting the use of templates. - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef TEMPLATE_UTILS_HPP_ -#define TEMPLATE_UTILS_HPP_ - -namespace libsnark { - -/* A commonly used SFINAE helper type */ -template -struct void_type -{ - typedef void type; -}; - -} // libsnark - -#endif // TEMPLATE_UTILS_HPP_ diff --git a/src/snark/libsnark/common/utils.cpp b/src/snark/libsnark/common/utils.cpp deleted file mode 100644 index e2d7ab407..000000000 --- a/src/snark/libsnark/common/utils.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/** @file - ***************************************************************************** - Implementation of misc math and serialization utility functions - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#include -#include -#include -#include -#include "common/utils.hpp" - -namespace libsnark { - -size_t log2(size_t n) -/* returns ceil(log2(n)), so UINT64_C(1)< 1) - { - n >>= 1; - r++; - } - - return r; -} - -uint64_t bitreverse(uint64_t n, const uint64_t l) -{ - uint64_t r = 0; - for (uint64_t k = 0; k < l; ++k) - { - r = (r << 1) | (n & 1); - n >>= 1; - } - return r; -} - -bit_vector int_list_to_bits(const std::initializer_list &l, const size_t wordsize) -{ - bit_vector res(wordsize*l.size()); - for (uint64_t i = 0; i < l.size(); ++i) - { - for (uint64_t j = 0; j < wordsize; ++j) - { - res[i*wordsize + j] = (*(l.begin()+i) & (UINT64_C(1)<<(wordsize-1-j))); - } - } - return res; -} - -int64_t div_ceil(int64_t x, int64_t y) -{ - return (x + (y-1)) / y; -} - -bool is_little_endian() -{ - uint64_t a = 0x12345678; - unsigned char *c = (unsigned char*)(&a); - return (*c = 0x78); -} - -std::string FORMAT(const std::string &prefix, const char* format, ...) -{ - const static uint64_t MAX_FMT = 256; - char buf[MAX_FMT]; - va_list args; - va_start(args, format); - vsnprintf(buf, MAX_FMT, format, args); - va_end(args); - - return prefix + std::string(buf); -} - -void serialize_bit_vector(std::ostream &out, const bit_vector &v) -{ - out << v.size() << "\n"; - for (uint64_t i = 0; i < v.size(); ++i) - { - out << v[i] << "\n"; - } -} - -void deserialize_bit_vector(std::istream &in, bit_vector &v) -{ - uint64_t size; - in >> size; - v.resize(size); - for (uint64_t i = 0; i < size; ++i) - { - bool b; - in >> b; - v[i] = b; - } -} -} // libsnark diff --git a/src/snark/libsnark/common/utils.hpp b/src/snark/libsnark/common/utils.hpp deleted file mode 100644 index c4ce26735..000000000 --- a/src/snark/libsnark/common/utils.hpp +++ /dev/null @@ -1,62 +0,0 @@ -/** @file - ***************************************************************************** - Declaration of misc math and serialization utility functions - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef UTILS_HPP_ -#define UTILS_HPP_ - -#include -#include -#include -#include -#include - -namespace libsnark { - -typedef std::vector bit_vector; - -/// returns ceil(log2(n)), so UINT64_C(1)< &l, const size_t wordsize); -int64_t div_ceil(int64_t x, int64_t y); - -bool is_little_endian(); - -std::string FORMAT(const std::string &prefix, const char* format, ...); - -/* A variadic template to suppress unused argument warnings */ -template -void UNUSED(Types&&...) {} - -#ifdef DEBUG -#define FMT FORMAT -#else -#define FMT(...) (UNUSED(__VA_ARGS__), "") -#endif - -void serialize_bit_vector(std::ostream &out, const bit_vector &v); -void deserialize_bit_vector(std::istream &in, bit_vector &v); - -#ifdef __APPLE__ -template -unsigned long size_in_bits(const std::vector &v); -#else -template -uint64_t size_in_bits(const std::vector &v); -#endif - -#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0])) - -} // libsnark - -#include "common/utils.tcc" /* note that utils has a templatized part (utils.tcc) and non-templatized part (utils.cpp) */ -#endif // UTILS_HPP_ diff --git a/src/snark/libsnark/common/utils.tcc b/src/snark/libsnark/common/utils.tcc deleted file mode 100644 index 4afdc8b3d..000000000 --- a/src/snark/libsnark/common/utils.tcc +++ /dev/null @@ -1,31 +0,0 @@ -/** @file - ***************************************************************************** - Implementation of templatized utility functions - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef UTILS_TCC_ -#define UTILS_TCC_ - -namespace libsnark { - -#ifdef __APPLE__ -template -unsigned long size_in_bits(const std::vector &v) -{ - return v.size() * T::size_in_bits(); -} -#else -template -size_t size_in_bits(const std::vector &v) -{ - return v.size() * T::size_in_bits(); -} -#endif - -} // libsnark - -#endif // UTILS_TCC_ diff --git a/src/snark/libsnark/gadgetlib1/constraint_profiling.cpp b/src/snark/libsnark/gadgetlib1/constraint_profiling.cpp deleted file mode 100644 index bc17e63bc..000000000 --- a/src/snark/libsnark/gadgetlib1/constraint_profiling.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/** @file - ***************************************************************************** - - Implementation of interfaces for profiling constraints. - - See constraint_profiling.hpp . - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#include "gadgetlib1/constraint_profiling.hpp" -#include "common/profiling.hpp" - -namespace libsnark { - -size_t constraint_profiling_indent = 0; -std::vector constraint_profiling_table; - -size_t PRINT_CONSTRAINT_PROFILING() -{ - size_t accounted = 0; - print_indent(); - printf("Constraint profiling:\n"); - for (constraint_profiling_entry &ent : constraint_profiling_table) - { - if (ent.indent == 0) - { - accounted += ent.count; - } - - print_indent(); - for (size_t i = 0; i < ent.indent; ++i) - { - printf(" "); - } - printf("* Number of constraints in [%s]: %zu\n", ent.annotation.c_str(), ent.count); - } - - constraint_profiling_table.clear(); - constraint_profiling_indent = 0; - - return accounted; -} - -} diff --git a/src/snark/libsnark/gadgetlib1/constraint_profiling.hpp b/src/snark/libsnark/gadgetlib1/constraint_profiling.hpp deleted file mode 100644 index df8a55de1..000000000 --- a/src/snark/libsnark/gadgetlib1/constraint_profiling.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/** @file - ***************************************************************************** - - Declaration of interfaces for profiling constraints. - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef CONSTRAINT_PROFILING_HPP_ -#define CONSTRAINT_PROFILING_HPP_ - -#include -#include -#include -#include - -namespace libsnark { - -extern size_t constraint_profiling_indent; - -struct constraint_profiling_entry { - size_t indent; - std::string annotation; - size_t count; -}; - -extern std::vector constraint_profiling_table; - -#define PROFILE_CONSTRAINTS(pb, annotation) \ - for (size_t _num_constraints_before = pb.num_constraints(), _iter = (++constraint_profiling_indent, 0), _cp_pos = constraint_profiling_table.size(); \ - _iter == 0; \ - constraint_profiling_table.insert(constraint_profiling_table.begin() + _cp_pos, constraint_profiling_entry{--constraint_profiling_indent, annotation, pb.num_constraints() - _num_constraints_before}), \ - _iter = 1) - -size_t PRINT_CONSTRAINT_PROFILING(); // returns # of top level constraints - -} // libsnark - -#endif // CONSTRAINT_PROFILING_HPP_ diff --git a/src/snark/libsnark/gadgetlib1/examples/simple_example.hpp b/src/snark/libsnark/gadgetlib1/examples/simple_example.hpp deleted file mode 100644 index faa3a9605..000000000 --- a/src/snark/libsnark/gadgetlib1/examples/simple_example.hpp +++ /dev/null @@ -1,23 +0,0 @@ -/** @file - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef SIMPLE_EXAMPLE_HPP_ -#define SIMPLE_EXAMPLE_HPP_ - -#include "examples/r1cs_examples.hpp" - -namespace libsnark { - -template -r1cs_example gen_r1cs_example_from_protoboard(const size_t num_constraints, - const size_t num_inputs); - -} // libsnark - -#include "gadgetlib1/examples/simple_example.tcc" - -#endif // SIMPLE_EXAMPLE_HPP_ diff --git a/src/snark/libsnark/gadgetlib1/examples/simple_example.tcc b/src/snark/libsnark/gadgetlib1/examples/simple_example.tcc deleted file mode 100644 index 9d500b5c7..000000000 --- a/src/snark/libsnark/gadgetlib1/examples/simple_example.tcc +++ /dev/null @@ -1,54 +0,0 @@ -/** @file - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef SIMPLE_EXAMPLE_TCC_ -#define SIMPLE_EXAMPLE_TCC_ - -#include -#include "gadgetlib1/gadgets/basic_gadgets.hpp" - -namespace libsnark { - -/* NOTE: all examples here actually generate one constraint less to account for soundness constraint in QAP */ - -template -r1cs_example gen_r1cs_example_from_protoboard(const size_t num_constraints, - const size_t num_inputs) -{ - const size_t new_num_constraints = num_constraints - 1; - - /* construct dummy example: inner products of two vectors */ - protoboard pb; - pb_variable_array A; - pb_variable_array B; - pb_variable res; - - // the variables on the protoboard are (ONE (constant 1 term), res, A[0], ..., A[num_constraints-1], B[0], ..., B[num_constraints-1]) - res.allocate(pb, "res"); - A.allocate(pb, new_num_constraints, "A"); - B.allocate(pb, new_num_constraints, "B"); - - inner_product_gadget compute_inner_product(pb, A, B, res, "compute_inner_product"); - compute_inner_product.generate_r1cs_constraints(); - - /* fill in random example */ - for (size_t i = 0; i < new_num_constraints; ++i) - { - pb.val(A[i]) = FieldT::random_element(); - pb.val(B[i]) = FieldT::random_element(); - } - - compute_inner_product.generate_r1cs_witness(); - - pb.constraint_system.num_inputs = num_inputs; - const r1cs_variable_assignment va = pb.values; - const r1cs_variable_assignment input(va.begin(), va.begin() + num_inputs); - return r1cs_example(pb.constraint_system, input, va, num_inputs); -} - -} // libsnark -#endif // R1CS_EXAMPLES_TCC_ diff --git a/src/snark/libsnark/gadgetlib1/gadget.hpp b/src/snark/libsnark/gadgetlib1/gadget.hpp deleted file mode 100644 index dbeaa9d4b..000000000 --- a/src/snark/libsnark/gadgetlib1/gadget.hpp +++ /dev/null @@ -1,27 +0,0 @@ -/** @file - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef GADGET_HPP_ -#define GADGET_HPP_ - -#include "gadgetlib1/protoboard.hpp" - -namespace libsnark { - -template -class gadget { -protected: - protoboard &pb; - const std::string annotation_prefix; -public: - gadget(protoboard &pb, const std::string &annotation_prefix=""); -}; - -} // libsnark -#include "gadgetlib1/gadget.tcc" - -#endif // GADGET_HPP_ diff --git a/src/snark/libsnark/gadgetlib1/gadget.tcc b/src/snark/libsnark/gadgetlib1/gadget.tcc deleted file mode 100644 index 120229bbe..000000000 --- a/src/snark/libsnark/gadgetlib1/gadget.tcc +++ /dev/null @@ -1,23 +0,0 @@ -/** @file - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef GADGET_TCC_ -#define GADGET_TCC_ - -namespace libsnark { - -template -gadget::gadget(protoboard &pb, const std::string &annotation_prefix) : - pb(pb), annotation_prefix(annotation_prefix) -{ -#ifdef DEBUG - assert(annotation_prefix != ""); -#endif -} - -} // libsnark -#endif // GADGET_TCC_ diff --git a/src/snark/libsnark/gadgetlib1/gadgets/basic_gadgets.hpp b/src/snark/libsnark/gadgetlib1/gadgets/basic_gadgets.hpp deleted file mode 100644 index 08e596bee..000000000 --- a/src/snark/libsnark/gadgetlib1/gadgets/basic_gadgets.hpp +++ /dev/null @@ -1,351 +0,0 @@ -/** @file - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef BASIC_GADGETS_HPP_ -#define BASIC_GADGETS_HPP_ - -#include -#include - -#include "gadgetlib1/gadget.hpp" - -namespace libsnark { - -/* forces lc to take value 0 or 1 by adding constraint lc * (1-lc) = 0 */ -template -void generate_boolean_r1cs_constraint(protoboard &pb, const pb_linear_combination &lc, const std::string &annotation_prefix=""); - -template -void generate_r1cs_equals_const_constraint(protoboard &pb, const pb_linear_combination &lc, const FieldT& c, const std::string &annotation_prefix=""); - -template -class packing_gadget : public gadget { -private: - /* no internal variables */ -public: - const pb_linear_combination_array bits; - const pb_linear_combination packed; - - packing_gadget(protoboard &pb, - const pb_linear_combination_array &bits, - const pb_linear_combination &packed, - const std::string &annotation_prefix="") : - gadget(pb, annotation_prefix), bits(bits), packed(packed) {} - - void generate_r1cs_constraints(const bool enforce_bitness); - /* adds constraint result = \sum bits[i] * 2^i */ - - void generate_r1cs_witness_from_packed(); - void generate_r1cs_witness_from_bits(); -}; - -template -class multipacking_gadget : public gadget { -private: - std::vector > packers; -public: - const pb_linear_combination_array bits; - const pb_linear_combination_array packed_vars; - - const size_t chunk_size; - const size_t num_chunks; - // const size_t last_chunk_size; - - multipacking_gadget(protoboard &pb, - const pb_linear_combination_array &bits, - const pb_linear_combination_array &packed_vars, - const size_t chunk_size, - const std::string &annotation_prefix=""); - void generate_r1cs_constraints(const bool enforce_bitness); - void generate_r1cs_witness_from_packed(); - void generate_r1cs_witness_from_bits(); -}; - -template -class field_vector_copy_gadget : public gadget { -public: - const pb_variable_array source; - const pb_variable_array target; - const pb_linear_combination do_copy; - - field_vector_copy_gadget(protoboard &pb, - const pb_variable_array &source, - const pb_variable_array &target, - const pb_linear_combination &do_copy, - const std::string &annotation_prefix=""); - void generate_r1cs_constraints(); - void generate_r1cs_witness(); -}; - -template -class bit_vector_copy_gadget : public gadget { -public: - const pb_variable_array source_bits; - const pb_variable_array target_bits; - const pb_linear_combination do_copy; - - pb_variable_array packed_source; - pb_variable_array packed_target; - - std::shared_ptr > pack_source; - std::shared_ptr > pack_target; - std::shared_ptr > copier; - - const size_t chunk_size; - const size_t num_chunks; - - bit_vector_copy_gadget(protoboard &pb, - const pb_variable_array &source_bits, - const pb_variable_array &target_bits, - const pb_linear_combination &do_copy, - const size_t chunk_size, - const std::string &annotation_prefix=""); - void generate_r1cs_constraints(const bool enforce_source_bitness, const bool enforce_target_bitness); - void generate_r1cs_witness(); -}; - -template -class dual_variable_gadget : public gadget { -private: - std::shared_ptr > consistency_check; -public: - pb_variable packed; - pb_variable_array bits; - - dual_variable_gadget(protoboard &pb, - const size_t width, - const std::string &annotation_prefix="") : - gadget(pb, annotation_prefix) - { - packed.allocate(pb, FMT(this->annotation_prefix, " packed")); - bits.allocate(pb, width, FMT(this->annotation_prefix, " bits")); - consistency_check.reset(new packing_gadget(pb, - bits, - packed, - FMT(this->annotation_prefix, " consistency_check"))); - } - - dual_variable_gadget(protoboard &pb, - const pb_variable_array &bits, - const std::string &annotation_prefix="") : - gadget(pb, annotation_prefix), bits(bits) - { - packed.allocate(pb, FMT(this->annotation_prefix, " packed")); - consistency_check.reset(new packing_gadget(pb, - bits, - packed, - FMT(this->annotation_prefix, " consistency_check"))); - } - - dual_variable_gadget(protoboard &pb, - const pb_variable &packed, - const size_t width, - const std::string &annotation_prefix="") : - gadget(pb, annotation_prefix), packed(packed) - { - bits.allocate(pb, width, FMT(this->annotation_prefix, " bits")); - consistency_check.reset(new packing_gadget(pb, - bits, - packed, - FMT(this->annotation_prefix, " consistency_check"))); - } - - void generate_r1cs_constraints(const bool enforce_bitness); - void generate_r1cs_witness_from_packed(); - void generate_r1cs_witness_from_bits(); -}; - -/* - the gadgets below are Fp specific: - I * X = R - (1-R) * X = 0 - - if X = 0 then R = 0 - if X != 0 then R = 1 and I = X^{-1} -*/ - -template -class disjunction_gadget : public gadget { -private: - pb_variable inv; -public: - const pb_variable_array inputs; - const pb_variable output; - - disjunction_gadget(protoboard& pb, - const pb_variable_array &inputs, - const pb_variable &output, - const std::string &annotation_prefix="") : - gadget(pb, annotation_prefix), inputs(inputs), output(output) - { - assert(inputs.size() >= 1); - inv.allocate(pb, FMT(this->annotation_prefix, " inv")); - } - - void generate_r1cs_constraints(); - void generate_r1cs_witness(); -}; - -template -void test_disjunction_gadget(const size_t n); - -template -class conjunction_gadget : public gadget { -private: - pb_variable inv; -public: - const pb_variable_array inputs; - const pb_variable output; - - conjunction_gadget(protoboard& pb, - const pb_variable_array &inputs, - const pb_variable &output, - const std::string &annotation_prefix="") : - gadget(pb, annotation_prefix), inputs(inputs), output(output) - { - assert(inputs.size() >= 1); - inv.allocate(pb, FMT(this->annotation_prefix, " inv")); - } - - void generate_r1cs_constraints(); - void generate_r1cs_witness(); -}; - -template -void test_conjunction_gadget(const size_t n); - -template -class comparison_gadget : public gadget { -private: - pb_variable_array alpha; - pb_variable alpha_packed; - std::shared_ptr > pack_alpha; - - std::shared_ptr > all_zeros_test; - pb_variable not_all_zeros; -public: - const size_t n; - const pb_linear_combination A; - const pb_linear_combination B; - const pb_variable less; - const pb_variable less_or_eq; - - comparison_gadget(protoboard& pb, - const size_t n, - const pb_linear_combination &A, - const pb_linear_combination &B, - const pb_variable &less, - const pb_variable &less_or_eq, - const std::string &annotation_prefix="") : - gadget(pb, annotation_prefix), n(n), A(A), B(B), less(less), less_or_eq(less_or_eq) - { - alpha.allocate(pb, n, FMT(this->annotation_prefix, " alpha")); - alpha.emplace_back(less_or_eq); // alpha[n] is less_or_eq - - alpha_packed.allocate(pb, FMT(this->annotation_prefix, " alpha_packed")); - not_all_zeros.allocate(pb, FMT(this->annotation_prefix, " not_all_zeros")); - - pack_alpha.reset(new packing_gadget(pb, alpha, alpha_packed, - FMT(this->annotation_prefix, " pack_alpha"))); - - all_zeros_test.reset(new disjunction_gadget(pb, - pb_variable_array(alpha.begin(), alpha.begin() + n), - not_all_zeros, - FMT(this->annotation_prefix, " all_zeros_test"))); - }; - - void generate_r1cs_constraints(); - void generate_r1cs_witness(); -}; - -template -void test_comparison_gadget(const size_t n); - -template -class inner_product_gadget : public gadget { -private: - /* S_i = \sum_{k=0}^{i+1} A[i] * B[i] */ - pb_variable_array S; -public: - const pb_linear_combination_array A; - const pb_linear_combination_array B; - const pb_variable result; - - inner_product_gadget(protoboard& pb, - const pb_linear_combination_array &A, - const pb_linear_combination_array &B, - const pb_variable &result, - const std::string &annotation_prefix="") : - gadget(pb, annotation_prefix), A(A), B(B), result(result) - { - assert(A.size() >= 1); - assert(A.size() == B.size()); - - S.allocate(pb, A.size()-1, FMT(this->annotation_prefix, " S")); - } - - void generate_r1cs_constraints(); - void generate_r1cs_witness(); -}; - -template -void test_inner_product_gadget(const size_t n); - -template -class loose_multiplexing_gadget : public gadget { -/* - this implements loose multiplexer: - index not in bounds -> success_flag = 0 - index in bounds && success_flag = 1 -> result is correct - however if index is in bounds we can also set success_flag to 0 (and then result will be forced to be 0) -*/ -public: - pb_variable_array alpha; -private: - std::shared_ptr > compute_result; -public: - const pb_linear_combination_array arr; - const pb_variable index; - const pb_variable result; - const pb_variable success_flag; - - loose_multiplexing_gadget(protoboard& pb, - const pb_linear_combination_array &arr, - const pb_variable &index, - const pb_variable &result, - const pb_variable &success_flag, - const std::string &annotation_prefix="") : - gadget(pb, annotation_prefix), arr(arr), index(index), result(result), success_flag(success_flag) - { - alpha.allocate(pb, arr.size(), FMT(this->annotation_prefix, " alpha")); - compute_result.reset(new inner_product_gadget(pb, alpha, arr, result, FMT(this->annotation_prefix, " compute_result"))); - }; - - void generate_r1cs_constraints(); - void generate_r1cs_witness(); -}; - -template -void test_loose_multiplexing_gadget(const size_t n); - -template -void create_linear_combination_constraints(protoboard &pb, - const std::vector &base, - const std::vector > &v, - const VarT &target, - const std::string &annotation_prefix); - -template -void create_linear_combination_witness(protoboard &pb, - const std::vector &base, - const std::vector > &v, - const VarT &target); - -} // libsnark -#include "gadgetlib1/gadgets/basic_gadgets.tcc" - -#endif // BASIC_GADGETS_HPP_ diff --git a/src/snark/libsnark/gadgetlib1/gadgets/basic_gadgets.tcc b/src/snark/libsnark/gadgetlib1/gadgets/basic_gadgets.tcc deleted file mode 100644 index 4e2d9fce3..000000000 --- a/src/snark/libsnark/gadgetlib1/gadgets/basic_gadgets.tcc +++ /dev/null @@ -1,705 +0,0 @@ -/** @file - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef BASIC_GADGETS_TCC_ -#define BASIC_GADGETS_TCC_ - -#include "common/profiling.hpp" -#include "common/utils.hpp" - -namespace libsnark { - -template -void generate_boolean_r1cs_constraint(protoboard &pb, const pb_linear_combination &lc, const std::string &annotation_prefix) -/* forces lc to take value 0 or 1 by adding constraint lc * (1-lc) = 0 */ -{ - pb.add_r1cs_constraint(r1cs_constraint(lc, 1-lc, 0), - FMT(annotation_prefix, " boolean_r1cs_constraint")); -} - -template -void generate_r1cs_equals_const_constraint(protoboard &pb, const pb_linear_combination &lc, const FieldT& c, const std::string &annotation_prefix) -{ - pb.add_r1cs_constraint(r1cs_constraint(1, lc, c), - FMT(annotation_prefix, " constness_constraint")); -} - -template -void packing_gadget::generate_r1cs_constraints(const bool enforce_bitness) -/* adds constraint result = \sum bits[i] * 2^i */ -{ - this->pb.add_r1cs_constraint(r1cs_constraint(1, pb_packing_sum(bits), packed), FMT(this->annotation_prefix, " packing_constraint")); - - if (enforce_bitness) - { - for (size_t i = 0; i < bits.size(); ++i) - { - generate_boolean_r1cs_constraint(this->pb, bits[i], FMT(this->annotation_prefix, " bitness_%zu", i)); - } - } -} - -template -void packing_gadget::generate_r1cs_witness_from_packed() -{ - packed.evaluate(this->pb); - assert(this->pb.lc_val(packed).as_bigint().num_bits() <= bits.size()); - bits.fill_with_bits_of_field_element(this->pb, this->pb.lc_val(packed)); -} - -template -void packing_gadget::generate_r1cs_witness_from_bits() -{ - bits.evaluate(this->pb); - this->pb.lc_val(packed) = bits.get_field_element_from_bits(this->pb); -} - -template -multipacking_gadget::multipacking_gadget(protoboard &pb, - const pb_linear_combination_array &bits, - const pb_linear_combination_array &packed_vars, - const size_t chunk_size, - const std::string &annotation_prefix) : - gadget(pb, annotation_prefix), bits(bits), packed_vars(packed_vars), - chunk_size(chunk_size), - num_chunks(div_ceil(bits.size(), chunk_size)) - // last_chunk_size(bits.size() - (num_chunks-1) * chunk_size) -{ - assert(packed_vars.size() == num_chunks); - for (size_t i = 0; i < num_chunks; ++i) - { - packers.emplace_back(packing_gadget(this->pb, pb_linear_combination_array(bits.begin() + i * chunk_size, - bits.begin() + std::min((i+1) * chunk_size, bits.size())), - packed_vars[i], FMT(this->annotation_prefix, " packers_%zu", i))); - } -} - -template -void multipacking_gadget::generate_r1cs_constraints(const bool enforce_bitness) -{ - for (size_t i = 0; i < num_chunks; ++i) - { - packers[i].generate_r1cs_constraints(enforce_bitness); - } -} - -template -void multipacking_gadget::generate_r1cs_witness_from_packed() -{ - for (size_t i = 0; i < num_chunks; ++i) - { - packers[i].generate_r1cs_witness_from_packed(); - } -} - -template -void multipacking_gadget::generate_r1cs_witness_from_bits() -{ - for (size_t i = 0; i < num_chunks; ++i) - { - packers[i].generate_r1cs_witness_from_bits(); - } -} - -template -size_t multipacking_num_chunks(const size_t num_bits) -{ - return div_ceil(num_bits, FieldT::capacity()); -} - -template -field_vector_copy_gadget::field_vector_copy_gadget(protoboard &pb, - const pb_variable_array &source, - const pb_variable_array &target, - const pb_linear_combination &do_copy, - const std::string &annotation_prefix) : -gadget(pb, annotation_prefix), source(source), target(target), do_copy(do_copy) -{ - assert(source.size() == target.size()); -} - -template -void field_vector_copy_gadget::generate_r1cs_constraints() -{ - for (size_t i = 0; i < source.size(); ++i) - { - this->pb.add_r1cs_constraint(r1cs_constraint(do_copy, source[i] - target[i], 0), - FMT(this->annotation_prefix, " copying_check_%zu", i)); - } -} - -template -void field_vector_copy_gadget::generate_r1cs_witness() -{ - do_copy.evaluate(this->pb); - assert(this->pb.lc_val(do_copy) == FieldT::one() || this->pb.lc_val(do_copy) == FieldT::zero()); - if (this->pb.lc_val(do_copy) != FieldT::zero()) - { - for (size_t i = 0; i < source.size(); ++i) - { - this->pb.val(target[i]) = this->pb.val(source[i]); - } - } -} - -template -bit_vector_copy_gadget::bit_vector_copy_gadget(protoboard &pb, - const pb_variable_array &source_bits, - const pb_variable_array &target_bits, - const pb_linear_combination &do_copy, - const size_t chunk_size, - const std::string &annotation_prefix) : - gadget(pb, annotation_prefix), source_bits(source_bits), target_bits(target_bits), do_copy(do_copy), - chunk_size(chunk_size), num_chunks(div_ceil(source_bits.size(), chunk_size)) -{ - assert(source_bits.size() == target_bits.size()); - - packed_source.allocate(pb, num_chunks, FMT(annotation_prefix, " packed_source")); - pack_source.reset(new multipacking_gadget(pb, source_bits, packed_source, chunk_size, FMT(annotation_prefix, " pack_source"))); - - packed_target.allocate(pb, num_chunks, FMT(annotation_prefix, " packed_target")); - pack_target.reset(new multipacking_gadget(pb, target_bits, packed_target, chunk_size, FMT(annotation_prefix, " pack_target"))); - - copier.reset(new field_vector_copy_gadget(pb, packed_source, packed_target, do_copy, FMT(annotation_prefix, " copier"))); -} - -template -void bit_vector_copy_gadget::generate_r1cs_constraints(const bool enforce_source_bitness, const bool enforce_target_bitness) -{ - pack_source->generate_r1cs_constraints(enforce_source_bitness); - pack_target->generate_r1cs_constraints(enforce_target_bitness); - - copier->generate_r1cs_constraints(); -} - -template -void bit_vector_copy_gadget::generate_r1cs_witness() -{ - do_copy.evaluate(this->pb); - assert(this->pb.lc_val(do_copy) == FieldT::zero() || this->pb.lc_val(do_copy) == FieldT::one()); - if (this->pb.lc_val(do_copy) == FieldT::one()) - { - for (size_t i = 0; i < source_bits.size(); ++i) - { - this->pb.val(target_bits[i]) = this->pb.val(source_bits[i]); - } - } - - pack_source->generate_r1cs_witness_from_bits(); - pack_target->generate_r1cs_witness_from_bits(); -} - -template -void dual_variable_gadget::generate_r1cs_constraints(const bool enforce_bitness) -{ - consistency_check->generate_r1cs_constraints(enforce_bitness); -} - -template -void dual_variable_gadget::generate_r1cs_witness_from_packed() -{ - consistency_check->generate_r1cs_witness_from_packed(); -} - -template -void dual_variable_gadget::generate_r1cs_witness_from_bits() -{ - consistency_check->generate_r1cs_witness_from_bits(); -} - -template -void disjunction_gadget::generate_r1cs_constraints() -{ - /* inv * sum = output */ - linear_combination a1, b1, c1; - a1.add_term(inv); - for (size_t i = 0; i < inputs.size(); ++i) - { - b1.add_term(inputs[i]); - } - c1.add_term(output); - - this->pb.add_r1cs_constraint(r1cs_constraint(a1, b1, c1), FMT(this->annotation_prefix, " inv*sum=output")); - - /* (1-output) * sum = 0 */ - linear_combination a2, b2, c2; - a2.add_term(ONE); - a2.add_term(output, -1); - for (size_t i = 0; i < inputs.size(); ++i) - { - b2.add_term(inputs[i]); - } - c2.add_term(ONE, 0); - - this->pb.add_r1cs_constraint(r1cs_constraint(a2, b2, c2), FMT(this->annotation_prefix, " (1-output)*sum=0")); -} - -template -void disjunction_gadget::generate_r1cs_witness() -{ - FieldT sum = FieldT::zero(); - - for (size_t i = 0; i < inputs.size(); ++i) - { - sum += this->pb.val(inputs[i]); - } - - if (sum.is_zero()) - { - this->pb.val(inv) = FieldT::zero(); - this->pb.val(output) = FieldT::zero(); - } - else - { - this->pb.val(inv) = sum.inverse(); - this->pb.val(output) = FieldT::one(); - } -} - -template -void test_disjunction_gadget(const size_t n) -{ - printf("testing disjunction_gadget on all %zu bit strings\n", n); - - protoboard pb; - pb_variable_array inputs; - inputs.allocate(pb, n, "inputs"); - - pb_variable output; - output.allocate(pb, "output"); - - disjunction_gadget d(pb, inputs, output, "d"); - d.generate_r1cs_constraints(); - - for (size_t w = 0; w < UINT64_C(1)< -void conjunction_gadget::generate_r1cs_constraints() -{ - /* inv * (n-sum) = 1-output */ - linear_combination a1, b1, c1; - a1.add_term(inv); - b1.add_term(ONE, inputs.size()); - for (size_t i = 0; i < inputs.size(); ++i) - { - b1.add_term(inputs[i], -1); - } - c1.add_term(ONE); - c1.add_term(output, -1); - - this->pb.add_r1cs_constraint(r1cs_constraint(a1, b1, c1), FMT(this->annotation_prefix, " inv*(n-sum)=(1-output)")); - - /* output * (n-sum) = 0 */ - linear_combination a2, b2, c2; - a2.add_term(output); - b2.add_term(ONE, inputs.size()); - for (size_t i = 0; i < inputs.size(); ++i) - { - b2.add_term(inputs[i], -1); - } - c2.add_term(ONE, 0); - - this->pb.add_r1cs_constraint(r1cs_constraint(a2, b2, c2), FMT(this->annotation_prefix, " output*(n-sum)=0")); -} - -template -void conjunction_gadget::generate_r1cs_witness() -{ - FieldT sum = FieldT(inputs.size()); - - for (size_t i = 0; i < inputs.size(); ++i) - { - sum -= this->pb.val(inputs[i]); - } - - if (sum.is_zero()) - { - this->pb.val(inv) = FieldT::zero(); - this->pb.val(output) = FieldT::one(); - } - else - { - this->pb.val(inv) = sum.inverse(); - this->pb.val(output) = FieldT::zero(); - } -} - -template -void test_conjunction_gadget(const size_t n) -{ - printf("testing conjunction_gadget on all %zu bit strings\n", n); - - protoboard pb; - pb_variable_array inputs; - inputs.allocate(pb, n, "inputs"); - - pb_variable output; - output.allocate(pb, "output"); - - conjunction_gadget c(pb, inputs, output, "c"); - c.generate_r1cs_constraints(); - - for (size_t w = 0; w < UINT64_C(1)< -void comparison_gadget::generate_r1cs_constraints() -{ - /* - packed(alpha) = 2^n + B - A - - not_all_zeros = \bigvee_{i=0}^{n-1} alpha_i - - if B - A > 0, then 2^n + B - A > 2^n, - so alpha_n = 1 and not_all_zeros = 1 - if B - A = 0, then 2^n + B - A = 2^n, - so alpha_n = 1 and not_all_zeros = 0 - if B - A < 0, then 2^n + B - A \in {0, 1, \ldots, 2^n-1}, - so alpha_n = 0 - - therefore alpha_n = less_or_eq and alpha_n * not_all_zeros = less - */ - - /* not_all_zeros to be Boolean, alpha_i are Boolean by packing gadget */ - generate_boolean_r1cs_constraint(this->pb, not_all_zeros, - FMT(this->annotation_prefix, " not_all_zeros")); - - /* constraints for packed(alpha) = 2^n + B - A */ - pack_alpha->generate_r1cs_constraints(true); - this->pb.add_r1cs_constraint(r1cs_constraint(1, (FieldT(2)^n) + B - A, alpha_packed), FMT(this->annotation_prefix, " main_constraint")); - - /* compute result */ - all_zeros_test->generate_r1cs_constraints(); - this->pb.add_r1cs_constraint(r1cs_constraint(less_or_eq, not_all_zeros, less), - FMT(this->annotation_prefix, " less")); -} - -template -void comparison_gadget::generate_r1cs_witness() -{ - A.evaluate(this->pb); - B.evaluate(this->pb); - - /* unpack 2^n + B - A into alpha_packed */ - this->pb.val(alpha_packed) = (FieldT(2)^n) + this->pb.lc_val(B) - this->pb.lc_val(A); - pack_alpha->generate_r1cs_witness_from_packed(); - - /* compute result */ - all_zeros_test->generate_r1cs_witness(); - this->pb.val(less) = this->pb.val(less_or_eq) * this->pb.val(not_all_zeros); -} - -template -void test_comparison_gadget(const size_t n) -{ - printf("testing comparison_gadget on all %zu bit inputs\n", n); - - protoboard pb; - - pb_variable A, B, less, less_or_eq; - A.allocate(pb, "A"); - B.allocate(pb, "B"); - less.allocate(pb, "less"); - less_or_eq.allocate(pb, "less_or_eq"); - - comparison_gadget cmp(pb, n, A, B, less, less_or_eq, "cmp"); - cmp.generate_r1cs_constraints(); - - for (size_t a = 0; a < UINT64_C(1)< -void inner_product_gadget::generate_r1cs_constraints() -{ - /* - S_i = \sum_{k=0}^{i+1} A[i] * B[i] - S[0] = A[0] * B[0] - S[i+1] - S[i] = A[i] * B[i] - */ - for (size_t i = 0; i < A.size(); ++i) - { - this->pb.add_r1cs_constraint( - r1cs_constraint(A[i], B[i], - (i == A.size()-1 ? result : S[i]) + (i == 0 ? 0 * ONE : -S[i-1])), - FMT(this->annotation_prefix, " S_%zu", i)); - } -} - -template -void inner_product_gadget::generate_r1cs_witness() -{ - FieldT total = FieldT::zero(); - for (size_t i = 0; i < A.size(); ++i) - { - A[i].evaluate(this->pb); - B[i].evaluate(this->pb); - - total += this->pb.lc_val(A[i]) * this->pb.lc_val(B[i]); - this->pb.val(i == A.size()-1 ? result : S[i]) = total; - } -} - -template -void test_inner_product_gadget(const size_t n) -{ - printf("testing inner_product_gadget on all %zu bit strings\n", n); - - protoboard pb; - pb_variable_array A; - A.allocate(pb, n, "A"); - pb_variable_array B; - B.allocate(pb, n, "B"); - - pb_variable result; - result.allocate(pb, "result"); - - inner_product_gadget g(pb, A, B, result, "g"); - g.generate_r1cs_constraints(); - - for (size_t i = 0; i < UINT64_C(1)< -void loose_multiplexing_gadget::generate_r1cs_constraints() -{ - /* \alpha_i (index - i) = 0 */ - for (size_t i = 0; i < arr.size(); ++i) - { - this->pb.add_r1cs_constraint( - r1cs_constraint(alpha[i], index - i, 0), - FMT(this->annotation_prefix, " alpha_%zu", i)); - } - - /* 1 * (\sum \alpha_i) = success_flag */ - linear_combination a, b, c; - a.add_term(ONE); - for (size_t i = 0; i < arr.size(); ++i) - { - b.add_term(alpha[i]); - } - c.add_term(success_flag); - this->pb.add_r1cs_constraint(r1cs_constraint(a, b, c), FMT(this->annotation_prefix, " main_constraint")); - - /* now success_flag is constrained to either 0 (if index is out of - range) or \alpha_i. constrain it and \alpha_i to zero */ - generate_boolean_r1cs_constraint(this->pb, success_flag, FMT(this->annotation_prefix, " success_flag")); - - /* compute result */ - compute_result->generate_r1cs_constraints(); -} - -template -void loose_multiplexing_gadget::generate_r1cs_witness() -{ - /* assumes that idx can be fit in uint64_t; true for our purposes for now */ - const bigint valint = this->pb.val(index).as_bigint(); - uint64_t idx = valint.as_uint64(); - const bigint arrsize(arr.size()); - - if (idx >= arr.size() || mpn_cmp(valint.data, arrsize.data, FieldT::num_limbs) >= 0) - { - for (size_t i = 0; i < arr.size(); ++i) - { - this->pb.val(alpha[i]) = FieldT::zero(); - } - - this->pb.val(success_flag) = FieldT::zero(); - } - else - { - for (size_t i = 0; i < arr.size(); ++i) - { - this->pb.val(alpha[i]) = (i == idx ? FieldT::one() : FieldT::zero()); - } - - this->pb.val(success_flag) = FieldT::one(); - } - - compute_result->generate_r1cs_witness(); -} - -template -void test_loose_multiplexing_gadget(const size_t n) -{ - printf("testing loose_multiplexing_gadget on 2**%zu pb_variable array inputs\n", n); - protoboard pb; - - pb_variable_array arr; - arr.allocate(pb, UINT64_C(1)< index, result, success_flag; - index.allocate(pb, "index"); - result.allocate(pb, "result"); - success_flag.allocate(pb, "success_flag"); - - loose_multiplexing_gadget g(pb, arr, index, result, success_flag, "g"); - g.generate_r1cs_constraints(); - - for (size_t i = 0; i < UINT64_C(1)< -void create_linear_combination_constraints(protoboard &pb, - const std::vector &base, - const std::vector > &v, - const VarT &target, - const std::string &annotation_prefix) -{ - for (size_t i = 0; i < base.size(); ++i) - { - linear_combination a, b, c; - - a.add_term(ONE); - b.add_term(ONE, base[i]); - - for (auto &p : v) - { - b.add_term(p.first.all_vars[i], p.second); - } - - c.add_term(target.all_vars[i]); - - pb.add_r1cs_constraint(r1cs_constraint(a, b, c), FMT(annotation_prefix, " linear_combination_%zu", i)); - } -} - -template -void create_linear_combination_witness(protoboard &pb, - const std::vector &base, - const std::vector > &v, - const VarT &target) -{ - for (size_t i = 0; i < base.size(); ++i) - { - pb.val(target.all_vars[i]) = base[i]; - - for (auto &p : v) - { - pb.val(target.all_vars[i]) += p.second * pb.val(p.first.all_vars[i]); - } - } -} - -} // libsnark -#endif // BASIC_GADGETS_TCC_ diff --git a/src/snark/libsnark/gadgetlib1/gadgets/gadget_from_r1cs.hpp b/src/snark/libsnark/gadgetlib1/gadgets/gadget_from_r1cs.hpp deleted file mode 100644 index e4b8a2acf..000000000 --- a/src/snark/libsnark/gadgetlib1/gadgets/gadget_from_r1cs.hpp +++ /dev/null @@ -1,45 +0,0 @@ -/** @file - ***************************************************************************** - - Declaration of interfaces for a gadget that can be created from an R1CS constraint system. - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef GADGET_FROM_R1CS_HPP_ -#define GADGET_FROM_R1CS_HPP_ - -#include - -#include "gadgetlib1/gadget.hpp" - -namespace libsnark { - -template -class gadget_from_r1cs : public gadget { - -private: - const std::vector > vars; - const r1cs_constraint_system cs; - std::map cs_to_vars; - -public: - - gadget_from_r1cs(protoboard &pb, - const std::vector > &vars, - const r1cs_constraint_system &cs, - const std::string &annotation_prefix); - - void generate_r1cs_constraints(); - void generate_r1cs_witness(const r1cs_primary_input &primary_input, - const r1cs_auxiliary_input &auxiliary_input); -}; - -} // libsnark - -#include "gadgetlib1/gadgets/gadget_from_r1cs.tcc" - -#endif // GADGET_FROM_R1CS_HPP_ diff --git a/src/snark/libsnark/gadgetlib1/gadgets/gadget_from_r1cs.tcc b/src/snark/libsnark/gadgetlib1/gadgets/gadget_from_r1cs.tcc deleted file mode 100644 index bc59b4587..000000000 --- a/src/snark/libsnark/gadgetlib1/gadgets/gadget_from_r1cs.tcc +++ /dev/null @@ -1,123 +0,0 @@ -/** @file - ***************************************************************************** - - Implementation of interfaces for a gadget that can be created from an R1CS constraint system. - - See gadget_from_r1cs.hpp . - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef GADGET_FROM_R1CS_TCC_ -#define GADGET_FROM_R1CS_TCC_ - -namespace libsnark { - -template -gadget_from_r1cs::gadget_from_r1cs(protoboard &pb, - const std::vector > &vars, - const r1cs_constraint_system &cs, - const std::string &annotation_prefix) : - gadget(pb, annotation_prefix), - vars(vars), - cs(cs) -{ - cs_to_vars[0] = 0; /* constant term maps to constant term */ - - size_t cs_var_idx = 1; - for (auto va : vars) - { -#ifdef DEBUG - printf("gadget_from_r1cs: translating a block of variables with length %zu\n", va.size()); -#endif - for (auto v : va) - { - cs_to_vars[cs_var_idx] = v.index; - -#ifdef DEBUG - if (v.index != 0) - { - // handle annotations, except for re-annotating constant term - const std::map::const_iterator it = cs.variable_annotations.find(cs_var_idx); - - std::string annotation = FMT(annotation_prefix, " variable_%zu", cs_var_idx); - if (it != cs.variable_annotations.end()) - { - annotation = annotation_prefix + " " + it->second; - } - - pb.augment_variable_annotation(v, annotation); - } -#endif - ++cs_var_idx; - } - } - -#ifdef DEBUG - printf("gadget_from_r1cs: sum of all block lengths: %zu\n", cs_var_idx-1); - printf("gadget_from_r1cs: cs.num_variables(): %zu\n", cs.num_variables()); -#endif - - assert(cs_var_idx - 1 == cs.num_variables()); -} - -template -void gadget_from_r1cs::generate_r1cs_constraints() -{ - for (size_t i = 0; i < cs.num_constraints(); ++i) - { - const r1cs_constraint &constr = cs.constraints[i]; - r1cs_constraint translated_constr; - - for (const linear_term &t: constr.a.terms) - { - translated_constr.a.terms.emplace_back(linear_term(pb_variable(cs_to_vars[t.index]), t.coeff)); - } - - for (const linear_term &t: constr.b.terms) - { - translated_constr.b.terms.emplace_back(linear_term(pb_variable(cs_to_vars[t.index]), t.coeff)); - } - - for (const linear_term &t: constr.c.terms) - { - translated_constr.c.terms.emplace_back(linear_term(pb_variable(cs_to_vars[t.index]), t.coeff)); - } - - std::string annotation = FMT(this->annotation_prefix, " constraint_%zu", i); - -#ifdef DEBUG - auto it = cs.constraint_annotations.find(i); - if (it != cs.constraint_annotations.end()) - { - annotation = this->annotation_prefix + " " + it->second; - } -#endif - this->pb.add_r1cs_constraint(translated_constr, annotation); - } -} - -template -void gadget_from_r1cs::generate_r1cs_witness(const r1cs_primary_input &primary_input, - const r1cs_auxiliary_input &auxiliary_input) -{ - assert(cs.num_inputs() == primary_input.size()); - assert(cs.num_variables() == primary_input.size() + auxiliary_input.size()); - - for (size_t i = 0; i < primary_input.size(); ++i) - { - this->pb.val(pb_variable(cs_to_vars[i+1])) = primary_input[i]; - } - - for (size_t i = 0; i < auxiliary_input.size(); ++i) - { - this->pb.val(pb_variable(cs_to_vars[primary_input.size()+i+1])) = auxiliary_input[i]; - } -} - -} // libsnark - -#endif // GADGET_FROM_R1CS_TCC_ diff --git a/src/snark/libsnark/gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp b/src/snark/libsnark/gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp deleted file mode 100644 index a7598b9be..000000000 --- a/src/snark/libsnark/gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp +++ /dev/null @@ -1,42 +0,0 @@ -/** - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ -#ifndef DIGEST_SELECTOR_GADGET_HPP_ -#define DIGEST_SELECTOR_GADGET_HPP_ - -#include - -#include "gadgetlib1/gadgets/basic_gadgets.hpp" -#include "gadgetlib1/gadgets/hashes/hash_io.hpp" - -namespace libsnark { - -template -class digest_selector_gadget : public gadget { -public: - size_t digest_size; - digest_variable input; - pb_linear_combination is_right; - digest_variable left; - digest_variable right; - - digest_selector_gadget(protoboard &pb, - const size_t digest_size, - const digest_variable &input, - const pb_linear_combination &is_right, - const digest_variable &left, - const digest_variable &right, - const std::string &annotation_prefix); - - void generate_r1cs_constraints(); - void generate_r1cs_witness(); -}; - -} // libsnark - -#include "gadgetlib1/gadgets/hashes/digest_selector_gadget.tcc" - -#endif // DIGEST_SELECTOR_GADGET_HPP_ diff --git a/src/snark/libsnark/gadgetlib1/gadgets/hashes/digest_selector_gadget.tcc b/src/snark/libsnark/gadgetlib1/gadgets/hashes/digest_selector_gadget.tcc deleted file mode 100644 index 422ee170a..000000000 --- a/src/snark/libsnark/gadgetlib1/gadgets/hashes/digest_selector_gadget.tcc +++ /dev/null @@ -1,62 +0,0 @@ -/** - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ -#ifndef DIGEST_SELECTOR_GADGET_TCC_ -#define DIGEST_SELECTOR_GADGET_TCC_ - -namespace libsnark { - -template -digest_selector_gadget::digest_selector_gadget(protoboard &pb, - const size_t digest_size, - const digest_variable &input, - const pb_linear_combination &is_right, - const digest_variable &left, - const digest_variable &right, - const std::string &annotation_prefix) : -gadget(pb, annotation_prefix), digest_size(digest_size), input(input), is_right(is_right), left(left), right(right) -{ -} - -template -void digest_selector_gadget::generate_r1cs_constraints() -{ - for (size_t i = 0; i < digest_size; ++i) - { - /* - input = is_right * right + (1-is_right) * left - input - left = is_right(right - left) - */ - this->pb.add_r1cs_constraint(r1cs_constraint(is_right, right.bits[i] - left.bits[i], input.bits[i] - left.bits[i]), - FMT(this->annotation_prefix, " propagate_%zu", i)); - } -} - -template -void digest_selector_gadget::generate_r1cs_witness() -{ - is_right.evaluate(this->pb); - - assert(this->pb.lc_val(is_right) == FieldT::one() || this->pb.lc_val(is_right) == FieldT::zero()); - if (this->pb.lc_val(is_right) == FieldT::one()) - { - for (size_t i = 0; i < digest_size; ++i) - { - this->pb.val(right.bits[i]) = this->pb.val(input.bits[i]); - } - } - else - { - for (size_t i = 0; i < digest_size; ++i) - { - this->pb.val(left.bits[i]) = this->pb.val(input.bits[i]); - } - } -} - -} // libsnark - -#endif // DIGEST_SELECTOR_GADGET_TCC_ diff --git a/src/snark/libsnark/gadgetlib1/gadgets/hashes/hash_io.hpp b/src/snark/libsnark/gadgetlib1/gadgets/hashes/hash_io.hpp deleted file mode 100644 index 80ca19c61..000000000 --- a/src/snark/libsnark/gadgetlib1/gadgets/hashes/hash_io.hpp +++ /dev/null @@ -1,63 +0,0 @@ -/** - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ -#ifndef HASH_IO_HPP_ -#define HASH_IO_HPP_ -#include -#include -#include "gadgetlib1/gadgets/basic_gadgets.hpp" - -namespace libsnark { - -template -class digest_variable : public gadget { -public: - size_t digest_size; - pb_variable_array bits; - - digest_variable(protoboard &pb, - const size_t digest_size, - const std::string &annotation_prefix); - - digest_variable(protoboard &pb, - const size_t digest_size, - const pb_variable_array &partial_bits, - const pb_variable &padding, - const std::string &annotation_prefix); - - void generate_r1cs_constraints(); - void generate_r1cs_witness(const bit_vector& contents); - bit_vector get_digest() const; -}; - -template -class block_variable : public gadget { -public: - size_t block_size; - pb_variable_array bits; - - block_variable(protoboard &pb, - const size_t block_size, - const std::string &annotation_prefix); - - block_variable(protoboard &pb, - const std::vector > &parts, - const std::string &annotation_prefix); - - block_variable(protoboard &pb, - const digest_variable &left, - const digest_variable &right, - const std::string &annotation_prefix); - - void generate_r1cs_constraints(); - void generate_r1cs_witness(const bit_vector& contents); - bit_vector get_block() const; -}; - -} // libsnark -#include "gadgetlib1/gadgets/hashes/hash_io.tcc" - -#endif // HASH_IO_HPP_ diff --git a/src/snark/libsnark/gadgetlib1/gadgets/hashes/hash_io.tcc b/src/snark/libsnark/gadgetlib1/gadgets/hashes/hash_io.tcc deleted file mode 100644 index b122d8f98..000000000 --- a/src/snark/libsnark/gadgetlib1/gadgets/hashes/hash_io.tcc +++ /dev/null @@ -1,105 +0,0 @@ -/** - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ -#ifndef HASH_IO_TCC_ -#define HASH_IO_TCC_ - -namespace libsnark { - -template -digest_variable::digest_variable(protoboard &pb, - const size_t digest_size, - const std::string &annotation_prefix) : - gadget(pb, annotation_prefix), digest_size(digest_size) -{ - bits.allocate(pb, digest_size, FMT(this->annotation_prefix, " bits")); -} - -template -digest_variable::digest_variable(protoboard &pb, - const size_t digest_size, - const pb_variable_array &partial_bits, - const pb_variable &padding, - const std::string &annotation_prefix) : - gadget(pb, annotation_prefix), digest_size(digest_size) -{ - assert(bits.size() <= digest_size); - bits = partial_bits; - while (bits.size() != digest_size) - { - bits.emplace_back(padding); - } -} - -template -void digest_variable::generate_r1cs_constraints() -{ - for (size_t i = 0; i < digest_size; ++i) - { - generate_boolean_r1cs_constraint(this->pb, bits[i], FMT(this->annotation_prefix, " bits_%zu", i)); - } -} - -template -void digest_variable::generate_r1cs_witness(const bit_vector& contents) -{ - bits.fill_with_bits(this->pb, contents); -} - -template -bit_vector digest_variable::get_digest() const -{ - return bits.get_bits(this->pb); -} - -template -block_variable::block_variable(protoboard &pb, - const size_t block_size, - const std::string &annotation_prefix) : - gadget(pb, annotation_prefix), block_size(block_size) -{ - bits.allocate(pb, block_size, FMT(this->annotation_prefix, " bits")); -} - -template -block_variable::block_variable(protoboard &pb, - const std::vector > &parts, - const std::string &annotation_prefix) : - gadget(pb, annotation_prefix) -{ - for (auto &part : parts) - { - bits.insert(bits.end(), part.begin(), part.end()); - } -} - -template -block_variable::block_variable(protoboard &pb, - const digest_variable &left, - const digest_variable &right, - const std::string &annotation_prefix) : - gadget(pb, annotation_prefix) -{ - assert(left.bits.size() == right.bits.size()); - block_size = 2 * left.bits.size(); - bits.insert(bits.end(), left.bits.begin(), left.bits.end()); - bits.insert(bits.end(), right.bits.begin(), right.bits.end()); -} - -template -void block_variable::generate_r1cs_witness(const bit_vector& contents) -{ - bits.fill_with_bits(this->pb, contents); -} - -template -bit_vector block_variable::get_block() const -{ - return bits.get_bits(this->pb); -} - -} // libsnark -#endif // HASH_IO_TCC_ diff --git a/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_aux.hpp b/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_aux.hpp deleted file mode 100644 index e0c7a7e0b..000000000 --- a/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_aux.hpp +++ /dev/null @@ -1,160 +0,0 @@ -/** @file - ***************************************************************************** - - Declaration of interfaces for auxiliary gadgets for the SHA256 gadget. - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef SHA256_AUX_HPP_ -#define SHA256_AUX_HPP_ - -#include "gadgetlib1/gadgets/basic_gadgets.hpp" - -namespace libsnark { - -template -class lastbits_gadget : public gadget { -public: - pb_variable X; - size_t X_bits; - pb_variable result; - pb_linear_combination_array result_bits; - - pb_linear_combination_array full_bits; - std::shared_ptr > unpack_bits; - std::shared_ptr > pack_result; - - lastbits_gadget(protoboard &pb, - const pb_variable &X, - const size_t X_bits, - const pb_variable &result, - const pb_linear_combination_array &result_bits, - const std::string &annotation_prefix); - - void generate_r1cs_constraints(); - void generate_r1cs_witness(); -}; - -template -class XOR3_gadget : public gadget { -private: - pb_variable tmp; -public: - pb_linear_combination A; - pb_linear_combination B; - pb_linear_combination C; - bool assume_C_is_zero; - pb_linear_combination out; - - XOR3_gadget(protoboard &pb, - const pb_linear_combination &A, - const pb_linear_combination &B, - const pb_linear_combination &C, - const bool assume_C_is_zero, - const pb_linear_combination &out, - const std::string &annotation_prefix); - - void generate_r1cs_constraints(); - void generate_r1cs_witness(); -}; - -/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */ -template -class small_sigma_gadget : public gadget { -private: - pb_variable_array W; - pb_variable result; -public: - pb_variable_array result_bits; - std::vector > > compute_bits; - std::shared_ptr > pack_result; - - small_sigma_gadget(protoboard &pb, - const pb_variable_array &W, - const pb_variable &result, - const size_t rot1, - const size_t rot2, - const size_t shift, - const std::string &annotation_prefix); - - void generate_r1cs_constraints(); - void generate_r1cs_witness(); -}; - -/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */ -template -class big_sigma_gadget : public gadget { -private: - pb_linear_combination_array W; - pb_variable result; -public: - pb_variable_array result_bits; - std::vector > > compute_bits; - std::shared_ptr > pack_result; - - big_sigma_gadget(protoboard &pb, - const pb_linear_combination_array &W, - const pb_variable &result, - const size_t rot1, - const size_t rot2, - const size_t rot3, - const std::string &annotation_prefix); - - void generate_r1cs_constraints(); - void generate_r1cs_witness(); -}; - -/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */ -template -class choice_gadget : public gadget { -private: - pb_variable_array result_bits; -public: - pb_linear_combination_array X; - pb_linear_combination_array Y; - pb_linear_combination_array Z; - pb_variable result; - std::shared_ptr > pack_result; - - choice_gadget(protoboard &pb, - const pb_linear_combination_array &X, - const pb_linear_combination_array &Y, - const pb_linear_combination_array &Z, - const pb_variable &result, const std::string &annotation_prefix); - - void generate_r1cs_constraints(); - void generate_r1cs_witness(); -}; - -/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */ -template -class majority_gadget : public gadget { -private: - pb_variable_array result_bits; - std::shared_ptr > pack_result; -public: - pb_linear_combination_array X; - pb_linear_combination_array Y; - pb_linear_combination_array Z; - pb_variable result; - - majority_gadget(protoboard &pb, - const pb_linear_combination_array &X, - const pb_linear_combination_array &Y, - const pb_linear_combination_array &Z, - const pb_variable &result, - const std::string &annotation_prefix); - - void generate_r1cs_constraints(); - void generate_r1cs_witness(); -}; - -} // libsnark - -#include "gadgetlib1/gadgets/hashes/sha256/sha256_aux.tcc" - -#endif // SHA256_AUX_HPP_ diff --git a/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_aux.tcc b/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_aux.tcc deleted file mode 100644 index 0885f0b6d..000000000 --- a/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_aux.tcc +++ /dev/null @@ -1,297 +0,0 @@ -/** @file - ***************************************************************************** - - Implementation of interfaces for auxiliary gadgets for the SHA256 gadget. - - See sha256_aux.hpp . - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef SHA256_AUX_TCC_ -#define SHA256_AUX_TCC_ - -namespace libsnark { - -template -lastbits_gadget::lastbits_gadget(protoboard &pb, - const pb_variable &X, - const size_t X_bits, - const pb_variable &result, - const pb_linear_combination_array &result_bits, - const std::string &annotation_prefix) : - gadget(pb, annotation_prefix), - X(X), - X_bits(X_bits), - result(result), - result_bits(result_bits) -{ - full_bits = result_bits; - for (size_t i = result_bits.size(); i < X_bits; ++i) - { - pb_variable full_bits_overflow; - full_bits_overflow.allocate(pb, FMT(this->annotation_prefix, " full_bits_%zu", i)); - full_bits.emplace_back(full_bits_overflow); - } - - unpack_bits.reset(new packing_gadget(pb, full_bits, X, FMT(this->annotation_prefix, " unpack_bits"))); - pack_result.reset(new packing_gadget(pb, result_bits, result, FMT(this->annotation_prefix, " pack_result"))); -} - -template -void lastbits_gadget::generate_r1cs_constraints() -{ - unpack_bits->generate_r1cs_constraints(true); - pack_result->generate_r1cs_constraints(false); -} - -template -void lastbits_gadget::generate_r1cs_witness() -{ - unpack_bits->generate_r1cs_witness_from_packed(); - pack_result->generate_r1cs_witness_from_bits(); -} - -template -XOR3_gadget::XOR3_gadget(protoboard &pb, - const pb_linear_combination &A, - const pb_linear_combination &B, - const pb_linear_combination &C, - const bool assume_C_is_zero, - const pb_linear_combination &out, - const std::string &annotation_prefix) : - gadget(pb, annotation_prefix), - A(A), - B(B), - C(C), - assume_C_is_zero(assume_C_is_zero), - out(out) -{ - if (!assume_C_is_zero) - { - tmp.allocate(pb, FMT(this->annotation_prefix, " tmp")); - } -} - -template -void XOR3_gadget::generate_r1cs_constraints() -{ - /* - tmp = A + B - 2AB i.e. tmp = A xor B - out = tmp + C - 2tmp C i.e. out = tmp xor C - */ - if (assume_C_is_zero) - { - this->pb.add_r1cs_constraint(r1cs_constraint(2*A, B, A + B - out), FMT(this->annotation_prefix, " implicit_tmp_equals_out")); - } - else - { - this->pb.add_r1cs_constraint(r1cs_constraint(2*A, B, A + B - tmp), FMT(this->annotation_prefix, " tmp")); - this->pb.add_r1cs_constraint(r1cs_constraint(2 * tmp, C, tmp + C - out), FMT(this->annotation_prefix, " out")); - } -} - -template -void XOR3_gadget::generate_r1cs_witness() -{ - if (assume_C_is_zero) - { - this->pb.lc_val(out) = this->pb.lc_val(A) + this->pb.lc_val(B) - FieldT(2) * this->pb.lc_val(A) * this->pb.lc_val(B); - } - else - { - this->pb.val(tmp) = this->pb.lc_val(A) + this->pb.lc_val(B) - FieldT(2) * this->pb.lc_val(A) * this->pb.lc_val(B); - this->pb.lc_val(out) = this->pb.val(tmp) + this->pb.lc_val(C) - FieldT(2) * this->pb.val(tmp) * this->pb.lc_val(C); - } -} - -#define SHA256_GADGET_ROTR(A, i, k) A[((i)+(k)) % 32] - -/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */ -template -small_sigma_gadget::small_sigma_gadget(protoboard &pb, - const pb_variable_array &W, - const pb_variable &result, - const size_t rot1, - const size_t rot2, - const size_t shift, - const std::string &annotation_prefix) : - gadget(pb, annotation_prefix), - W(W), - result(result) -{ - result_bits.allocate(pb, 32, FMT(this->annotation_prefix, " result_bits")); - compute_bits.resize(32); - for (size_t i = 0; i < 32; ++i) - { - compute_bits[i].reset(new XOR3_gadget(pb, SHA256_GADGET_ROTR(W, i, rot1), SHA256_GADGET_ROTR(W, i, rot2), - (i + shift < 32 ? W[i+shift] : ONE), - (i + shift >= 32), result_bits[i], - FMT(this->annotation_prefix, " compute_bits_%zu", i))); - } - pack_result.reset(new packing_gadget(pb, result_bits, result, FMT(this->annotation_prefix, " pack_result"))); -} - -template -void small_sigma_gadget::generate_r1cs_constraints() -{ - for (size_t i = 0; i < 32; ++i) - { - compute_bits[i]->generate_r1cs_constraints(); - } - - pack_result->generate_r1cs_constraints(false); -} - -template -void small_sigma_gadget::generate_r1cs_witness() -{ - for (size_t i = 0; i < 32; ++i) - { - compute_bits[i]->generate_r1cs_witness(); - } - - pack_result->generate_r1cs_witness_from_bits(); -} - -template -big_sigma_gadget::big_sigma_gadget(protoboard &pb, - const pb_linear_combination_array &W, - const pb_variable &result, - const size_t rot1, - const size_t rot2, - const size_t rot3, - const std::string &annotation_prefix) : - gadget(pb, annotation_prefix), - W(W), - result(result) -{ - result_bits.allocate(pb, 32, FMT(this->annotation_prefix, " result_bits")); - compute_bits.resize(32); - for (size_t i = 0; i < 32; ++i) - { - compute_bits[i].reset(new XOR3_gadget(pb, SHA256_GADGET_ROTR(W, i, rot1), SHA256_GADGET_ROTR(W, i, rot2), SHA256_GADGET_ROTR(W, i, rot3), false, result_bits[i], - FMT(this->annotation_prefix, " compute_bits_%zu", i))); - } - - pack_result.reset(new packing_gadget(pb, result_bits, result, FMT(this->annotation_prefix, " pack_result"))); -} - -template -void big_sigma_gadget::generate_r1cs_constraints() -{ - for (size_t i = 0; i < 32; ++i) - { - compute_bits[i]->generate_r1cs_constraints(); - } - - pack_result->generate_r1cs_constraints(false); -} - -template -void big_sigma_gadget::generate_r1cs_witness() -{ - for (size_t i = 0; i < 32; ++i) - { - compute_bits[i]->generate_r1cs_witness(); - } - - pack_result->generate_r1cs_witness_from_bits(); -} - -/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */ -template -choice_gadget::choice_gadget(protoboard &pb, - const pb_linear_combination_array &X, - const pb_linear_combination_array &Y, - const pb_linear_combination_array &Z, - const pb_variable &result, const std::string &annotation_prefix) : - gadget(pb, annotation_prefix), - X(X), - Y(Y), - Z(Z), - result(result) -{ - result_bits.allocate(pb, 32, FMT(this->annotation_prefix, " result_bits")); - pack_result.reset(new packing_gadget(pb, result_bits, result, FMT(this->annotation_prefix, " result"))); -} - -template -void choice_gadget::generate_r1cs_constraints() -{ - for (size_t i = 0; i < 32; ++i) - { - /* - result = x * y + (1-x) * z - result - z = x * (y - z) - */ - this->pb.add_r1cs_constraint(r1cs_constraint(X[i], Y[i] - Z[i], result_bits[i] - Z[i]), FMT(this->annotation_prefix, " result_bits_%zu", i)); - } - pack_result->generate_r1cs_constraints(false); -} - -template -void choice_gadget::generate_r1cs_witness() -{ - for (size_t i = 0; i < 32; ++i) - { - this->pb.val(result_bits[i]) = this->pb.lc_val(X[i]) * this->pb.lc_val(Y[i]) + (FieldT::one() - this->pb.lc_val(X[i])) * this->pb.lc_val(Z[i]); - } - pack_result->generate_r1cs_witness_from_bits(); -} - -/* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */ -template -majority_gadget::majority_gadget(protoboard &pb, - const pb_linear_combination_array &X, - const pb_linear_combination_array &Y, - const pb_linear_combination_array &Z, - const pb_variable &result, - const std::string &annotation_prefix) : - gadget(pb, annotation_prefix), - X(X), - Y(Y), - Z(Z), - result(result) -{ - result_bits.allocate(pb, 32, FMT(this->annotation_prefix, " result_bits")); - pack_result.reset(new packing_gadget(pb, result_bits, result, FMT(this->annotation_prefix, " result"))); -} - -template -void majority_gadget::generate_r1cs_constraints() -{ - for (size_t i = 0; i < 32; ++i) - { - /* - 2*result + aux = x + y + z - x, y, z, aux -- bits - aux = x + y + z - 2*result - */ - generate_boolean_r1cs_constraint(this->pb, result_bits[i], FMT(this->annotation_prefix, " result_%zu", i)); - this->pb.add_r1cs_constraint(r1cs_constraint(X[i] + Y[i] + Z[i] - 2 * result_bits[i], - 1 - (X[i] + Y[i] + Z[i] - 2 * result_bits[i]), - 0), - FMT(this->annotation_prefix, " result_bits_%zu", i)); - } - pack_result->generate_r1cs_constraints(false); -} - -template -void majority_gadget::generate_r1cs_witness() -{ - for (size_t i = 0; i < 32; ++i) - { - const uint64_t v = (this->pb.lc_val(X[i]) + this->pb.lc_val(Y[i]) + this->pb.lc_val(Z[i])).as_uint64(); - this->pb.val(result_bits[i]) = FieldT(v / 2); - } - - pack_result->generate_r1cs_witness_from_bits(); -} - -} // libsnark - -#endif // SHA256_AUX_TCC_ diff --git a/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_components.hpp b/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_components.hpp deleted file mode 100644 index 2f7e71e35..000000000 --- a/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_components.hpp +++ /dev/null @@ -1,108 +0,0 @@ -/** @file - ***************************************************************************** - - Declaration of interfaces for gadgets for the SHA256 message schedule and round function. - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef SHA256_COMPONENTS_HPP_ -#define SHA256_COMPONENTS_HPP_ - -#include "gadgetlib1/gadgets/basic_gadgets.hpp" -#include "gadgetlib1/gadgets/hashes/hash_io.hpp" -#include "gadgetlib1/gadgets/hashes/sha256/sha256_aux.hpp" - -namespace libsnark { - -const size_t SHA256_digest_size = 256; -const size_t SHA256_block_size = 512; - -template -pb_linear_combination_array SHA256_default_IV(protoboard &pb); - -template -class sha256_message_schedule_gadget : public gadget { -public: - std::vector > W_bits; - std::vector > > pack_W; - - std::vector > sigma0; - std::vector > sigma1; - std::vector > > compute_sigma0; - std::vector > > compute_sigma1; - std::vector > unreduced_W; - std::vector > > mod_reduce_W; -public: - pb_variable_array M; - pb_variable_array packed_W; - sha256_message_schedule_gadget(protoboard &pb, - const pb_variable_array &M, - const pb_variable_array &packed_W, - const std::string &annotation_prefix); - void generate_r1cs_constraints(); - void generate_r1cs_witness(); -}; - -template -class sha256_round_function_gadget : public gadget { -public: - pb_variable sigma0; - pb_variable sigma1; - std::shared_ptr > compute_sigma0; - std::shared_ptr > compute_sigma1; - pb_variable choice; - pb_variable majority; - std::shared_ptr > compute_choice; - std::shared_ptr > compute_majority; - pb_variable packed_d; - std::shared_ptr > pack_d; - pb_variable packed_h; - std::shared_ptr > pack_h; - pb_variable unreduced_new_a; - pb_variable unreduced_new_e; - std::shared_ptr > mod_reduce_new_a; - std::shared_ptr > mod_reduce_new_e; - pb_variable packed_new_a; - pb_variable packed_new_e; -public: - pb_linear_combination_array a; - pb_linear_combination_array b; - pb_linear_combination_array c; - pb_linear_combination_array d; - pb_linear_combination_array e; - pb_linear_combination_array f; - pb_linear_combination_array g; - pb_linear_combination_array h; - pb_variable W; - uint32_t K; - pb_linear_combination_array new_a; - pb_linear_combination_array new_e; - - sha256_round_function_gadget(protoboard &pb, - const pb_linear_combination_array &a, - const pb_linear_combination_array &b, - const pb_linear_combination_array &c, - const pb_linear_combination_array &d, - const pb_linear_combination_array &e, - const pb_linear_combination_array &f, - const pb_linear_combination_array &g, - const pb_linear_combination_array &h, - const pb_variable &W, - const uint32_t &K, - const pb_linear_combination_array &new_a, - const pb_linear_combination_array &new_e, - const std::string &annotation_prefix); - - void generate_r1cs_constraints(); - void generate_r1cs_witness(); -}; - -} // libsnark - -#include "gadgetlib1/gadgets/hashes/sha256/sha256_components.tcc" - -#endif // SHA256_COMPONENTS_HPP_ diff --git a/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_components.tcc b/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_components.tcc deleted file mode 100644 index 41ad20883..000000000 --- a/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_components.tcc +++ /dev/null @@ -1,250 +0,0 @@ -/** @file - ***************************************************************************** - - Implementation of interfaces for gadgets for the SHA256 message schedule and round function. - - See sha256_components.hpp . - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef SHA256_COMPONENTS_TCC_ -#define SHA256_COMPONENTS_TCC_ - -namespace libsnark { - -const uint32_t SHA256_K[64] = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 -}; - -const uint32_t SHA256_H[8] = { - 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 -}; - -template -pb_linear_combination_array SHA256_default_IV(protoboard &pb) -{ - pb_linear_combination_array result; - result.reserve(SHA256_digest_size); - - for (size_t i = 0; i < SHA256_digest_size; ++i) - { - int iv_val = (SHA256_H[i / 32] >> (31-(i % 32))) & 1; - - pb_linear_combination iv_element; - iv_element.assign(pb, iv_val * ONE); - iv_element.evaluate(pb); - - result.emplace_back(iv_element); - } - - return result; -} - -template -sha256_message_schedule_gadget::sha256_message_schedule_gadget(protoboard &pb, - const pb_variable_array &M, - const pb_variable_array &packed_W, - const std::string &annotation_prefix) : - gadget(pb, annotation_prefix), - M(M), - packed_W(packed_W) -{ - W_bits.resize(64); - - pack_W.resize(16); - for (size_t i = 0; i < 16; ++i) - { - W_bits[i] = pb_variable_array(M.rbegin() + (15-i) * 32, M.rbegin() + (16-i) * 32); - pack_W[i].reset(new packing_gadget(pb, W_bits[i], packed_W[i], FMT(this->annotation_prefix, " pack_W_%zu", i))); - } - - /* NB: some of those will be un-allocated */ - sigma0.resize(64); - sigma1.resize(64); - compute_sigma0.resize(64); - compute_sigma1.resize(64); - unreduced_W.resize(64); - mod_reduce_W.resize(64); - - for (size_t i = 16; i < 64; ++i) - { - /* allocate result variables for sigma0/sigma1 invocations */ - sigma0[i].allocate(pb, FMT(this->annotation_prefix, " sigma0_%zu", i)); - sigma1[i].allocate(pb, FMT(this->annotation_prefix, " sigma1_%zu", i)); - - /* compute sigma0/sigma1 */ - compute_sigma0[i].reset(new small_sigma_gadget(pb, W_bits[i-15], sigma0[i], 7, 18, 3, FMT(this->annotation_prefix, " compute_sigma0_%zu", i))); - compute_sigma1[i].reset(new small_sigma_gadget(pb, W_bits[i-2], sigma1[i], 17, 19, 10, FMT(this->annotation_prefix, " compute_sigma1_%zu", i))); - - /* unreduced_W = sigma0(W_{i-15}) + sigma1(W_{i-2}) + W_{i-7} + W_{i-16} before modulo 2^32 */ - unreduced_W[i].allocate(pb, FMT(this->annotation_prefix, "unreduced_W_%zu", i)); - - /* allocate the bit representation of packed_W[i] */ - W_bits[i].allocate(pb, 32, FMT(this->annotation_prefix, " W_bits_%zu", i)); - - /* and finally reduce this into packed and bit representations */ - mod_reduce_W[i].reset(new lastbits_gadget(pb, unreduced_W[i], 32+2, packed_W[i], W_bits[i], FMT(this->annotation_prefix, " mod_reduce_W_%zu", i))); - } -} - -template -void sha256_message_schedule_gadget::generate_r1cs_constraints() -{ - for (size_t i = 0; i < 16; ++i) - { - pack_W[i]->generate_r1cs_constraints(false); // do not enforce bitness here; caller be aware. - } - - for (size_t i = 16; i < 64; ++i) - { - compute_sigma0[i]->generate_r1cs_constraints(); - compute_sigma1[i]->generate_r1cs_constraints(); - - this->pb.add_r1cs_constraint(r1cs_constraint(1, - sigma0[i] + sigma1[i] + packed_W[i-16] + packed_W[i-7], - unreduced_W[i]), - FMT(this->annotation_prefix, " unreduced_W_%zu", i)); - - mod_reduce_W[i]->generate_r1cs_constraints(); - } -} - -template -void sha256_message_schedule_gadget::generate_r1cs_witness() -{ - for (size_t i = 0; i < 16; ++i) - { - pack_W[i]->generate_r1cs_witness_from_bits(); - } - - for (size_t i = 16; i < 64; ++i) - { - compute_sigma0[i]->generate_r1cs_witness(); - compute_sigma1[i]->generate_r1cs_witness(); - - this->pb.val(unreduced_W[i]) = this->pb.val(sigma0[i]) + this->pb.val(sigma1[i]) + this->pb.val(packed_W[i-16]) + this->pb.val(packed_W[i-7]); - mod_reduce_W[i]->generate_r1cs_witness(); - } -} - -template -sha256_round_function_gadget::sha256_round_function_gadget(protoboard &pb, - const pb_linear_combination_array &a, - const pb_linear_combination_array &b, - const pb_linear_combination_array &c, - const pb_linear_combination_array &d, - const pb_linear_combination_array &e, - const pb_linear_combination_array &f, - const pb_linear_combination_array &g, - const pb_linear_combination_array &h, - const pb_variable &W, - const uint32_t &K, - const pb_linear_combination_array &new_a, - const pb_linear_combination_array &new_e, - const std::string &annotation_prefix) : - gadget(pb, annotation_prefix), - a(a), - b(b), - c(c), - d(d), - e(e), - f(f), - g(g), - h(h), - W(W), - K(K), - new_a(new_a), - new_e(new_e) -{ - /* compute sigma0 and sigma1 */ - sigma0.allocate(pb, FMT(this->annotation_prefix, " sigma0")); - sigma1.allocate(pb, FMT(this->annotation_prefix, " sigma1")); - compute_sigma0.reset(new big_sigma_gadget(pb, a, sigma0, 2, 13, 22, FMT(this->annotation_prefix, " compute_sigma0"))); - compute_sigma1.reset(new big_sigma_gadget(pb, e, sigma1, 6, 11, 25, FMT(this->annotation_prefix, " compute_sigma1"))); - - /* compute choice */ - choice.allocate(pb, FMT(this->annotation_prefix, " choice")); - compute_choice.reset(new choice_gadget(pb, e, f, g, choice, FMT(this->annotation_prefix, " compute_choice"))); - - /* compute majority */ - majority.allocate(pb, FMT(this->annotation_prefix, " majority")); - compute_majority.reset(new majority_gadget(pb, a, b, c, majority, FMT(this->annotation_prefix, " compute_majority"))); - - /* pack d */ - packed_d.allocate(pb, FMT(this->annotation_prefix, " packed_d")); - pack_d.reset(new packing_gadget(pb, d, packed_d, FMT(this->annotation_prefix, " pack_d"))); - - /* pack h */ - packed_h.allocate(pb, FMT(this->annotation_prefix, " packed_h")); - pack_h.reset(new packing_gadget(pb, h, packed_h, FMT(this->annotation_prefix, " pack_h"))); - - /* compute the actual results for the round */ - unreduced_new_a.allocate(pb, FMT(this->annotation_prefix, " unreduced_new_a")); - unreduced_new_e.allocate(pb, FMT(this->annotation_prefix, " unreduced_new_e")); - - packed_new_a.allocate(pb, FMT(this->annotation_prefix, " packed_new_a")); - packed_new_e.allocate(pb, FMT(this->annotation_prefix, " packed_new_e")); - - mod_reduce_new_a.reset(new lastbits_gadget(pb, unreduced_new_a, 32+3, packed_new_a, new_a, FMT(this->annotation_prefix, " mod_reduce_new_a"))); - mod_reduce_new_e.reset(new lastbits_gadget(pb, unreduced_new_e, 32+3, packed_new_e, new_e, FMT(this->annotation_prefix, " mod_reduce_new_e"))); -} - -template -void sha256_round_function_gadget::generate_r1cs_constraints() -{ - compute_sigma0->generate_r1cs_constraints(); - compute_sigma1->generate_r1cs_constraints(); - - compute_choice->generate_r1cs_constraints(); - compute_majority->generate_r1cs_constraints(); - - pack_d->generate_r1cs_constraints(false); - pack_h->generate_r1cs_constraints(false); - - this->pb.add_r1cs_constraint(r1cs_constraint(1, - packed_h + sigma1 + choice + K + W + sigma0 + majority, - unreduced_new_a), - FMT(this->annotation_prefix, " unreduced_new_a")); - - this->pb.add_r1cs_constraint(r1cs_constraint(1, - packed_d + packed_h + sigma1 + choice + K + W, - unreduced_new_e), - FMT(this->annotation_prefix, " unreduced_new_e")); - - mod_reduce_new_a->generate_r1cs_constraints(); - mod_reduce_new_e->generate_r1cs_constraints(); -} - -template -void sha256_round_function_gadget::generate_r1cs_witness() -{ - compute_sigma0->generate_r1cs_witness(); - compute_sigma1->generate_r1cs_witness(); - - compute_choice->generate_r1cs_witness(); - compute_majority->generate_r1cs_witness(); - - pack_d->generate_r1cs_witness_from_bits(); - pack_h->generate_r1cs_witness_from_bits(); - - this->pb.val(unreduced_new_a) = this->pb.val(packed_h) + this->pb.val(sigma1) + this->pb.val(choice) + FieldT(K) + this->pb.val(W) + this->pb.val(sigma0) + this->pb.val(majority); - this->pb.val(unreduced_new_e) = this->pb.val(packed_d) + this->pb.val(packed_h) + this->pb.val(sigma1) + this->pb.val(choice) + FieldT(K) + this->pb.val(W); - - mod_reduce_new_a->generate_r1cs_witness(); - mod_reduce_new_e->generate_r1cs_witness(); -} - -} // libsnark - -#endif // SHA256_COMPONENTS_TCC_ diff --git a/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp b/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp deleted file mode 100644 index 8cb6365c8..000000000 --- a/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp +++ /dev/null @@ -1,98 +0,0 @@ -/** @file - ***************************************************************************** - - Declaration of interfaces for top-level SHA256 gadgets. - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef SHA256_GADGET_HPP_ -#define SHA256_GADGET_HPP_ - -#include "common/data_structures/merkle_tree.hpp" -#include "gadgetlib1/gadgets/basic_gadgets.hpp" -#include "gadgetlib1/gadgets/hashes/hash_io.hpp" -#include "gadgetlib1/gadgets/hashes/sha256/sha256_components.hpp" - -namespace libsnark { - -/** - * Gadget for the SHA256 compression function. - */ -template -class sha256_compression_function_gadget : public gadget { -public: - std::vector > round_a; - std::vector > round_b; - std::vector > round_c; - std::vector > round_d; - std::vector > round_e; - std::vector > round_f; - std::vector > round_g; - std::vector > round_h; - - pb_variable_array packed_W; - std::shared_ptr > message_schedule; - std::vector > round_functions; - - pb_variable_array unreduced_output; - pb_variable_array reduced_output; - std::vector > reduce_output; -public: - pb_linear_combination_array prev_output; - pb_variable_array new_block; - digest_variable output; - - sha256_compression_function_gadget(protoboard &pb, - const pb_linear_combination_array &prev_output, - const pb_variable_array &new_block, - const digest_variable &output, - const std::string &annotation_prefix); - void generate_r1cs_constraints(); - void generate_r1cs_witness(); -}; - -/** - * Gadget for the SHA256 compression function, viewed as a 2-to-1 hash - * function, and using the same initialization vector as in SHA256 - * specification. Thus, any collision for - * sha256_two_to_one_hash_gadget trivially extends to a collision for - * full SHA256 (by appending the same padding). - */ -template -class sha256_two_to_one_hash_gadget : public gadget { -public: - typedef bit_vector hash_value_type; - typedef merkle_authentication_path merkle_authentication_path_type; - - std::shared_ptr > f; - - sha256_two_to_one_hash_gadget(protoboard &pb, - const digest_variable &left, - const digest_variable &right, - const digest_variable &output, - const std::string &annotation_prefix); - sha256_two_to_one_hash_gadget(protoboard &pb, - const size_t block_length, - const block_variable &input_block, - const digest_variable &output, - const std::string &annotation_prefix); - - void generate_r1cs_constraints(const bool ensure_output_bitness=true); // TODO: ignored for now - void generate_r1cs_witness(); - - static size_t get_block_len(); - static size_t get_digest_len(); - static bit_vector get_hash(const bit_vector &input); - - static size_t expected_constraints(const bool ensure_output_bitness=true); // TODO: ignored for now -}; - -} // libsnark - -#include "gadgetlib1/gadgets/hashes/sha256/sha256_gadget.tcc" - -#endif // SHA256_GADGET_HPP_ diff --git a/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.tcc b/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.tcc deleted file mode 100644 index 3004f9e83..000000000 --- a/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/sha256_gadget.tcc +++ /dev/null @@ -1,230 +0,0 @@ -/** @file - ***************************************************************************** - - Implementation of interfaces for top-level SHA256 gadgets. - - See sha256_gadget.hpp . - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef SHA256_GADGET_TCC_ -#define SHA256_GADGET_TCC_ - -namespace libsnark { - -template -sha256_compression_function_gadget::sha256_compression_function_gadget(protoboard &pb, - const pb_linear_combination_array &prev_output, - const pb_variable_array &new_block, - const digest_variable &output, - const std::string &annotation_prefix) : - gadget(pb, annotation_prefix), - prev_output(prev_output), - new_block(new_block), - output(output) -{ - /* message schedule and inputs for it */ - packed_W.allocate(pb, 64, FMT(this->annotation_prefix, " packed_W")); - message_schedule.reset(new sha256_message_schedule_gadget(pb, new_block, packed_W, FMT(this->annotation_prefix, " message_schedule"))); - - /* initalize */ - round_a.push_back(pb_linear_combination_array(prev_output.rbegin() + 7*32, prev_output.rbegin() + 8*32)); - round_b.push_back(pb_linear_combination_array(prev_output.rbegin() + 6*32, prev_output.rbegin() + 7*32)); - round_c.push_back(pb_linear_combination_array(prev_output.rbegin() + 5*32, prev_output.rbegin() + 6*32)); - round_d.push_back(pb_linear_combination_array(prev_output.rbegin() + 4*32, prev_output.rbegin() + 5*32)); - round_e.push_back(pb_linear_combination_array(prev_output.rbegin() + 3*32, prev_output.rbegin() + 4*32)); - round_f.push_back(pb_linear_combination_array(prev_output.rbegin() + 2*32, prev_output.rbegin() + 3*32)); - round_g.push_back(pb_linear_combination_array(prev_output.rbegin() + 1*32, prev_output.rbegin() + 2*32)); - round_h.push_back(pb_linear_combination_array(prev_output.rbegin() + 0*32, prev_output.rbegin() + 1*32)); - - /* do the rounds */ - for (size_t i = 0; i < 64; ++i) - { - round_h.push_back(round_g[i]); - round_g.push_back(round_f[i]); - round_f.push_back(round_e[i]); - round_d.push_back(round_c[i]); - round_c.push_back(round_b[i]); - round_b.push_back(round_a[i]); - - pb_variable_array new_round_a_variables; - new_round_a_variables.allocate(pb, 32, FMT(this->annotation_prefix, " new_round_a_variables_%zu", i+1)); - round_a.emplace_back(new_round_a_variables); - - pb_variable_array new_round_e_variables; - new_round_e_variables.allocate(pb, 32, FMT(this->annotation_prefix, " new_round_e_variables_%zu", i+1)); - round_e.emplace_back(new_round_e_variables); - - round_functions.push_back(sha256_round_function_gadget(pb, - round_a[i], round_b[i], round_c[i], round_d[i], - round_e[i], round_f[i], round_g[i], round_h[i], - packed_W[i], SHA256_K[i], round_a[i+1], round_e[i+1], - FMT(this->annotation_prefix, " round_functions_%zu", i))); - } - - /* finalize */ - unreduced_output.allocate(pb, 8, FMT(this->annotation_prefix, " unreduced_output")); - reduced_output.allocate(pb, 8, FMT(this->annotation_prefix, " reduced_output")); - for (size_t i = 0; i < 8; ++i) - { - reduce_output.push_back(lastbits_gadget(pb, - unreduced_output[i], - 32+1, - reduced_output[i], - pb_variable_array(output.bits.rbegin() + (7-i) * 32, output.bits.rbegin() + (8-i) * 32), - FMT(this->annotation_prefix, " reduce_output_%zu", i))); - } -} - -template -void sha256_compression_function_gadget::generate_r1cs_constraints() -{ - message_schedule->generate_r1cs_constraints(); - for (size_t i = 0; i < 64; ++i) - { - round_functions[i].generate_r1cs_constraints(); - } - - for (size_t i = 0; i < 4; ++i) - { - this->pb.add_r1cs_constraint(r1cs_constraint(1, - round_functions[3-i].packed_d + round_functions[63-i].packed_new_a, - unreduced_output[i]), - FMT(this->annotation_prefix, " unreduced_output_%zu", i)); - - this->pb.add_r1cs_constraint(r1cs_constraint(1, - round_functions[3-i].packed_h + round_functions[63-i].packed_new_e, - unreduced_output[4+i]), - FMT(this->annotation_prefix, " unreduced_output_%zu", 4+i)); - } - - for (size_t i = 0; i < 8; ++i) - { - reduce_output[i].generate_r1cs_constraints(); - } -} - -template -void sha256_compression_function_gadget::generate_r1cs_witness() -{ - message_schedule->generate_r1cs_witness(); - -#ifdef DEBUG - printf("Input:\n"); - for (size_t j = 0; j < 16; ++j) - { - printf("%lx ", this->pb.val(packed_W[j]).as_uint64()); - } - printf("\n"); -#endif - - for (size_t i = 0; i < 64; ++i) - { - round_functions[i].generate_r1cs_witness(); - } - - for (size_t i = 0; i < 4; ++i) - { - this->pb.val(unreduced_output[i]) = this->pb.val(round_functions[3-i].packed_d) + this->pb.val(round_functions[63-i].packed_new_a); - this->pb.val(unreduced_output[4+i]) = this->pb.val(round_functions[3-i].packed_h) + this->pb.val(round_functions[63-i].packed_new_e); - } - - for (size_t i = 0; i < 8; ++i) - { - reduce_output[i].generate_r1cs_witness(); - } - -#ifdef DEBUG - printf("Output:\n"); - for (size_t j = 0; j < 8; ++j) - { - printf("%lx ", this->pb.val(reduced_output[j]).as_uint64()); - } - printf("\n"); -#endif -} - -template -sha256_two_to_one_hash_gadget::sha256_two_to_one_hash_gadget(protoboard &pb, - const digest_variable &left, - const digest_variable &right, - const digest_variable &output, - const std::string &annotation_prefix) : - gadget(pb, annotation_prefix) -{ - /* concatenate block = left || right */ - pb_variable_array block; - block.insert(block.end(), left.bits.begin(), left.bits.end()); - block.insert(block.end(), right.bits.begin(), right.bits.end()); - - /* compute the hash itself */ - f.reset(new sha256_compression_function_gadget(pb, SHA256_default_IV(pb), block, output, FMT(this->annotation_prefix, " f"))); -} - -template -sha256_two_to_one_hash_gadget::sha256_two_to_one_hash_gadget(protoboard &pb, - const size_t block_length, - const block_variable &input_block, - const digest_variable &output, - const std::string &annotation_prefix) : - gadget(pb, annotation_prefix) -{ - assert(block_length == SHA256_block_size); - assert(input_block.bits.size() == block_length); - f.reset(new sha256_compression_function_gadget(pb, SHA256_default_IV(pb), input_block.bits, output, FMT(this->annotation_prefix, " f"))); -} - -template -void sha256_two_to_one_hash_gadget::generate_r1cs_constraints(const bool ensure_output_bitness) -{ - UNUSED(ensure_output_bitness); - f->generate_r1cs_constraints(); -} - -template -void sha256_two_to_one_hash_gadget::generate_r1cs_witness() -{ - f->generate_r1cs_witness(); -} - -template -size_t sha256_two_to_one_hash_gadget::get_block_len() -{ - return SHA256_block_size; -} - -template -size_t sha256_two_to_one_hash_gadget::get_digest_len() -{ - return SHA256_digest_size; -} - -template -bit_vector sha256_two_to_one_hash_gadget::get_hash(const bit_vector &input) -{ - protoboard pb; - - block_variable input_variable(pb, SHA256_block_size, "input"); - digest_variable output_variable(pb, SHA256_digest_size, "output"); - sha256_two_to_one_hash_gadget f(pb, SHA256_block_size, input_variable, output_variable, "f"); - - input_variable.generate_r1cs_witness(input); - f.generate_r1cs_witness(); - - return output_variable.get_digest(); -} - -template -size_t sha256_two_to_one_hash_gadget::expected_constraints(const bool ensure_output_bitness) -{ - UNUSED(ensure_output_bitness); - return 27280; /* hardcoded for now */ -} - -} // libsnark - -#endif // SHA256_GADGET_TCC_ diff --git a/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/tests/generate_sha256_gadget_tests.py b/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/tests/generate_sha256_gadget_tests.py deleted file mode 100644 index 452317ffb..000000000 --- a/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/tests/generate_sha256_gadget_tests.py +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env python -## -# @author This file is part of libsnark, developed by SCIPR Lab -# and contributors (see AUTHORS). -# @copyright MIT license (see LICENSE file) - -import random -import pypy_sha256 # PyPy's implementation of SHA256 compression function; see copyright and authorship notice within. - -BLOCK_LEN = 512 -BLOCK_BYTES = BLOCK_LEN // 8 -HASH_LEN = 256 -HASH_BYTES = HASH_LEN // 8 - -def gen_random_bytes(n): - return [random.randint(0, 255) for i in xrange(n)] - -def words_to_bytes(arr): - return sum(([x >> 24, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff] for x in arr), []) - -def bytes_to_words(arr): - l = len(arr) - assert l % 4 == 0 - return [(arr[i*4 + 3] << 24) + (arr[i*4+2] << 16) + (arr[i*4+1] << 8) + arr[i*4] for i in xrange(l//4)] - -def cpp_val(s, log_radix=32): - if log_radix == 8: - hexfmt = '0x%02x' - elif log_radix == 32: - hexfmt = '0x%08x' - s = bytes_to_words(s) - else: - raise - return 'int_list_to_bits({%s}, %d)' % (', '.join(hexfmt % x for x in s), log_radix) - -def H_bytes(x): - assert len(x) == BLOCK_BYTES - state = pypy_sha256.sha_init() - state['data'] = words_to_bytes(bytes_to_words(x)) - pypy_sha256.sha_transform(state) - return words_to_bytes(bytes_to_words(words_to_bytes(state['digest']))) - -def generate_sha256_gadget_tests(): - left = gen_random_bytes(HASH_BYTES) - right = gen_random_bytes(HASH_BYTES) - hash = H_bytes(left + right) - - print "const bit_vector left_bv = %s;" % cpp_val(left) - print "const bit_vector right_bv = %s;" % cpp_val(right) - print "const bit_vector hash_bv = %s;" % cpp_val(hash) - -if __name__ == '__main__': - random.seed(0) # for reproducibility - generate_sha256_gadget_tests() - diff --git a/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/tests/pypy_sha256.py b/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/tests/pypy_sha256.py deleted file mode 100644 index 496989c11..000000000 --- a/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/tests/pypy_sha256.py +++ /dev/null @@ -1,263 +0,0 @@ -#!/usr/bin/env python -# -# SHA256 compression function implementation below is a verbatim copy of PyPy's implementation from -# https://bitbucket.org/pypy/pypy/raw/f1f064b3faf1e012f7a9a9ab08f18074637ebe8a/lib_pypy/_sha256.py . -# -# It is licensed under the MIT license and copyright PyPy Copyright holders 2003-2015 -# See https://bitbucket.org/pypy/pypy/src/tip/LICENSE for the full copyright notice. -# - -SHA_BLOCKSIZE = 64 -SHA_DIGESTSIZE = 32 - - -def new_shaobject(): - return { - 'digest': [0]*8, - 'count_lo': 0, - 'count_hi': 0, - 'data': [0]* SHA_BLOCKSIZE, - 'local': 0, - 'digestsize': 0 - } - -ROR = lambda x, y: (((x & 0xffffffff) >> (y & 31)) | (x << (32 - (y & 31)))) & 0xffffffff -Ch = lambda x, y, z: (z ^ (x & (y ^ z))) -Maj = lambda x, y, z: (((x | y) & z) | (x & y)) -S = lambda x, n: ROR(x, n) -R = lambda x, n: (x & 0xffffffff) >> n -Sigma0 = lambda x: (S(x, 2) ^ S(x, 13) ^ S(x, 22)) -Sigma1 = lambda x: (S(x, 6) ^ S(x, 11) ^ S(x, 25)) -Gamma0 = lambda x: (S(x, 7) ^ S(x, 18) ^ R(x, 3)) -Gamma1 = lambda x: (S(x, 17) ^ S(x, 19) ^ R(x, 10)) - -def sha_transform(sha_info): - W = [] - - d = sha_info['data'] - for i in range(0,16): - W.append( (d[4*i]<<24) + (d[4*i+1]<<16) + (d[4*i+2]<<8) + d[4*i+3]) - - for i in range(16,64): - W.append( (Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]) & 0xffffffff ) - - ss = sha_info['digest'][:] - - def RND(a,b,c,d,e,f,g,h,i,ki): - t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; - t1 = Sigma0(a) + Maj(a, b, c); - d += t0; - h = t0 + t1; - return d & 0xffffffff, h & 0xffffffff - - ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],0,0x428a2f98); - ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],1,0x71374491); - ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],2,0xb5c0fbcf); - ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],3,0xe9b5dba5); - ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],4,0x3956c25b); - ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],5,0x59f111f1); - ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],6,0x923f82a4); - ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],7,0xab1c5ed5); - ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],8,0xd807aa98); - ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],9,0x12835b01); - ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],10,0x243185be); - ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],11,0x550c7dc3); - ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],12,0x72be5d74); - ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],13,0x80deb1fe); - ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],14,0x9bdc06a7); - ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],15,0xc19bf174); - ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],16,0xe49b69c1); - ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],17,0xefbe4786); - ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],18,0x0fc19dc6); - ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],19,0x240ca1cc); - ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],20,0x2de92c6f); - ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],21,0x4a7484aa); - ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],22,0x5cb0a9dc); - ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],23,0x76f988da); - ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],24,0x983e5152); - ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],25,0xa831c66d); - ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],26,0xb00327c8); - ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],27,0xbf597fc7); - ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],28,0xc6e00bf3); - ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],29,0xd5a79147); - ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],30,0x06ca6351); - ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],31,0x14292967); - ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],32,0x27b70a85); - ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],33,0x2e1b2138); - ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],34,0x4d2c6dfc); - ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],35,0x53380d13); - ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],36,0x650a7354); - ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],37,0x766a0abb); - ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],38,0x81c2c92e); - ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],39,0x92722c85); - ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],40,0xa2bfe8a1); - ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],41,0xa81a664b); - ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],42,0xc24b8b70); - ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],43,0xc76c51a3); - ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],44,0xd192e819); - ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],45,0xd6990624); - ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],46,0xf40e3585); - ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],47,0x106aa070); - ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],48,0x19a4c116); - ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],49,0x1e376c08); - ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],50,0x2748774c); - ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],51,0x34b0bcb5); - ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],52,0x391c0cb3); - ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],53,0x4ed8aa4a); - ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],54,0x5b9cca4f); - ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],55,0x682e6ff3); - ss[3], ss[7] = RND(ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],56,0x748f82ee); - ss[2], ss[6] = RND(ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],57,0x78a5636f); - ss[1], ss[5] = RND(ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],ss[5],58,0x84c87814); - ss[0], ss[4] = RND(ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],ss[4],59,0x8cc70208); - ss[7], ss[3] = RND(ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],ss[3],60,0x90befffa); - ss[6], ss[2] = RND(ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],ss[2],61,0xa4506ceb); - ss[5], ss[1] = RND(ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],ss[1],62,0xbef9a3f7); - ss[4], ss[0] = RND(ss[1],ss[2],ss[3],ss[4],ss[5],ss[6],ss[7],ss[0],63,0xc67178f2); - - dig = [] - for i, x in enumerate(sha_info['digest']): - dig.append( (x + ss[i]) & 0xffffffff ) - sha_info['digest'] = dig - -def sha_init(): - sha_info = new_shaobject() - sha_info['digest'] = [0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19] - sha_info['count_lo'] = 0 - sha_info['count_hi'] = 0 - sha_info['local'] = 0 - sha_info['digestsize'] = 32 - return sha_info - -def sha224_init(): - sha_info = new_shaobject() - sha_info['digest'] = [0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4] - sha_info['count_lo'] = 0 - sha_info['count_hi'] = 0 - sha_info['local'] = 0 - sha_info['digestsize'] = 28 - return sha_info - -def sha_update(sha_info, buffer): - if isinstance(buffer, str): - raise TypeError("Unicode strings must be encoded before hashing") - count = len(buffer) - buffer_idx = 0 - clo = (sha_info['count_lo'] + (count << 3)) & 0xffffffff - if clo < sha_info['count_lo']: - sha_info['count_hi'] += 1 - sha_info['count_lo'] = clo - - sha_info['count_hi'] += (count >> 29) - - if sha_info['local']: - i = SHA_BLOCKSIZE - sha_info['local'] - if i > count: - i = count - - # copy buffer - sha_info['data'][sha_info['local']:sha_info['local']+i] = buffer[buffer_idx:buffer_idx+i] - - count -= i - buffer_idx += i - - sha_info['local'] += i - if sha_info['local'] == SHA_BLOCKSIZE: - sha_transform(sha_info) - sha_info['local'] = 0 - else: - return - - while count >= SHA_BLOCKSIZE: - # copy buffer - sha_info['data'] = list(buffer[buffer_idx:buffer_idx + SHA_BLOCKSIZE]) - count -= SHA_BLOCKSIZE - buffer_idx += SHA_BLOCKSIZE - sha_transform(sha_info) - - - # copy buffer - pos = sha_info['local'] - sha_info['data'][pos:pos+count] = buffer[buffer_idx:buffer_idx + count] - sha_info['local'] = count - -def sha_final(sha_info): - lo_bit_count = sha_info['count_lo'] - hi_bit_count = sha_info['count_hi'] - count = (lo_bit_count >> 3) & 0x3f - sha_info['data'][count] = 0x80; - count += 1 - if count > SHA_BLOCKSIZE - 8: - # zero the bytes in data after the count - sha_info['data'] = sha_info['data'][:count] + ([0] * (SHA_BLOCKSIZE - count)) - sha_transform(sha_info) - # zero bytes in data - sha_info['data'] = [0] * SHA_BLOCKSIZE - else: - sha_info['data'] = sha_info['data'][:count] + ([0] * (SHA_BLOCKSIZE - count)) - - sha_info['data'][56] = (hi_bit_count >> 24) & 0xff - sha_info['data'][57] = (hi_bit_count >> 16) & 0xff - sha_info['data'][58] = (hi_bit_count >> 8) & 0xff - sha_info['data'][59] = (hi_bit_count >> 0) & 0xff - sha_info['data'][60] = (lo_bit_count >> 24) & 0xff - sha_info['data'][61] = (lo_bit_count >> 16) & 0xff - sha_info['data'][62] = (lo_bit_count >> 8) & 0xff - sha_info['data'][63] = (lo_bit_count >> 0) & 0xff - - sha_transform(sha_info) - - dig = [] - for i in sha_info['digest']: - dig.extend([ ((i>>24) & 0xff), ((i>>16) & 0xff), ((i>>8) & 0xff), (i & 0xff) ]) - return ''.join([chr(i) for i in dig]) - -class sha256(object): - digest_size = digestsize = SHA_DIGESTSIZE - block_size = SHA_BLOCKSIZE - - def __init__(self, s=None): - self._sha = sha_init() - if s: - sha_update(self._sha, s) - - def update(self, s): - sha_update(self._sha, s) - - def digest(self): - return sha_final(self._sha.copy())[:self._sha['digestsize']] - - def hexdigest(self): - return ''.join(['%.2x' % ord(i) for i in self.digest()]) - - def copy(self): - new = sha256.__new__(sha256) - new._sha = self._sha.copy() - return new - -class sha224(sha256): - digest_size = digestsize = 28 - - def __init__(self, s=None): - self._sha = sha224_init() - if s: - sha_update(self._sha, s) - - def copy(self): - new = sha224.__new__(sha224) - new._sha = self._sha.copy() - return new - -def test(): - a_str = "just a test string" - - assert 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' == sha256().hexdigest() - assert 'd7b553c6f09ac85d142415f857c5310f3bbbe7cdd787cce4b985acedd585266f' == sha256(a_str).hexdigest() - assert '8113ebf33c97daa9998762aacafe750c7cefc2b2f173c90c59663a57fe626f21' == sha256(a_str*7).hexdigest() - - s = sha256(a_str) - s.update(a_str) - assert '03d9963e05a094593190b6fc794cb1a3e1ac7d7883f0b5855268afeccc70d461' == s.hexdigest() - -if __name__ == "__main__": - test() diff --git a/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp b/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp deleted file mode 100644 index 471928f6a..000000000 --- a/src/snark/libsnark/gadgetlib1/gadgets/hashes/sha256/tests/test_sha256_gadget.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/** @file - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#include "common/default_types/ec_pp.hpp" -#include "common/utils.hpp" -#include "common/profiling.hpp" -#include "gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp" - -using namespace libsnark; - -template -void test_two_to_one() -{ - protoboard pb; - - digest_variable left(pb, SHA256_digest_size, "left"); - digest_variable right(pb, SHA256_digest_size, "right"); - digest_variable output(pb, SHA256_digest_size, "output"); - - sha256_two_to_one_hash_gadget f(pb, left, right, output, "f"); - f.generate_r1cs_constraints(); - printf("Number of constraints for sha256_two_to_one_hash_gadget: %zu\n", pb.num_constraints()); - - const bit_vector left_bv = int_list_to_bits({0x426bc2d8, 0x4dc86782, 0x81e8957a, 0x409ec148, 0xe6cffbe8, 0xafe6ba4f, 0x9c6f1978, 0xdd7af7e9}, 32); - const bit_vector right_bv = int_list_to_bits({0x038cce42, 0xabd366b8, 0x3ede7e00, 0x9130de53, 0x72cdf73d, 0xee825114, 0x8cb48d1b, 0x9af68ad0}, 32); - const bit_vector hash_bv = int_list_to_bits({0xeffd0b7f, 0x1ccba116, 0x2ee816f7, 0x31c62b48, 0x59305141, 0x990e5c0a, 0xce40d33d, 0x0b1167d1}, 32); - - left.generate_r1cs_witness(left_bv); - right.generate_r1cs_witness(right_bv); - - f.generate_r1cs_witness(); - output.generate_r1cs_witness(hash_bv); - - assert(pb.is_satisfied()); -} - -int main(void) -{ - start_profiling(); - default_ec_pp::init_public_params(); - test_two_to_one >(); -} diff --git a/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp b/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp deleted file mode 100644 index 0efa7cf4d..000000000 --- a/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp +++ /dev/null @@ -1,38 +0,0 @@ -/** - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef MERKLE_AUTHENTICATION_PATH_VARIABLE_HPP_ -#define MERKLE_AUTHENTICATION_PATH_VARIABLE_HPP_ - -#include "common/data_structures/merkle_tree.hpp" -#include "gadgetlib1/gadget.hpp" -#include "gadgetlib1/gadgets/hashes/hash_io.hpp" - -namespace libsnark { - -template -class merkle_authentication_path_variable : public gadget { -public: - - const size_t tree_depth; - std::vector > left_digests; - std::vector > right_digests; - - merkle_authentication_path_variable(protoboard &pb, - const size_t tree_depth, - const std::string &annotation_prefix); - - void generate_r1cs_constraints(); - void generate_r1cs_witness(const size_t address, const merkle_authentication_path &path); - merkle_authentication_path get_authentication_path(const size_t address) const; -}; - -} // libsnark - -#include "gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.tcc" - -#endif // MERKLE_AUTHENTICATION_PATH_VARIABLE_HPP diff --git a/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.tcc b/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.tcc deleted file mode 100644 index b3d805d8e..000000000 --- a/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.tcc +++ /dev/null @@ -1,76 +0,0 @@ -/** - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef MERKLE_AUTHENTICATION_PATH_VARIABLE_TCC_ -#define MERKLE_AUTHENTICATION_PATH_VARIABLE_TCC_ - -namespace libsnark { - -template -merkle_authentication_path_variable::merkle_authentication_path_variable(protoboard &pb, - const size_t tree_depth, - const std::string &annotation_prefix) : - gadget(pb, annotation_prefix), - tree_depth(tree_depth) -{ - for (size_t i = 0; i < tree_depth; ++i) - { - left_digests.emplace_back(digest_variable(pb, HashT::get_digest_len(), FMT(annotation_prefix, " left_digests_%zu", i))); - right_digests.emplace_back(digest_variable(pb, HashT::get_digest_len(), FMT(annotation_prefix, " right_digests_%zu", i))); - } -} - -template -void merkle_authentication_path_variable::generate_r1cs_constraints() -{ - for (size_t i = 0; i < tree_depth; ++i) - { - left_digests[i].generate_r1cs_constraints(); - right_digests[i].generate_r1cs_constraints(); - } -} - -template -void merkle_authentication_path_variable::generate_r1cs_witness(const size_t address, const merkle_authentication_path &path) -{ - assert(path.size() == tree_depth); - - for (size_t i = 0; i < tree_depth; ++i) - { - if (address & (UINT64_C(1) << (tree_depth-1-i))) - { - left_digests[i].generate_r1cs_witness(path[i]); - } - else - { - right_digests[i].generate_r1cs_witness(path[i]); - } - } -} - -template -merkle_authentication_path merkle_authentication_path_variable::get_authentication_path(const size_t address) const -{ - merkle_authentication_path result; - for (size_t i = 0; i < tree_depth; ++i) - { - if (address & (UINT64_C(1) << (tree_depth-1-i))) - { - result.emplace_back(left_digests[i].get_digest()); - } - else - { - result.emplace_back(right_digests[i].get_digest()); - } - } - - return result; -} - -} // libsnark - -#endif // MERKLE_AUTHENTICATION_PATH_VARIABLE_TCC diff --git a/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp b/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp deleted file mode 100644 index b1e3a4f05..000000000 --- a/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp +++ /dev/null @@ -1,73 +0,0 @@ -/** @file - ***************************************************************************** - - Declaration of interfaces for the Merkle tree check read gadget. - - The gadget checks the following: given a root R, address A, value V, and - authentication path P, check that P is a valid authentication path for the - value V as the A-th leaf in a Merkle tree with root R. - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef MERKLE_TREE_CHECK_READ_GADGET_HPP_ -#define MERKLE_TREE_CHECK_READ_GADGET_HPP_ - -#include "common/data_structures/merkle_tree.hpp" -#include "gadgetlib1/gadget.hpp" -#include "gadgetlib1/gadgets/hashes/hash_io.hpp" -#include "gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp" -#include "gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp" - -namespace libsnark { - -template -class merkle_tree_check_read_gadget : public gadget { -private: - - std::vector hashers; - std::vector > hasher_inputs; - std::vector > propagators; - std::vector > internal_output; - - std::shared_ptr > computed_root; - std::shared_ptr > check_root; - -public: - - const size_t digest_size; - const size_t tree_depth; - pb_linear_combination_array address_bits; - digest_variable leaf; - digest_variable root; - merkle_authentication_path_variable path; - pb_linear_combination read_successful; - - merkle_tree_check_read_gadget(protoboard &pb, - const size_t tree_depth, - const pb_linear_combination_array &address_bits, - const digest_variable &leaf_digest, - const digest_variable &root_digest, - const merkle_authentication_path_variable &path, - const pb_linear_combination &read_successful, - const std::string &annotation_prefix); - - void generate_r1cs_constraints(); - void generate_r1cs_witness(); - - static size_t root_size_in_bits(); - /* for debugging purposes */ - static size_t expected_constraints(const size_t tree_depth); -}; - -template -void test_merkle_tree_check_read_gadget(); - -} // libsnark - -#include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.tcc" - -#endif // MERKLE_TREE_CHECK_READ_GADGET_HPP_ diff --git a/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.tcc b/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.tcc deleted file mode 100644 index 29ce1b8ac..000000000 --- a/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.tcc +++ /dev/null @@ -1,196 +0,0 @@ -/** @file - ***************************************************************************** - - Implementation of interfaces for the Merkle tree check read. - - See merkle_tree_check_read_gadget.hpp . - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef MERKLE_TREE_CHECK_READ_GADGET_TCC_ -#define MERKLE_TREE_CHECK_READ_GADGET_TCC_ - -namespace libsnark { - -template -merkle_tree_check_read_gadget::merkle_tree_check_read_gadget(protoboard &pb, - const size_t tree_depth, - const pb_linear_combination_array &address_bits, - const digest_variable &leaf, - const digest_variable &root, - const merkle_authentication_path_variable &path, - const pb_linear_combination &read_successful, - const std::string &annotation_prefix) : - gadget(pb, annotation_prefix), - digest_size(HashT::get_digest_len()), - tree_depth(tree_depth), - address_bits(address_bits), - leaf(leaf), - root(root), - path(path), - read_successful(read_successful) -{ - /* - The tricky part here is ordering. For Merkle tree - authentication paths, path[0] corresponds to one layer below - the root (and path[tree_depth-1] corresponds to the layer - containing the leaf), while address_bits has the reverse order: - address_bits[0] is LSB, and corresponds to layer containing the - leaf, and address_bits[tree_depth-1] is MSB, and corresponds to - the subtree directly under the root. - */ - assert(tree_depth > 0); - assert(tree_depth == address_bits.size()); - - for (size_t i = 0; i < tree_depth-1; ++i) - { - internal_output.emplace_back(digest_variable(pb, digest_size, FMT(this->annotation_prefix, " internal_output_%zu", i))); - } - - computed_root.reset(new digest_variable(pb, digest_size, FMT(this->annotation_prefix, " computed_root"))); - - for (size_t i = 0; i < tree_depth; ++i) - { - block_variable inp(pb, path.left_digests[i], path.right_digests[i], FMT(this->annotation_prefix, " inp_%zu", i)); - hasher_inputs.emplace_back(inp); - hashers.emplace_back(HashT(pb, 2*digest_size, inp, (i == 0 ? *computed_root : internal_output[i-1]), - FMT(this->annotation_prefix, " load_hashers_%zu", i))); - } - - for (size_t i = 0; i < tree_depth; ++i) - { - /* - The propagators take a computed hash value (or leaf in the - base case) and propagate it one layer up, either in the left - or the right slot of authentication_path_variable. - */ - propagators.emplace_back(digest_selector_gadget(pb, digest_size, i < tree_depth - 1 ? internal_output[i] : leaf, - address_bits[tree_depth-1-i], path.left_digests[i], path.right_digests[i], - FMT(this->annotation_prefix, " digest_selector_%zu", i))); - } - - check_root.reset(new bit_vector_copy_gadget(pb, computed_root->bits, root.bits, read_successful, FieldT::capacity(), FMT(annotation_prefix, " check_root"))); -} - -template -void merkle_tree_check_read_gadget::generate_r1cs_constraints() -{ - /* ensure correct hash computations */ - for (size_t i = 0; i < tree_depth; ++i) - { - // Note that we check root outside and have enforced booleanity of path.left_digests/path.right_digests outside in path.generate_r1cs_constraints - hashers[i].generate_r1cs_constraints(false); - } - - /* ensure consistency of path.left_digests/path.right_digests with internal_output */ - for (size_t i = 0; i < tree_depth; ++i) - { - propagators[i].generate_r1cs_constraints(); - } - - check_root->generate_r1cs_constraints(false, false); -} - -template -void merkle_tree_check_read_gadget::generate_r1cs_witness() -{ - /* do the hash computations bottom-up */ - for (int i = tree_depth-1; i >= 0; --i) - { - /* propagate previous input */ - propagators[i].generate_r1cs_witness(); - - /* compute hash */ - hashers[i].generate_r1cs_witness(); - } - - check_root->generate_r1cs_witness(); -} - -template -size_t merkle_tree_check_read_gadget::root_size_in_bits() -{ - return HashT::get_digest_len(); -} - -template -size_t merkle_tree_check_read_gadget::expected_constraints(const size_t tree_depth) -{ - /* NB: this includes path constraints */ - const size_t hasher_constraints = tree_depth * HashT::expected_constraints(false); - const size_t propagator_constraints = tree_depth * HashT::get_digest_len(); - const size_t authentication_path_constraints = 2 * tree_depth * HashT::get_digest_len(); - const size_t check_root_constraints = 3 * div_ceil(HashT::get_digest_len(), FieldT::capacity()); - - return hasher_constraints + propagator_constraints + authentication_path_constraints + check_root_constraints; -} - -template -void test_merkle_tree_check_read_gadget() -{ - /* prepare test */ - const size_t digest_len = HashT::get_digest_len(); - const size_t tree_depth = 16; - std::vector path(tree_depth); - - bit_vector prev_hash(digest_len); - std::generate(prev_hash.begin(), prev_hash.end(), [&]() { return std::rand() % 2; }); - bit_vector leaf = prev_hash; - - bit_vector address_bits; - - size_t address = 0; - for (int64_t level = tree_depth-1; level >= 0; --level) - { - const bool computed_is_right = (std::rand() % 2); - address |= (computed_is_right ? UINT64_C(1) << (tree_depth-1-level) : 0); - address_bits.push_back(computed_is_right); - bit_vector other(digest_len); - std::generate(other.begin(), other.end(), [&]() { return std::rand() % 2; }); - - bit_vector block = prev_hash; - block.insert(computed_is_right ? block.begin() : block.end(), other.begin(), other.end()); - bit_vector h = HashT::get_hash(block); - - path[level] = other; - - prev_hash = h; - } - bit_vector root = prev_hash; - - /* execute test */ - protoboard pb; - pb_variable_array address_bits_va; - address_bits_va.allocate(pb, tree_depth, "address_bits"); - digest_variable leaf_digest(pb, digest_len, "input_block"); - digest_variable root_digest(pb, digest_len, "output_digest"); - merkle_authentication_path_variable path_var(pb, tree_depth, "path_var"); - merkle_tree_check_read_gadget ml(pb, tree_depth, address_bits_va, leaf_digest, root_digest, path_var, ONE, "ml"); - - path_var.generate_r1cs_constraints(); - ml.generate_r1cs_constraints(); - - address_bits_va.fill_with_bits(pb, address_bits); - assert(address_bits_va.get_field_element_from_bits(pb).as_uint64() == address); - leaf_digest.generate_r1cs_witness(leaf); - path_var.generate_r1cs_witness(address, path); - ml.generate_r1cs_witness(); - - /* make sure that read checker didn't accidentally overwrite anything */ - address_bits_va.fill_with_bits(pb, address_bits); - leaf_digest.generate_r1cs_witness(leaf); - root_digest.generate_r1cs_witness(root); - assert(pb.is_satisfied()); - - const size_t num_constraints = pb.num_constraints(); - const size_t expected_constraints = merkle_tree_check_read_gadget::expected_constraints(tree_depth); - assert(num_constraints == expected_constraints); -} - -} // libsnark - -#endif // MERKLE_TREE_CHECK_READ_GADGET_TCC_ diff --git a/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp b/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp deleted file mode 100644 index 2d6840d61..000000000 --- a/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp +++ /dev/null @@ -1,91 +0,0 @@ -/** @file - ***************************************************************************** - - Declaration of interfaces for the Merkle tree check read gadget. - - The gadget checks the following: given two roots R1 and R2, address A, two - values V1 and V2, and authentication path P, check that - - P is a valid authentication path for the value V1 as the A-th leaf in a Merkle tree with root R1, and - - P is a valid authentication path for the value V2 as the A-th leaf in a Merkle tree with root R2. - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef MERKLE_TREE_CHECK_UPDATE_GADGET_HPP_ -#define MERKLE_TREE_CHECK_UPDATE_GADGET_HPP_ - -#include "common/data_structures/merkle_tree.hpp" -#include "gadgetlib1/gadget.hpp" -#include "gadgetlib1/gadgets/hashes/crh_gadget.hpp" -#include "gadgetlib1/gadgets/hashes/hash_io.hpp" -#include "gadgetlib1/gadgets/hashes/digest_selector_gadget.hpp" -#include "gadgetlib1/gadgets/merkle_tree/merkle_authentication_path_variable.hpp" - -namespace libsnark { - -template -class merkle_tree_check_update_gadget : public gadget { -private: - - std::vector prev_hashers; - std::vector > prev_hasher_inputs; - std::vector > prev_propagators; - std::vector > prev_internal_output; - - std::vector next_hashers; - std::vector > next_hasher_inputs; - std::vector > next_propagators; - std::vector > next_internal_output; - - std::shared_ptr > computed_next_root; - std::shared_ptr > check_next_root; - -public: - - const size_t digest_size; - const size_t tree_depth; - - pb_variable_array address_bits; - digest_variable prev_leaf_digest; - digest_variable prev_root_digest; - merkle_authentication_path_variable prev_path; - digest_variable next_leaf_digest; - digest_variable next_root_digest; - merkle_authentication_path_variable next_path; - pb_linear_combination update_successful; - - /* Note that while it is necessary to generate R1CS constraints - for prev_path, it is not necessary to do so for next_path. See - comment in the implementation of generate_r1cs_constraints() */ - - merkle_tree_check_update_gadget(protoboard &pb, - const size_t tree_depth, - const pb_variable_array &address_bits, - const digest_variable &prev_leaf_digest, - const digest_variable &prev_root_digest, - const merkle_authentication_path_variable &prev_path, - const digest_variable &next_leaf_digest, - const digest_variable &next_root_digest, - const merkle_authentication_path_variable &next_path, - const pb_linear_combination &update_successful, - const std::string &annotation_prefix); - - void generate_r1cs_constraints(); - void generate_r1cs_witness(); - - static size_t root_size_in_bits(); - /* for debugging purposes */ - static size_t expected_constraints(const size_t tree_depth); -}; - -template -void test_merkle_tree_check_update_gadget(); - -} // libsnark - -#include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.tcc" - -#endif // MERKLE_TREE_CHECK_UPDATE_GADGET_HPP_ diff --git a/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.tcc b/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.tcc deleted file mode 100644 index 507c7526d..000000000 --- a/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.tcc +++ /dev/null @@ -1,265 +0,0 @@ -/** @file - ***************************************************************************** - - Implementation of interfaces for the Merkle tree check update gadget. - - See merkle_tree_check_update_gadget.hpp . - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef MERKLE_TREE_CHECK_UPDATE_GADGET_TCC_ -#define MERKLE_TREE_CHECK_UPDATE_GADGET_TCC_ - -namespace libsnark { - -template -merkle_tree_check_update_gadget::merkle_tree_check_update_gadget(protoboard &pb, - const size_t tree_depth, - const pb_variable_array &address_bits, - const digest_variable &prev_leaf_digest, - const digest_variable &prev_root_digest, - const merkle_authentication_path_variable &prev_path, - const digest_variable &next_leaf_digest, - const digest_variable &next_root_digest, - const merkle_authentication_path_variable &next_path, - const pb_linear_combination &update_successful, - const std::string &annotation_prefix) : - gadget(pb, annotation_prefix), - digest_size(HashT::get_digest_len()), - tree_depth(tree_depth), - address_bits(address_bits), - prev_leaf_digest(prev_leaf_digest), - prev_root_digest(prev_root_digest), - prev_path(prev_path), - next_leaf_digest(next_leaf_digest), - next_root_digest(next_root_digest), - next_path(next_path), - update_successful(update_successful) -{ - assert(tree_depth > 0); - assert(tree_depth == address_bits.size()); - - for (size_t i = 0; i < tree_depth-1; ++i) - { - prev_internal_output.emplace_back(digest_variable(pb, digest_size, FMT(this->annotation_prefix, " prev_internal_output_%zu", i))); - next_internal_output.emplace_back(digest_variable(pb, digest_size, FMT(this->annotation_prefix, " next_internal_output_%zu", i))); - } - - computed_next_root.reset(new digest_variable(pb, digest_size, FMT(this->annotation_prefix, " computed_root"))); - - for (size_t i = 0; i < tree_depth; ++i) - { - block_variable prev_inp(pb, prev_path.left_digests[i], prev_path.right_digests[i], FMT(this->annotation_prefix, " prev_inp_%zu", i)); - prev_hasher_inputs.emplace_back(prev_inp); - prev_hashers.emplace_back(HashT(pb, 2*digest_size, prev_inp, (i == 0 ? prev_root_digest : prev_internal_output[i-1]), - FMT(this->annotation_prefix, " prev_hashers_%zu", i))); - - block_variable next_inp(pb, next_path.left_digests[i], next_path.right_digests[i], FMT(this->annotation_prefix, " next_inp_%zu", i)); - next_hasher_inputs.emplace_back(next_inp); - next_hashers.emplace_back(HashT(pb, 2*digest_size, next_inp, (i == 0 ? *computed_next_root : next_internal_output[i-1]), - FMT(this->annotation_prefix, " next_hashers_%zu", i))); - } - - for (size_t i = 0; i < tree_depth; ++i) - { - prev_propagators.emplace_back(digest_selector_gadget(pb, digest_size, i < tree_depth -1 ? prev_internal_output[i] : prev_leaf_digest, - address_bits[tree_depth-1-i], prev_path.left_digests[i], prev_path.right_digests[i], - FMT(this->annotation_prefix, " prev_propagators_%zu", i))); - next_propagators.emplace_back(digest_selector_gadget(pb, digest_size, i < tree_depth -1 ? next_internal_output[i] : next_leaf_digest, - address_bits[tree_depth-1-i], next_path.left_digests[i], next_path.right_digests[i], - FMT(this->annotation_prefix, " next_propagators_%zu", i))); - } - - check_next_root.reset(new bit_vector_copy_gadget(pb, computed_next_root->bits, next_root_digest.bits, update_successful, FieldT::capacity(), FMT(annotation_prefix, " check_next_root"))); -} - -template -void merkle_tree_check_update_gadget::generate_r1cs_constraints() -{ - /* ensure correct hash computations */ - for (size_t i = 0; i < tree_depth; ++i) - { - prev_hashers[i].generate_r1cs_constraints(false); // we check root outside and prev_left/prev_right above - next_hashers[i].generate_r1cs_constraints(true); // however we must check right side hashes - } - - /* ensure consistency of internal_left/internal_right with internal_output */ - for (size_t i = 0; i < tree_depth; ++i) - { - prev_propagators[i].generate_r1cs_constraints(); - next_propagators[i].generate_r1cs_constraints(); - } - - /* ensure that prev auxiliary input and next auxiliary input match */ - for (size_t i = 0; i < tree_depth; ++i) - { - for (size_t j = 0; j < digest_size; ++j) - { - /* - addr * (prev_left - next_left) + (1 - addr) * (prev_right - next_right) = 0 - addr * (prev_left - next_left - prev_right + next_right) = next_right - prev_right - */ - this->pb.add_r1cs_constraint(r1cs_constraint(address_bits[tree_depth-1-i], - prev_path.left_digests[i].bits[j] - next_path.left_digests[i].bits[j] - prev_path.right_digests[i].bits[j] + next_path.right_digests[i].bits[j], - next_path.right_digests[i].bits[j] - prev_path.right_digests[i].bits[j]), - FMT(this->annotation_prefix, " aux_check_%zu_%zu", i, j)); - } - } - - /* Note that while it is necessary to generate R1CS constraints - for prev_path, it is not necessary to do so for next_path. - - This holds, because { next_path.left_inputs[i], - next_path.right_inputs[i] } is a pair { hash_output, - auxiliary_input }. The bitness for hash_output is enforced - above by next_hashers[i].generate_r1cs_constraints. - - Because auxiliary input is the same for prev_path and next_path - (enforced above), we have that auxiliary_input part is also - constrained to be boolean, because prev_path is *all* - constrained to be all boolean. */ - - check_next_root->generate_r1cs_constraints(false, false); -} - -template -void merkle_tree_check_update_gadget::generate_r1cs_witness() -{ - /* do the hash computations bottom-up */ - for (int i = tree_depth-1; i >= 0; --i) - { - /* ensure consistency of prev_path and next_path */ - if (this->pb.val(address_bits[tree_depth-1-i]) == FieldT::one()) - { - next_path.left_digests[i].generate_r1cs_witness(prev_path.left_digests[i].get_digest()); - } - else - { - next_path.right_digests[i].generate_r1cs_witness(prev_path.right_digests[i].get_digest()); - } - - /* propagate previous input */ - prev_propagators[i].generate_r1cs_witness(); - next_propagators[i].generate_r1cs_witness(); - - /* compute hash */ - prev_hashers[i].generate_r1cs_witness(); - next_hashers[i].generate_r1cs_witness(); - } - - check_next_root->generate_r1cs_witness(); -} - -template -size_t merkle_tree_check_update_gadget::root_size_in_bits() -{ - return HashT::get_digest_len(); -} - -template -size_t merkle_tree_check_update_gadget::expected_constraints(const size_t tree_depth) -{ - /* NB: this includes path constraints */ - const size_t prev_hasher_constraints = tree_depth * HashT::expected_constraints(false); - const size_t next_hasher_constraints = tree_depth * HashT::expected_constraints(true); - const size_t prev_authentication_path_constraints = 2 * tree_depth * HashT::get_digest_len(); - const size_t prev_propagator_constraints = tree_depth * HashT::get_digest_len(); - const size_t next_propagator_constraints = tree_depth * HashT::get_digest_len(); - const size_t check_next_root_constraints = 3 * div_ceil(HashT::get_digest_len(), FieldT::capacity()); - const size_t aux_equality_constraints = tree_depth * HashT::get_digest_len(); - - return (prev_hasher_constraints + next_hasher_constraints + prev_authentication_path_constraints + - prev_propagator_constraints + next_propagator_constraints + check_next_root_constraints + - aux_equality_constraints); -} - -template -void test_merkle_tree_check_update_gadget() -{ - /* prepare test */ - const size_t digest_len = HashT::get_digest_len(); - - const size_t tree_depth = 16; - std::vector prev_path(tree_depth); - - bit_vector prev_load_hash(digest_len); - std::generate(prev_load_hash.begin(), prev_load_hash.end(), [&]() { return std::rand() % 2; }); - bit_vector prev_store_hash(digest_len); - std::generate(prev_store_hash.begin(), prev_store_hash.end(), [&]() { return std::rand() % 2; }); - - bit_vector loaded_leaf = prev_load_hash; - bit_vector stored_leaf = prev_store_hash; - - bit_vector address_bits; - - size_t address = 0; - for (int64_t level = tree_depth-1; level >= 0; --level) - { - const bool computed_is_right = (std::rand() % 2); - address |= (computed_is_right ? UINT64_C(1) << (tree_depth-1-level) : 0); - address_bits.push_back(computed_is_right); - bit_vector other(digest_len); - std::generate(other.begin(), other.end(), [&]() { return std::rand() % 2; }); - - bit_vector load_block = prev_load_hash; - load_block.insert(computed_is_right ? load_block.begin() : load_block.end(), other.begin(), other.end()); - bit_vector store_block = prev_store_hash; - store_block.insert(computed_is_right ? store_block.begin() : store_block.end(), other.begin(), other.end()); - - bit_vector load_h = HashT::get_hash(load_block); - bit_vector store_h = HashT::get_hash(store_block); - - prev_path[level] = other; - - prev_load_hash = load_h; - prev_store_hash = store_h; - } - - bit_vector load_root = prev_load_hash; - bit_vector store_root = prev_store_hash; - - /* execute the test */ - protoboard pb; - pb_variable_array address_bits_va; - address_bits_va.allocate(pb, tree_depth, "address_bits"); - digest_variable prev_leaf_digest(pb, digest_len, "prev_leaf_digest"); - digest_variable prev_root_digest(pb, digest_len, "prev_root_digest"); - merkle_authentication_path_variable prev_path_var(pb, tree_depth, "prev_path_var"); - digest_variable next_leaf_digest(pb, digest_len, "next_leaf_digest"); - digest_variable next_root_digest(pb, digest_len, "next_root_digest"); - merkle_authentication_path_variable next_path_var(pb, tree_depth, "next_path_var"); - merkle_tree_check_update_gadget mls(pb, tree_depth, address_bits_va, - prev_leaf_digest, prev_root_digest, prev_path_var, - next_leaf_digest, next_root_digest, next_path_var, ONE, "mls"); - - prev_path_var.generate_r1cs_constraints(); - mls.generate_r1cs_constraints(); - - address_bits_va.fill_with_bits(pb, address_bits); - assert(address_bits_va.get_field_element_from_bits(pb).as_uint64() == address); - prev_leaf_digest.generate_r1cs_witness(loaded_leaf); - prev_path_var.generate_r1cs_witness(address, prev_path); - next_leaf_digest.generate_r1cs_witness(stored_leaf); - address_bits_va.fill_with_bits(pb, address_bits); - mls.generate_r1cs_witness(); - - /* make sure that update check will check for the right things */ - prev_leaf_digest.generate_r1cs_witness(loaded_leaf); - next_leaf_digest.generate_r1cs_witness(stored_leaf); - prev_root_digest.generate_r1cs_witness(load_root); - next_root_digest.generate_r1cs_witness(store_root); - address_bits_va.fill_with_bits(pb, address_bits); - assert(pb.is_satisfied()); - - const size_t num_constraints = pb.num_constraints(); - const size_t expected_constraints = merkle_tree_check_update_gadget::expected_constraints(tree_depth); - assert(num_constraints == expected_constraints); -} - -} // libsnark - -#endif // MERKLE_TREE_CHECK_UPDATE_GADGET_TCC_ diff --git a/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp b/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp deleted file mode 100644 index 8d52c579b..000000000 --- a/src/snark/libsnark/gadgetlib1/gadgets/merkle_tree/tests/test_merkle_tree_gadgets.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/** - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifdef CURVE_BN128 -#include "algebra/curves/bn128/bn128_pp.hpp" -#endif -#include "algebra/curves/edwards/edwards_pp.hpp" -#include "algebra/curves/mnt/mnt4/mnt4_pp.hpp" -#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" -#include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_read_gadget.hpp" -#include "gadgetlib1/gadgets/merkle_tree/merkle_tree_check_update_gadget.hpp" -#include "gadgetlib1/gadgets/hashes/sha256/sha256_gadget.hpp" - -using namespace libsnark; - -template -void test_all_merkle_tree_gadgets() -{ - typedef Fr FieldT; - test_merkle_tree_check_read_gadget >(); - test_merkle_tree_check_read_gadget >(); - - test_merkle_tree_check_update_gadget >(); - test_merkle_tree_check_update_gadget >(); -} - -int main(void) -{ - start_profiling(); - -#ifdef CURVE_BN128 // BN128 has fancy dependencies so it may be disabled - bn128_pp::init_public_params(); - test_all_merkle_tree_gadgets(); -#endif - - edwards_pp::init_public_params(); - test_all_merkle_tree_gadgets(); - - mnt4_pp::init_public_params(); - test_all_merkle_tree_gadgets(); - - mnt6_pp::init_public_params(); - test_all_merkle_tree_gadgets(); -} diff --git a/src/snark/libsnark/gadgetlib1/pb_variable.hpp b/src/snark/libsnark/gadgetlib1/pb_variable.hpp deleted file mode 100644 index caa44cec1..000000000 --- a/src/snark/libsnark/gadgetlib1/pb_variable.hpp +++ /dev/null @@ -1,144 +0,0 @@ -/** @file - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef PB_VARIABLE_HPP_ -#define PB_VARIABLE_HPP_ - -#include -#include -#include -#include "common/utils.hpp" -#include "relations/variable.hpp" - -namespace libsnark { - -typedef size_t lc_index_t; - -template -class protoboard; - -template -class pb_variable : public variable { -public: - pb_variable(const var_index_t index = 0) : variable(index) {}; - - void allocate(protoboard &pb, const std::string &annotation=""); -}; - -template -class pb_variable_array : private std::vector > -{ - typedef std::vector > contents; -public: - using typename contents::iterator; - using typename contents::const_iterator; - using typename contents::reverse_iterator; - using typename contents::const_reverse_iterator; - - using contents::begin; - using contents::end; - using contents::rbegin; - using contents::rend; - using contents::emplace_back; - using contents::insert; - using contents::reserve; - using contents::size; - using contents::empty; - using contents::operator[]; - using contents::resize; - - pb_variable_array() : contents() {}; - pb_variable_array(size_t count, const pb_variable &value) : contents(count, value) {}; - pb_variable_array(typename contents::const_iterator first, typename contents::const_iterator last) : contents(first, last) {}; - pb_variable_array(typename contents::const_reverse_iterator first, typename contents::const_reverse_iterator last) : contents(first, last) {}; - void allocate(protoboard &pb, const size_t n, const std::string &annotation_prefix=""); - - void fill_with_field_elements(protoboard &pb, const std::vector& vals) const; - void fill_with_bits(protoboard &pb, const bit_vector& bits) const; - void fill_with_bits_of_uint64(protoboard &pb, const uint64_t i) const; - void fill_with_bits_of_field_element(protoboard &pb, const FieldT &r) const; - - std::vector get_vals(const protoboard &pb) const; - bit_vector get_bits(const protoboard &pb) const; - - FieldT get_field_element_from_bits(const protoboard &pb) const; -}; - -/* index 0 corresponds to the constant term (used in legacy code) */ -#define ONE pb_variable(0) - -template -class pb_linear_combination : public linear_combination { -public: - bool is_variable; - lc_index_t index; - - pb_linear_combination(); - pb_linear_combination(const pb_variable &var); - - void assign(protoboard &pb, const linear_combination &lc); - void evaluate(protoboard &pb) const; - - bool is_constant() const; - FieldT constant_term() const; -}; - -template -class pb_linear_combination_array : private std::vector > -{ - typedef std::vector > contents; -public: - using typename contents::iterator; - using typename contents::const_iterator; - using typename contents::reverse_iterator; - using typename contents::const_reverse_iterator; - - using contents::begin; - using contents::end; - using contents::rbegin; - using contents::rend; - using contents::emplace_back; - using contents::insert; - using contents::reserve; - using contents::size; - using contents::empty; - using contents::operator[]; - using contents::resize; - - pb_linear_combination_array() : contents() {}; - pb_linear_combination_array(const pb_variable_array &arr) { for (auto &v : arr) this->emplace_back(pb_linear_combination(v)); }; - pb_linear_combination_array(size_t count) : contents(count) {}; - pb_linear_combination_array(size_t count, const pb_linear_combination &value) : contents(count, value) {}; - pb_linear_combination_array(typename contents::const_iterator first, typename contents::const_iterator last) : contents(first, last) {}; - pb_linear_combination_array(typename contents::const_reverse_iterator first, typename contents::const_reverse_iterator last) : contents(first, last) {}; - - void evaluate(protoboard &pb) const; - - void fill_with_field_elements(protoboard &pb, const std::vector& vals) const; - void fill_with_bits(protoboard &pb, const bit_vector& bits) const; - void fill_with_bits_of_uint64(protoboard &pb, const uint64_t i) const; - void fill_with_bits_of_field_element(protoboard &pb, const FieldT &r) const; - - std::vector get_vals(const protoboard &pb) const; - bit_vector get_bits(const protoboard &pb) const; - - FieldT get_field_element_from_bits(const protoboard &pb) const; -}; - -template -linear_combination pb_sum(const pb_linear_combination_array &v); - -template -linear_combination pb_packing_sum(const pb_linear_combination_array &v); - -template -linear_combination pb_coeff_sum(const pb_linear_combination_array &v, const std::vector &coeffs); - -} // libsnark -#include "gadgetlib1/pb_variable.tcc" - -#endif // PB_VARIABLE_HPP_ diff --git a/src/snark/libsnark/gadgetlib1/pb_variable.tcc b/src/snark/libsnark/gadgetlib1/pb_variable.tcc deleted file mode 100644 index b4c6ad4f9..000000000 --- a/src/snark/libsnark/gadgetlib1/pb_variable.tcc +++ /dev/null @@ -1,330 +0,0 @@ -/** @file - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef PB_VARIABLE_TCC_ -#define PB_VARIABLE_TCC_ -#include -#include "gadgetlib1/protoboard.hpp" -#include "common/utils.hpp" - -namespace libsnark { - -template -void pb_variable::allocate(protoboard &pb, const std::string &annotation) -{ - this->index = pb.allocate_var_index(annotation); -} - -/* allocates pb_variable array in MSB->LSB order */ -template -void pb_variable_array::allocate(protoboard &pb, const size_t n, const std::string &annotation_prefix) -{ -#ifdef DEBUG - assert(annotation_prefix != ""); -#endif - (*this).resize(n); - - for (size_t i = 0; i < n; ++i) - { - (*this)[i].allocate(pb, FMT(annotation_prefix, "_%zu", i)); - } -} - -template -void pb_variable_array::fill_with_field_elements(protoboard &pb, const std::vector& vals) const -{ - assert(this->size() == vals.size()); - for (size_t i = 0; i < vals.size(); ++i) - { - pb.val((*this)[i]) = vals[i]; - } -} - -template -void pb_variable_array::fill_with_bits(protoboard &pb, const bit_vector& bits) const -{ - assert(this->size() == bits.size()); - for (size_t i = 0; i < bits.size(); ++i) - { - pb.val((*this)[i]) = (bits[i] ? FieldT::one() : FieldT::zero()); - } -} - -template -void pb_variable_array::fill_with_bits_of_field_element(protoboard &pb, const FieldT &r) const -{ - const bigint rint = r.as_bigint(); - for (size_t i = 0; i < this->size(); ++i) - { - pb.val((*this)[i]) = rint.test_bit(i) ? FieldT::one() : FieldT::zero(); - } -} - -template -void pb_variable_array::fill_with_bits_of_uint64(protoboard &pb, const uint64_t i) const -{ - this->fill_with_bits_of_field_element(pb, FieldT(i, true)); -} - -template -std::vector pb_variable_array::get_vals(const protoboard &pb) const -{ - std::vector result(this->size()); - for (size_t i = 0; i < this->size(); ++i) - { - result[i] = pb.val((*this)[i]); - } - return result; -} - -template -bit_vector pb_variable_array::get_bits(const protoboard &pb) const -{ - bit_vector result; - for (size_t i = 0; i < this->size(); ++i) - { - const FieldT v = pb.val((*this)[i]); - assert(v == FieldT::zero() || v == FieldT::one()); - result.push_back(v == FieldT::one()); - } - return result; -} - -template -FieldT pb_variable_array::get_field_element_from_bits(const protoboard &pb) const -{ - FieldT result = FieldT::zero(); - - for (size_t i = 0; i < this->size(); ++i) - { - /* push in the new bit */ - const FieldT v = pb.val((*this)[this->size()-1-i]); - assert(v == FieldT::zero() || v == FieldT::one()); - result += result + v; - } - - return result; -} - -template -pb_linear_combination::pb_linear_combination() -{ - this->is_variable = false; - this->index = 0; -} - -template -pb_linear_combination::pb_linear_combination(const pb_variable &var) -{ - this->is_variable = true; - this->index = var.index; - this->terms.emplace_back(linear_term(var)); -} - -template -void pb_linear_combination::assign(protoboard &pb, const linear_combination &lc) -{ - assert(this->is_variable == false); - this->index = pb.allocate_lc_index(); - this->terms = lc.terms; -} - -template -void pb_linear_combination::evaluate(protoboard &pb) const -{ - if (this->is_variable) - { - return; // do nothing - } - - FieldT sum = 0; - for (auto term : this->terms) - { - sum += term.coeff * pb.val(pb_variable(term.index)); - } - - pb.lc_val(*this) = sum; -} - -template -bool pb_linear_combination::is_constant() const -{ - if (is_variable) - { - return (index == 0); - } - else - { - for (auto term : this->terms) - { - if (term.index != 0) - { - return false; - } - } - - return true; - } -} - -template -FieldT pb_linear_combination::constant_term() const -{ - if (is_variable) - { - return (index == 0 ? FieldT::one() : FieldT::zero()); - } - else - { - FieldT result = FieldT::zero(); - for (auto term : this->terms) - { - if (term.index == 0) - { - result += term.coeff; - } - } - return result; - } -} - -template -void pb_linear_combination_array::evaluate(protoboard &pb) const -{ - for (size_t i = 0; i < this->size(); ++i) - { - (*this)[i].evaluate(pb); - } -} - -template -void pb_linear_combination_array::fill_with_field_elements(protoboard &pb, const std::vector& vals) const -{ - assert(this->size() == vals.size()); - for (size_t i = 0; i < vals.size(); ++i) - { - pb.lc_val((*this)[i]) = vals[i]; - } -} - -template -void pb_linear_combination_array::fill_with_bits(protoboard &pb, const bit_vector& bits) const -{ - assert(this->size() == bits.size()); - for (size_t i = 0; i < bits.size(); ++i) - { - pb.lc_val((*this)[i]) = (bits[i] ? FieldT::one() : FieldT::zero()); - } -} - -template -void pb_linear_combination_array::fill_with_bits_of_field_element(protoboard &pb, const FieldT &r) const -{ - const bigint rint = r.as_bigint(); - for (size_t i = 0; i < this->size(); ++i) - { - pb.lc_val((*this)[i]) = rint.test_bit(i) ? FieldT::one() : FieldT::zero(); - } -} - -template -void pb_linear_combination_array::fill_with_bits_of_uint64(protoboard &pb, const uint64_t i) const -{ - this->fill_with_bits_of_field_element(pb, FieldT(i)); -} - -template -std::vector pb_linear_combination_array::get_vals(const protoboard &pb) const -{ - std::vector result(this->size()); - for (size_t i = 0; i < this->size(); ++i) - { - result[i] = pb.lc_val((*this)[i]); - } - return result; -} - -template -bit_vector pb_linear_combination_array::get_bits(const protoboard &pb) const -{ - bit_vector result; - for (size_t i = 0; i < this->size(); ++i) - { - const FieldT v = pb.lc_val((*this)[i]); - assert(v == FieldT::zero() || v == FieldT::one()); - result.push_back(v == FieldT::one()); - } - return result; -} - -template -FieldT pb_linear_combination_array::get_field_element_from_bits(const protoboard &pb) const -{ - FieldT result = FieldT::zero(); - - for (size_t i = 0; i < this->size(); ++i) - { - /* push in the new bit */ - const FieldT v = pb.lc_val((*this)[this->size()-1-i]); - assert(v == FieldT::zero() || v == FieldT::one()); - result += result + v; - } - - return result; -} - -template -linear_combination pb_sum(const pb_linear_combination_array &v) -{ - linear_combination result; - for (auto &term : v) - { - result = result + term; - } - - return result; -} - -template -linear_combination pb_packing_sum(const pb_linear_combination_array &v) -{ - FieldT twoi = FieldT::one(); // will hold 2^i entering each iteration - std::vector > all_terms; - for (auto &lc : v) - { - for (auto &term : lc.terms) - { - all_terms.emplace_back(twoi * term); - } - twoi += twoi; - } - - return linear_combination(all_terms); -} - -template -linear_combination pb_coeff_sum(const pb_linear_combination_array &v, const std::vector &coeffs) -{ - assert(v.size() == coeffs.size()); - std::vector > all_terms; - - auto coeff_it = coeffs.begin(); - for (auto &lc : v) - { - for (auto &term : lc.terms) - { - all_terms.emplace_back((*coeff_it) * term); - } - ++coeff_it; - } - - return linear_combination(all_terms); -} - - -} // libsnark -#endif // PB_VARIABLE_TCC diff --git a/src/snark/libsnark/gadgetlib1/protoboard.hpp b/src/snark/libsnark/gadgetlib1/protoboard.hpp deleted file mode 100644 index a910a6df9..000000000 --- a/src/snark/libsnark/gadgetlib1/protoboard.hpp +++ /dev/null @@ -1,75 +0,0 @@ -/** @file - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef PROTOBOARD_HPP_ -#define PROTOBOARD_HPP_ - -#include -#include -#include -#include -#include -#include "gadgetlib1/pb_variable.hpp" -#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" -#include "common/utils.hpp" - -namespace libsnark { - -template -class r1cs_constraint; - -template -class r1cs_constraint_system; - -template -class protoboard { -private: - FieldT constant_term; /* only here, because pb.val() needs to be able to return reference to the constant 1 term */ - r1cs_variable_assignment values; /* values[0] will hold the value of the first allocated variable of the protoboard, *NOT* constant 1 */ - var_index_t next_free_var; - lc_index_t next_free_lc; - std::vector lc_values; -public: - r1cs_constraint_system constraint_system; - - protoboard(); - - void clear_values(); - - FieldT& val(const pb_variable &var); - FieldT val(const pb_variable &var) const; - - FieldT& lc_val(const pb_linear_combination &lc); - FieldT lc_val(const pb_linear_combination &lc) const; - - void add_r1cs_constraint(const r1cs_constraint &constr, const std::string &annotation=""); - void augment_variable_annotation(const pb_variable &v, const std::string &postfix); - bool is_satisfied() const; - void dump_variables() const; - - size_t num_constraints() const; - size_t num_inputs() const; - size_t num_variables() const; - - void set_input_sizes(const size_t primary_input_size); - - r1cs_variable_assignment full_variable_assignment() const; - r1cs_primary_input primary_input() const; - r1cs_auxiliary_input auxiliary_input() const; - r1cs_constraint_system get_constraint_system() const; - - friend class pb_variable; - friend class pb_linear_combination; - -private: - var_index_t allocate_var_index(const std::string &annotation=""); - lc_index_t allocate_lc_index(); -}; - -} // libsnark -#include "gadgetlib1/protoboard.tcc" -#endif // PROTOBOARD_HPP_ diff --git a/src/snark/libsnark/gadgetlib1/protoboard.tcc b/src/snark/libsnark/gadgetlib1/protoboard.tcc deleted file mode 100644 index 882af28e6..000000000 --- a/src/snark/libsnark/gadgetlib1/protoboard.tcc +++ /dev/null @@ -1,189 +0,0 @@ -/** @file - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef PROTOBOARD_TCC_ -#define PROTOBOARD_TCC_ - -#include -#include -#include "common/profiling.hpp" - -namespace libsnark { - -template -protoboard::protoboard() -{ - constant_term = FieldT::one(); - -#ifdef DEBUG - constraint_system.variable_annotations[0] = "ONE"; -#endif - - next_free_var = 1; /* to account for constant 1 term */ - next_free_lc = 0; -} - -template -void protoboard::clear_values() -{ - std::fill(values.begin(), values.end(), FieldT::zero()); -} - -template -var_index_t protoboard::allocate_var_index(const std::string &annotation) -{ -#ifdef DEBUG - assert(annotation != ""); - constraint_system.variable_annotations[next_free_var] = annotation; -#else - UNUSED(annotation); -#endif - ++constraint_system.auxiliary_input_size; - values.emplace_back(FieldT::zero()); - return next_free_var++; -} - -template -lc_index_t protoboard::allocate_lc_index() -{ - lc_values.emplace_back(FieldT::zero()); - return next_free_lc++; -} - -template -FieldT& protoboard::val(const pb_variable &var) -{ - assert(var.index <= values.size()); - return (var.index == 0 ? constant_term : values[var.index-1]); -} - -template -FieldT protoboard::val(const pb_variable &var) const -{ - assert(var.index <= values.size()); - return (var.index == 0 ? constant_term : values[var.index-1]); -} - -template -FieldT& protoboard::lc_val(const pb_linear_combination &lc) -{ - if (lc.is_variable) - { - return this->val(pb_variable(lc.index)); - } - else - { - assert(lc.index < lc_values.size()); - return lc_values[lc.index]; - } -} - -template -FieldT protoboard::lc_val(const pb_linear_combination &lc) const -{ - if (lc.is_variable) - { - return this->val(pb_variable(lc.index)); - } - else - { - assert(lc.index < lc_values.size()); - return lc_values[lc.index]; - } -} - -template -void protoboard::add_r1cs_constraint(const r1cs_constraint &constr, const std::string &annotation) -{ -#ifdef DEBUG - assert(annotation != ""); - constraint_system.constraint_annotations[constraint_system.constraints.size()] = annotation; -#else - UNUSED(annotation); -#endif - constraint_system.constraints.emplace_back(constr); -} - -template -void protoboard::augment_variable_annotation(const pb_variable &v, const std::string &postfix) -{ -#ifdef DEBUG - auto it = constraint_system.variable_annotations.find(v.index); - constraint_system.variable_annotations[v.index] = (it == constraint_system.variable_annotations.end() ? "" : it->second + " ") + postfix; -#endif -} - -template -bool protoboard::is_satisfied() const -{ - return constraint_system.is_satisfied(primary_input(), auxiliary_input()); -} - -template -void protoboard::dump_variables() const -{ -#ifdef DEBUG - for (size_t i = 0; i < constraint_system.num_variables; ++i) - { - printf("%-40s --> ", constraint_system.variable_annotations[i].c_str()); - values[i].as_bigint().print_hex(); - } -#endif -} - -template -size_t protoboard::num_constraints() const -{ - return constraint_system.num_constraints(); -} - -template -size_t protoboard::num_inputs() const -{ - return constraint_system.num_inputs(); -} - -template -size_t protoboard::num_variables() const -{ - return next_free_var - 1; -} - -template -void protoboard::set_input_sizes(const size_t primary_input_size) -{ - assert(primary_input_size <= num_variables()); - constraint_system.primary_input_size = primary_input_size; - constraint_system.auxiliary_input_size = num_variables() - primary_input_size; -} - -template -r1cs_variable_assignment protoboard::full_variable_assignment() const -{ - return values; -} - -template -r1cs_primary_input protoboard::primary_input() const -{ - return r1cs_primary_input(values.begin(), values.begin() + num_inputs()); -} - -template -r1cs_auxiliary_input protoboard::auxiliary_input() const -{ - return r1cs_primary_input(values.begin() + num_inputs(), values.end()); -} - -template -r1cs_constraint_system protoboard::get_constraint_system() const -{ - return constraint_system; -} - -} // libsnark -#endif // PROTOBOARD_TCC_ diff --git a/src/snark/libsnark/gtests.cpp b/src/snark/libsnark/gtests.cpp deleted file mode 100644 index 74c66bdad..000000000 --- a/src/snark/libsnark/gtests.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include - -#include "common/profiling.hpp" - -int main(int argc, char **argv) { - libsnark::inhibit_profiling_info = true; - libsnark::inhibit_profiling_counters = true; - - testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} - diff --git a/src/snark/libsnark/reductions/r1cs_to_qap/r1cs_to_qap.hpp b/src/snark/libsnark/reductions/r1cs_to_qap/r1cs_to_qap.hpp deleted file mode 100644 index b3cde710c..000000000 --- a/src/snark/libsnark/reductions/r1cs_to_qap/r1cs_to_qap.hpp +++ /dev/null @@ -1,70 +0,0 @@ -/** @file - ***************************************************************************** - - Declaration of interfaces for a R1CS-to-QAP reduction, that is, constructing - a QAP ("Quadratic Arithmetic Program") from a R1CS ("Rank-1 Constraint System"). - - QAPs are defined in \[GGPR13], and construced for R1CS also in \[GGPR13]. - - The implementation of the reduction follows, extends, and optimizes - the efficient approach described in Appendix E of \[BCGTV13]. - - References: - - \[BCGTV13] - "SNARKs for C: Verifying Program Executions Succinctly and in Zero Knowledge", - Eli Ben-Sasson, Alessandro Chiesa, Daniel Genkin, Eran Tromer, Madars Virza, - CRYPTO 2013, - - - \[GGPR13]: - "Quadratic span programs and succinct NIZKs without PCPs", - Rosario Gennaro, Craig Gentry, Bryan Parno, Mariana Raykova, - EUROCRYPT 2013, - - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef R1CS_TO_QAP_HPP_ -#define R1CS_TO_QAP_HPP_ - -#include "relations/arithmetic_programs/qap/qap.hpp" -#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" - -namespace libsnark { - -/** - * Instance map for the R1CS-to-QAP reduction. - */ -template -qap_instance r1cs_to_qap_instance_map(const r1cs_constraint_system &cs); - -/** - * Instance map for the R1CS-to-QAP reduction followed by evaluation of the resulting QAP instance. - */ -template -qap_instance_evaluation r1cs_to_qap_instance_map_with_evaluation(const r1cs_constraint_system &cs, - const FieldT &t); - -/** - * Witness map for the R1CS-to-QAP reduction. - * - * The witness map takes zero knowledge into account when d1,d2,d3 are random. - */ -template -qap_witness r1cs_to_qap_witness_map(const r1cs_constraint_system &cs, - const r1cs_primary_input &primary_input, - const r1cs_auxiliary_input &auxiliary_input, - const FieldT &d1, - const FieldT &d2, - const FieldT &d3); - -} // libsnark - -#include "reductions/r1cs_to_qap/r1cs_to_qap.tcc" - -#endif // R1CS_TO_QAP_HPP_ diff --git a/src/snark/libsnark/reductions/r1cs_to_qap/r1cs_to_qap.tcc b/src/snark/libsnark/reductions/r1cs_to_qap/r1cs_to_qap.tcc deleted file mode 100644 index 3d0bee273..000000000 --- a/src/snark/libsnark/reductions/r1cs_to_qap/r1cs_to_qap.tcc +++ /dev/null @@ -1,338 +0,0 @@ -/** @file - ***************************************************************************** - - Implementation of interfaces for a R1CS-to-QAP reduction. - - See r1cs_to_qap.hpp . - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef R1CS_TO_QAP_TCC_ -#define R1CS_TO_QAP_TCC_ - -#include "common/profiling.hpp" -#include "common/utils.hpp" -#include "algebra/evaluation_domain/evaluation_domain.hpp" - -namespace libsnark { - -/** - * Instance map for the R1CS-to-QAP reduction. - * - * Namely, given a R1CS constraint system cs, construct a QAP instance for which: - * A := (A_0(z),A_1(z),...,A_m(z)) - * B := (B_0(z),B_1(z),...,B_m(z)) - * C := (C_0(z),C_1(z),...,C_m(z)) - * where - * m = number of variables of the QAP - * and - * each A_i,B_i,C_i is expressed in the Lagrange basis. - */ -template -qap_instance r1cs_to_qap_instance_map(const r1cs_constraint_system &cs) -{ - enter_block("Call to r1cs_to_qap_instance_map"); - - const std::shared_ptr > domain = get_evaluation_domain(cs.num_constraints() + cs.num_inputs() + 1); - - std::vector > A_in_Lagrange_basis(cs.num_variables()+1); - std::vector > B_in_Lagrange_basis(cs.num_variables()+1); - std::vector > C_in_Lagrange_basis(cs.num_variables()+1); - - enter_block("Compute polynomials A, B, C in Lagrange basis"); - /** - * add and process the constraints - * input_i * 0 = 0 - * to ensure soundness of input consistency - */ - for (size_t i = 0; i <= cs.num_inputs(); ++i) - { - A_in_Lagrange_basis[i][cs.num_constraints() + i] = FieldT::one(); - } - /* process all other constraints */ - for (size_t i = 0; i < cs.num_constraints(); ++i) - { - for (size_t j = 0; j < cs.constraints[i].a.terms.size(); ++j) - { - A_in_Lagrange_basis[cs.constraints[i].a.terms[j].index][i] += - cs.constraints[i].a.terms[j].coeff; - } - - for (size_t j = 0; j < cs.constraints[i].b.terms.size(); ++j) - { - B_in_Lagrange_basis[cs.constraints[i].b.terms[j].index][i] += - cs.constraints[i].b.terms[j].coeff; - } - - for (size_t j = 0; j < cs.constraints[i].c.terms.size(); ++j) - { - C_in_Lagrange_basis[cs.constraints[i].c.terms[j].index][i] += - cs.constraints[i].c.terms[j].coeff; - } - } - leave_block("Compute polynomials A, B, C in Lagrange basis"); - - leave_block("Call to r1cs_to_qap_instance_map"); - - return qap_instance(domain, - cs.num_variables(), - domain->m, - cs.num_inputs(), - std::move(A_in_Lagrange_basis), - std::move(B_in_Lagrange_basis), - std::move(C_in_Lagrange_basis)); -} - -/** - * Instance map for the R1CS-to-QAP reduction followed by evaluation of the resulting QAP instance. - * - * Namely, given a R1CS constraint system cs and a field element t, construct - * a QAP instance (evaluated at t) for which: - * At := (A_0(t),A_1(t),...,A_m(t)) - * Bt := (B_0(t),B_1(t),...,B_m(t)) - * Ct := (C_0(t),C_1(t),...,C_m(t)) - * Ht := (1,t,t^2,...,t^n) - * Zt := Z(t) = "vanishing polynomial of a certain set S, evaluated at t" - * where - * m = number of variables of the QAP - * n = degree of the QAP - */ -template -qap_instance_evaluation r1cs_to_qap_instance_map_with_evaluation(const r1cs_constraint_system &cs, - const FieldT &t) -{ - enter_block("Call to r1cs_to_qap_instance_map_with_evaluation"); - - const std::shared_ptr > domain = get_evaluation_domain(cs.num_constraints() + cs.num_inputs() + 1); - - std::vector At, Bt, Ct, Ht; - - At.resize(cs.num_variables()+1, FieldT::zero()); - Bt.resize(cs.num_variables()+1, FieldT::zero()); - Ct.resize(cs.num_variables()+1, FieldT::zero()); - Ht.reserve(domain->m+1); - - const FieldT Zt = domain->compute_Z(t); - - enter_block("Compute evaluations of A, B, C, H at t"); - const std::vector u = domain->lagrange_coeffs(t); - /** - * add and process the constraints - * input_i * 0 = 0 - * to ensure soundness of input consistency - */ - for (size_t i = 0; i <= cs.num_inputs(); ++i) - { - At[i] = u[cs.num_constraints() + i]; - } - /* process all other constraints */ - for (size_t i = 0; i < cs.num_constraints(); ++i) - { - for (size_t j = 0; j < cs.constraints[i].a.terms.size(); ++j) - { - At[cs.constraints[i].a.terms[j].index] += - u[i]*cs.constraints[i].a.terms[j].coeff; - } - - for (size_t j = 0; j < cs.constraints[i].b.terms.size(); ++j) - { - Bt[cs.constraints[i].b.terms[j].index] += - u[i]*cs.constraints[i].b.terms[j].coeff; - } - - for (size_t j = 0; j < cs.constraints[i].c.terms.size(); ++j) - { - Ct[cs.constraints[i].c.terms[j].index] += - u[i]*cs.constraints[i].c.terms[j].coeff; - } - } - - FieldT ti = FieldT::one(); - for (size_t i = 0; i < domain->m+1; ++i) - { - Ht.emplace_back(ti); - ti *= t; - } - leave_block("Compute evaluations of A, B, C, H at t"); - - leave_block("Call to r1cs_to_qap_instance_map_with_evaluation"); - - return qap_instance_evaluation(domain, - cs.num_variables(), - domain->m, - cs.num_inputs(), - t, - std::move(At), - std::move(Bt), - std::move(Ct), - std::move(Ht), - Zt); -} - -/** - * Witness map for the R1CS-to-QAP reduction. - * - * The witness map takes zero knowledge into account when d1,d2,d3 are random. - * - * More precisely, compute the coefficients - * h_0,h_1,...,h_n - * of the polynomial - * H(z) := (A(z)*B(z)-C(z))/Z(z) - * where - * A(z) := A_0(z) + \sum_{k=1}^{m} w_k A_k(z) + d1 * Z(z) - * B(z) := B_0(z) + \sum_{k=1}^{m} w_k B_k(z) + d2 * Z(z) - * C(z) := C_0(z) + \sum_{k=1}^{m} w_k C_k(z) + d3 * Z(z) - * Z(z) := "vanishing polynomial of set S" - * and - * m = number of variables of the QAP - * n = degree of the QAP - * - * This is done as follows: - * (1) compute evaluations of A,B,C on S = {sigma_1,...,sigma_n} - * (2) compute coefficients of A,B,C - * (3) compute evaluations of A,B,C on T = "coset of S" - * (4) compute evaluation of H on T - * (5) compute coefficients of H - * (6) patch H to account for d1,d2,d3 (i.e., add coefficients of the polynomial (A d2 + B d1 - d3) + d1*d2*Z ) - * - * The code below is not as simple as the above high-level description due to - * some reshuffling to save space. - */ -template -qap_witness r1cs_to_qap_witness_map(const r1cs_constraint_system &cs, - const r1cs_primary_input &primary_input, - const r1cs_auxiliary_input &auxiliary_input, - const FieldT &d1, - const FieldT &d2, - const FieldT &d3) -{ - enter_block("Call to r1cs_to_qap_witness_map"); - - /* sanity check */ - assert(cs.is_satisfied(primary_input, auxiliary_input)); - - const std::shared_ptr > domain = get_evaluation_domain(cs.num_constraints() + cs.num_inputs() + 1); - - r1cs_variable_assignment full_variable_assignment = primary_input; - full_variable_assignment.insert(full_variable_assignment.end(), auxiliary_input.begin(), auxiliary_input.end()); - - enter_block("Compute evaluation of polynomials A, B on set S"); - std::vector aA(domain->m, FieldT::zero()), aB(domain->m, FieldT::zero()); - - /* account for the additional constraints input_i * 0 = 0 */ - for (size_t i = 0; i <= cs.num_inputs(); ++i) - { - aA[i+cs.num_constraints()] = (i > 0 ? full_variable_assignment[i-1] : FieldT::one()); - } - /* account for all other constraints */ - for (size_t i = 0; i < cs.num_constraints(); ++i) - { - aA[i] += cs.constraints[i].a.evaluate(full_variable_assignment); - aB[i] += cs.constraints[i].b.evaluate(full_variable_assignment); - } - leave_block("Compute evaluation of polynomials A, B on set S"); - - enter_block("Compute coefficients of polynomial A"); - domain->iFFT(aA); - leave_block("Compute coefficients of polynomial A"); - - enter_block("Compute coefficients of polynomial B"); - domain->iFFT(aB); - leave_block("Compute coefficients of polynomial B"); - - enter_block("Compute ZK-patch"); - std::vector coefficients_for_H(domain->m+1, FieldT::zero()); -#ifdef MULTICORE -#pragma omp parallel for -#endif - /* add coefficients of the polynomial (d2*A + d1*B - d3) + d1*d2*Z */ - for (size_t i = 0; i < domain->m; ++i) - { - coefficients_for_H[i] = d2*aA[i] + d1*aB[i]; - } - coefficients_for_H[0] -= d3; - domain->add_poly_Z(d1*d2, coefficients_for_H); - leave_block("Compute ZK-patch"); - - enter_block("Compute evaluation of polynomial A on set T"); - domain->cosetFFT(aA, FieldT::multiplicative_generator); - leave_block("Compute evaluation of polynomial A on set T"); - - enter_block("Compute evaluation of polynomial B on set T"); - domain->cosetFFT(aB, FieldT::multiplicative_generator); - leave_block("Compute evaluation of polynomial B on set T"); - - enter_block("Compute evaluation of polynomial H on set T"); - std::vector &H_tmp = aA; // can overwrite aA because it is not used later -#ifdef MULTICORE -#pragma omp parallel for -#endif - for (size_t i = 0; i < domain->m; ++i) - { - H_tmp[i] = aA[i]*aB[i]; - } - std::vector().swap(aB); // destroy aB - - enter_block("Compute evaluation of polynomial C on set S"); - std::vector aC(domain->m, FieldT::zero()); - for (size_t i = 0; i < cs.num_constraints(); ++i) - { - aC[i] += cs.constraints[i].c.evaluate(full_variable_assignment); - } - leave_block("Compute evaluation of polynomial C on set S"); - - enter_block("Compute coefficients of polynomial C"); - domain->iFFT(aC); - leave_block("Compute coefficients of polynomial C"); - - enter_block("Compute evaluation of polynomial C on set T"); - domain->cosetFFT(aC, FieldT::multiplicative_generator); - leave_block("Compute evaluation of polynomial C on set T"); - -#ifdef MULTICORE -#pragma omp parallel for -#endif - for (size_t i = 0; i < domain->m; ++i) - { - H_tmp[i] = (H_tmp[i]-aC[i]); - } - - enter_block("Divide by Z on set T"); - domain->divide_by_Z_on_coset(H_tmp); - leave_block("Divide by Z on set T"); - - leave_block("Compute evaluation of polynomial H on set T"); - - enter_block("Compute coefficients of polynomial H"); - domain->icosetFFT(H_tmp, FieldT::multiplicative_generator); - leave_block("Compute coefficients of polynomial H"); - - enter_block("Compute sum of H and ZK-patch"); -#ifdef MULTICORE -#pragma omp parallel for -#endif - for (size_t i = 0; i < domain->m; ++i) - { - coefficients_for_H[i] += H_tmp[i]; - } - leave_block("Compute sum of H and ZK-patch"); - - leave_block("Call to r1cs_to_qap_witness_map"); - - return qap_witness(cs.num_variables(), - domain->m, - cs.num_inputs(), - d1, - d2, - d3, - full_variable_assignment, - std::move(coefficients_for_H)); -} - -} // libsnark - -#endif // R1CS_TO_QAP_TCC_ diff --git a/src/snark/libsnark/relations/arithmetic_programs/qap/qap.hpp b/src/snark/libsnark/relations/arithmetic_programs/qap/qap.hpp deleted file mode 100644 index 4991d203b..000000000 --- a/src/snark/libsnark/relations/arithmetic_programs/qap/qap.hpp +++ /dev/null @@ -1,193 +0,0 @@ -/** @file - ***************************************************************************** - - Declaration of interfaces for a QAP ("Quadratic Arithmetic Program"). - - QAPs are defined in \[GGPR13]. - - References: - - \[GGPR13]: - "Quadratic span programs and succinct NIZKs without PCPs", - Rosario Gennaro, Craig Gentry, Bryan Parno, Mariana Raykova, - EUROCRYPT 2013, - - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef QAP_HPP_ -#define QAP_HPP_ - -#include "algebra/evaluation_domain/evaluation_domain.hpp" - -namespace libsnark { - -/* forward declaration */ -template -class qap_witness; - -/** - * A QAP instance. - * - * Specifically, the datastructure stores: - * - a choice of domain (corresponding to a certain subset of the field); - * - the number of variables, the degree, and the number of inputs; and - * - coefficients of the A,B,C polynomials in the Lagrange basis. - * - * There is no need to store the Z polynomial because it is uniquely - * determined by the domain (as Z is its vanishing polynomial). - */ -template -class qap_instance { -private: - size_t num_variables_; - size_t degree_; - size_t num_inputs_; - -public: - std::shared_ptr > domain; - - std::vector > A_in_Lagrange_basis; - std::vector > B_in_Lagrange_basis; - std::vector > C_in_Lagrange_basis; - - qap_instance(const std::shared_ptr > &domain, - const size_t num_variables, - const size_t degree, - const size_t num_inputs, - const std::vector > &A_in_Lagrange_basis, - const std::vector > &B_in_Lagrange_basis, - const std::vector > &C_in_Lagrange_basis); - - qap_instance(const std::shared_ptr > &domain, - const size_t num_variables, - const size_t degree, - const size_t num_inputs, - std::vector > &&A_in_Lagrange_basis, - std::vector > &&B_in_Lagrange_basis, - std::vector > &&C_in_Lagrange_basis); - - qap_instance(const qap_instance &other) = default; - qap_instance(qap_instance &&other) = default; - qap_instance& operator=(const qap_instance &other) = default; - qap_instance& operator=(qap_instance &&other) = default; - - size_t num_variables() const; - size_t degree() const; - size_t num_inputs() const; - - bool is_satisfied(const qap_witness &witness) const; -}; - -/** - * A QAP instance evaluation is a QAP instance that is evaluated at a field element t. - * - * Specifically, the datastructure stores: - * - a choice of domain (corresponding to a certain subset of the field); - * - the number of variables, the degree, and the number of inputs; - * - a field element t; - * - evaluations of the A,B,C (and Z) polynomials at t; - * - evaluations of all monomials of t; - * - counts about how many of the above evaluations are in fact non-zero. - */ -template -class qap_instance_evaluation { -private: - size_t num_variables_; - size_t degree_; - size_t num_inputs_; -public: - std::shared_ptr > domain; - - FieldT t; - - std::vector At, Bt, Ct, Ht; - - FieldT Zt; - - qap_instance_evaluation(const std::shared_ptr > &domain, - const size_t num_variables, - const size_t degree, - const size_t num_inputs, - const FieldT &t, - const std::vector &At, - const std::vector &Bt, - const std::vector &Ct, - const std::vector &Ht, - const FieldT &Zt); - qap_instance_evaluation(const std::shared_ptr > &domain, - const size_t num_variables, - const size_t degree, - const size_t num_inputs, - const FieldT &t, - std::vector &&At, - std::vector &&Bt, - std::vector &&Ct, - std::vector &&Ht, - const FieldT &Zt); - - qap_instance_evaluation(const qap_instance_evaluation &other) = default; - qap_instance_evaluation(qap_instance_evaluation &&other) = default; - qap_instance_evaluation& operator=(const qap_instance_evaluation &other) = default; - qap_instance_evaluation& operator=(qap_instance_evaluation &&other) = default; - - size_t num_variables() const; - size_t degree() const; - size_t num_inputs() const; - - bool is_satisfied(const qap_witness &witness) const; -}; - -/** - * A QAP witness. - */ -template -class qap_witness { -private: - size_t num_variables_; - size_t degree_; - size_t num_inputs_; - -public: - FieldT d1, d2, d3; - - std::vector coefficients_for_ABCs; - std::vector coefficients_for_H; - - qap_witness(const size_t num_variables, - const size_t degree, - const size_t num_inputs, - const FieldT &d1, - const FieldT &d2, - const FieldT &d3, - const std::vector &coefficients_for_ABCs, - const std::vector &coefficients_for_H); - - qap_witness(const size_t num_variables, - const size_t degree, - const size_t num_inputs, - const FieldT &d1, - const FieldT &d2, - const FieldT &d3, - const std::vector &coefficients_for_ABCs, - std::vector &&coefficients_for_H); - - qap_witness(const qap_witness &other) = default; - qap_witness(qap_witness &&other) = default; - qap_witness& operator=(const qap_witness &other) = default; - qap_witness& operator=(qap_witness &&other) = default; - - size_t num_variables() const; - size_t degree() const; - size_t num_inputs() const; -}; - -} // libsnark - -#include "relations/arithmetic_programs/qap/qap.tcc" - -#endif // QAP_HPP_ diff --git a/src/snark/libsnark/relations/arithmetic_programs/qap/qap.tcc b/src/snark/libsnark/relations/arithmetic_programs/qap/qap.tcc deleted file mode 100644 index a4a3c96a2..000000000 --- a/src/snark/libsnark/relations/arithmetic_programs/qap/qap.tcc +++ /dev/null @@ -1,324 +0,0 @@ -/** @file -***************************************************************************** - -Implementation of interfaces for a QAP ("Quadratic Arithmetic Program"). - -See qap.hpp . - -***************************************************************************** -* @author This file is part of libsnark, developed by SCIPR Lab -* and contributors (see AUTHORS). -* @copyright MIT license (see LICENSE file) -*****************************************************************************/ - -#ifndef QAP_TCC_ -#define QAP_TCC_ - -#include "common/profiling.hpp" -#include "common/utils.hpp" -#include "algebra/evaluation_domain/evaluation_domain.hpp" -#include "algebra/scalar_multiplication/multiexp.hpp" - -namespace libsnark { - -template -qap_instance::qap_instance(const std::shared_ptr > &domain, - const size_t num_variables, - const size_t degree, - const size_t num_inputs, - const std::vector > &A_in_Lagrange_basis, - const std::vector > &B_in_Lagrange_basis, - const std::vector > &C_in_Lagrange_basis) : - num_variables_(num_variables), - degree_(degree), - num_inputs_(num_inputs), - domain(domain), - A_in_Lagrange_basis(A_in_Lagrange_basis), - B_in_Lagrange_basis(B_in_Lagrange_basis), - C_in_Lagrange_basis(C_in_Lagrange_basis) -{ -} - -template -qap_instance::qap_instance(const std::shared_ptr > &domain, - const size_t num_variables, - const size_t degree, - const size_t num_inputs, - std::vector > &&A_in_Lagrange_basis, - std::vector > &&B_in_Lagrange_basis, - std::vector > &&C_in_Lagrange_basis) : - num_variables_(num_variables), - degree_(degree), - num_inputs_(num_inputs), - domain(domain), - A_in_Lagrange_basis(std::move(A_in_Lagrange_basis)), - B_in_Lagrange_basis(std::move(B_in_Lagrange_basis)), - C_in_Lagrange_basis(std::move(C_in_Lagrange_basis)) -{ -} - -template -size_t qap_instance::num_variables() const -{ - return num_variables_; -} - -template -size_t qap_instance::degree() const -{ - return degree_; -} - -template -size_t qap_instance::num_inputs() const -{ - return num_inputs_; -} - -template -bool qap_instance::is_satisfied(const qap_witness &witness) const -{ - const FieldT t = FieldT::random_element(); - - std::vector At(this->num_variables()+1, FieldT::zero()); - std::vector Bt(this->num_variables()+1, FieldT::zero()); - std::vector Ct(this->num_variables()+1, FieldT::zero()); - std::vector Ht(this->degree()+1); - - const FieldT Zt = this->domain->compute_Z(t); - - const std::vector u = this->domain->lagrange_coeffs(t); - - for (size_t i = 0; i < this->num_variables()+1; ++i) - { - for (auto &el : A_in_Lagrange_basis[i]) - { - At[i] += u[el.first] * el.second; - } - - for (auto &el : B_in_Lagrange_basis[i]) - { - Bt[i] += u[el.first] * el.second; - } - - for (auto &el : C_in_Lagrange_basis[i]) - { - Ct[i] += u[el.first] * el.second; - } - } - - FieldT ti = FieldT::one(); - for (size_t i = 0; i < this->degree()+1; ++i) - { - Ht[i] = ti; - ti *= t; - } - - const qap_instance_evaluation eval_qap_inst(this->domain, - this->num_variables(), - this->degree(), - this->num_inputs(), - t, - std::move(At), - std::move(Bt), - std::move(Ct), - std::move(Ht), - Zt); - return eval_qap_inst.is_satisfied(witness); -} - -template -qap_instance_evaluation::qap_instance_evaluation(const std::shared_ptr > &domain, - const size_t num_variables, - const size_t degree, - const size_t num_inputs, - const FieldT &t, - const std::vector &At, - const std::vector &Bt, - const std::vector &Ct, - const std::vector &Ht, - const FieldT &Zt) : - num_variables_(num_variables), - degree_(degree), - num_inputs_(num_inputs), - domain(domain), - t(t), - At(At), - Bt(Bt), - Ct(Ct), - Ht(Ht), - Zt(Zt) -{ -} - -template -qap_instance_evaluation::qap_instance_evaluation(const std::shared_ptr > &domain, - const size_t num_variables, - const size_t degree, - const size_t num_inputs, - const FieldT &t, - std::vector &&At, - std::vector &&Bt, - std::vector &&Ct, - std::vector &&Ht, - const FieldT &Zt) : - num_variables_(num_variables), - degree_(degree), - num_inputs_(num_inputs), - domain(domain), - t(t), - At(std::move(At)), - Bt(std::move(Bt)), - Ct(std::move(Ct)), - Ht(std::move(Ht)), - Zt(Zt) -{ -} - -template -size_t qap_instance_evaluation::num_variables() const -{ - return num_variables_; -} - -template -size_t qap_instance_evaluation::degree() const -{ - return degree_; -} - -template -size_t qap_instance_evaluation::num_inputs() const -{ - return num_inputs_; -} - -template -bool qap_instance_evaluation::is_satisfied(const qap_witness &witness) const -{ - - if (this->num_variables() != witness.num_variables()) - { - return false; - } - - if (this->degree() != witness.degree()) - { - return false; - } - - if (this->num_inputs() != witness.num_inputs()) - { - return false; - } - - if (this->num_variables() != witness.coefficients_for_ABCs.size()) - { - return false; - } - - if (this->degree()+1 != witness.coefficients_for_H.size()) - { - return false; - } - - if (this->At.size() != this->num_variables()+1 || this->Bt.size() != this->num_variables()+1 || this->Ct.size() != this->num_variables()+1) - { - return false; - } - - if (this->Ht.size() != this->degree()+1) - { - return false; - } - - if (this->Zt != this->domain->compute_Z(this->t)) - { - return false; - } - - FieldT ans_A = this->At[0] + witness.d1*this->Zt; - FieldT ans_B = this->Bt[0] + witness.d2*this->Zt; - FieldT ans_C = this->Ct[0] + witness.d3*this->Zt; - FieldT ans_H = FieldT::zero(); - - ans_A = ans_A + naive_plain_exp(this->At.begin()+1, this->At.begin()+1+this->num_variables(), - witness.coefficients_for_ABCs.begin(), witness.coefficients_for_ABCs.begin()+this->num_variables()); - ans_B = ans_B + naive_plain_exp(this->Bt.begin()+1, this->Bt.begin()+1+this->num_variables(), - witness.coefficients_for_ABCs.begin(), witness.coefficients_for_ABCs.begin()+this->num_variables()); - ans_C = ans_C + naive_plain_exp(this->Ct.begin()+1, this->Ct.begin()+1+this->num_variables(), - witness.coefficients_for_ABCs.begin(), witness.coefficients_for_ABCs.begin()+this->num_variables()); - ans_H = ans_H + naive_plain_exp(this->Ht.begin(), this->Ht.begin()+this->degree()+1, - witness.coefficients_for_H.begin(), witness.coefficients_for_H.begin()+this->degree()+1); - - if (ans_A * ans_B - ans_C != ans_H * this->Zt) - { - return false; - } - - return true; -} - -template -qap_witness::qap_witness(const size_t num_variables, - const size_t degree, - const size_t num_inputs, - const FieldT &d1, - const FieldT &d2, - const FieldT &d3, - const std::vector &coefficients_for_ABCs, - const std::vector &coefficients_for_H) : - num_variables_(num_variables), - degree_(degree), - num_inputs_(num_inputs), - d1(d1), - d2(d2), - d3(d3), - coefficients_for_ABCs(coefficients_for_ABCs), - coefficients_for_H(coefficients_for_H) -{ -} - -template -qap_witness::qap_witness(const size_t num_variables, - const size_t degree, - const size_t num_inputs, - const FieldT &d1, - const FieldT &d2, - const FieldT &d3, - const std::vector &coefficients_for_ABCs, - std::vector &&coefficients_for_H) : - num_variables_(num_variables), - degree_(degree), - num_inputs_(num_inputs), - d1(d1), - d2(d2), - d3(d3), - coefficients_for_ABCs(coefficients_for_ABCs), - coefficients_for_H(std::move(coefficients_for_H)) -{ -} - - -template -size_t qap_witness::num_variables() const -{ - return num_variables_; -} - -template -size_t qap_witness::degree() const -{ - return degree_; -} - -template -size_t qap_witness::num_inputs() const -{ - return num_inputs_; -} - - -} // libsnark - -#endif // QAP_TCC_ diff --git a/src/snark/libsnark/relations/arithmetic_programs/qap/tests/test_qap.cpp b/src/snark/libsnark/relations/arithmetic_programs/qap/tests/test_qap.cpp deleted file mode 100644 index 5dd48d1e0..000000000 --- a/src/snark/libsnark/relations/arithmetic_programs/qap/tests/test_qap.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/** - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ -#include -#include -#include -#include -#include - -#include "algebra/curves/mnt/mnt6/mnt6_pp.hpp" -#include "algebra/fields/field_utils.hpp" -#include "common/profiling.hpp" -#include "common/utils.hpp" -#include "reductions/r1cs_to_qap/r1cs_to_qap.hpp" -#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" - -using namespace libsnark; - -template -void test_qap(const size_t qap_degree, const size_t num_inputs, const bool binary_input) -{ - /* - We construct an instance where the QAP degree is qap_degree. - So we generate an instance of R1CS where the number of constraints qap_degree - num_inputs - 1. - See the transformation from R1CS to QAP for why this is the case. - So we need that qap_degree >= num_inputs + 1. - */ - assert(num_inputs + 1 <= qap_degree); - enter_block("Call to test_qap"); - - const size_t num_constraints = qap_degree - num_inputs - 1; - - print_indent(); printf("* QAP degree: %zu\n", qap_degree); - print_indent(); printf("* Number of inputs: %zu\n", num_inputs); - print_indent(); printf("* Number of R1CS constraints: %zu\n", num_constraints); - print_indent(); printf("* Input type: %s\n", binary_input ? "binary" : "field"); - - enter_block("Generate constraint system and assignment"); - r1cs_example example; - if (binary_input) - { - example = generate_r1cs_example_with_binary_input(num_constraints, num_inputs); - } - else - { - example = generate_r1cs_example_with_field_input(num_constraints, num_inputs); - } - leave_block("Generate constraint system and assignment"); - - enter_block("Check satisfiability of constraint system"); - assert(example.constraint_system.is_satisfied(example.primary_input, example.auxiliary_input)); - leave_block("Check satisfiability of constraint system"); - - const FieldT t = FieldT::random_element(), - d1 = FieldT::random_element(), - d2 = FieldT::random_element(), - d3 = FieldT::random_element(); - - enter_block("Compute QAP instance 1"); - qap_instance qap_inst_1 = r1cs_to_qap_instance_map(example.constraint_system); - leave_block("Compute QAP instance 1"); - - enter_block("Compute QAP instance 2"); - qap_instance_evaluation qap_inst_2 = r1cs_to_qap_instance_map_with_evaluation(example.constraint_system, t); - leave_block("Compute QAP instance 2"); - - enter_block("Compute QAP witness"); - qap_witness qap_wit = r1cs_to_qap_witness_map(example.constraint_system, example.primary_input, example.auxiliary_input, d1, d2, d3); - leave_block("Compute QAP witness"); - - enter_block("Check satisfiability of QAP instance 1"); - assert(qap_inst_1.is_satisfied(qap_wit)); - leave_block("Check satisfiability of QAP instance 1"); - - enter_block("Check satisfiability of QAP instance 2"); - assert(qap_inst_2.is_satisfied(qap_wit)); - leave_block("Check satisfiability of QAP instance 2"); - - leave_block("Call to test_qap"); -} - -int main() -{ - start_profiling(); - - mnt6_pp::init_public_params(); - - const size_t num_inputs = 10; - - const size_t basic_domain_size = UINT64_C(1)< >(UINT64_C(1) << 21, num_inputs, true); - - leave_block("Test QAP with binary input"); - - enter_block("Test QAP with field input"); - - test_qap >(UINT64_C(1) << 21, num_inputs, false); - - leave_block("Test QAP with field input"); -} diff --git a/src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp b/src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp deleted file mode 100644 index 47003e959..000000000 --- a/src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp +++ /dev/null @@ -1,73 +0,0 @@ -/** @file - ***************************************************************************** - - Declaration of interfaces for a R1CS example, as well as functions to sample - R1CS examples with prescribed parameters (according to some distribution). - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef R1CS_EXAMPLES_HPP_ -#define R1CS_EXAMPLES_HPP_ - -#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" - -namespace libsnark { - -/** - * A R1CS example comprises a R1CS constraint system, R1CS input, and R1CS witness. - */ -template -struct r1cs_example { - r1cs_constraint_system constraint_system; - r1cs_primary_input primary_input; - r1cs_auxiliary_input auxiliary_input; - - r1cs_example() = default; - r1cs_example(const r1cs_example &other) = default; - r1cs_example(const r1cs_constraint_system &constraint_system, - const r1cs_primary_input &primary_input, - const r1cs_auxiliary_input &auxiliary_input) : - constraint_system(constraint_system), - primary_input(primary_input), - auxiliary_input(auxiliary_input) - {}; - r1cs_example(r1cs_constraint_system &&constraint_system, - r1cs_primary_input &&primary_input, - r1cs_auxiliary_input &&auxiliary_input) : - constraint_system(std::move(constraint_system)), - primary_input(std::move(primary_input)), - auxiliary_input(std::move(auxiliary_input)) - {}; -}; - -/** - * Generate a R1CS example such that: - * - the number of constraints of the R1CS constraint system is num_constraints; - * - the number of variables of the R1CS constraint system is (approximately) num_constraints; - * - the number of inputs of the R1CS constraint system is num_inputs; - * - the R1CS input consists of ``full'' field elements (typically require the whole log|Field| bits to represent). - */ -template -r1cs_example generate_r1cs_example_with_field_input(const size_t num_constraints, - const size_t num_inputs); - -/** - * Generate a R1CS example such that: - * - the number of constraints of the R1CS constraint system is num_constraints; - * - the number of variables of the R1CS constraint system is (approximately) num_constraints; - * - the number of inputs of the R1CS constraint system is num_inputs; - * - the R1CS input consists of binary values (as opposed to ``full'' field elements). - */ -template -r1cs_example generate_r1cs_example_with_binary_input(const size_t num_constraints, - const size_t num_inputs); - -} // libsnark - -#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.tcc" - -#endif // R1CS_EXAMPLES_HPP_ diff --git a/src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.tcc b/src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.tcc deleted file mode 100644 index defa07721..000000000 --- a/src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.tcc +++ /dev/null @@ -1,164 +0,0 @@ -/** @file - ***************************************************************************** - - Implementation of functions to sample R1CS examples with prescribed parameters - (according to some distribution). - - See r1cs_examples.hpp . - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef R1CS_EXAMPLES_TCC_ -#define R1CS_EXAMPLES_TCC_ - -#include - -#include "common/utils.hpp" - -namespace libsnark { - -template -r1cs_example generate_r1cs_example_with_field_input(const size_t num_constraints, - const size_t num_inputs) -{ - enter_block("Call to generate_r1cs_example_with_field_input"); - - assert(num_inputs <= num_constraints + 2); - - r1cs_constraint_system cs; - cs.primary_input_size = num_inputs; - cs.auxiliary_input_size = 2 + num_constraints - num_inputs; // TODO: explain this - - r1cs_variable_assignment full_variable_assignment; - FieldT a = FieldT::random_element(); - FieldT b = FieldT::random_element(); - full_variable_assignment.push_back(a); - full_variable_assignment.push_back(b); - - for (size_t i = 0; i < num_constraints-1; ++i) - { - linear_combination A, B, C; - - if (i % 2) - { - // a * b = c - A.add_term(i+1, 1); - B.add_term(i+2, 1); - C.add_term(i+3, 1); - FieldT tmp = a*b; - full_variable_assignment.push_back(tmp); - a = b; b = tmp; - } - else - { - // a + b = c - B.add_term(0, 1); - A.add_term(i+1, 1); - A.add_term(i+2, 1); - C.add_term(i+3, 1); - FieldT tmp = a+b; - full_variable_assignment.push_back(tmp); - a = b; b = tmp; - } - - cs.add_constraint(r1cs_constraint(A, B, C)); - } - - linear_combination A, B, C; - FieldT fin = FieldT::zero(); - for (size_t i = 1; i < cs.num_variables(); ++i) - { - A.add_term(i, 1); - B.add_term(i, 1); - fin = fin + full_variable_assignment[i-1]; - } - C.add_term(cs.num_variables(), 1); - cs.add_constraint(r1cs_constraint(A, B, C)); - full_variable_assignment.push_back(fin.squared()); - - /* split variable assignment */ - r1cs_primary_input primary_input(full_variable_assignment.begin(), full_variable_assignment.begin() + num_inputs); - r1cs_primary_input auxiliary_input(full_variable_assignment.begin() + num_inputs, full_variable_assignment.end()); - - /* sanity checks */ - assert(cs.num_variables() == full_variable_assignment.size()); - assert(cs.num_variables() >= num_inputs); - assert(cs.num_inputs() == num_inputs); - assert(cs.num_constraints() == num_constraints); - assert(cs.is_satisfied(primary_input, auxiliary_input)); - - leave_block("Call to generate_r1cs_example_with_field_input"); - - return r1cs_example(std::move(cs), std::move(primary_input), std::move(auxiliary_input)); -} - -template -r1cs_example generate_r1cs_example_with_binary_input(const size_t num_constraints, - const size_t num_inputs) -{ - enter_block("Call to generate_r1cs_example_with_binary_input"); - - assert(num_inputs >= 1); - - r1cs_constraint_system cs; - cs.primary_input_size = num_inputs; - cs.auxiliary_input_size = num_constraints; /* we will add one auxiliary variable per constraint */ - - r1cs_variable_assignment full_variable_assignment; - for (size_t i = 0; i < num_inputs; ++i) - { - full_variable_assignment.push_back(FieldT(std::rand() % 2)); - } - - size_t lastvar = num_inputs-1; - for (size_t i = 0; i < num_constraints; ++i) - { - ++lastvar; - const size_t u = (i == 0 ? std::rand() % num_inputs : std::rand() % i); - const size_t v = (i == 0 ? std::rand() % num_inputs : std::rand() % i); - - /* chose two random bits and XOR them together: - res = u + v - 2 * u * v - 2 * u * v = u + v - res - */ - linear_combination A, B, C; - A.add_term(u+1, 2); - B.add_term(v+1, 1); - if (u == v) - { - C.add_term(u+1, 2); - } - else - { - C.add_term(u+1, 1); - C.add_term(v+1, 1); - } - C.add_term(lastvar+1, -FieldT::one()); - - cs.add_constraint(r1cs_constraint(A, B, C)); - full_variable_assignment.push_back(full_variable_assignment[u] + full_variable_assignment[v] - full_variable_assignment[u] * full_variable_assignment[v] - full_variable_assignment[u] * full_variable_assignment[v]); - } - - /* split variable assignment */ - r1cs_primary_input primary_input(full_variable_assignment.begin(), full_variable_assignment.begin() + num_inputs); - r1cs_primary_input auxiliary_input(full_variable_assignment.begin() + num_inputs, full_variable_assignment.end()); - - /* sanity checks */ - assert(cs.num_variables() == full_variable_assignment.size()); - assert(cs.num_variables() >= num_inputs); - assert(cs.num_inputs() == num_inputs); - assert(cs.num_constraints() == num_constraints); - assert(cs.is_satisfied(primary_input, auxiliary_input)); - - leave_block("Call to generate_r1cs_example_with_binary_input"); - - return r1cs_example(std::move(cs), std::move(primary_input), std::move(auxiliary_input)); -} - -} // libsnark - -#endif // R1CS_EXAMPLES_TCC diff --git a/src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp b/src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp deleted file mode 100644 index ca3acb3a9..000000000 --- a/src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/r1cs.hpp +++ /dev/null @@ -1,153 +0,0 @@ -/** @file - ***************************************************************************** - - Declaration of interfaces for: - - a R1CS constraint, - - a R1CS variable assignment, and - - a R1CS constraint system. - - Above, R1CS stands for "Rank-1 Constraint System". - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef R1CS_HPP_ -#define R1CS_HPP_ - -#include -#include -#include -#include -#include - -#include "relations/variable.hpp" - -namespace libsnark { - -/************************* R1CS constraint ***********************************/ - -template -class r1cs_constraint; - -template -std::ostream& operator<<(std::ostream &out, const r1cs_constraint &c); - -template -std::istream& operator>>(std::istream &in, r1cs_constraint &c); - -/** - * A R1CS constraint is a formal expression of the form - * - * < A , X > * < B , X > = < C , X > , - * - * where X = (x_0,x_1,...,x_m) is a vector of formal variables and A,B,C each - * consist of 1+m elements in . - * - * A R1CS constraint is used to construct a R1CS constraint system (see below). - */ -template -class r1cs_constraint { -public: - - linear_combination a, b, c; - - r1cs_constraint() {}; - r1cs_constraint(const linear_combination &a, - const linear_combination &b, - const linear_combination &c); - - r1cs_constraint(const std::initializer_list > &A, - const std::initializer_list > &B, - const std::initializer_list > &C); - - bool operator==(const r1cs_constraint &other) const; - - friend std::ostream& operator<< (std::ostream &out, const r1cs_constraint &c); - friend std::istream& operator>> (std::istream &in, r1cs_constraint &c); -}; - -/************************* R1CS variable assignment **************************/ - -/** - * A R1CS variable assignment is a vector of elements that represents - * a candidate solution to a R1CS constraint system (see below). - */ - -/* TODO: specify that it does *NOT* include the constant 1 */ -template -using r1cs_primary_input = std::vector; - -template -using r1cs_auxiliary_input = std::vector; - -template -using r1cs_variable_assignment = std::vector; /* note the changed name! (TODO: remove this comment after primary_input transition is complete) */ - -/************************* R1CS constraint system ****************************/ - -template -class r1cs_constraint_system; - -template -std::ostream& operator<<(std::ostream &out, const r1cs_constraint_system &cs); - -template -std::istream& operator>>(std::istream &in, r1cs_constraint_system &cs); - -/** - * A system of R1CS constraints looks like - * - * { < A_k , X > * < B_k , X > = < C_k , X > }_{k=1}^{n} . - * - * In other words, the system is satisfied if and only if there exist a - * USCS variable assignment for which each R1CS constraint is satisfied. - * - * NOTE: - * The 0-th variable (i.e., "x_{0}") always represents the constant 1. - * Thus, the 0-th variable is not included in num_variables. - */ -template -class r1cs_constraint_system { -public: - size_t primary_input_size; - size_t auxiliary_input_size; - - std::vector > constraints; - - r1cs_constraint_system() : primary_input_size(0), auxiliary_input_size(0) {} - - size_t num_inputs() const; - size_t num_variables() const; - size_t num_constraints() const; - -#ifdef DEBUG - std::map constraint_annotations; - std::map variable_annotations; -#endif - - bool is_valid() const; - bool is_satisfied(const r1cs_primary_input &primary_input, - const r1cs_auxiliary_input &auxiliary_input) const; - - void add_constraint(const r1cs_constraint &c); - void add_constraint(const r1cs_constraint &c, const std::string &annotation); - - void swap_AB_if_beneficial(); - - bool operator==(const r1cs_constraint_system &other) const; - - friend std::ostream& operator<< (std::ostream &out, const r1cs_constraint_system &cs); - friend std::istream& operator>> (std::istream &in, r1cs_constraint_system &cs); - - void report_linear_constraint_statistics() const; -}; - - -} // libsnark - -#include "relations/constraint_satisfaction_problems/r1cs/r1cs.tcc" - -#endif // R1CS_HPP_ diff --git a/src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc b/src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc deleted file mode 100644 index 0faa56a87..000000000 --- a/src/snark/libsnark/relations/constraint_satisfaction_problems/r1cs/r1cs.tcc +++ /dev/null @@ -1,310 +0,0 @@ -/** @file - ***************************************************************************** - - Declaration of interfaces for: - - a R1CS constraint, - - a R1CS variable assignment, and - - a R1CS constraint system. - - See r1cs.hpp . - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef R1CS_TCC_ -#define R1CS_TCC_ - -#include -#include -#include -#include "common/utils.hpp" -#include "common/profiling.hpp" -#include "algebra/fields/bigint.hpp" - -namespace libsnark { - -template -r1cs_constraint::r1cs_constraint(const linear_combination &a, - const linear_combination &b, - const linear_combination &c) : - a(a), b(b), c(c) -{ -} - -template -r1cs_constraint::r1cs_constraint(const std::initializer_list > &A, - const std::initializer_list > &B, - const std::initializer_list > &C) -{ - for (auto lc_A : A) - { - a.terms.insert(a.terms.end(), lc_A.terms.begin(), lc_A.terms.end()); - } - for (auto lc_B : B) - { - b.terms.insert(b.terms.end(), lc_B.terms.begin(), lc_B.terms.end()); - } - for (auto lc_C : C) - { - c.terms.insert(c.terms.end(), lc_C.terms.begin(), lc_C.terms.end()); - } -} - -template -bool r1cs_constraint::operator==(const r1cs_constraint &other) const -{ - return (this->a == other.a && - this->b == other.b && - this->c == other.c); -} - -template -std::ostream& operator<<(std::ostream &out, const r1cs_constraint &c) -{ - out << c.a; - out << c.b; - out << c.c; - - return out; -} - -template -std::istream& operator>>(std::istream &in, r1cs_constraint &c) -{ - in >> c.a; - in >> c.b; - in >> c.c; - - return in; -} - -template -size_t r1cs_constraint_system::num_inputs() const -{ - return primary_input_size; -} - -template -size_t r1cs_constraint_system::num_variables() const -{ - return primary_input_size + auxiliary_input_size; -} - - -template -size_t r1cs_constraint_system::num_constraints() const -{ - return constraints.size(); -} - -template -bool r1cs_constraint_system::is_valid() const -{ - if (this->num_inputs() > this->num_variables()) return false; - - for (size_t c = 0; c < constraints.size(); ++c) - { - if (!(constraints[c].a.is_valid(this->num_variables()) && - constraints[c].b.is_valid(this->num_variables()) && - constraints[c].c.is_valid(this->num_variables()))) - { - return false; - } - } - - return true; -} - -template -void dump_r1cs_constraint(const r1cs_constraint &constraint, - const r1cs_variable_assignment &full_variable_assignment, - const std::map &variable_annotations) -{ - printf("terms for a:\n"); constraint.a.print_with_assignment(full_variable_assignment, variable_annotations); - printf("terms for b:\n"); constraint.b.print_with_assignment(full_variable_assignment, variable_annotations); - printf("terms for c:\n"); constraint.c.print_with_assignment(full_variable_assignment, variable_annotations); -} - -template -bool r1cs_constraint_system::is_satisfied(const r1cs_primary_input &primary_input, - const r1cs_auxiliary_input &auxiliary_input) const -{ - assert(primary_input.size() == num_inputs()); - assert(primary_input.size() + auxiliary_input.size() == num_variables()); - - r1cs_variable_assignment full_variable_assignment = primary_input; - full_variable_assignment.insert(full_variable_assignment.end(), auxiliary_input.begin(), auxiliary_input.end()); - - for (size_t c = 0; c < constraints.size(); ++c) - { - const FieldT ares = constraints[c].a.evaluate(full_variable_assignment); - const FieldT bres = constraints[c].b.evaluate(full_variable_assignment); - const FieldT cres = constraints[c].c.evaluate(full_variable_assignment); - - if (!(ares*bres == cres)) - { -#ifdef DEBUG - auto it = constraint_annotations.find(c); - printf("constraint %zu (%s) unsatisfied\n", c, (it == constraint_annotations.end() ? "no annotation" : it->second.c_str())); - printf(" = "); ares.print(); - printf(" = "); bres.print(); - printf(" = "); cres.print(); - printf("constraint was:\n"); - dump_r1cs_constraint(constraints[c], full_variable_assignment, variable_annotations); -#endif // DEBUG - return false; - } - } - - return true; -} - -template -void r1cs_constraint_system::add_constraint(const r1cs_constraint &c) -{ - constraints.emplace_back(c); -} - -template -void r1cs_constraint_system::add_constraint(const r1cs_constraint &c, const std::string &annotation) -{ -#ifdef DEBUG - constraint_annotations[constraints.size()] = annotation; -#endif - constraints.emplace_back(c); -} - -template -void r1cs_constraint_system::swap_AB_if_beneficial() -{ - enter_block("Call to r1cs_constraint_system::swap_AB_if_beneficial"); - - enter_block("Estimate densities"); - bit_vector touched_by_A(this->num_variables() + 1, false), touched_by_B(this->num_variables() + 1, false); - - for (size_t i = 0; i < this->constraints.size(); ++i) - { - for (size_t j = 0; j < this->constraints[i].a.terms.size(); ++j) - { - touched_by_A[this->constraints[i].a.terms[j].index] = true; - } - - for (size_t j = 0; j < this->constraints[i].b.terms.size(); ++j) - { - touched_by_B[this->constraints[i].b.terms[j].index] = true; - } - } - - size_t non_zero_A_count = 0, non_zero_B_count = 0; - for (size_t i = 0; i < this->num_variables() + 1; ++i) - { - non_zero_A_count += touched_by_A[i] ? 1 : 0; - non_zero_B_count += touched_by_B[i] ? 1 : 0; - } - - if (!inhibit_profiling_info) - { - print_indent(); printf("* Non-zero A-count (estimate): %zu\n", non_zero_A_count); - print_indent(); printf("* Non-zero B-count (estimate): %zu\n", non_zero_B_count); - } - leave_block("Estimate densities"); - - if (non_zero_B_count > non_zero_A_count) - { - enter_block("Perform the swap"); - for (size_t i = 0; i < this->constraints.size(); ++i) - { - std::swap(this->constraints[i].a, this->constraints[i].b); - } - leave_block("Perform the swap"); - } - else - { - print_indent(); printf("Swap is not beneficial, not performing\n"); - } - - leave_block("Call to r1cs_constraint_system::swap_AB_if_beneficial"); -} - -template -bool r1cs_constraint_system::operator==(const r1cs_constraint_system &other) const -{ - return (this->constraints == other.constraints && - this->primary_input_size == other.primary_input_size && - this->auxiliary_input_size == other.auxiliary_input_size); -} - -template -std::ostream& operator<<(std::ostream &out, const r1cs_constraint_system &cs) -{ - out << cs.primary_input_size << "\n"; - out << cs.auxiliary_input_size << "\n"; - - out << cs.num_constraints() << "\n"; - for (const r1cs_constraint& c : cs.constraints) - { - out << c; - } - - return out; -} - -template -std::istream& operator>>(std::istream &in, r1cs_constraint_system &cs) -{ - in >> cs.primary_input_size; - in >> cs.auxiliary_input_size; - - cs.constraints.clear(); - - size_t s; - in >> s; - - char b; - in.read(&b, 1); - - cs.constraints.reserve(s); - - for (size_t i = 0; i < s; ++i) - { - r1cs_constraint c; - in >> c; - cs.constraints.emplace_back(c); - } - - return in; -} - -template -void r1cs_constraint_system::report_linear_constraint_statistics() const -{ -#ifdef DEBUG - for (size_t i = 0; i < constraints.size(); ++i) - { - auto &constr = constraints[i]; - bool a_is_const = true; - for (auto &t : constr.a.terms) - { - a_is_const = a_is_const && (t.index == 0); - } - - bool b_is_const = true; - for (auto &t : constr.b.terms) - { - b_is_const = b_is_const && (t.index == 0); - } - - if (a_is_const || b_is_const) - { - auto it = constraint_annotations.find(i); - printf("%s\n", (it == constraint_annotations.end() ? FORMAT("", "constraint_%zu", i) : it->second).c_str()); - } - } -#endif -} - -} // libsnark -#endif // R1CS_TCC_ diff --git a/src/snark/libsnark/relations/variable.hpp b/src/snark/libsnark/relations/variable.hpp deleted file mode 100644 index c63f57b42..000000000 --- a/src/snark/libsnark/relations/variable.hpp +++ /dev/null @@ -1,213 +0,0 @@ -/** @file - ***************************************************************************** - - Declaration of interfaces for: - - a variable (i.e., x_i), - - a linear term (i.e., a_i * x_i), and - - a linear combination (i.e., sum_i a_i * x_i). - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef VARIABLE_HPP_ -#define VARIABLE_HPP_ - -#include -#include -#include -#include - -namespace libsnark { - -/** - * Mnemonic typedefs. - */ -typedef size_t var_index_t; -typedef int64_t integer_coeff_t; - -/** - * Forward declaration. - */ -template -class linear_term; - -/** - * Forward declaration. - */ -template -class linear_combination; - -/********************************* Variable **********************************/ - -/** - * A variable represents a formal expresison of the form "x_{index}". - */ -template -class variable { -public: - - var_index_t index; - - variable(const var_index_t index = 0) : index(index) {}; - - linear_term operator*(const integer_coeff_t int_coeff) const; - linear_term operator*(const FieldT &field_coeff) const; - - linear_combination operator+(const linear_combination &other) const; - linear_combination operator-(const linear_combination &other) const; - - linear_term operator-() const; - - bool operator==(const variable &other) const; -}; - -template -linear_term operator*(const integer_coeff_t int_coeff, const variable &var); - -template -linear_term operator*(const FieldT &field_coeff, const variable &var); - -template -linear_combination operator+(const integer_coeff_t int_coeff, const variable &var); - -template -linear_combination operator+(const FieldT &field_coeff, const variable &var); - -template -linear_combination operator-(const integer_coeff_t int_coeff, const variable &var); - -template -linear_combination operator-(const FieldT &field_coeff, const variable &var); - - -/****************************** Linear term **********************************/ - -/** - * A linear term represents a formal expression of the form "coeff * x_{index}". - */ -template -class linear_term { -public: - - var_index_t index = 0; - FieldT coeff; - - linear_term() {}; - linear_term(const variable &var); - linear_term(const variable &var, const integer_coeff_t int_coeff); - linear_term(const variable &var, const FieldT &field_coeff); - - linear_term operator*(const integer_coeff_t int_coeff) const; - linear_term operator*(const FieldT &field_coeff) const; - - linear_combination operator+(const linear_combination &other) const; - linear_combination operator-(const linear_combination &other) const; - - linear_term operator-() const; - - bool operator==(const linear_term &other) const; -}; - -template -linear_term operator*(const integer_coeff_t int_coeff, const linear_term <); - -template -linear_term operator*(const FieldT &field_coeff, const linear_term <); - -template -linear_combination operator+(const integer_coeff_t int_coeff, const linear_term <); - -template -linear_combination operator+(const FieldT &field_coeff, const linear_term <); - -template -linear_combination operator-(const integer_coeff_t int_coeff, const linear_term <); - -template -linear_combination operator-(const FieldT &field_coeff, const linear_term <); - - -/***************************** Linear combination ****************************/ - -template -class linear_combination; - -template -std::ostream& operator<<(std::ostream &out, const linear_combination &lc); - -template -std::istream& operator>>(std::istream &in, linear_combination &lc); - -/** - * A linear combination represents a formal expression of the form "sum_i coeff_i * x_{index_i}". - */ -template -class linear_combination { -public: - - std::vector > terms; - - linear_combination() {}; - linear_combination(const integer_coeff_t int_coeff); - linear_combination(const FieldT &field_coeff); - linear_combination(const variable &var); - linear_combination(const linear_term <); - linear_combination(const std::vector > &all_terms); - - /* for supporting range-based for loops over linear_combination */ - typename std::vector >::const_iterator begin() const; - typename std::vector >::const_iterator end() const; - - void add_term(const variable &var); - void add_term(const variable &var, const integer_coeff_t int_coeff); - void add_term(const variable &var, const FieldT &field_coeff); - - void add_term(const linear_term <); - - FieldT evaluate(const std::vector &assignment) const; - - linear_combination operator*(const integer_coeff_t int_coeff) const; - linear_combination operator*(const FieldT &field_coeff) const; - - linear_combination operator+(const linear_combination &other) const; - - linear_combination operator-(const linear_combination &other) const; - linear_combination operator-() const; - - bool operator==(const linear_combination &other) const; - - bool is_valid(const size_t num_variables) const; - - void print(const std::map &variable_annotations = std::map()) const; - void print_with_assignment(const std::vector &full_assignment, const std::map &variable_annotations = std::map()) const; - - friend std::ostream& operator<< (std::ostream &out, const linear_combination &lc); - friend std::istream& operator>> (std::istream &in, linear_combination &lc); -}; - -template -linear_combination operator*(const integer_coeff_t int_coeff, const linear_combination &lc); - -template -linear_combination operator*(const FieldT &field_coeff, const linear_combination &lc); - -template -linear_combination operator+(const integer_coeff_t int_coeff, const linear_combination &lc); - -template -linear_combination operator+(const FieldT &field_coeff, const linear_combination &lc); - -template -linear_combination operator-(const integer_coeff_t int_coeff, const linear_combination &lc); - -template -linear_combination operator-(const FieldT &field_coeff, const linear_combination &lc); - -} // libsnark - -#include "relations/variable.tcc" - -#endif // VARIABLE_HPP_ diff --git a/src/snark/libsnark/relations/variable.tcc b/src/snark/libsnark/relations/variable.tcc deleted file mode 100644 index 4c4cab97f..000000000 --- a/src/snark/libsnark/relations/variable.tcc +++ /dev/null @@ -1,512 +0,0 @@ -/** @file - ***************************************************************************** - - Implementation of interfaces for: - - a variable (i.e., x_i), - - a linear term (i.e., a_i * x_i), and - - a linear combination (i.e., sum_i a_i * x_i). - - See variabe.hpp . - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef VARIABLE_TCC_ -#define VARIABLE_TCC_ - -#include -#include - -#include "algebra/fields/bigint.hpp" - -namespace libsnark { - -template -linear_term variable::operator*(const integer_coeff_t int_coeff) const -{ - return linear_term(*this, int_coeff); -} - -template -linear_term variable::operator*(const FieldT &field_coeff) const -{ - return linear_term(*this, field_coeff); -} - -template -linear_combination variable::operator+(const linear_combination &other) const -{ - linear_combination result; - - result.add_term(*this); - result.terms.insert(result.terms.begin(), other.terms.begin(), other.terms.end()); - - return result; -} - -template -linear_combination variable::operator-(const linear_combination &other) const -{ - return (*this) + (-other); -} - -template -linear_term variable::operator-() const -{ - return linear_term(*this, -FieldT::one()); -} - -template -bool variable::operator==(const variable &other) const -{ - return (this->index == other.index); -} - -template -linear_term operator*(const integer_coeff_t int_coeff, const variable &var) -{ - return linear_term(var, int_coeff); -} - -template -linear_term operator*(const FieldT &field_coeff, const variable &var) -{ - return linear_term(var, field_coeff); -} - -template -linear_combination operator+(const integer_coeff_t int_coeff, const variable &var) -{ - return linear_combination(int_coeff) + var; -} - -template -linear_combination operator+(const FieldT &field_coeff, const variable &var) -{ - return linear_combination(field_coeff) + var; -} - -template -linear_combination operator-(const integer_coeff_t int_coeff, const variable &var) -{ - return linear_combination(int_coeff) - var; -} - -template -linear_combination operator-(const FieldT &field_coeff, const variable &var) -{ - return linear_combination(field_coeff) - var; -} - -template -linear_term::linear_term(const variable &var) : - index(var.index), coeff(FieldT::one()) -{ -} - -template -linear_term::linear_term(const variable &var, const integer_coeff_t int_coeff) : - index(var.index), coeff(FieldT(int_coeff)) -{ -} - -template -linear_term::linear_term(const variable &var, const FieldT &coeff) : - index(var.index), coeff(coeff) -{ -} - -template -linear_term linear_term::operator*(const integer_coeff_t int_coeff) const -{ - return (this->operator*(FieldT(int_coeff))); -} - -template -linear_term linear_term::operator*(const FieldT &field_coeff) const -{ - return linear_term(this->index, field_coeff * this->coeff); -} - -template -linear_combination operator+(const integer_coeff_t int_coeff, const linear_term <) -{ - return linear_combination(int_coeff) + lt; -} - -template -linear_combination operator+(const FieldT &field_coeff, const linear_term <) -{ - return linear_combination(field_coeff) + lt; -} - -template -linear_combination operator-(const integer_coeff_t int_coeff, const linear_term <) -{ - return linear_combination(int_coeff) - lt; -} - -template -linear_combination operator-(const FieldT &field_coeff, const linear_term <) -{ - return linear_combination(field_coeff) - lt; -} - -template -linear_combination linear_term::operator+(const linear_combination &other) const -{ - return linear_combination(*this) + other; -} - -template -linear_combination linear_term::operator-(const linear_combination &other) const -{ - return (*this) + (-other); -} - -template -linear_term linear_term::operator-() const -{ - return linear_term(this->index, -this->coeff); -} - -template -bool linear_term::operator==(const linear_term &other) const -{ - return (this->index == other.index && - this->coeff == other.coeff); -} - -template -linear_term operator*(const integer_coeff_t int_coeff, const linear_term <) -{ - return FieldT(int_coeff) * lt; -} - -template -linear_term operator*(const FieldT &field_coeff, const linear_term <) -{ - return linear_term(lt.index, field_coeff * lt.coeff); -} - -template -linear_combination::linear_combination(const integer_coeff_t int_coeff) -{ - this->add_term(linear_term(0, int_coeff)); -} - -template -linear_combination::linear_combination(const FieldT &field_coeff) -{ - this->add_term(linear_term(0, field_coeff)); -} - -template -linear_combination::linear_combination(const variable &var) -{ - this->add_term(var); -} - -template -linear_combination::linear_combination(const linear_term <) -{ - this->add_term(lt); -} - -template -typename std::vector >::const_iterator linear_combination::begin() const -{ - return terms.begin(); -} - -template -typename std::vector >::const_iterator linear_combination::end() const -{ - return terms.end(); -} - -template -void linear_combination::add_term(const variable &var) -{ - this->terms.emplace_back(linear_term(var.index, FieldT::one())); -} - -template -void linear_combination::add_term(const variable &var, const integer_coeff_t int_coeff) -{ - this->terms.emplace_back(linear_term(var.index, int_coeff)); -} - -template -void linear_combination::add_term(const variable &var, const FieldT &coeff) -{ - this->terms.emplace_back(linear_term(var.index, coeff)); -} - -template -void linear_combination::add_term(const linear_term &other) -{ - this->terms.emplace_back(other); -} - -template -linear_combination linear_combination::operator*(const integer_coeff_t int_coeff) const -{ - return (*this) * FieldT(int_coeff); -} - -template -FieldT linear_combination::evaluate(const std::vector &assignment) const -{ - FieldT acc = FieldT::zero(); - for (auto < : terms) - { - acc += (lt.index == 0 ? FieldT::one() : assignment[lt.index-1]) * lt.coeff; - } - return acc; -} - -template -linear_combination linear_combination::operator*(const FieldT &field_coeff) const -{ - linear_combination result; - result.terms.reserve(this->terms.size()); - for (const linear_term < : this->terms) - { - result.terms.emplace_back(lt * field_coeff); - } - return result; -} - -template -linear_combination linear_combination::operator+(const linear_combination &other) const -{ - linear_combination result; - - auto it1 = this->terms.begin(); - auto it2 = other.terms.begin(); - - /* invariant: it1 and it2 always point to unprocessed items in the corresponding linear combinations */ - while (it1 != this->terms.end() && it2 != other.terms.end()) - { - if (it1->index < it2->index) - { - result.terms.emplace_back(*it1); - ++it1; - } - else if (it1->index > it2->index) - { - result.terms.emplace_back(*it2); - ++it2; - } - else - { - /* it1->index == it2->index */ - result.terms.emplace_back(linear_term(variable(it1->index), it1->coeff + it2->coeff)); - ++it1; - ++it2; - } - } - - if (it1 != this->terms.end()) - { - result.terms.insert(result.terms.end(), it1, this->terms.end()); - } - else - { - result.terms.insert(result.terms.end(), it2, other.terms.end()); - } - - return result; -} - -template -linear_combination linear_combination::operator-(const linear_combination &other) const -{ - return (*this) + (-other); -} - -template -linear_combination linear_combination::operator-() const -{ - return (*this) * (-FieldT::one()); -} - -template -bool linear_combination::operator==(const linear_combination &other) const -{ - return (this->terms == other.terms); -} - -template -bool linear_combination::is_valid(const size_t num_variables) const -{ - /* check that all terms in linear combination are sorted */ - for (size_t i = 1; i < terms.size(); ++i) - { - if (terms[i-1].index >= terms[i].index) - { - return false; - } - } - - /* check that the variables are in proper range. as the variables - are sorted, it suffices to check the last term */ - if ((--terms.end())->index >= num_variables) - { - return false; - } - - return true; -} - -template -void linear_combination::print(const std::map &variable_annotations) const -{ - for (auto < : terms) - { - if (lt.index == 0) - { - printf(" 1 * "); - lt.coeff.print(); - } - else - { - auto it = variable_annotations.find(lt.index); - printf(" x_%zu (%s) * ", lt.index, (it == variable_annotations.end() ? "no annotation" : it->second.c_str())); - lt.coeff.print(); - } - } -} - -template -void linear_combination::print_with_assignment(const std::vector &full_assignment, const std::map &variable_annotations) const -{ - for (auto < : terms) - { - if (lt.index == 0) - { - printf(" 1 * "); - lt.coeff.print(); - } - else - { - printf(" x_%zu * ", lt.index); - lt.coeff.print(); - - auto it = variable_annotations.find(lt.index); - printf(" where x_%zu (%s) was assigned value ", lt.index, - (it == variable_annotations.end() ? "no annotation" : it->second.c_str())); - full_assignment[lt.index-1].print(); - printf(" i.e. negative of "); - (-full_assignment[lt.index-1]).print(); - } - } -} - -template -std::ostream& operator<<(std::ostream &out, const linear_combination &lc) -{ - out << lc.terms.size() << "\n"; - for (const linear_term& lt : lc.terms) - { - out << lt.index << "\n"; - out << lt.coeff << OUTPUT_NEWLINE; - } - - return out; -} - -template -std::istream& operator>>(std::istream &in, linear_combination &lc) -{ - lc.terms.clear(); - - size_t s; - in >> s; - - consume_newline(in); - - lc.terms.reserve(s); - - for (size_t i = 0; i < s; ++i) - { - linear_term lt; - in >> lt.index; - consume_newline(in); - in >> lt.coeff; - consume_OUTPUT_NEWLINE(in); - lc.terms.emplace_back(lt); - } - - return in; -} - -template -linear_combination operator*(const integer_coeff_t int_coeff, const linear_combination &lc) -{ - return lc * int_coeff; -} - -template -linear_combination operator*(const FieldT &field_coeff, const linear_combination &lc) -{ - return lc * field_coeff; -} - -template -linear_combination operator+(const integer_coeff_t int_coeff, const linear_combination &lc) -{ - return linear_combination(int_coeff) + lc; -} - -template -linear_combination operator+(const FieldT &field_coeff, const linear_combination &lc) -{ - return linear_combination(field_coeff) + lc; -} - -template -linear_combination operator-(const integer_coeff_t int_coeff, const linear_combination &lc) -{ - return linear_combination(int_coeff) - lc; -} - -template -linear_combination operator-(const FieldT &field_coeff, const linear_combination &lc) -{ - return linear_combination(field_coeff) - lc; -} - -template -linear_combination::linear_combination(const std::vector > &all_terms) -{ - if (all_terms.empty()) - { - return; - } - - terms = all_terms; - std::sort(terms.begin(), terms.end(), [](linear_term a, linear_term b) { return a.index < b.index; }); - - auto result_it = terms.begin(); - for (auto it = ++terms.begin(); it != terms.end(); ++it) - { - if (it->index == result_it->index) - { - result_it->coeff += it->coeff; - } - else - { - *(++result_it) = *it; - } - } - terms.resize((result_it - terms.begin()) + 1); -} - -} // libsnark - -#endif // VARIABLE_TCC diff --git a/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp b/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp deleted file mode 100644 index fcd28abf3..000000000 --- a/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp +++ /dev/null @@ -1,35 +0,0 @@ -/** @file - ***************************************************************************** - - Declaration of functionality that runs the R1CS ppzkSNARK for - a given R1CS example. - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef RUN_R1CS_PPZKSNARK_HPP_ -#define RUN_R1CS_PPZKSNARK_HPP_ - -#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" - -namespace libsnark { - -/** - * Runs the ppzkSNARK (generator, prover, and verifier) for a given - * R1CS example (specified by a constraint system, input, and witness). - * - * Optionally, also test the serialization routines for keys and proofs. - * (This takes additional time.) - */ -template -bool run_r1cs_ppzksnark(const r1cs_example > &example, - const bool test_serialization); - -} // libsnark - -#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc" - -#endif // RUN_R1CS_PPZKSNARK_HPP_ diff --git a/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc b/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc deleted file mode 100644 index 9bc875869..000000000 --- a/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.tcc +++ /dev/null @@ -1,114 +0,0 @@ -/** @file - ***************************************************************************** - - Implementation of functionality that runs the R1CS ppzkSNARK for - a given R1CS example. - - See run_r1cs_ppzksnark.hpp . - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef RUN_R1CS_PPZKSNARK_TCC_ -#define RUN_R1CS_PPZKSNARK_TCC_ - -#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp" - -#include -#include - -#include "common/profiling.hpp" - -namespace libsnark { - -template -typename std::enable_if::type -test_affine_verifier(const r1cs_ppzksnark_verification_key &vk, - const r1cs_ppzksnark_primary_input &primary_input, - const r1cs_ppzksnark_proof &proof, - const bool expected_answer) -{ - print_header("R1CS ppzkSNARK Affine Verifier"); - const bool answer = r1cs_ppzksnark_affine_verifier_weak_IC(vk, primary_input, proof); - assert(answer == expected_answer); -} - -template -typename std::enable_if::type -test_affine_verifier(const r1cs_ppzksnark_verification_key &vk, - const r1cs_ppzksnark_primary_input &primary_input, - const r1cs_ppzksnark_proof &proof, - const bool expected_answer) -{ - UNUSED(vk, primary_input, proof, expected_answer); - print_header("R1CS ppzkSNARK Affine Verifier"); - printf("Affine verifier is not supported; not testing anything.\n"); -} - -/** - * The code below provides an example of all stages of running a R1CS ppzkSNARK. - * - * Of course, in a real-life scenario, we would have three distinct entities, - * mangled into one in the demonstration below. The three entities are as follows. - * (1) The "generator", which runs the ppzkSNARK generator on input a given - * constraint system CS to create a proving and a verification key for CS. - * (2) The "prover", which runs the ppzkSNARK prover on input the proving key, - * a primary input for CS, and an auxiliary input for CS. - * (3) The "verifier", which runs the ppzkSNARK verifier on input the verification key, - * a primary input for CS, and a proof. - */ -template -bool run_r1cs_ppzksnark(const r1cs_example > &example, - const bool test_serialization) -{ - enter_block("Call to run_r1cs_ppzksnark"); - - print_header("R1CS ppzkSNARK Generator"); - r1cs_ppzksnark_keypair keypair = r1cs_ppzksnark_generator(example.constraint_system); - printf("\n"); print_indent(); print_mem("after generator"); - - print_header("Preprocess verification key"); - r1cs_ppzksnark_processed_verification_key pvk = r1cs_ppzksnark_verifier_process_vk(keypair.vk); - - if (test_serialization) - { - enter_block("Test serialization of keys"); - keypair.pk = reserialize >(keypair.pk); - keypair.vk = reserialize >(keypair.vk); - pvk = reserialize >(pvk); - leave_block("Test serialization of keys"); - } - - print_header("R1CS ppzkSNARK Prover"); - r1cs_ppzksnark_proof proof = r1cs_ppzksnark_prover(keypair.pk, example.primary_input, example.auxiliary_input); - printf("\n"); print_indent(); print_mem("after prover"); - - if (test_serialization) - { - enter_block("Test serialization of proof"); - proof = reserialize >(proof); - leave_block("Test serialization of proof"); - } - - print_header("R1CS ppzkSNARK Verifier"); - const bool ans = r1cs_ppzksnark_verifier_strong_IC(keypair.vk, example.primary_input, proof); - printf("\n"); print_indent(); print_mem("after verifier"); - printf("* The verification result is: %s\n", (ans ? "PASS" : "FAIL")); - - print_header("R1CS ppzkSNARK Online Verifier"); - const bool ans2 = r1cs_ppzksnark_online_verifier_strong_IC(pvk, example.primary_input, proof); - assert(ans == ans2); - - test_affine_verifier(keypair.vk, example.primary_input, proof, ans); - - leave_block("Call to run_r1cs_ppzksnark"); - - return ans; -} - -} // libsnark - -#endif // RUN_R1CS_PPZKSNARK_TCC_ diff --git a/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark.cpp b/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark.cpp deleted file mode 100644 index 5c5415028..000000000 --- a/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/** @file - ***************************************************************************** - Profiling program that exercises the ppzkSNARK (first generator, then prover, - then verifier) on a synthetic R1CS instance. - - The command - - $ src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark 1000 10 Fr - - exercises the ppzkSNARK (first generator, then prover, then verifier) on an R1CS instance with 1000 equations and an input consisting of 10 field elements. - - (If you get the error `zmInit ERR:can't protect`, see the discussion [above](#elliptic-curve-choices).) - - The command - - $ src/zk_proof_systems/ppzksnark/r1cs_ppzksnark/profiling/profile_r1cs_ppzksnark 1000 10 bytes - - does the same but now the input consists of 10 bytes. - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ -#include -#include - -#include "common/default_types/r1cs_ppzksnark_pp.hpp" -#include "common/profiling.hpp" -#include "common/utils.hpp" -#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" -#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp" - -using namespace libsnark; - -int main(int argc, const char * argv[]) -{ - default_r1cs_ppzksnark_pp::init_public_params(); - start_profiling(); - - if (argc == 2 && strcmp(argv[1], "-v") == 0) - { - print_compilation_info(); - return 0; - } - - if (argc != 3 && argc != 4) - { - printf("usage: %s num_constraints input_size [Fr|bytes]\n", argv[0]); - return 1; - } - const int num_constraints = atoi(argv[1]); - int input_size = atoi(argv[2]); - if (argc == 4) - { - assert(strcmp(argv[3], "Fr") == 0 || strcmp(argv[3], "bytes") == 0); - if (strcmp(argv[3], "bytes") == 0) - { - input_size = div_ceil(8 * input_size, Fr::capacity()); - } - } - - enter_block("Generate R1CS example"); - r1cs_example > example = generate_r1cs_example_with_field_input >(num_constraints, input_size); - leave_block("Generate R1CS example"); - - print_header("(enter) Profile R1CS ppzkSNARK"); - const bool test_serialization = true; - run_r1cs_ppzksnark(example, test_serialization); - print_header("(leave) Profile R1CS ppzkSNARK"); -} diff --git a/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp b/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp deleted file mode 100644 index 615acd6a6..000000000 --- a/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.hpp +++ /dev/null @@ -1,485 +0,0 @@ -/** @file - ***************************************************************************** - - Declaration of interfaces for a ppzkSNARK for R1CS. - - This includes: - - class for proving key - - class for verification key - - class for processed verification key - - class for key pair (proving key & verification key) - - class for proof - - generator algorithm - - prover algorithm - - verifier algorithm (with strong or weak input consistency) - - online verifier algorithm (with strong or weak input consistency) - - The implementation instantiates (a modification of) the protocol of \[PGHR13], - by following extending, and optimizing the approach described in \[BCTV14]. - - - Acronyms: - - - R1CS = "Rank-1 Constraint Systems" - - ppzkSNARK = "PreProcessing Zero-Knowledge Succinct Non-interactive ARgument of Knowledge" - - References: - - \[BCTV14]: - "Succinct Non-Interactive Zero Knowledge for a von Neumann Architecture", - Eli Ben-Sasson, Alessandro Chiesa, Eran Tromer, Madars Virza, - USENIX Security 2014, - - - \[PGHR13]: - "Pinocchio: Nearly practical verifiable computation", - Bryan Parno, Craig Gentry, Jon Howell, Mariana Raykova, - IEEE S&P 2013, - - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef R1CS_PPZKSNARK_HPP_ -#define R1CS_PPZKSNARK_HPP_ - -#include - -#include "algebra/curves/public_params.hpp" -#include "common/data_structures/accumulation_vector.hpp" -#include "algebra/knowledge_commitment/knowledge_commitment.hpp" -#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" -#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark_params.hpp" - -namespace libsnark { - -/******************************** Proving key ********************************/ - -template -class r1cs_ppzksnark_proving_key; - -template -std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_proving_key &pk); - -template -std::istream& operator>>(std::istream &in, r1cs_ppzksnark_proving_key &pk); - -/** - * A proving key for the R1CS ppzkSNARK. - */ -template -class r1cs_ppzksnark_proving_key { -public: - knowledge_commitment_vector, G1 > A_query; - knowledge_commitment_vector, G1 > B_query; - knowledge_commitment_vector, G1 > C_query; - G1_vector H_query; - G1_vector K_query; - - r1cs_ppzksnark_proving_key() {}; - r1cs_ppzksnark_proving_key& operator=(const r1cs_ppzksnark_proving_key &other) = default; - r1cs_ppzksnark_proving_key(const r1cs_ppzksnark_proving_key &other) = default; - r1cs_ppzksnark_proving_key(r1cs_ppzksnark_proving_key &&other) = default; - r1cs_ppzksnark_proving_key(knowledge_commitment_vector, G1 > &&A_query, - knowledge_commitment_vector, G1 > &&B_query, - knowledge_commitment_vector, G1 > &&C_query, - G1_vector &&H_query, - G1_vector &&K_query) : - A_query(std::move(A_query)), - B_query(std::move(B_query)), - C_query(std::move(C_query)), - H_query(std::move(H_query)), - K_query(std::move(K_query)) - {}; - - size_t G1_size() const - { - return 2*(A_query.domain_size() + C_query.domain_size()) + B_query.domain_size() + H_query.size() + K_query.size(); - } - - size_t G2_size() const - { - return B_query.domain_size(); - } - - size_t G1_sparse_size() const - { - return 2*(A_query.size() + C_query.size()) + B_query.size() + H_query.size() + K_query.size(); - } - - size_t G2_sparse_size() const - { - return B_query.size(); - } - - size_t size_in_bits() const - { - return A_query.size_in_bits() + B_query.size_in_bits() + C_query.size_in_bits() + libsnark::size_in_bits(H_query) + libsnark::size_in_bits(K_query); - } - - void print_size() const - { - print_indent(); printf("* G1 elements in PK: %zu\n", this->G1_size()); - print_indent(); printf("* Non-zero G1 elements in PK: %zu\n", this->G1_sparse_size()); - print_indent(); printf("* G2 elements in PK: %zu\n", this->G2_size()); - print_indent(); printf("* Non-zero G2 elements in PK: %zu\n", this->G2_sparse_size()); - print_indent(); printf("* PK size in bits: %zu\n", this->size_in_bits()); - } - - bool operator==(const r1cs_ppzksnark_proving_key &other) const; - friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzksnark_proving_key &pk); - friend std::istream& operator>> (std::istream &in, r1cs_ppzksnark_proving_key &pk); -}; - - -/******************************* Verification key ****************************/ - -template -class r1cs_ppzksnark_verification_key; - -template -std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_verification_key &vk); - -template -std::istream& operator>>(std::istream &in, r1cs_ppzksnark_verification_key &vk); - -/** - * A verification key for the R1CS ppzkSNARK. - */ -template -class r1cs_ppzksnark_verification_key { -public: - G2 alphaA_g2; - G1 alphaB_g1; - G2 alphaC_g2; - G2 gamma_g2; - G1 gamma_beta_g1; - G2 gamma_beta_g2; - G2 rC_Z_g2; - - accumulation_vector > encoded_IC_query; - - r1cs_ppzksnark_verification_key() = default; - r1cs_ppzksnark_verification_key(const G2 &alphaA_g2, - const G1 &alphaB_g1, - const G2 &alphaC_g2, - const G2 &gamma_g2, - const G1 &gamma_beta_g1, - const G2 &gamma_beta_g2, - const G2 &rC_Z_g2, - const accumulation_vector > &eIC) : - alphaA_g2(alphaA_g2), - alphaB_g1(alphaB_g1), - alphaC_g2(alphaC_g2), - gamma_g2(gamma_g2), - gamma_beta_g1(gamma_beta_g1), - gamma_beta_g2(gamma_beta_g2), - rC_Z_g2(rC_Z_g2), - encoded_IC_query(eIC) - {}; - - size_t G1_size() const - { - return 2 + encoded_IC_query.size(); - } - - size_t G2_size() const - { - return 5; - } - - size_t size_in_bits() const - { - return (2 * G1::size_in_bits() + encoded_IC_query.size_in_bits() + 5 * G2::size_in_bits()); - } - - void print_size() const - { - print_indent(); printf("* G1 elements in VK: %zu\n", this->G1_size()); - print_indent(); printf("* G2 elements in VK: %zu\n", this->G2_size()); - print_indent(); printf("* VK size in bits: %zu\n", this->size_in_bits()); - } - - bool operator==(const r1cs_ppzksnark_verification_key &other) const; - friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzksnark_verification_key &vk); - friend std::istream& operator>> (std::istream &in, r1cs_ppzksnark_verification_key &vk); - - static r1cs_ppzksnark_verification_key dummy_verification_key(const size_t input_size); -}; - - -/************************ Processed verification key *************************/ - -template -class r1cs_ppzksnark_processed_verification_key; - -template -std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_processed_verification_key &pvk); - -template -std::istream& operator>>(std::istream &in, r1cs_ppzksnark_processed_verification_key &pvk); - -/** - * A processed verification key for the R1CS ppzkSNARK. - * - * Compared to a (non-processed) verification key, a processed verification key - * contains a small constant amount of additional pre-computed information that - * enables a faster verification time. - */ -template -class r1cs_ppzksnark_processed_verification_key { -public: - G2_precomp pp_G2_one_precomp; - G2_precomp vk_alphaA_g2_precomp; - G1_precomp vk_alphaB_g1_precomp; - G2_precomp vk_alphaC_g2_precomp; - G2_precomp vk_rC_Z_g2_precomp; - G2_precomp vk_gamma_g2_precomp; - G1_precomp vk_gamma_beta_g1_precomp; - G2_precomp vk_gamma_beta_g2_precomp; - - accumulation_vector > encoded_IC_query; - - bool operator==(const r1cs_ppzksnark_processed_verification_key &other) const; - friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzksnark_processed_verification_key &pvk); - friend std::istream& operator>> (std::istream &in, r1cs_ppzksnark_processed_verification_key &pvk); -}; - - -/********************************** Key pair *********************************/ - -/** - * A key pair for the R1CS ppzkSNARK, which consists of a proving key and a verification key. - */ -template -class r1cs_ppzksnark_keypair { -public: - r1cs_ppzksnark_proving_key pk; - r1cs_ppzksnark_verification_key vk; - - r1cs_ppzksnark_keypair() = default; - r1cs_ppzksnark_keypair(const r1cs_ppzksnark_keypair &other) = default; - r1cs_ppzksnark_keypair(r1cs_ppzksnark_proving_key &&pk, - r1cs_ppzksnark_verification_key &&vk) : - pk(std::move(pk)), - vk(std::move(vk)) - {} - - r1cs_ppzksnark_keypair(r1cs_ppzksnark_keypair &&other) = default; -}; - - -/*********************************** Proof ***********************************/ - -template -class r1cs_ppzksnark_proof; - -template -std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_proof &proof); - -template -std::istream& operator>>(std::istream &in, r1cs_ppzksnark_proof &proof); - -/** - * A proof for the R1CS ppzkSNARK. - * - * While the proof has a structure, externally one merely opaquely produces, - * seralizes/deserializes, and verifies proofs. We only expose some information - * about the structure for statistics purposes. - */ -template -class r1cs_ppzksnark_proof { -public: - knowledge_commitment, G1 > g_A; - knowledge_commitment, G1 > g_B; - knowledge_commitment, G1 > g_C; - G1 g_H; - G1 g_K; - - r1cs_ppzksnark_proof() - { - // invalid proof with valid curve points - this->g_A.g = G1 ::one(); - this->g_A.h = G1::one(); - this->g_B.g = G2 ::one(); - this->g_B.h = G1::one(); - this->g_C.g = G1 ::one(); - this->g_C.h = G1::one(); - this->g_H = G1::one(); - this->g_K = G1::one(); - } - r1cs_ppzksnark_proof(knowledge_commitment, G1 > &&g_A, - knowledge_commitment, G1 > &&g_B, - knowledge_commitment, G1 > &&g_C, - G1 &&g_H, - G1 &&g_K) : - g_A(std::move(g_A)), - g_B(std::move(g_B)), - g_C(std::move(g_C)), - g_H(std::move(g_H)), - g_K(std::move(g_K)) - {}; - - size_t G1_size() const - { - return 7; - } - - size_t G2_size() const - { - return 1; - } - - size_t size_in_bits() const - { - return G1_size() * G1::size_in_bits() + G2_size() * G2::size_in_bits(); - } - - void print_size() const - { - print_indent(); printf("* G1 elements in proof: %zu\n", this->G1_size()); - print_indent(); printf("* G2 elements in proof: %zu\n", this->G2_size()); - print_indent(); printf("* Proof size in bits: %zu\n", this->size_in_bits()); - } - - bool is_well_formed() const - { - return (g_A.g.is_well_formed() && g_A.h.is_well_formed() && - g_B.g.is_well_formed() && g_B.h.is_well_formed() && - g_C.g.is_well_formed() && g_C.h.is_well_formed() && - g_H.is_well_formed() && - g_K.is_well_formed()); - } - - bool operator==(const r1cs_ppzksnark_proof &other) const; - friend std::ostream& operator<< (std::ostream &out, const r1cs_ppzksnark_proof &proof); - friend std::istream& operator>> (std::istream &in, r1cs_ppzksnark_proof &proof); -}; - - -/***************************** Main algorithms *******************************/ - -/** - * A generator algorithm for the R1CS ppzkSNARK. - * - * Given a R1CS constraint system CS, this algorithm produces proving and verification keys for CS. - */ -template -r1cs_ppzksnark_keypair r1cs_ppzksnark_generator(const r1cs_ppzksnark_constraint_system &cs); - -template -r1cs_ppzksnark_keypair r1cs_ppzksnark_generator( - const r1cs_ppzksnark_constraint_system &cs, - const Fr& t, - const Fr& alphaA, - const Fr& alphaB, - const Fr& alphaC, - const Fr& rA, - const Fr& rB, - const Fr& beta, - const Fr& gamma -); - -/** - * A prover algorithm for the R1CS ppzkSNARK. - * - * Given a R1CS primary input X and a R1CS auxiliary input Y, this algorithm - * produces a proof (of knowledge) that attests to the following statement: - * ``there exists Y such that CS(X,Y)=0''. - * Above, CS is the R1CS constraint system that was given as input to the generator algorithm. - */ -template -r1cs_ppzksnark_proof r1cs_ppzksnark_prover(const r1cs_ppzksnark_proving_key &pk, - const r1cs_ppzksnark_primary_input &primary_input, - const r1cs_ppzksnark_auxiliary_input &auxiliary_input); - -template -r1cs_ppzksnark_proof r1cs_ppzksnark_prover_streaming(std::ifstream &proving_key_file, - const r1cs_ppzksnark_primary_input &primary_input, - const r1cs_ppzksnark_auxiliary_input &auxiliary_input, - const r1cs_ppzksnark_constraint_system &constraint_system); - -/* - Below are four variants of verifier algorithm for the R1CS ppzkSNARK. - - These are the four cases that arise from the following two choices: - - (1) The verifier accepts a (non-processed) verification key or, instead, a processed verification key. - In the latter case, we call the algorithm an "online verifier". - - (2) The verifier checks for "weak" input consistency or, instead, "strong" input consistency. - Strong input consistency requires that |primary_input| = CS.num_inputs, whereas - weak input consistency requires that |primary_input| <= CS.num_inputs (and - the primary input is implicitly padded with zeros up to length CS.num_inputs). - */ - -/** - * A verifier algorithm for the R1CS ppzkSNARK that: - * (1) accepts a non-processed verification key, and - * (2) has weak input consistency. - */ -template -bool r1cs_ppzksnark_verifier_weak_IC(const r1cs_ppzksnark_verification_key &vk, - const r1cs_ppzksnark_primary_input &primary_input, - const r1cs_ppzksnark_proof &proof); - -/** - * A verifier algorithm for the R1CS ppzkSNARK that: - * (1) accepts a non-processed verification key, and - * (2) has strong input consistency. - */ -template -bool r1cs_ppzksnark_verifier_strong_IC(const r1cs_ppzksnark_verification_key &vk, - const r1cs_ppzksnark_primary_input &primary_input, - const r1cs_ppzksnark_proof &proof); - -/** - * Convert a (non-processed) verification key into a processed verification key. - */ -template -r1cs_ppzksnark_processed_verification_key r1cs_ppzksnark_verifier_process_vk(const r1cs_ppzksnark_verification_key &vk); - -/** - * A verifier algorithm for the R1CS ppzkSNARK that: - * (1) accepts a processed verification key, and - * (2) has weak input consistency. - */ -template -bool r1cs_ppzksnark_online_verifier_weak_IC(const r1cs_ppzksnark_processed_verification_key &pvk, - const r1cs_ppzksnark_primary_input &input, - const r1cs_ppzksnark_proof &proof); - -/** - * A verifier algorithm for the R1CS ppzkSNARK that: - * (1) accepts a processed verification key, and - * (2) has strong input consistency. - */ -template -bool r1cs_ppzksnark_online_verifier_strong_IC(const r1cs_ppzksnark_processed_verification_key &pvk, - const r1cs_ppzksnark_primary_input &primary_input, - const r1cs_ppzksnark_proof &proof); - -/****************************** Miscellaneous ********************************/ - -/** - * For debugging purposes (of r1cs_ppzksnark_r1cs_ppzksnark_verifier_gadget): - * - * A verifier algorithm for the R1CS ppzkSNARK that: - * (1) accepts a non-processed verification key, - * (2) has weak input consistency, and - * (3) uses affine coordinates for elliptic-curve computations. - */ -template -bool r1cs_ppzksnark_affine_verifier_weak_IC(const r1cs_ppzksnark_verification_key &vk, - const r1cs_ppzksnark_primary_input &primary_input, - const r1cs_ppzksnark_proof &proof); - - -} // libsnark - -#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc" - -#endif // R1CS_PPZKSNARK_HPP_ diff --git a/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc b/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc deleted file mode 100644 index 84db9fc1a..000000000 --- a/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark.tcc +++ /dev/null @@ -1,886 +0,0 @@ -/** @file -***************************************************************************** - -Implementation of interfaces for a ppzkSNARK for R1CS. - -See r1cs_ppzksnark.hpp . - -***************************************************************************** -* @author This file is part of libsnark, developed by SCIPR Lab -* and contributors (see AUTHORS). -* @copyright MIT license (see LICENSE file) -*****************************************************************************/ - -#ifndef R1CS_PPZKSNARK_TCC_ -#define R1CS_PPZKSNARK_TCC_ - -#include -#include -#include -#include -#include - -#include "common/profiling.hpp" -#include "common/utils.hpp" -#include "algebra/scalar_multiplication/multiexp.hpp" -#include "algebra/scalar_multiplication/kc_multiexp.hpp" -#include "reductions/r1cs_to_qap/r1cs_to_qap.hpp" - -namespace libsnark { - -template -bool r1cs_ppzksnark_proving_key::operator==(const r1cs_ppzksnark_proving_key &other) const -{ - return (this->A_query == other.A_query && - this->B_query == other.B_query && - this->C_query == other.C_query && - this->H_query == other.H_query && - this->K_query == other.K_query); -} - -template -std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_proving_key &pk) -{ - out << pk.A_query; - out << pk.B_query; - out << pk.C_query; - out << pk.H_query; - out << pk.K_query; - - return out; -} - -template -std::istream& operator>>(std::istream &in, r1cs_ppzksnark_proving_key &pk) -{ - in >> pk.A_query; - in >> pk.B_query; - in >> pk.C_query; - in >> pk.H_query; - in >> pk.K_query; - - return in; -} - -template -bool r1cs_ppzksnark_verification_key::operator==(const r1cs_ppzksnark_verification_key &other) const -{ - return (this->alphaA_g2 == other.alphaA_g2 && - this->alphaB_g1 == other.alphaB_g1 && - this->alphaC_g2 == other.alphaC_g2 && - this->gamma_g2 == other.gamma_g2 && - this->gamma_beta_g1 == other.gamma_beta_g1 && - this->gamma_beta_g2 == other.gamma_beta_g2 && - this->rC_Z_g2 == other.rC_Z_g2 && - this->encoded_IC_query == other.encoded_IC_query); -} - -template -std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_verification_key &vk) -{ - out << vk.alphaA_g2 << OUTPUT_NEWLINE; - out << vk.alphaB_g1 << OUTPUT_NEWLINE; - out << vk.alphaC_g2 << OUTPUT_NEWLINE; - out << vk.gamma_g2 << OUTPUT_NEWLINE; - out << vk.gamma_beta_g1 << OUTPUT_NEWLINE; - out << vk.gamma_beta_g2 << OUTPUT_NEWLINE; - out << vk.rC_Z_g2 << OUTPUT_NEWLINE; - out << vk.encoded_IC_query << OUTPUT_NEWLINE; - - return out; -} - -template -std::istream& operator>>(std::istream &in, r1cs_ppzksnark_verification_key &vk) -{ - in >> vk.alphaA_g2; - consume_OUTPUT_NEWLINE(in); - in >> vk.alphaB_g1; - consume_OUTPUT_NEWLINE(in); - in >> vk.alphaC_g2; - consume_OUTPUT_NEWLINE(in); - in >> vk.gamma_g2; - consume_OUTPUT_NEWLINE(in); - in >> vk.gamma_beta_g1; - consume_OUTPUT_NEWLINE(in); - in >> vk.gamma_beta_g2; - consume_OUTPUT_NEWLINE(in); - in >> vk.rC_Z_g2; - consume_OUTPUT_NEWLINE(in); - in >> vk.encoded_IC_query; - consume_OUTPUT_NEWLINE(in); - - return in; -} - -template -bool r1cs_ppzksnark_processed_verification_key::operator==(const r1cs_ppzksnark_processed_verification_key &other) const -{ - return (this->pp_G2_one_precomp == other.pp_G2_one_precomp && - this->vk_alphaA_g2_precomp == other.vk_alphaA_g2_precomp && - this->vk_alphaB_g1_precomp == other.vk_alphaB_g1_precomp && - this->vk_alphaC_g2_precomp == other.vk_alphaC_g2_precomp && - this->vk_rC_Z_g2_precomp == other.vk_rC_Z_g2_precomp && - this->vk_gamma_g2_precomp == other.vk_gamma_g2_precomp && - this->vk_gamma_beta_g1_precomp == other.vk_gamma_beta_g1_precomp && - this->vk_gamma_beta_g2_precomp == other.vk_gamma_beta_g2_precomp && - this->encoded_IC_query == other.encoded_IC_query); -} - -template -std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_processed_verification_key &pvk) -{ - out << pvk.pp_G2_one_precomp << OUTPUT_NEWLINE; - out << pvk.vk_alphaA_g2_precomp << OUTPUT_NEWLINE; - out << pvk.vk_alphaB_g1_precomp << OUTPUT_NEWLINE; - out << pvk.vk_alphaC_g2_precomp << OUTPUT_NEWLINE; - out << pvk.vk_rC_Z_g2_precomp << OUTPUT_NEWLINE; - out << pvk.vk_gamma_g2_precomp << OUTPUT_NEWLINE; - out << pvk.vk_gamma_beta_g1_precomp << OUTPUT_NEWLINE; - out << pvk.vk_gamma_beta_g2_precomp << OUTPUT_NEWLINE; - out << pvk.encoded_IC_query << OUTPUT_NEWLINE; - - return out; -} - -template -std::istream& operator>>(std::istream &in, r1cs_ppzksnark_processed_verification_key &pvk) -{ - in >> pvk.pp_G2_one_precomp; - consume_OUTPUT_NEWLINE(in); - in >> pvk.vk_alphaA_g2_precomp; - consume_OUTPUT_NEWLINE(in); - in >> pvk.vk_alphaB_g1_precomp; - consume_OUTPUT_NEWLINE(in); - in >> pvk.vk_alphaC_g2_precomp; - consume_OUTPUT_NEWLINE(in); - in >> pvk.vk_rC_Z_g2_precomp; - consume_OUTPUT_NEWLINE(in); - in >> pvk.vk_gamma_g2_precomp; - consume_OUTPUT_NEWLINE(in); - in >> pvk.vk_gamma_beta_g1_precomp; - consume_OUTPUT_NEWLINE(in); - in >> pvk.vk_gamma_beta_g2_precomp; - consume_OUTPUT_NEWLINE(in); - in >> pvk.encoded_IC_query; - consume_OUTPUT_NEWLINE(in); - - return in; -} - -template -bool r1cs_ppzksnark_proof::operator==(const r1cs_ppzksnark_proof &other) const -{ - return (this->g_A == other.g_A && - this->g_B == other.g_B && - this->g_C == other.g_C && - this->g_H == other.g_H && - this->g_K == other.g_K); -} - -template -std::ostream& operator<<(std::ostream &out, const r1cs_ppzksnark_proof &proof) -{ - out << proof.g_A << OUTPUT_NEWLINE; - out << proof.g_B << OUTPUT_NEWLINE; - out << proof.g_C << OUTPUT_NEWLINE; - out << proof.g_H << OUTPUT_NEWLINE; - out << proof.g_K << OUTPUT_NEWLINE; - - return out; -} - -template -std::istream& operator>>(std::istream &in, r1cs_ppzksnark_proof &proof) -{ - in >> proof.g_A; - consume_OUTPUT_NEWLINE(in); - in >> proof.g_B; - consume_OUTPUT_NEWLINE(in); - in >> proof.g_C; - consume_OUTPUT_NEWLINE(in); - in >> proof.g_H; - consume_OUTPUT_NEWLINE(in); - in >> proof.g_K; - consume_OUTPUT_NEWLINE(in); - - return in; -} - -template -r1cs_ppzksnark_verification_key r1cs_ppzksnark_verification_key::dummy_verification_key(const size_t input_size) -{ - r1cs_ppzksnark_verification_key result; - result.alphaA_g2 = Fr::random_element() * G2::one(); - result.alphaB_g1 = Fr::random_element() * G1::one(); - result.alphaC_g2 = Fr::random_element() * G2::one(); - result.gamma_g2 = Fr::random_element() * G2::one(); - result.gamma_beta_g1 = Fr::random_element() * G1::one(); - result.gamma_beta_g2 = Fr::random_element() * G2::one(); - result.rC_Z_g2 = Fr::random_element() * G2::one(); - - G1 base = Fr::random_element() * G1::one(); - G1_vector v; - for (size_t i = 0; i < input_size; ++i) - { - v.emplace_back(Fr::random_element() * G1::one()); - } - - result.encoded_IC_query = accumulation_vector >(std::move(base), std::move(v)); - - return result; -} - -template -r1cs_ppzksnark_keypair r1cs_ppzksnark_generator(const r1cs_ppzksnark_constraint_system &cs) -{ - /* draw random element at which the QAP is evaluated */ - const Fr t = Fr::random_element(); - - const Fr alphaA = Fr::random_element(), - alphaB = Fr::random_element(), - alphaC = Fr::random_element(), - rA = Fr::random_element(), - rB = Fr::random_element(), - beta = Fr::random_element(), - gamma = Fr::random_element(); - - return r1cs_ppzksnark_generator(cs, t, alphaA, alphaB, alphaC, rA, rB, beta, gamma); -} - -template -r1cs_ppzksnark_keypair r1cs_ppzksnark_generator( - const r1cs_ppzksnark_constraint_system &cs, - const Fr& t, - const Fr& alphaA, - const Fr& alphaB, - const Fr& alphaC, - const Fr& rA, - const Fr& rB, - const Fr& beta, - const Fr& gamma -) -{ - enter_block("Call to r1cs_ppzksnark_generator"); - - /* make the B_query "lighter" if possible */ - r1cs_ppzksnark_constraint_system cs_copy(cs); - cs_copy.swap_AB_if_beneficial(); - - qap_instance_evaluation > qap_inst = r1cs_to_qap_instance_map_with_evaluation(cs_copy, t); - - print_indent(); printf("* QAP number of variables: %zu\n", qap_inst.num_variables()); - print_indent(); printf("* QAP pre degree: %zu\n", cs_copy.constraints.size()); - print_indent(); printf("* QAP degree: %zu\n", qap_inst.degree()); - print_indent(); printf("* QAP number of input variables: %zu\n", qap_inst.num_inputs()); - - enter_block("Compute query densities"); - size_t non_zero_At = 0, non_zero_Bt = 0, non_zero_Ct = 0, non_zero_Ht = 0; - for (size_t i = 0; i < qap_inst.num_variables()+1; ++i) - { - if (!qap_inst.At[i].is_zero()) - { - ++non_zero_At; - } - if (!qap_inst.Bt[i].is_zero()) - { - ++non_zero_Bt; - } - if (!qap_inst.Ct[i].is_zero()) - { - ++non_zero_Ct; - } - } - for (size_t i = 0; i < qap_inst.degree()+1; ++i) - { - if (!qap_inst.Ht[i].is_zero()) - { - ++non_zero_Ht; - } - } - leave_block("Compute query densities"); - - Fr_vector At = std::move(qap_inst.At); // qap_inst.At is now in unspecified state, but we do not use it later - Fr_vector Bt = std::move(qap_inst.Bt); // qap_inst.Bt is now in unspecified state, but we do not use it later - Fr_vector Ct = std::move(qap_inst.Ct); // qap_inst.Ct is now in unspecified state, but we do not use it later - Fr_vector Ht = std::move(qap_inst.Ht); // qap_inst.Ht is now in unspecified state, but we do not use it later - - /* append Zt to At,Bt,Ct with */ - At.emplace_back(qap_inst.Zt); - Bt.emplace_back(qap_inst.Zt); - Ct.emplace_back(qap_inst.Zt); - - const Fr rC = rA * rB; - - // consrtuct the same-coefficient-check query (must happen before zeroing out the prefix of At) - Fr_vector Kt; - Kt.reserve(qap_inst.num_variables()+4); - for (size_t i = 0; i < qap_inst.num_variables()+1; ++i) - { - Kt.emplace_back( beta * (rA * At[i] + rB * Bt[i] + rC * Ct[i] ) ); - } - Kt.emplace_back(beta * rA * qap_inst.Zt); - Kt.emplace_back(beta * rB * qap_inst.Zt); - Kt.emplace_back(beta * rC * qap_inst.Zt); - - /* zero out prefix of At and stick it into IC coefficients */ - Fr_vector IC_coefficients; - IC_coefficients.reserve(qap_inst.num_inputs() + 1); - for (size_t i = 0; i < qap_inst.num_inputs() + 1; ++i) - { - IC_coefficients.emplace_back(At[i]); - assert(!IC_coefficients[i].is_zero()); - At[i] = Fr::zero(); - } - - const size_t g1_exp_count = 2*(non_zero_At - qap_inst.num_inputs() + non_zero_Ct) + non_zero_Bt + non_zero_Ht + Kt.size(); - const size_t g2_exp_count = non_zero_Bt; - - size_t g1_window = get_exp_window_size >(g1_exp_count); - size_t g2_window = get_exp_window_size >(g2_exp_count); - print_indent(); printf("* G1 window: %zu\n", g1_window); - print_indent(); printf("* G2 window: %zu\n", g2_window); - -#ifdef MULTICORE - const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads() -#else - const size_t chunks = 1; -#endif - - enter_block("Generating G1 multiexp table"); - window_table > g1_table = get_window_table(Fr::size_in_bits(), g1_window, G1::one()); - leave_block("Generating G1 multiexp table"); - - enter_block("Generating G2 multiexp table"); - window_table > g2_table = get_window_table(Fr::size_in_bits(), g2_window, G2::one()); - leave_block("Generating G2 multiexp table"); - - enter_block("Generate R1CS proving key"); - - enter_block("Generate knowledge commitments"); - enter_block("Compute the A-query", false); - knowledge_commitment_vector, G1 > A_query = kc_batch_exp(Fr::size_in_bits(), g1_window, g1_window, g1_table, g1_table, rA, rA*alphaA, At, chunks); - leave_block("Compute the A-query", false); - - enter_block("Compute the B-query", false); - knowledge_commitment_vector, G1 > B_query = kc_batch_exp(Fr::size_in_bits(), g2_window, g1_window, g2_table, g1_table, rB, rB*alphaB, Bt, chunks); - leave_block("Compute the B-query", false); - - enter_block("Compute the C-query", false); - knowledge_commitment_vector, G1 > C_query = kc_batch_exp(Fr::size_in_bits(), g1_window, g1_window, g1_table, g1_table, rC, rC*alphaC, Ct, chunks); - leave_block("Compute the C-query", false); - - enter_block("Compute the H-query", false); - G1_vector H_query = batch_exp(Fr::size_in_bits(), g1_window, g1_table, Ht); - leave_block("Compute the H-query", false); - - enter_block("Compute the K-query", false); - G1_vector K_query = batch_exp(Fr::size_in_bits(), g1_window, g1_table, Kt); -#ifdef USE_MIXED_ADDITION - batch_to_special >(K_query); -#endif - leave_block("Compute the K-query", false); - - leave_block("Generate knowledge commitments"); - - leave_block("Generate R1CS proving key"); - - enter_block("Generate R1CS verification key"); - G2 alphaA_g2 = alphaA * G2::one(); - G1 alphaB_g1 = alphaB * G1::one(); - G2 alphaC_g2 = alphaC * G2::one(); - G2 gamma_g2 = gamma * G2::one(); - G1 gamma_beta_g1 = (gamma * beta) * G1::one(); - G2 gamma_beta_g2 = (gamma * beta) * G2::one(); - G2 rC_Z_g2 = (rC * qap_inst.Zt) * G2::one(); - - enter_block("Encode IC query for R1CS verification key"); - G1 encoded_IC_base = (rA * IC_coefficients[0]) * G1::one(); - Fr_vector multiplied_IC_coefficients; - multiplied_IC_coefficients.reserve(qap_inst.num_inputs()); - for (size_t i = 1; i < qap_inst.num_inputs() + 1; ++i) - { - multiplied_IC_coefficients.emplace_back(rA * IC_coefficients[i]); - } - G1_vector encoded_IC_values = batch_exp(Fr::size_in_bits(), g1_window, g1_table, multiplied_IC_coefficients); - - leave_block("Encode IC query for R1CS verification key"); - leave_block("Generate R1CS verification key"); - - leave_block("Call to r1cs_ppzksnark_generator"); - - accumulation_vector > encoded_IC_query(std::move(encoded_IC_base), std::move(encoded_IC_values)); - - r1cs_ppzksnark_verification_key vk = r1cs_ppzksnark_verification_key(alphaA_g2, - alphaB_g1, - alphaC_g2, - gamma_g2, - gamma_beta_g1, - gamma_beta_g2, - rC_Z_g2, - encoded_IC_query); - r1cs_ppzksnark_proving_key pk = r1cs_ppzksnark_proving_key(std::move(A_query), - std::move(B_query), - std::move(C_query), - std::move(H_query), - std::move(K_query)); - - pk.print_size(); - vk.print_size(); - - return r1cs_ppzksnark_keypair(std::move(pk), std::move(vk)); -} - -template -knowledge_commitment r1cs_compute_proof_kc(const qap_witness > &qap_wit, - const knowledge_commitment_vector &kcv, - const Fr &zk_shift) -{ - knowledge_commitment returnval = kcv[0] + (zk_shift * kcv[qap_wit.num_variables()+1]); - -#ifdef DEBUG - assert(kcv.domain_size() == qap_wit.num_variables()+2); -#endif - -#ifdef MULTICORE - const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads() -#else - const size_t chunks = 1; -#endif - - returnval = returnval + kc_multi_exp_with_mixed_addition >( - kcv, - 1, - 1 + qap_wit.num_variables(), - qap_wit.coefficients_for_ABCs.begin(), - qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(), - chunks, - true - ); - - return returnval; -} - - - -template -G1 r1cs_compute_proof_K(const qap_witness> &qap_wit, const G1_vector &K_query, const G1 &zk_shift) -{ -#ifdef DEBUG - assert(K_query.size() == qap_wit.num_variables()+4); -#endif - -#ifdef MULTICORE - const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads() -#else - const size_t chunks = 1; -#endif - - G1 g_K = K_query[0] + zk_shift; - g_K = g_K + multi_exp_with_mixed_addition, Fr >( - K_query.begin()+1, - K_query.begin()+1+qap_wit.num_variables(), - qap_wit.coefficients_for_ABCs.begin(), - qap_wit.coefficients_for_ABCs.begin()+qap_wit.num_variables(), - chunks, - true - ); - - return g_K; -} - - -template -G1 r1cs_compute_proof_H(const qap_witness > &qap_wit, const G1_vector &H_query) -{ - G1 g_H = G1::zero(); - -#ifdef DEBUG - assert(H_query.size() == qap_wit.degree()+1); -#endif - -#ifdef MULTICORE - const size_t chunks = omp_get_max_threads(); // to override, set OMP_NUM_THREADS env var or call omp_set_num_threads() -#else - const size_t chunks = 1; -#endif - - g_H = g_H + multi_exp, Fr >( - H_query.begin(), - H_query.begin()+qap_wit.degree()+1, - qap_wit.coefficients_for_H.begin(), - qap_wit.coefficients_for_H.begin()+qap_wit.degree()+1, - chunks, - true - ); - - return g_H; -} - -template -r1cs_ppzksnark_proof r1cs_ppzksnark_prover(const r1cs_ppzksnark_proving_key &pk, - const r1cs_ppzksnark_primary_input &primary_input, - const r1cs_ppzksnark_auxiliary_input &auxiliary_input, - const r1cs_ppzksnark_constraint_system &constraint_system) -{ - enter_block("Call to r1cs_ppzksnark_prover"); - -#ifdef DEBUG - assert(constraint_system.is_satisfied(primary_input, auxiliary_input)); -#endif - - const Fr d1 = Fr::random_element(), - d2 = Fr::random_element(), - d3 = Fr::random_element(); - - enter_block("Compute the polynomial H"); - const qap_witness > qap_wit = r1cs_to_qap_witness_map(constraint_system, primary_input, auxiliary_input, d1, d2, d3); - leave_block("Compute the polynomial H"); - -#ifdef DEBUG - const Fr t = Fr::random_element(); - qap_instance_evaluation > qap_inst = r1cs_to_qap_instance_map_with_evaluation(constraint_system, t); - assert(qap_inst.is_satisfied(qap_wit)); -#endif - -#ifdef DEBUG - for (size_t i = 0; i < qap_wit.num_inputs() + 1; ++i) - { - assert(pk.A_query[i].g == G1::zero()); - } -#endif - - enter_block("Compute the proof"); - - enter_block("Compute answer to A-query", false); - auto g_A = r1cs_compute_proof_kc, G1 >(qap_wit, pk.A_query, qap_wit.d1); - leave_block("Compute answer to A-query", false); - - enter_block("Compute answer to B-query", false); - auto g_B = r1cs_compute_proof_kc, G1 >(qap_wit, pk.B_query, qap_wit.d2); - leave_block("Compute answer to B-query", false); - - enter_block("Compute answer to C-query", false); - auto g_C = r1cs_compute_proof_kc, G1 >(qap_wit, pk.C_query, qap_wit.d3); - leave_block("Compute answer to C-query", false); - - enter_block("Compute answer to H-query", false); - auto g_H = r1cs_compute_proof_H(qap_wit, pk.H_query); - leave_block("Compute answer to H-query", false); - - enter_block("Compute answer to K-query", false); - G1 zk_shift = qap_wit.d1*pk.K_query[qap_wit.num_variables()+1] + - qap_wit.d2*pk.K_query[qap_wit.num_variables()+2] + - qap_wit.d3*pk.K_query[qap_wit.num_variables()+3]; - G1 g_K = r1cs_compute_proof_K(qap_wit, pk.K_query, zk_shift); - leave_block("Compute answer to K-query", false); - - leave_block("Compute the proof"); - - leave_block("Call to r1cs_ppzksnark_prover"); - - r1cs_ppzksnark_proof proof = r1cs_ppzksnark_proof(std::move(g_A), std::move(g_B), std::move(g_C), std::move(g_H), std::move(g_K)); - - return proof; -} - -template -r1cs_ppzksnark_proof r1cs_ppzksnark_prover_streaming(std::ifstream &proving_key_file, - const r1cs_ppzksnark_primary_input &primary_input, - const r1cs_ppzksnark_auxiliary_input &auxiliary_input, - const r1cs_ppzksnark_constraint_system &constraint_system) -{ - enter_block("Call to r1cs_ppzksnark_prover_streaming"); - - const Fr d1 = Fr::random_element(), - d2 = Fr::random_element(), - d3 = Fr::random_element(); - - enter_block("Compute the polynomial H"); - const qap_witness > qap_wit = r1cs_to_qap_witness_map(constraint_system, primary_input, auxiliary_input, d1, d2, d3); - leave_block("Compute the polynomial H"); - - enter_block("Compute the proof"); - - r1cs_ppzksnark_proof proof; - - enter_block("Compute answer to A-query", false); - { - knowledge_commitment_vector, G1 > A_query; - proving_key_file >> A_query; - proof.g_A = r1cs_compute_proof_kc, G1 >(qap_wit, A_query, qap_wit.d1); - } - leave_block("Compute answer to A-query", false); - - enter_block("Compute answer to B-query", false); - { - knowledge_commitment_vector, G1 > B_query; - proving_key_file >> B_query; - proof.g_B = r1cs_compute_proof_kc, G1 >(qap_wit, B_query, qap_wit.d2); - } - leave_block("Compute answer to B-query", false); - - enter_block("Compute answer to C-query", false); - { - knowledge_commitment_vector, G1 > C_query; - proving_key_file >> C_query; - proof.g_C = r1cs_compute_proof_kc, G1 >(qap_wit, C_query, qap_wit.d3); - } - leave_block("Compute answer to C-query", false); - - enter_block("Compute answer to H-query", false); - { - G1_vector H_query; - proving_key_file >> H_query; - proof.g_H = r1cs_compute_proof_H(qap_wit, H_query); - } - leave_block("Compute answer to H-query", false); - - enter_block("Compute answer to K-query", false); - { - G1_vector K_query; - proving_key_file >> K_query; - G1 zk_shift = qap_wit.d1*K_query[qap_wit.num_variables()+1] + - qap_wit.d2*K_query[qap_wit.num_variables()+2] + - qap_wit.d3*K_query[qap_wit.num_variables()+3]; - proof.g_K = r1cs_compute_proof_K(qap_wit, K_query, zk_shift); - } - leave_block("Compute answer to K-query", false); - - leave_block("Compute the proof"); - - leave_block("Call to r1cs_ppzksnark_prover_streaming"); - - return proof; -} - -template -r1cs_ppzksnark_processed_verification_key r1cs_ppzksnark_verifier_process_vk(const r1cs_ppzksnark_verification_key &vk) -{ - enter_block("Call to r1cs_ppzksnark_verifier_process_vk"); - - r1cs_ppzksnark_processed_verification_key pvk; - pvk.pp_G2_one_precomp = ppT::precompute_G2(G2::one()); - pvk.vk_alphaA_g2_precomp = ppT::precompute_G2(vk.alphaA_g2); - pvk.vk_alphaB_g1_precomp = ppT::precompute_G1(vk.alphaB_g1); - pvk.vk_alphaC_g2_precomp = ppT::precompute_G2(vk.alphaC_g2); - pvk.vk_rC_Z_g2_precomp = ppT::precompute_G2(vk.rC_Z_g2); - pvk.vk_gamma_g2_precomp = ppT::precompute_G2(vk.gamma_g2); - pvk.vk_gamma_beta_g1_precomp = ppT::precompute_G1(vk.gamma_beta_g1); - pvk.vk_gamma_beta_g2_precomp = ppT::precompute_G2(vk.gamma_beta_g2); - - pvk.encoded_IC_query = vk.encoded_IC_query; - - leave_block("Call to r1cs_ppzksnark_verifier_process_vk"); - - return pvk; -} - -template -bool r1cs_ppzksnark_online_verifier_weak_IC(const r1cs_ppzksnark_processed_verification_key &pvk, - const r1cs_ppzksnark_primary_input &primary_input, - const r1cs_ppzksnark_proof &proof) -{ - assert(pvk.encoded_IC_query.domain_size() >= primary_input.size()); - - const accumulation_vector > accumulated_IC = pvk.encoded_IC_query.template accumulate_chunk >(primary_input.begin(), primary_input.end(), 0); - const G1 &acc = accumulated_IC.first; - - if (!proof.is_well_formed()) - { - return false; - } - - G1_precomp proof_g_A_g_precomp = ppT::precompute_G1(proof.g_A.g); - G1_precomp proof_g_A_h_precomp = ppT::precompute_G1(proof.g_A.h); - Fqk kc_A_1 = ppT::miller_loop(proof_g_A_g_precomp, pvk.vk_alphaA_g2_precomp); - Fqk kc_A_2 = ppT::miller_loop(proof_g_A_h_precomp, pvk.pp_G2_one_precomp); - GT kc_A = ppT::final_exponentiation(kc_A_1 * kc_A_2.unitary_inverse()); - if (kc_A != GT::one()) - { - return false; - } - - G2_precomp proof_g_B_g_precomp = ppT::precompute_G2(proof.g_B.g); - G1_precomp proof_g_B_h_precomp = ppT::precompute_G1(proof.g_B.h); - Fqk kc_B_1 = ppT::miller_loop(pvk.vk_alphaB_g1_precomp, proof_g_B_g_precomp); - Fqk kc_B_2 = ppT::miller_loop(proof_g_B_h_precomp, pvk.pp_G2_one_precomp); - GT kc_B = ppT::final_exponentiation(kc_B_1 * kc_B_2.unitary_inverse()); - if (kc_B != GT::one()) - { - return false; - } - - G1_precomp proof_g_C_g_precomp = ppT::precompute_G1(proof.g_C.g); - G1_precomp proof_g_C_h_precomp = ppT::precompute_G1(proof.g_C.h); - Fqk kc_C_1 = ppT::miller_loop(proof_g_C_g_precomp, pvk.vk_alphaC_g2_precomp); - Fqk kc_C_2 = ppT::miller_loop(proof_g_C_h_precomp, pvk.pp_G2_one_precomp); - GT kc_C = ppT::final_exponentiation(kc_C_1 * kc_C_2.unitary_inverse()); - if (kc_C != GT::one()) - { - return false; - } - - // check that g^((A+acc)*B)=g^(H*\Prod(t-\sigma)+C) - // equivalently, via pairings, that e(g^(A+acc), g^B) = e(g^H, g^Z) + e(g^C, g^1) - G1_precomp proof_g_A_g_acc_precomp = ppT::precompute_G1(proof.g_A.g + acc); - G1_precomp proof_g_H_precomp = ppT::precompute_G1(proof.g_H); - Fqk QAP_1 = ppT::miller_loop(proof_g_A_g_acc_precomp, proof_g_B_g_precomp); - Fqk QAP_23 = ppT::double_miller_loop(proof_g_H_precomp, pvk.vk_rC_Z_g2_precomp, proof_g_C_g_precomp, pvk.pp_G2_one_precomp); - GT QAP = ppT::final_exponentiation(QAP_1 * QAP_23.unitary_inverse()); - if (QAP != GT::one()) - { - return false; - } - - G1_precomp proof_g_K_precomp = ppT::precompute_G1(proof.g_K); - G1_precomp proof_g_A_g_acc_C_precomp = ppT::precompute_G1((proof.g_A.g + acc) + proof.g_C.g); - Fqk K_1 = ppT::miller_loop(proof_g_K_precomp, pvk.vk_gamma_g2_precomp); - Fqk K_23 = ppT::double_miller_loop(proof_g_A_g_acc_C_precomp, pvk.vk_gamma_beta_g2_precomp, pvk.vk_gamma_beta_g1_precomp, proof_g_B_g_precomp); - GT K = ppT::final_exponentiation(K_1 * K_23.unitary_inverse()); - if (K != GT::one()) - { - return false; - } - - return true; -} - -template -bool r1cs_ppzksnark_verifier_weak_IC(const r1cs_ppzksnark_verification_key &vk, - const r1cs_ppzksnark_primary_input &primary_input, - const r1cs_ppzksnark_proof &proof) -{ - enter_block("Call to r1cs_ppzksnark_verifier_weak_IC"); - r1cs_ppzksnark_processed_verification_key pvk = r1cs_ppzksnark_verifier_process_vk(vk); - bool result = r1cs_ppzksnark_online_verifier_weak_IC(pvk, primary_input, proof); - leave_block("Call to r1cs_ppzksnark_verifier_weak_IC"); - return result; -} - -template -bool r1cs_ppzksnark_online_verifier_strong_IC(const r1cs_ppzksnark_processed_verification_key &pvk, - const r1cs_ppzksnark_primary_input &primary_input, - const r1cs_ppzksnark_proof &proof) -{ - bool result = true; - enter_block("Call to r1cs_ppzksnark_online_verifier_strong_IC"); - - if (pvk.encoded_IC_query.domain_size() != primary_input.size()) - { - print_indent(); printf("Input length differs from expected (got %zu, expected %zu).\n", primary_input.size(), pvk.encoded_IC_query.domain_size()); - result = false; - } - else - { - result = r1cs_ppzksnark_online_verifier_weak_IC(pvk, primary_input, proof); - } - - leave_block("Call to r1cs_ppzksnark_online_verifier_strong_IC"); - return result; -} - -template -bool r1cs_ppzksnark_verifier_strong_IC(const r1cs_ppzksnark_verification_key &vk, - const r1cs_ppzksnark_primary_input &primary_input, - const r1cs_ppzksnark_proof &proof) -{ - enter_block("Call to r1cs_ppzksnark_verifier_strong_IC"); - r1cs_ppzksnark_processed_verification_key pvk = r1cs_ppzksnark_verifier_process_vk(vk); - bool result = r1cs_ppzksnark_online_verifier_strong_IC(pvk, primary_input, proof); - leave_block("Call to r1cs_ppzksnark_verifier_strong_IC"); - return result; -} - -template -bool r1cs_ppzksnark_affine_verifier_weak_IC(const r1cs_ppzksnark_verification_key &vk, - const r1cs_ppzksnark_primary_input &primary_input, - const r1cs_ppzksnark_proof &proof) -{ - enter_block("Call to r1cs_ppzksnark_affine_verifier_weak_IC"); - assert(vk.encoded_IC_query.domain_size() >= primary_input.size()); - - affine_ate_G2_precomp pvk_pp_G2_one_precomp = ppT::affine_ate_precompute_G2(G2::one()); - affine_ate_G2_precomp pvk_vk_alphaA_g2_precomp = ppT::affine_ate_precompute_G2(vk.alphaA_g2); - affine_ate_G1_precomp pvk_vk_alphaB_g1_precomp = ppT::affine_ate_precompute_G1(vk.alphaB_g1); - affine_ate_G2_precomp pvk_vk_alphaC_g2_precomp = ppT::affine_ate_precompute_G2(vk.alphaC_g2); - affine_ate_G2_precomp pvk_vk_rC_Z_g2_precomp = ppT::affine_ate_precompute_G2(vk.rC_Z_g2); - affine_ate_G2_precomp pvk_vk_gamma_g2_precomp = ppT::affine_ate_precompute_G2(vk.gamma_g2); - affine_ate_G1_precomp pvk_vk_gamma_beta_g1_precomp = ppT::affine_ate_precompute_G1(vk.gamma_beta_g1); - affine_ate_G2_precomp pvk_vk_gamma_beta_g2_precomp = ppT::affine_ate_precompute_G2(vk.gamma_beta_g2); - - enter_block("Compute input-dependent part of A"); - const accumulation_vector > accumulated_IC = vk.encoded_IC_query.template accumulate_chunk >(primary_input.begin(), primary_input.end(), 0); - assert(accumulated_IC.is_fully_accumulated()); - const G1 &acc = accumulated_IC.first; - leave_block("Compute input-dependent part of A"); - - bool result = true; - enter_block("Check knowledge commitment for A is valid"); - affine_ate_G1_precomp proof_g_A_g_precomp = ppT::affine_ate_precompute_G1(proof.g_A.g); - affine_ate_G1_precomp proof_g_A_h_precomp = ppT::affine_ate_precompute_G1(proof.g_A.h); - Fqk kc_A_miller = ppT::affine_ate_e_over_e_miller_loop(proof_g_A_g_precomp, pvk_vk_alphaA_g2_precomp, proof_g_A_h_precomp, pvk_pp_G2_one_precomp); - GT kc_A = ppT::final_exponentiation(kc_A_miller); - - if (kc_A != GT::one()) - { - print_indent(); printf("Knowledge commitment for A query incorrect.\n"); - result = false; - } - leave_block("Check knowledge commitment for A is valid"); - - enter_block("Check knowledge commitment for B is valid"); - affine_ate_G2_precomp proof_g_B_g_precomp = ppT::affine_ate_precompute_G2(proof.g_B.g); - affine_ate_G1_precomp proof_g_B_h_precomp = ppT::affine_ate_precompute_G1(proof.g_B.h); - Fqk kc_B_miller = ppT::affine_ate_e_over_e_miller_loop(pvk_vk_alphaB_g1_precomp, proof_g_B_g_precomp, proof_g_B_h_precomp, pvk_pp_G2_one_precomp); - GT kc_B = ppT::final_exponentiation(kc_B_miller); - if (kc_B != GT::one()) - { - print_indent(); printf("Knowledge commitment for B query incorrect.\n"); - result = false; - } - leave_block("Check knowledge commitment for B is valid"); - - enter_block("Check knowledge commitment for C is valid"); - affine_ate_G1_precomp proof_g_C_g_precomp = ppT::affine_ate_precompute_G1(proof.g_C.g); - affine_ate_G1_precomp proof_g_C_h_precomp = ppT::affine_ate_precompute_G1(proof.g_C.h); - Fqk kc_C_miller = ppT::affine_ate_e_over_e_miller_loop(proof_g_C_g_precomp, pvk_vk_alphaC_g2_precomp, proof_g_C_h_precomp, pvk_pp_G2_one_precomp); - GT kc_C = ppT::final_exponentiation(kc_C_miller); - if (kc_C != GT::one()) - { - print_indent(); printf("Knowledge commitment for C query incorrect.\n"); - result = false; - } - leave_block("Check knowledge commitment for C is valid"); - - enter_block("Check QAP divisibility"); - affine_ate_G1_precomp proof_g_A_g_acc_precomp = ppT::affine_ate_precompute_G1(proof.g_A.g + acc); - affine_ate_G1_precomp proof_g_H_precomp = ppT::affine_ate_precompute_G1(proof.g_H); - Fqk QAP_miller = ppT::affine_ate_e_times_e_over_e_miller_loop(proof_g_H_precomp, pvk_vk_rC_Z_g2_precomp, proof_g_C_g_precomp, pvk_pp_G2_one_precomp, proof_g_A_g_acc_precomp, proof_g_B_g_precomp); - GT QAP = ppT::final_exponentiation(QAP_miller); - if (QAP != GT::one()) - { - print_indent(); printf("QAP divisibility check failed.\n"); - result = false; - } - leave_block("Check QAP divisibility"); - - enter_block("Check same coefficients were used"); - affine_ate_G1_precomp proof_g_K_precomp = ppT::affine_ate_precompute_G1(proof.g_K); - affine_ate_G1_precomp proof_g_A_g_acc_C_precomp = ppT::affine_ate_precompute_G1((proof.g_A.g + acc) + proof.g_C.g); - Fqk K_miller = ppT::affine_ate_e_times_e_over_e_miller_loop(proof_g_A_g_acc_C_precomp, pvk_vk_gamma_beta_g2_precomp, pvk_vk_gamma_beta_g1_precomp, proof_g_B_g_precomp, proof_g_K_precomp, pvk_vk_gamma_g2_precomp); - GT K = ppT::final_exponentiation(K_miller); - if (K != GT::one()) - { - print_indent(); printf("Same-coefficient check failed.\n"); - result = false; - } - leave_block("Check same coefficients were used"); - - leave_block("Call to r1cs_ppzksnark_affine_verifier_weak_IC"); - - return result; -} - -} // libsnark -#endif // R1CS_PPZKSNARK_TCC_ diff --git a/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark_params.hpp b/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark_params.hpp deleted file mode 100644 index 4054b8e3b..000000000 --- a/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/r1cs_ppzksnark_params.hpp +++ /dev/null @@ -1,34 +0,0 @@ -/** @file - ***************************************************************************** - - Declaration of public-parameter selector for the R1CS ppzkSNARK. - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ - -#ifndef R1CS_PPZKSNARK_PARAMS_HPP_ -#define R1CS_PPZKSNARK_PARAMS_HPP_ - -#include "relations/constraint_satisfaction_problems/r1cs/r1cs.hpp" - -namespace libsnark { - -/** - * Below are various template aliases (used for convenience). - */ - -template -using r1cs_ppzksnark_constraint_system = r1cs_constraint_system >; - -template -using r1cs_ppzksnark_primary_input = r1cs_primary_input >; - -template -using r1cs_ppzksnark_auxiliary_input = r1cs_auxiliary_input >; - -} // libsnark - -#endif // R1CS_PPZKSNARK_PARAMS_HPP_ diff --git a/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp b/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp deleted file mode 100644 index 6f8b575f2..000000000 --- a/src/snark/libsnark/zk_proof_systems/ppzksnark/r1cs_ppzksnark/tests/test_r1cs_ppzksnark.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/** @file - ***************************************************************************** - Test program that exercises the ppzkSNARK (first generator, then - prover, then verifier) on a synthetic R1CS instance. - - ***************************************************************************** - * @author This file is part of libsnark, developed by SCIPR Lab - * and contributors (see AUTHORS). - * @copyright MIT license (see LICENSE file) - *****************************************************************************/ -#include -#include - -#include "common/default_types/r1cs_ppzksnark_pp.hpp" -#include "common/profiling.hpp" -#include "common/utils.hpp" -#include "relations/constraint_satisfaction_problems/r1cs/examples/r1cs_examples.hpp" -#include "zk_proof_systems/ppzksnark/r1cs_ppzksnark/examples/run_r1cs_ppzksnark.hpp" - -using namespace libsnark; - -template -void test_r1cs_ppzksnark(size_t num_constraints, - size_t input_size) -{ - print_header("(enter) Test R1CS ppzkSNARK"); - - const bool test_serialization = true; - r1cs_example > example = generate_r1cs_example_with_binary_input >(num_constraints, input_size); - const bool bit = run_r1cs_ppzksnark(example, test_serialization); - assert(bit); - - print_header("(leave) Test R1CS ppzkSNARK"); -} - -int main() -{ - default_r1cs_ppzksnark_pp::init_public_params(); - start_profiling(); - - test_r1cs_ppzksnark(1000, 100); -} diff --git a/src/test/addrman_tests.cpp b/src/test/addrman_tests.cpp index fc0600dfc..612802445 100644 --- a/src/test/addrman_tests.cpp +++ b/src/test/addrman_tests.cpp @@ -345,15 +345,15 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr) BOOST_CHECK(vAddr1.size() == 0); CAddress addr1 = CAddress(CService("250.250.2.1", 8333)); - addr1.nTime = GetAdjustedTime(); // Set time so isTerrible = false + addr1.nTime = GetTime(); // Set time so isTerrible = false CAddress addr2 = CAddress(CService("250.251.2.2", 9999)); - addr2.nTime = GetAdjustedTime(); + addr2.nTime = GetTime(); CAddress addr3 = CAddress(CService("251.252.2.3", 8333)); - addr3.nTime = GetAdjustedTime(); + addr3.nTime = GetTime(); CAddress addr4 = CAddress(CService("252.253.3.4", 8333)); - addr4.nTime = GetAdjustedTime(); + addr4.nTime = GetTime(); CAddress addr5 = CAddress(CService("252.254.4.5", 8333)); - addr5.nTime = GetAdjustedTime(); + addr5.nTime = GetTime(); CNetAddr source1 = CNetAddr("250.1.2.1"); CNetAddr source2 = CNetAddr("250.2.3.3"); @@ -381,7 +381,7 @@ BOOST_AUTO_TEST_CASE(addrman_getaddr) CAddress addr = CAddress(CService(strAddr)); // Ensure that for all addrs in addrman, isTerrible == false. - addr.nTime = GetAdjustedTime(); + addr.nTime = GetTime(); addrman.Add(addr, CNetAddr(strAddr)); if (i % 8 == 0) addrman.Good(addr); diff --git a/src/test/coins_tests.cpp b/src/test/coins_tests.cpp index dc795ad7a..8067b42b9 100644 --- a/src/test/coins_tests.cpp +++ b/src/test/coins_tests.cpp @@ -1,4 +1,5 @@ // Copyright (c) 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. @@ -39,22 +40,6 @@ public: hashBestSaplingAnchor_ = SaplingMerkleTree::empty_root(); } - bool GetSproutAnchorAt(const uint256& rt, SproutMerkleTree &tree) const { - if (rt == SproutMerkleTree::empty_root()) { - SproutMerkleTree new_tree; - tree = new_tree; - return true; - } - - std::map::const_iterator it = mapSproutAnchors_.find(rt); - if (it == mapSproutAnchors_.end()) { - return false; - } else { - tree = it->second; - return true; - } - } - bool GetSaplingAnchorAt(const uint256& rt, SaplingMerkleTree &tree) const { if (rt == SaplingMerkleTree::empty_root()) { SaplingMerkleTree new_tree; @@ -632,7 +617,7 @@ BOOST_AUTO_TEST_CASE(chained_joinsplits) CMutableTransaction mtx; mtx.vjoinsplit.push_back(js2); - BOOST_CHECK(!cache.HaveJoinSplitRequirements(mtx)); + BOOST_CHECK(!cache.HaveShieldedRequirements(mtx)); } { @@ -642,7 +627,7 @@ BOOST_AUTO_TEST_CASE(chained_joinsplits) mtx.vjoinsplit.push_back(js2); mtx.vjoinsplit.push_back(js1); - BOOST_CHECK(!cache.HaveJoinSplitRequirements(mtx)); + BOOST_CHECK(!cache.HaveShieldedRequirements(mtx)); } { @@ -650,7 +635,7 @@ BOOST_AUTO_TEST_CASE(chained_joinsplits) mtx.vjoinsplit.push_back(js1); mtx.vjoinsplit.push_back(js2); - BOOST_CHECK(cache.HaveJoinSplitRequirements(mtx)); + BOOST_CHECK(cache.HaveShieldedRequirements(mtx)); } { @@ -659,7 +644,7 @@ BOOST_AUTO_TEST_CASE(chained_joinsplits) mtx.vjoinsplit.push_back(js2); mtx.vjoinsplit.push_back(js3); - BOOST_CHECK(cache.HaveJoinSplitRequirements(mtx)); + BOOST_CHECK(cache.HaveShieldedRequirements(mtx)); } { @@ -669,7 +654,7 @@ BOOST_AUTO_TEST_CASE(chained_joinsplits) mtx.vjoinsplit.push_back(js2); mtx.vjoinsplit.push_back(js3); - BOOST_CHECK(cache.HaveJoinSplitRequirements(mtx)); + BOOST_CHECK(cache.HaveShieldedRequirements(mtx)); } } diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp index 220d6a9b7..390b2bc7b 100644 --- a/src/test/key_tests.cpp +++ b/src/test/key_tests.cpp @@ -1,4 +1,5 @@ // Copyright (c) 2012-2013 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. @@ -22,6 +23,7 @@ using namespace std; using namespace libzcash; +//TODO: convert to Hush addresses static const std::string strSecret1 = "5HxWvvfubhXpYYpS3tJkw6fq9jE9j18THftkZjHHfmFiWtmAbrj"; static const std::string strSecret2 = "5KC4ejrDjv152FGwP386VD1i2NYc5KkfSMyv1nGy1VGDxGHqVY3"; static const std::string strSecret1C = "Kwr371tjA9u2rFSMZjTNun2PXXP3WPZu2afRHTcta6KxEUdm1vEw"; @@ -186,41 +188,6 @@ BOOST_AUTO_TEST_CASE(key_test1) BOOST_CHECK(detsigc == ParseHex("2052d8a32079c11e79db95af63bb9600c5b04f21a9ca33dc129c2bfa8ac9dc1cd561d8ae5e0f6c1a16bde3719c64c2fd70e404b6428ab9a69566962e8771b5944d")); } -BOOST_AUTO_TEST_CASE(zc_address_test) -{ - for (size_t i = 0; i < 1000; i++) { - auto sk = SproutSpendingKey::random(); - { - string sk_string = EncodeSpendingKey(sk); - - BOOST_CHECK(sk_string[0] == 'S'); - BOOST_CHECK(sk_string[1] == 'K'); - - auto spendingkey2 = DecodeSpendingKey(sk_string); - BOOST_CHECK(IsValidSpendingKey(spendingkey2)); - BOOST_ASSERT(boost::get(&spendingkey2) != nullptr); - auto sk2 = boost::get(spendingkey2); - BOOST_CHECK(sk.inner() == sk2.inner()); - } - { - auto addr = sk.address(); - - std::string addr_string = EncodePaymentAddress(addr); - - BOOST_CHECK(addr_string[0] == 'z'); - BOOST_CHECK(addr_string[1] == 'c'); - - auto paymentaddr2 = DecodePaymentAddress(addr_string); - BOOST_ASSERT(IsValidPaymentAddress(paymentaddr2)); - - BOOST_ASSERT(boost::get(&paymentaddr2) != nullptr); - auto addr2 = boost::get(paymentaddr2); - BOOST_CHECK(addr.a_pk == addr2.a_pk); - BOOST_CHECK(addr.pk_enc == addr2.pk_enc); - } - } -} - BOOST_AUTO_TEST_CASE(zs_address_test) { SelectParams(CBaseChainParams::REGTEST); diff --git a/src/test/rpc_wallet_tests.cpp b/src/test/rpc_wallet_tests.cpp index 1eaade55b..2abe2d782 100644 --- a/src/test/rpc_wallet_tests.cpp +++ b/src/test/rpc_wallet_tests.cpp @@ -1,6 +1,7 @@ // Copyright (c) 2013-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. +// file COPYING or https://www.opensource.org/licenses/mit-license.php #include "rpc/server.h" #include "rpc/client.h" @@ -341,38 +342,12 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_validateaddress) BOOST_CHECK_THROW(CallRPC("z_validateaddress"), runtime_error); BOOST_CHECK_THROW(CallRPC("z_validateaddress toomany args"), runtime_error); - // Wallet should be empty - std::set addrs; - pwalletMain->GetSproutPaymentAddresses(addrs); - BOOST_CHECK(addrs.size()==0); - // This address is not valid, it belongs to another network BOOST_CHECK_NO_THROW(retValue = CallRPC("z_validateaddress ztaaga95QAPyp1kSQ1hD2kguCpzyMHjxWZqaYDEkzbvo7uYQYAw2S8X4Kx98AvhhofMtQL8PAXKHuZsmhRcanavKRKmdCzk")); UniValue resultObj = retValue.get_obj(); bool b = find_value(resultObj, "isvalid").get_bool(); BOOST_CHECK_EQUAL(b, false); - // This address is valid, but the spending key is not in this wallet - BOOST_CHECK_NO_THROW(retValue = CallRPC("z_validateaddress zcfA19SDAKRYHLoRDoShcoz4nPohqWxuHcqg8WAxsiB2jFrrs6k7oSvst3UZvMYqpMNSRBkxBsnyjjngX5L55FxMzLKach8")); - resultObj = retValue.get_obj(); - b = find_value(resultObj, "isvalid").get_bool(); - BOOST_CHECK_EQUAL(b, true); - BOOST_CHECK_EQUAL(find_value(resultObj, "type").get_str(), "sprout"); - b = find_value(resultObj, "ismine").get_bool(); - BOOST_CHECK_EQUAL(b, false); - - // Let's import a spending key to the wallet and validate its payment address - BOOST_CHECK_NO_THROW(CallRPC("z_importkey SKxoWv77WGwFnUJitQKNEcD636bL4X5Gd6wWmgaA4Q9x8jZBPJXT")); - BOOST_CHECK_NO_THROW(retValue = CallRPC("z_validateaddress zcWsmqT4X2V4jgxbgiCzyrAfRT1vi1F4sn7M5Pkh66izzw8Uk7LBGAH3DtcSMJeUb2pi3W4SQF8LMKkU2cUuVP68yAGcomL")); - resultObj = retValue.get_obj(); - b = find_value(resultObj, "isvalid").get_bool(); - BOOST_CHECK_EQUAL(b, true); - BOOST_CHECK_EQUAL(find_value(resultObj, "type").get_str(), "sprout"); - b = find_value(resultObj, "ismine").get_bool(); - BOOST_CHECK_EQUAL(b, true); - BOOST_CHECK_EQUAL(find_value(resultObj, "payingkey").get_str(), "f5bb3c888ccc9831e3f6ba06e7528e26a312eec3acc1823be8918b6a3a5e20ad"); - BOOST_CHECK_EQUAL(find_value(resultObj, "transmissionkey").get_str(), "7a58c7132446564e6b810cf895c20537b3528357dc00150a8e201f491efa9c1a"); - // This Sapling address is not valid, it belongs to another network BOOST_CHECK_NO_THROW(retValue = CallRPC("z_validateaddress ztestsapling1knww2nyjc62njkard0jmx7hlsj6twxmxwprn7anvrv4dc2zxanl3nemc0qx2hvplxmd2uau8gyw")); resultObj = retValue.get_obj(); @@ -398,16 +373,6 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_exportwallet) { LOCK2(cs_main, pwalletMain->cs_wallet); - // wallet should be empty - std::set addrs; - pwalletMain->GetSproutPaymentAddresses(addrs); - BOOST_CHECK(addrs.size()==0); - - // wallet should have one key - libzcash::SproutPaymentAddress addr = pwalletMain->GenerateNewSproutZKey(); - pwalletMain->GetSproutPaymentAddresses(addrs); - BOOST_CHECK(addrs.size()==1); - // Set up paths boost::filesystem::path tmppath = boost::filesystem::temp_directory_path(); boost::filesystem::path tmpfilename = boost::filesystem::unique_path("%%%%%%%%"); @@ -429,9 +394,6 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_exportwallet) BOOST_CHECK_NO_THROW(CallRPC(string("z_exportwallet ") + tmpfilename.string())); - libzcash::SproutSpendingKey key; - BOOST_CHECK(pwalletMain->GetSproutSpendingKey(addr, key)); - std::string s1 = EncodePaymentAddress(addr); std::string s2 = EncodeSpendingKey(key); @@ -474,13 +436,13 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importwallet) BOOST_CHECK_THROW(CallRPC("z_importwallet toomany args"), runtime_error); // create a random key locally - auto testSpendingKey = libzcash::SproutSpendingKey::random(); + auto testSpendingKey = libzcash::SaplingSpendingKey::random(); auto testPaymentAddress = testSpendingKey.address(); std::string testAddr = EncodePaymentAddress(testPaymentAddress); std::string testKey = EncodeSpendingKey(testSpendingKey); // create test data using the random key - std::string format_str = "# Wallet dump created by Komodo v0.11.2.0.z8-9155cc6-dirty (2016-08-11 11:37:00 -0700)\n" + std::string format_str = "# Wallet dump created by Hush v0.11.2.0.z8-9155cc6-dirty (2016-08-11 11:37:00 -0700)\n" "# * Created on 2016-08-12T21:55:36Z\n" "# * Best block at time of backup was 0 (0de0a3851fef2d433b9b4f51d4342bdd24c5ddd793eb8fba57189f07e9235d52),\n" "# mined on 2009-01-03T18:15:05Z\n" @@ -503,28 +465,31 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importwallet) file << std::flush; // wallet should currently be empty - std::set addrs; - pwalletMain->GetSproutPaymentAddresses(addrs); + std::set addrs; + pwalletMain->GetSaplingPaymentAddresses(addrs); BOOST_CHECK(addrs.size()==0); // import test data from file into wallet BOOST_CHECK_NO_THROW(CallRPC(string("z_importwallet ") + path)); // wallet should now have one zkey - pwalletMain->GetSproutPaymentAddresses(addrs); + pwalletMain->GetSaplingPaymentAddresses(addrs); BOOST_CHECK(addrs.size()==1); // check that we have the spending key for the address + /* auto address = DecodePaymentAddress(testAddr); BOOST_CHECK(IsValidPaymentAddress(address)); BOOST_ASSERT(boost::get(&address) != nullptr); auto addr = boost::get(address); BOOST_CHECK(pwalletMain->HaveSproutSpendingKey(addr)); + */ + // Verify the spending key is the same as the test data - libzcash::SproutSpendingKey k; - BOOST_CHECK(pwalletMain->GetSproutSpendingKey(addr, k)); - BOOST_CHECK_EQUAL(testKey, EncodeSpendingKey(k)); + //libzcash::SproutSpendingKey k; + //BOOST_CHECK(pwalletMain->GetSproutSpendingKey(addr, k)); + //BOOST_CHECK_EQUAL(testKey, EncodeSpendingKey(k)); } @@ -606,9 +571,8 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport) // Verify number of addresses stored in wallet is n1+n2 int numAddrs = myaddrs.size(); BOOST_CHECK(numAddrs == (2 * n1) + n2); - pwalletMain->GetSproutPaymentAddresses(addrs); pwalletMain->GetSaplingPaymentAddresses(saplingAddrs); - BOOST_CHECK(addrs.size() + saplingAddrs.size() == numAddrs); + BOOST_CHECK(saplingAddrs.size() == numAddrs); // Ask wallet to list addresses BOOST_CHECK_NO_THROW(retValue = CallRPC("z_listaddresses")); @@ -630,9 +594,6 @@ BOOST_AUTO_TEST_CASE(rpc_wallet_z_importexport) std::string newaddress = retValue.get_str(); auto address = DecodePaymentAddress(newaddress); BOOST_CHECK(IsValidPaymentAddress(address)); - BOOST_ASSERT(boost::get(&address) != nullptr); - auto newAddr = boost::get(address); - BOOST_CHECK(pwalletMain->HaveSproutSpendingKey(newAddr)); // Check if too many args BOOST_CHECK_THROW(CallRPC("z_getnewaddress toomanyargs"), runtime_error); diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index b6a6ebc26..eb948f92d 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -1,3 +1,4 @@ +// Copyright (c) 2019-2020 The Hush developers // Copyright (c) 2011-2014 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/src/timedata.cpp b/src/timedata.cpp index 584e0db8c..246159a50 100644 --- a/src/timedata.cpp +++ b/src/timedata.cpp @@ -1,9 +1,11 @@ // Copyright (c) 2014 The Bitcoin Core developers +// Copyright (c) 2019-2020 The Hush developers +// Copyright (c) 2020 The Zcash developers // Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. +// file COPYING or https://www.opensource.org/licenses/mit-license.php /****************************************************************************** - * Copyright © 2014-2019 The SuperNET Developers. * + * Copyright © 2014-2020 The SuperNET Developers. * * * * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * * the top-level directory of this distribution for the individual copyright * @@ -25,114 +27,56 @@ #include "util.h" #include "utilstrencodings.h" -#include - -using namespace std; - -static CCriticalSection cs_nTimeOffset; -static int64_t nTimeOffset = 0; -#define KOMODO_ASSETCHAIN_MAXLEN 65 -extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; +CTimeWarning timeWarning; /** - * "Never go to sea with two chronometers; take one or three." - * Our three time sources are: - * - System clock - * - Median of other nodes clocks - * - The user (asking the user to fix the system clock if the first two disagree) + * Warn if we have seen TIMEDATA_WARNING_SAMPLES peer times, in the version messages of the + * first TIMEDATA_MAX_SAMPLES unique (by IP address) peers that connect, that are more than + * TIMEDATA_WARNING_THRESHOLD seconds but less than TIMEDATA_IGNORE_THRESHOLD seconds away + * from local time. */ -int64_t GetTimeOffset() + +int64_t CTimeWarning::AddTimeData(const CNetAddr& ip, int64_t nTime, int64_t now) { - LOCK(cs_nTimeOffset); + assert(now >= 0 && now <= INT64_MAX - TIMEDATA_IGNORE_THRESHOLD); + + if (nTime <= now - TIMEDATA_IGNORE_THRESHOLD || nTime >= now + TIMEDATA_IGNORE_THRESHOLD) { + return 0; + } + + int64_t nTimeOffset = nTime - now; + + LOCK(cs); + // Ignore duplicate IPs. + if (setKnown.size() == TIMEDATA_MAX_SAMPLES || !setKnown.insert(ip).second) { + return nTimeOffset; + } + + LogPrintf("Added time data, samples %d, offset %+d (%+d minutes)\n", setKnown.size(), nTimeOffset, nTimeOffset/60); + + if (nPeersBehind + nPeersAhead < TIMEDATA_WARNING_SAMPLES) { + if (nTimeOffset < -TIMEDATA_WARNING_THRESHOLD) { + nPeersBehind++; + } else if (nTimeOffset > TIMEDATA_WARNING_THRESHOLD) { + nPeersAhead++; + } + if (nPeersBehind + nPeersAhead == TIMEDATA_WARNING_SAMPLES) { + Warn(nPeersAhead, nPeersBehind); + } + } return nTimeOffset; } -int64_t GetAdjustedTime() +void CTimeWarning::Warn(size_t peersAhead, size_t peersBehind) { - return GetTime() + GetTimeOffset(); -} - -static int64_t abs64(int64_t n) -{ - return (n >= 0 ? n : -n); -} - -#define BITCOIN_TIMEDATA_MAX_SAMPLES 200 - -void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample) -{ - LOCK(cs_nTimeOffset); - // Ignore duplicates - static set setKnown; - if (setKnown.size() == BITCOIN_TIMEDATA_MAX_SAMPLES) - return; - if (!setKnown.insert(ip).second) - return; - - // Add data - static CMedianFilter vTimeOffsets(BITCOIN_TIMEDATA_MAX_SAMPLES, 0); - vTimeOffsets.input(nOffsetSample); - LogPrintf("Added time data, samples %d, offset %+d (%+d minutes)\n", vTimeOffsets.size(), nOffsetSample, nOffsetSample/60); - - // There is a known issue here (see issue #4521): - // - // - The structure vTimeOffsets contains up to 200 elements, after which - // any new element added to it will not increase its size, replacing the - // oldest element. - // - // - The condition to update nTimeOffset includes checking whether the - // number of elements in vTimeOffsets is odd, which will never happen after - // there are 200 elements. - // - // But in this case the 'bug' is protective against some attacks, and may - // actually explain why we've never seen attacks which manipulate the - // clock offset. - // - // So we should hold off on fixing this and clean it up as part of - // a timing cleanup that strengthens it in a number of other ways. - // - if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1) - { - int64_t nMedian = vTimeOffsets.median(); - std::vector vSorted = vTimeOffsets.sorted(); - // Only let other nodes change our time by so much - if (abs64(nMedian) < 30) // thanks to zawy for pointing this out!! zcash issues 4021 //70 * 60) - { - nTimeOffset = nMedian; - } - else - { - nTimeOffset = 0; - - static bool fDone; - if (!fDone) - { - // If nobody has a time different than ours but within 5 minutes of ours, give a warning - bool fMatch = false; - BOOST_FOREACH(int64_t nOffset, vSorted) - if (nOffset != 0 && abs64(nOffset) < 5 * 60) - fMatch = true; - - if (!fMatch) - { - fDone = true; - string strMessage; - if( strncmp(ASSETCHAINS_SYMBOL, "HUSH3",5) == 0 ) { - strMessage = _("Warning: Please check that your computer's date and time are correct! If your clock is wrong Hush will not work properly."); - } else { - strMessage = _("Warning: Please check that your computer's date and time are correct! If your clock is wrong Komodo will not work properly."); - } - strMiscWarning = strMessage; - LogPrintf("*** %s\n", strMessage); - uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_WARNING); - } - } - } - if (fDebug) { - BOOST_FOREACH(int64_t n, vSorted) - LogPrintf("%+d ", n); - LogPrintf("| "); - } - LogPrintf("nTimeOffset = %+d (%+d minutes)\n", nTimeOffset, nTimeOffset/60); + std::string strMessage; + if (peersBehind >= TIMEDATA_WARNING_MAJORITY) { + strMessage = _("Warning: Your computer's date and time may be ahead of the rest of the network! If your clock is wrong Hush will not work properly."); + } else if (peersAhead >= TIMEDATA_WARNING_MAJORITY) { + strMessage = _("Warning: Your computer's date and time may be behind the rest of the network! If your clock is wrong Hush will not work properly."); + } else { + strMessage = _("Warning: Please check that your computer's date and time are correct! If your clock is wrong Hush will not work properly."); } + LogPrintf("*** %s\n", strMessage); + uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_WARNING); } diff --git a/src/timedata.h b/src/timedata.h index 2296baf11..4ced093b6 100644 --- a/src/timedata.h +++ b/src/timedata.h @@ -1,76 +1,39 @@ // Copyright (c) 2014 The Bitcoin Core developers +// Copyright (c) 2019-2020 The Hush developers +// Copyright (c) 2020 The Zcash developers // Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. +// file COPYING or https://www.opensource.org/licenses/mit-license.php #ifndef BITCOIN_TIMEDATA_H #define BITCOIN_TIMEDATA_H -#include -#include +#include #include -#include +#include "netbase.h" +#include "sync.h" -class CNetAddr; - -/** - * Median filter over a stream of values. - * Returns the median of the last N numbers - */ -template -class CMedianFilter +class CTimeWarning { private: - std::vector vValues; - std::vector vSorted; - unsigned int nSize; + CCriticalSection cs; + std::set setKnown; + size_t nPeersAhead; + size_t nPeersBehind; public: - CMedianFilter(unsigned int size, T initial_value) : nSize(size) - { - vValues.reserve(size); - vValues.push_back(initial_value); - vSorted = vValues; - } + static const size_t TIMEDATA_WARNING_SAMPLES = 8; + static const size_t TIMEDATA_WARNING_MAJORITY = 6; + static const size_t TIMEDATA_MAX_SAMPLES = 20; + static const int64_t TIMEDATA_WARNING_THRESHOLD = 10 * 60; + static const int64_t TIMEDATA_IGNORE_THRESHOLD = 10 * 24 * 60 * 60; - void input(T value) - { - if (vValues.size() == nSize) { - vValues.erase(vValues.begin()); - } - vValues.push_back(value); + CTimeWarning() : nPeersBehind(0), nPeersAhead(0) {} + virtual ~CTimeWarning() {} - vSorted.resize(vValues.size()); - std::copy(vValues.begin(), vValues.end(), vSorted.begin()); - std::sort(vSorted.begin(), vSorted.end()); - } - - T median() const - { - int size = vSorted.size(); - assert(size > 0); - if (size & 1) // Odd number of elements - { - return vSorted[size / 2]; - } else // Even number of elements - { - return (vSorted[size / 2 - 1] + vSorted[size / 2]) / 2; - } - } - - int size() const - { - return vValues.size(); - } - - std::vector sorted() const - { - return vSorted; - } + int64_t AddTimeData(const CNetAddr& ip, int64_t nTime, int64_t now); + virtual void Warn(size_t peersAhead, size_t peersBehind); }; -/** Functions to keep track of adjusted P2P time */ -int64_t GetTimeOffset(); -int64_t GetAdjustedTime(); -void AddTimeData(const CNetAddr& ip, int64_t nTime); +extern CTimeWarning timeWarning; #endif // BITCOIN_TIMEDATA_H diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp index 99c76995b..c2eb490da 100644 --- a/src/torcontrol.cpp +++ b/src/torcontrol.cpp @@ -1,5 +1,6 @@ // Copyright (c) 2015-2017 The Bitcoin Core developers // Copyright (c) 2017 The Zcash 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. diff --git a/src/torcontrol.h b/src/torcontrol.h index 72dc82c5b..44611c7b6 100644 --- a/src/torcontrol.h +++ b/src/torcontrol.h @@ -1,4 +1,5 @@ // Copyright (c) 2015 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. diff --git a/src/transaction_builder.cpp b/src/transaction_builder.cpp index 773792ba3..e1879e1d4 100644 --- a/src/transaction_builder.cpp +++ b/src/transaction_builder.cpp @@ -1,7 +1,5 @@ // Copyright (c) 2018 The Zcash developers // Copyright (c) 2019-2020 The Hush developers -// Released under the GPLv3 - // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -14,6 +12,7 @@ #include #include #include +#include "zcash/Note.hpp" SpendDescriptionInfo::SpendDescriptionInfo( libzcash::SaplingExpandedSpendingKey expsk, @@ -142,6 +141,7 @@ boost::optional TransactionBuilder::Build() change -= tOut.nValue; } if (change < 0) { + LogPrintf("%s: negative change!\n", __func__); return boost::none; } @@ -153,6 +153,7 @@ boost::optional TransactionBuilder::Build() // Send change to the specified change address. If no change address // was set, send change to the first Sapling address given as input. if (zChangeAddr) { + LogPrintf("%s: Adding specified Sapling change output: %s\n", __FUNCTION__, zChangeAddr->second.GetHash().ToString().c_str()); AddSaplingOutput(zChangeAddr->first, zChangeAddr->second, change); } else if (tChangeAddr) { // tChangeAddr has already been validated. @@ -162,6 +163,7 @@ boost::optional TransactionBuilder::Build() auto note = spends[0].note; libzcash::SaplingPaymentAddress changeAddr(note.d, note.pk_d); AddSaplingOutput(fvk.ovk, changeAddr, change); + LogPrintf("%s: Adding Sapling change output from first zinput: %s\n", __FUNCTION__, changeAddr.GetHash().ToString().c_str() ); } else { return boost::none; } @@ -180,6 +182,7 @@ boost::optional TransactionBuilder::Build() auto nf = spend.note.nullifier( spend.expsk.full_viewing_key(), spend.witness.position()); if (!(cm && nf)) { + LogPrintf("%s: Invalid commitment or nullifier!\n", __FUNCTION__); librustzcash_sapling_proving_ctx_free(ctx); return boost::none; } @@ -203,6 +206,7 @@ boost::optional TransactionBuilder::Build() sdesc.rk.begin(), sdesc.zkproof.data())) { librustzcash_sapling_proving_ctx_free(ctx); + LogPrintf("%s: Invalid sapling spend proof!\n", __FUNCTION__); return boost::none; } @@ -216,6 +220,7 @@ boost::optional TransactionBuilder::Build() for (auto output : outputs) { auto cm = output.note.cm(); if (!cm) { + LogPrintf("%s: Invalid sapling note commitment!\n", __FUNCTION__); librustzcash_sapling_proving_ctx_free(ctx); return boost::none; } @@ -241,6 +246,7 @@ boost::optional TransactionBuilder::Build() odesc.cv.begin(), odesc.zkproof.begin())) { librustzcash_sapling_proving_ctx_free(ctx); + LogPrintf("%s: Invalid sapling output proof!\n", __FUNCTION__); return boost::none; } @@ -273,6 +279,7 @@ boost::optional TransactionBuilder::Build() dataToBeSigned = SignatureHash(scriptCode, mtx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); } catch (std::logic_error ex) { librustzcash_sapling_proving_ctx_free(ctx); + LogPrintf("%s: SignatureHash exception!\n", __func__); return boost::none; } @@ -291,6 +298,7 @@ boost::optional TransactionBuilder::Build() mtx.bindingSig.data()); librustzcash_sapling_proving_ctx_free(ctx); + LogPrintf("%s: Created spendAuth and binding sigs\n", __func__); // Transparent signatures CTransaction txNewConst(mtx); diff --git a/src/transaction_builder.h b/src/transaction_builder.h index 49c09294d..39225433a 100644 --- a/src/transaction_builder.h +++ b/src/transaction_builder.h @@ -1,4 +1,5 @@ // Copyright (c) 2018 The Zcash 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. diff --git a/src/txdb.cpp b/src/txdb.cpp index b45df4448..78769c07c 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -67,18 +67,6 @@ CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(Get } -bool CCoinsViewDB::GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const { - if (rt == SproutMerkleTree::empty_root()) { - SproutMerkleTree new_tree; - tree = new_tree; - return true; - } - - bool read = db.Read(make_pair(DB_SPROUT_ANCHOR, rt), tree); - - return read; -} - bool CCoinsViewDB::GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const { if (rt == SaplingMerkleTree::empty_root()) { SaplingMerkleTree new_tree; @@ -199,10 +187,10 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, mapCoins.erase(itOld); } - ::BatchWriteAnchors(batch, mapSproutAnchors, DB_SPROUT_ANCHOR); + //::BatchWriteAnchors(batch, mapSproutAnchors, DB_SPROUT_ANCHOR); ::BatchWriteAnchors(batch, mapSaplingAnchors, DB_SAPLING_ANCHOR); - ::BatchWriteNullifiers(batch, mapSproutNullifiers, DB_NULLIFIER); + //::BatchWriteNullifiers(batch, mapSproutNullifiers, DB_NULLIFIER); ::BatchWriteNullifiers(batch, mapSaplingNullifiers, DB_SAPLING_NULLIFIER); if (!hashBlock.IsNull()) @@ -735,6 +723,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts() pindexNew->nPayments = diskindex.nPayments; pindexNew->nShieldedTx = diskindex.nShieldedTx; pindexNew->nShieldedOutputs = diskindex.nShieldedOutputs; + pindexNew->nShieldedSpends = diskindex.nShieldedSpends; pindexNew->nShieldedPayments = diskindex.nShieldedPayments; pindexNew->nShieldingTx = diskindex.nShieldingTx; pindexNew->nShieldingPayments = diskindex.nShieldingPayments; diff --git a/src/txdb.h b/src/txdb.h index e089d0190..81c0bb3ad 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -63,7 +63,7 @@ protected: public: CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false); - bool GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const; + //bool GetSproutAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const; bool GetSaplingAnchorAt(const uint256 &rt, SaplingMerkleTree &tree) const; bool GetNullifier(const uint256 &nf, ShieldedType type) const; bool GetCoins(const uint256 &txid, CCoins &coins) const; diff --git a/src/txmempool.cpp b/src/txmempool.cpp index ed5951e08..2f10856d4 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -513,7 +513,7 @@ void CTxMemPool::removeConflicts(const CTransaction &tx, std::list int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_t nTime,int32_t dispflag); extern char ASSETCHAINS_SYMBOL[]; -void CTxMemPool::removeExpired(unsigned int nBlockHeight) +std::vector CTxMemPool::removeExpired(unsigned int nBlockHeight) { CBlockIndex *tipindex; // Remove expired txs from the mempool @@ -523,16 +523,23 @@ void CTxMemPool::removeExpired(unsigned int nBlockHeight) { const CTransaction& tx = it->GetTx(); tipindex = chainActive.LastTip(); - if (IsExpiredTx(tx, nBlockHeight) || (ASSETCHAINS_SYMBOL[0] == 0 && tipindex != 0 && komodo_validate_interest(tx,tipindex->GetHeight()+1,tipindex->GetMedianTimePast() + 777,0)) < 0) + + bool fInterestNotValidated = ASSETCHAINS_SYMBOL[0] == 0 && tipindex != 0 && komodo_validate_interest(tx,tipindex->GetHeight()+1,tipindex->GetMedianTimePast() + 777,0) < 0; + if (IsExpiredTx(tx, nBlockHeight) || fInterestNotValidated) { + if (fInterestNotValidated && tipindex != 0) + LogPrintf("Removing interest violate txid.%s nHeight.%d nTime.%u vs locktime.%u\n",tx.GetHash().ToString(),tipindex->GetHeight()+1,tipindex->GetMedianTimePast() + 777,tx.nLockTime); transactionsToRemove.push_back(tx); } } + std::vector ids; for (const CTransaction& tx : transactionsToRemove) { list removed; remove(tx, removed, true); + ids.push_back(tx.GetHash()); LogPrint("mempool", "Removing expired txid: %s\n", tx.GetHash().ToString()); } + return ids; } /** @@ -637,8 +644,9 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const i++; } - boost::unordered_map intermediates; + /* + boost::unordered_map intermediates; BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) { BOOST_FOREACH(const uint256 &nf, joinsplit.nullifiers) { assert(!pcoins->GetNullifier(nf, SPROUT)); @@ -659,6 +667,7 @@ void CTxMemPool::check(const CCoinsViewCache *pcoins) const intermediates.insert(std::make_pair(tree.root(), tree)); } + */ for (const SpendDescription &spendDescription : tx.vShieldedSpend) { SaplingMerkleTree tree; @@ -844,7 +853,7 @@ bool CTxMemPool::nullifierExists(const uint256& nullifier, ShieldedType type) co } } -void CTxMemPool::NotifyRecentlyAdded() +std::pair, uint64_t> CTxMemPool::DrainRecentlyAdded() { uint64_t recentlyAddedSequence; std::vector txs; @@ -857,29 +866,13 @@ void CTxMemPool::NotifyRecentlyAdded() mapRecentlyAddedTx.clear(); } - // A race condition can occur here between these SyncWithWallets calls, and - // the ones triggered by block logic (in ConnectTip and DisconnectTip). It - // is harmless because calling SyncWithWallets(_, NULL) does not alter the - // wallet transaction's block information. - for (auto tx : txs) { - try { - SyncWithWallets(tx, NULL); - } catch (const boost::thread_interrupted&) { - fprintf(stderr,"%s: thread interrupted\n", __FUNCTION__); - throw; - } catch (const std::exception& e) { - PrintExceptionContinue(&e, "CTxMemPool::NotifyRecentlyAdded()"); - } catch (...) { - PrintExceptionContinue(NULL, "CTxMemPool::NotifyRecentlyAdded()"); - } - } + return std::make_pair(txs, recentlyAddedSequence); +} - // Update the notified sequence number. We only need this in regtest mode, - // and should not lock on cs after calling SyncWithWallets otherwise. - if (Params().NetworkIDString() == "regtest") { - LOCK(cs); - nNotifiedSequence = recentlyAddedSequence; - } +void CTxMemPool::SetNotifiedSequence(uint64_t recentlyAddedSequence) { + assert(Params().NetworkIDString() == "regtest"); + LOCK(cs); + nNotifiedSequence = recentlyAddedSequence; } bool CTxMemPool::IsFullyNotified() { diff --git a/src/txmempool.h b/src/txmempool.h index fbf7e4784..59eeb0d98 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -218,7 +218,7 @@ public: void removeWithAnchor(const uint256 &invalidRoot, ShieldedType type); void removeForReorg(const CCoinsViewCache *pcoins, unsigned int nMemPoolHeight, int flags); void removeConflicts(const CTransaction &tx, std::list& removed); - void removeExpired(unsigned int nBlockHeight); + std::vector removeExpired(unsigned int nBlockHeight); void removeForBlock(const std::vector& vtx, unsigned int nBlockHeight, std::list& conflicts, bool fCurrentEstimate = true); void removeWithoutBranchId(uint32_t nMemPoolBranchId); @@ -240,7 +240,8 @@ public: bool nullifierExists(const uint256& nullifier, ShieldedType type) const; - void NotifyRecentlyAdded(); + std::pair, uint64_t> DrainRecentlyAdded(); + void SetNotifiedSequence(uint64_t recentlyAddedSequence); bool IsFullyNotified(); unsigned long size() diff --git a/src/ui_interface.h b/src/ui_interface.h index ee0fd9113..59a549a9d 100644 --- a/src/ui_interface.h +++ b/src/ui_interface.h @@ -98,6 +98,9 @@ public: /** New block has been accepted */ boost::signals2::signal NotifyBlockTip; + + /** Transaction expired */ + boost::signals2::signal NotifyTxExpiration; }; extern CClientUIInterface uiInterface; diff --git a/src/util.h b/src/util.h index 2e8232871..d1bbdd26d 100644 --- a/src/util.h +++ b/src/util.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. diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp index d4bba72ee..132ae82ab 100644 --- a/src/utilstrencodings.cpp +++ b/src/utilstrencodings.cpp @@ -20,7 +20,8 @@ static const string CHARS_ALPHA_NUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO static const string SAFE_CHARS[] = { CHARS_ALPHA_NUM + " .,;_/:?@()", // SAFE_CHARS_DEFAULT - CHARS_ALPHA_NUM + " .,;_?@" // SAFE_CHARS_UA_COMMENT + CHARS_ALPHA_NUM + " .,;_?@", // SAFE_CHARS_UA_COMMENT + CHARS_ALPHA_NUM + "!*'();:@&=+$,/?#[]-_.~%" // SAFE_CHARS_URI }; string SanitizeString(const string& str, int rule) diff --git a/src/utilstrencodings.h b/src/utilstrencodings.h index 37a07ea06..2d851093f 100644 --- a/src/utilstrencodings.h +++ b/src/utilstrencodings.h @@ -26,7 +26,8 @@ enum SafeChars { SAFE_CHARS_DEFAULT, //!< The full set of allowed chars - SAFE_CHARS_UA_COMMENT //!< BIP-0014 subset + SAFE_CHARS_UA_COMMENT, //!< BIP-0014 subset + SAFE_CHARS_URI //!< Chars allowed in URIs (RFC 3986) }; std::string SanitizeFilename(const std::string& str); diff --git a/src/utiltest.cpp b/src/utiltest.cpp deleted file mode 100644 index 898f2c4c9..000000000 --- a/src/utiltest.cpp +++ /dev/null @@ -1,153 +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 "utiltest.h" - -#include "consensus/upgrades.h" - -#include - -CWalletTx GetValidReceive(ZCJoinSplit& params, - const libzcash::SproutSpendingKey& sk, CAmount value, - bool randomInputs, - int32_t version /* = 2 */) { - CMutableTransaction mtx; - mtx.nVersion = version; - mtx.vin.resize(2); - if (randomInputs) { - mtx.vin[0].prevout.hash = GetRandHash(); - mtx.vin[1].prevout.hash = GetRandHash(); - } else { - mtx.vin[0].prevout.hash = uint256S("0000000000000000000000000000000000000000000000000000000000000001"); - mtx.vin[1].prevout.hash = uint256S("0000000000000000000000000000000000000000000000000000000000000002"); - } - mtx.vin[0].prevout.n = 0; - mtx.vin[1].prevout.n = 0; - - // Generate an ephemeral keypair. - uint256 joinSplitPubKey; - unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES]; - crypto_sign_keypair(joinSplitPubKey.begin(), joinSplitPrivKey); - mtx.joinSplitPubKey = joinSplitPubKey; - - std::array inputs = { - libzcash::JSInput(), // dummy input - libzcash::JSInput() // dummy input - }; - - std::array outputs = { - libzcash::JSOutput(sk.address(), value), - libzcash::JSOutput(sk.address(), value) - }; - - // Prepare JoinSplits - uint256 rt; - JSDescription jsdesc {false, params, mtx.joinSplitPubKey, rt, - inputs, outputs, 2*value, 0, false}; - mtx.vjoinsplit.push_back(jsdesc); - - if (version >= 4) { - // Shielded Output - OutputDescription od; - mtx.vShieldedOutput.push_back(od); - } - - // Empty output script. - uint32_t consensusBranchId = SPROUT_BRANCH_ID; - CScript scriptCode; - CTransaction signTx(mtx); - uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); - - // Add the signature - assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL, - dataToBeSigned.begin(), 32, - joinSplitPrivKey - ) == 0); - - CTransaction tx {mtx}; - CWalletTx wtx {NULL, tx}; - return wtx; -} - -libzcash::SproutNote GetNote(ZCJoinSplit& params, - const libzcash::SproutSpendingKey& sk, - const CTransaction& tx, size_t js, size_t n) { - ZCNoteDecryption decryptor {sk.receiving_key()}; - auto hSig = tx.vjoinsplit[js].h_sig(params, tx.joinSplitPubKey); - auto note_pt = libzcash::SproutNotePlaintext::decrypt( - decryptor, - tx.vjoinsplit[js].ciphertexts[n], - tx.vjoinsplit[js].ephemeralKey, - hSig, - (unsigned char) n); - return note_pt.note(sk.address()); -} - -CWalletTx GetValidSpend(ZCJoinSplit& params, - const libzcash::SproutSpendingKey& sk, - const libzcash::SproutNote& note, CAmount value) { - CMutableTransaction mtx; - mtx.vout.resize(2); - mtx.vout[0].nValue = value; - mtx.vout[1].nValue = 0; - - // Generate an ephemeral keypair. - uint256 joinSplitPubKey; - unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES]; - crypto_sign_keypair(joinSplitPubKey.begin(), joinSplitPrivKey); - mtx.joinSplitPubKey = joinSplitPubKey; - - // Fake tree for the unused witness - SproutMerkleTree tree; - - libzcash::JSOutput dummyout; - libzcash::JSInput dummyin; - - { - if (note.value() > value) { - libzcash::SproutSpendingKey dummykey = libzcash::SproutSpendingKey::random(); - libzcash::SproutPaymentAddress dummyaddr = dummykey.address(); - dummyout = libzcash::JSOutput(dummyaddr, note.value() - value); - } else if (note.value() < value) { - libzcash::SproutSpendingKey dummykey = libzcash::SproutSpendingKey::random(); - libzcash::SproutPaymentAddress dummyaddr = dummykey.address(); - libzcash::SproutNote dummynote(dummyaddr.a_pk, (value - note.value()), uint256(), uint256()); - tree.append(dummynote.cm()); - dummyin = libzcash::JSInput(tree.witness(), dummynote, dummykey); - } - } - - tree.append(note.cm()); - - std::array inputs = { - libzcash::JSInput(tree.witness(), note, sk), - dummyin - }; - - std::array outputs = { - dummyout, // dummy output - libzcash::JSOutput() // dummy output - }; - - // Prepare JoinSplits - uint256 rt = tree.root(); - JSDescription jsdesc {false, params, mtx.joinSplitPubKey, rt, - inputs, outputs, 0, value, false}; - mtx.vjoinsplit.push_back(jsdesc); - - // Empty output script. - uint32_t consensusBranchId = SPROUT_BRANCH_ID; - CScript scriptCode; - CTransaction signTx(mtx); - uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); - - // Add the signature - assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL, - dataToBeSigned.begin(), 32, - joinSplitPrivKey - ) == 0); - CTransaction tx {mtx}; - CWalletTx wtx {NULL, tx}; - return wtx; -} diff --git a/src/utiltest.h b/src/utiltest.h deleted file mode 100644 index 327dc7be4..000000000 --- a/src/utiltest.h +++ /dev/null @@ -1,19 +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 "wallet/wallet.h" -#include "zcash/JoinSplit.hpp" -#include "zcash/Note.hpp" -#include "zcash/NoteEncryption.hpp" - -CWalletTx GetValidReceive(ZCJoinSplit& params, - const libzcash::SproutSpendingKey& sk, CAmount value, - bool randomInputs, - int32_t version = 2); -libzcash::SproutNote GetNote(ZCJoinSplit& params, - const libzcash::SproutSpendingKey& sk, - const CTransaction& tx, size_t js, size_t n); -CWalletTx GetValidSpend(ZCJoinSplit& params, - const libzcash::SproutSpendingKey& sk, - const libzcash::SproutNote& note, CAmount value); diff --git a/src/validationinterface.cpp b/src/validationinterface.cpp index 6ea07be9e..44b5115d6 100644 --- a/src/validationinterface.cpp +++ b/src/validationinterface.cpp @@ -1,10 +1,22 @@ // 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. +// file COPYING or https://www.opensource.org/licenses/mit-license.php . #include "validationinterface.h" +#include "chainparams.h" +#include "init.h" +#include "main.h" +#include "txmempool.h" +#include "ui_interface.h" + +#include + +#include +#include + static CMainSignals g_signals; CMainSignals& GetMainSignals() @@ -17,28 +29,32 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) { g_signals.SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2)); g_signals.EraseTransaction.connect(boost::bind(&CValidationInterface::EraseFromWallet, pwalletIn, _1)); g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); - g_signals.RescanWallet.connect(boost::bind(&CValidationInterface::RescanWallet, pwalletIn)); - g_signals.ChainTip.connect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, _1, _2, _3, _4, _5)); + g_signals.ChainTip.connect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, _1, _2, _3)); g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1)); g_signals.BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2)); + //g_signals.ScriptForMining.connect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1)); + g_signals.BlockFound.connect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1)); } void UnregisterValidationInterface(CValidationInterface* pwalletIn) { + g_signals.BlockFound.disconnect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1)); + //g_signals.ScriptForMining.disconnect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1)); g_signals.BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2)); g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1)); g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); - g_signals.ChainTip.disconnect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, _1, _2, _3, _4, _5)); + g_signals.ChainTip.disconnect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, _1, _2, _3)); g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); g_signals.EraseTransaction.disconnect(boost::bind(&CValidationInterface::EraseFromWallet, pwalletIn, _1)); g_signals.SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2)); - g_signals.RescanWallet.disconnect(boost::bind(&CValidationInterface::RescanWallet, pwalletIn)); g_signals.UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1)); } void UnregisterAllValidationInterfaces() { + g_signals.BlockFound.disconnect_all_slots(); + //g_signals.ScriptForMining.disconnect_all_slots(); g_signals.BlockChecked.disconnect_all_slots(); g_signals.Broadcast.disconnect_all_slots(); g_signals.Inventory.disconnect_all_slots(); @@ -47,7 +63,6 @@ void UnregisterAllValidationInterfaces() { g_signals.UpdatedTransaction.disconnect_all_slots(); g_signals.EraseTransaction.disconnect_all_slots(); g_signals.SyncTransaction.disconnect_all_slots(); - g_signals.RescanWallet.disconnect_all_slots(); g_signals.UpdatedBlockTip.disconnect_all_slots(); } @@ -55,10 +70,181 @@ void SyncWithWallets(const CTransaction &tx, const CBlock *pblock) { g_signals.SyncTransaction(tx, pblock); } -void EraseFromWallets(const uint256 &hash) { - g_signals.EraseTransaction(hash); -} +struct CachedBlockData { + CBlockIndex *pindex; + std::pair oldTrees; + std::list txConflicted; -void RescanWallets() { - g_signals.RescanWallet(); -} \ No newline at end of file + CachedBlockData( + CBlockIndex *pindex, + std::pair oldTrees, + std::list txConflicted): + pindex(pindex), oldTrees(oldTrees), txConflicted(txConflicted) {} +}; + +void ThreadNotifyWallets(CBlockIndex *pindexLastTip) +{ + // If pindexLastTip == nullptr, the wallet is at genesis. + // However, the genesis block is not loaded synchronously. + // We need to wait for ThreadImport to finish. + while (pindexLastTip == nullptr) { + { + LOCK(cs_main); + pindexLastTip = chainActive.Genesis(); + } + MilliSleep(50); + } + + while (true) { + // Run the notifier on an integer second in the steady clock. + auto now = std::chrono::steady_clock::now().time_since_epoch(); + auto nextFire = std::chrono::duration_cast( + now + std::chrono::seconds(1)); + std::this_thread::sleep_until( + std::chrono::time_point(nextFire)); + + boost::this_thread::interruption_point(); + + auto chainParams = Params(); + + // + // Collect all the state we require + // + + // The common ancestor between the last chain tip we notified and the + // current chain tip. + const CBlockIndex *pindexFork; + // The stack of blocks we will notify as having been connected. + // Pushed in reverse, popped in order. + std::vector blockStack; + // Transactions that have been recently conflicted out of the mempool. + std::pair>, uint64_t> recentlyConflicted; + // Transactions that have been recently added to the mempool. + std::pair, uint64_t> recentlyAdded; + + { + LOCK(cs_main); + + // Figure out the path from the last block we notified to the + // current chain tip. + CBlockIndex *pindex = chainActive.Tip(); + pindexFork = chainActive.FindFork(pindexLastTip); + + // Fetch recently-conflicted transactions. These will include any + // block that has been connected since the last cycle, but we only + // notify for the conflicts created by the current active chain. + recentlyConflicted = DrainRecentlyConflicted(); + + // Iterate backwards over the connected blocks we need to notify. + while (pindex && pindex != pindexFork) { + // Get the Sprout commitment tree as of the start of this block. + SproutMerkleTree oldSproutTree; + //TODO: how important is oldSproutTree ? + //assert(pcoinsTip->GetSproutAnchorAt(pindex->hashSproutAnchor, oldSproutTree)); + + // Get the Sapling commitment tree as of the start of this block. + // We can get this from the `hashFinalSaplingRoot` of the last block + // However, this is only reliable if the last block was on or after + // the Sapling activation height. Otherwise, the last anchor was the + // empty root. + SaplingMerkleTree oldSaplingTree; + if (NetworkUpgradeActive(pindex->pprev->GetHeight(),Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) { + assert(pcoinsTip->GetSaplingAnchorAt(pindex->pprev->hashFinalSaplingRoot, oldSaplingTree)); + } else { + assert(pcoinsTip->GetSaplingAnchorAt(SaplingMerkleTree::empty_root(), oldSaplingTree)); + } + + blockStack.emplace_back( + pindex, + std::make_pair(oldSproutTree, oldSaplingTree), + recentlyConflicted.first.at(pindex)); + + pindex = pindex->pprev; + } + + recentlyAdded = mempool.DrainRecentlyAdded(); + } + + // + // Execute wallet logic based on the collected state. We MUST NOT take + // the cs_main or mempool.cs locks again until after the next sleep; + // doing so introduces a locking side-channel between this code and the + // network message processing thread. + // + + // Notify block disconnects + while (pindexLastTip && pindexLastTip != pindexFork) { + // Read block from disk. + CBlock block; + if (!ReadBlockFromDisk(block, pindexLastTip,1)) { + LogPrintf("*** %s\n", "Failed to read block while notifying wallets of block disconnects"); + uiInterface.ThreadSafeMessageBox( + _("Error: A fatal internal error occurred, see debug.log for details"), + "", CClientUIInterface::MSG_ERROR); + StartShutdown(); + } + + // Let wallets know transactions went from 1-confirmed to + // 0-confirmed or conflicted: + for (const CTransaction &tx : block.vtx) { + SyncWithWallets(tx, NULL); + } + // Update cached incremental witnesses + GetMainSignals().ChainTip(pindexLastTip, &block, boost::none); + + // On to the next block! + pindexLastTip = pindexLastTip->pprev; + } + + // Notify block connections + while (!blockStack.empty()) { + auto blockData = blockStack.back(); + blockStack.pop_back(); + + // Read block from disk. + CBlock block; + if (!ReadBlockFromDisk(block, blockData.pindex, 1)) { + LogPrintf("*** %s\n", "Failed to read block while notifying wallets of block connects"); + uiInterface.ThreadSafeMessageBox( + _("Error: A fatal internal error occurred, see debug.log for details"), + "", CClientUIInterface::MSG_ERROR); + StartShutdown(); + } + + // Tell wallet about transactions that went from mempool + // to conflicted: + for (const CTransaction &tx : blockData.txConflicted) { + SyncWithWallets(tx, NULL); + } + // ... and about transactions that got confirmed: + for (const CTransaction &tx : block.vtx) { + SyncWithWallets(tx, &block); + } + // Update cached incremental witnesses + GetMainSignals().ChainTip(blockData.pindex, &block, blockData.oldTrees); + + // This block is done! + pindexLastTip = blockData.pindex; + } + + // Notify transactions in the mempool + for (auto tx : recentlyAdded.first) { + try { + SyncWithWallets(tx, NULL); + } catch (const boost::thread_interrupted&) { + throw; + } catch (const std::exception& e) { + PrintExceptionContinue(&e, "ThreadNotifyWallets()"); + } catch (...) { + PrintExceptionContinue(NULL, "ThreadNotifyWallets()"); + } + } + + // Update the notified sequence numbers. We only need this in regtest mode, + // and should not lock on cs or cs_main here otherwise. + if (chainParams.NetworkIDString() == "regtest") { + SetChainNotifiedSequence(recentlyConflicted.second); + mempool.SetNotifiedSequence(recentlyAdded.second); + } + } +} diff --git a/src/validationinterface.h b/src/validationinterface.h index 30b9cf0a7..bc5477c99 100644 --- a/src/validationinterface.h +++ b/src/validationinterface.h @@ -26,8 +26,6 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn); void UnregisterValidationInterface(CValidationInterface* pwalletIn); /** Unregister all wallets from core */ void UnregisterAllValidationInterfaces(); -/** Push an updated transaction to all registered wallets */ -void SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL); /** Erase a transaction from all registered wallets */ void EraseFromWallets(const uint256 &hash); /** Rescan all registered wallets */ @@ -39,12 +37,13 @@ protected: virtual void SyncTransaction(const CTransaction &tx, const CBlock *pblock) {} virtual void EraseFromWallet(const uint256 &hash) {} virtual void RescanWallet() {} - virtual void ChainTip(const CBlockIndex *pindex, const CBlock *pblock, SproutMerkleTree sproutTree, SaplingMerkleTree saplingTree, bool added) {} + virtual void ChainTip(const CBlockIndex *pindex, const CBlock *pblock, boost::optional> added) {} virtual void SetBestChain(const CBlockLocator &locator) {} virtual void UpdatedTransaction(const uint256 &hash) {} virtual void Inventory(const uint256 &hash) {} virtual void ResendWalletTransactions(int64_t nBestBlockTime) {} virtual void BlockChecked(const CBlock&, const CValidationState&) {} + virtual void ResetRequestCount(const uint256 &hash) {}; friend void ::RegisterValidationInterface(CValidationInterface*); friend void ::UnregisterValidationInterface(CValidationInterface*); friend void ::UnregisterAllValidationInterfaces(); @@ -62,7 +61,7 @@ struct CMainSignals { /** Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). */ boost::signals2::signal UpdatedTransaction; /** Notifies listeners of a change to the tip of the active block chain. */ - boost::signals2::signal ChainTip; + boost::signals2::signal>)> ChainTip; /** Notifies listeners of a new active block chain. */ boost::signals2::signal SetBestChain; /** Notifies listeners about an inventory item being seen on the network. */ @@ -71,8 +70,14 @@ struct CMainSignals { boost::signals2::signal Broadcast; /** Notifies listeners of a block validation result */ boost::signals2::signal BlockChecked; + // boost::signals2::signal&)> ScriptForMining; + /** Notifies listeners that a block has been successfully mined */ + boost::signals2::signal BlockFound; + }; CMainSignals& GetMainSignals(); +void ThreadNotifyWallets(CBlockIndex *pindexLastTip); + #endif // BITCOIN_VALIDATIONINTERFACE_H diff --git a/src/wallet/asyncrpcoperation_mergetoaddress.cpp b/src/wallet/asyncrpcoperation_mergetoaddress.cpp index afac9c6eb..79eaee5a9 100644 --- a/src/wallet/asyncrpcoperation_mergetoaddress.cpp +++ b/src/wallet/asyncrpcoperation_mergetoaddress.cpp @@ -1,6 +1,7 @@ // Copyright (c) 2017 The Zcash 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. +// file COPYING or https://www.opensource.org/licenses/mit-license.php . /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * @@ -45,7 +46,6 @@ #include #include -#include "paymentdisclosuredb.h" int32_t komodo_blockheight(uint256 hash); using namespace libzcash; @@ -74,19 +74,17 @@ AsyncRPCOperation_mergetoaddress::AsyncRPCOperation_mergetoaddress( boost::optional builder, CMutableTransaction contextualTx, std::vector utxoInputs, - std::vector sproutNoteInputs, std::vector saplingNoteInputs, MergeToAddressRecipient recipient, CAmount fee, UniValue contextInfo) : -tx_(contextualTx), utxoInputs_(utxoInputs), sproutNoteInputs_(sproutNoteInputs), -saplingNoteInputs_(saplingNoteInputs), recipient_(recipient), fee_(fee), contextinfo_(contextInfo) +tx_(contextualTx), utxoInputs_(utxoInputs), saplingNoteInputs_(saplingNoteInputs), recipient_(recipient), fee_(fee), contextinfo_(contextInfo) { if (fee < 0 || fee > MAX_MONEY) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Fee is out of range"); } - if (utxoInputs.empty() && sproutNoteInputs.empty() && saplingNoteInputs.empty()) { + if (utxoInputs.empty() && saplingNoteInputs.empty()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "No inputs"); } @@ -94,14 +92,6 @@ saplingNoteInputs_(saplingNoteInputs), recipient_(recipient), fee_(fee), context throw JSONRPCError(RPC_INVALID_PARAMETER, "Recipient parameter missing"); } - if (sproutNoteInputs.size() > 0 && saplingNoteInputs.size() > 0) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot send from both Sprout and Sapling addresses using z_mergetoaddress"); - } - - if (sproutNoteInputs.size() > 0 && builder) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Sprout notes are not supported by the TransactionBuilder"); - } - isUsingBuilder_ = false; if (builder) { isUsingBuilder_ = true; @@ -132,9 +122,6 @@ saplingNoteInputs_(saplingNoteInputs), recipient_(recipient), fee_(fee), context // Lock UTXOs lock_utxos(); lock_notes(); - - // Enable payment disclosure if requested - paymentDisclosureMode = fExperimentalMode && GetBoolArg("-paymentdisclosure", true); } AsyncRPCOperation_mergetoaddress::~AsyncRPCOperation_mergetoaddress() @@ -209,31 +196,16 @@ void AsyncRPCOperation_mergetoaddress::main() unlock_utxos(); // clean up unlock_notes(); // clean up - - // !!! Payment disclosure START - if (success && paymentDisclosureMode && paymentDisclosureData_.size() > 0) { - uint256 txidhash = tx_.GetHash(); - std::shared_ptr db = PaymentDisclosureDB::sharedInstance(); - for (PaymentDisclosureKeyInfo p : paymentDisclosureData_) { - p.first.hash = txidhash; - if (!db->Put(p.first, p.second)) { - LogPrint("paymentdisclosure", "%s: Payment Disclosure: Error writing entry to database for key %s\n", getId(), p.first.ToString()); - } else { - LogPrint("paymentdisclosure", "%s: Payment Disclosure: Successfully added entry to database for key %s\n", getId(), p.first.ToString()); - } - } - } - // !!! Payment disclosure END } // Notes: -// 1. #1359 Currently there is no limit set on the number of joinsplits, so size of tx could be invalid. +// 1. #1359 Currently there is no limit set on the number of inputs+outputs, so size of tx could be invalid. // 2. #1277 Spendable notes are not locked, so an operation running in parallel could also try to use them. bool AsyncRPCOperation_mergetoaddress::main_impl() { assert(isToTaddr_ != isToZaddr_); - bool isPureTaddrOnlyTx = (sproutNoteInputs_.empty() && saplingNoteInputs_.empty() && isToTaddr_); + bool isPureTaddrOnlyTx = (saplingNoteInputs_.empty() && isToTaddr_); CAmount minersFee = fee_; size_t numInputs = utxoInputs_.size(); @@ -258,9 +230,6 @@ bool AsyncRPCOperation_mergetoaddress::main_impl() } CAmount z_inputs_total = 0; - for (const MergeToAddressInputSproutNote& t : sproutNoteInputs_) { - z_inputs_total += std::get<2>(t); - } for (const MergeToAddressInputSaplingNote& t : saplingNoteInputs_) { z_inputs_total += std::get<2>(t); @@ -311,7 +280,7 @@ bool AsyncRPCOperation_mergetoaddress::main_impl() /** * SCENARIO #0 * - * Sprout not involved, so we just use the TransactionBuilder and we're done. + * Only sapling involved, so we just use the TransactionBuilder and we're done. * * This is based on code from AsyncRPCOperation_sendmany::main_impl() and should be refactored. */ @@ -428,7 +397,6 @@ bool AsyncRPCOperation_mergetoaddress::main_impl() * END SCENARIO #0 */ - /** * SCENARIO #1 * @@ -446,337 +414,7 @@ bool AsyncRPCOperation_mergetoaddress::main_impl() * END SCENARIO #1 */ - - // Prepare raw transaction to handle JoinSplits - CMutableTransaction mtx(tx_); - crypto_sign_keypair(joinSplitPubKey_.begin(), joinSplitPrivKey_); - mtx.joinSplitPubKey = joinSplitPubKey_; - tx_ = CTransaction(mtx); - std::string hexMemo = std::get<1>(recipient_); - - - /** - * SCENARIO #2 - * - * taddrs -> zaddr - * - * We only need a single JoinSplit. - */ - if (sproutNoteInputs_.empty() && isToZaddr_) { - // Create JoinSplit to target z-addr. - MergeToAddressJSInfo info; - info.vpub_old = sendAmount; - info.vpub_new = 0; - - JSOutput jso = JSOutput(boost::get(toPaymentAddress_), sendAmount); - if (hexMemo.size() > 0) { - jso.memo = get_memo_from_hex_string(hexMemo); - } - info.vjsout.push_back(jso); - - UniValue obj(UniValue::VOBJ); - obj = perform_joinsplit(info); - sign_send_raw_transaction(obj); - return true; - } - /** - * END SCENARIO #2 - */ - - - // Copy zinputs to more flexible containers - std::deque zInputsDeque; - for (const auto& o : sproutNoteInputs_) { - zInputsDeque.push_back(o); - } - - // When spending notes, take a snapshot of note witnesses and anchors as the treestate will - // change upon arrival of new blocks which contain joinsplit transactions. This is likely - // to happen as creating a chained joinsplit transaction can take longer than the block interval. - { - LOCK2(cs_main, pwalletMain->cs_wallet); - for (auto t : sproutNoteInputs_) { - JSOutPoint jso = std::get<0>(t); - std::vector vOutPoints = {jso}; - uint256 inputAnchor; - std::vector> vInputWitnesses; - pwalletMain->GetSproutNoteWitnesses(vOutPoints, vInputWitnesses, inputAnchor); - jsopWitnessAnchorMap[jso.ToString()] = MergeToAddressWitnessAnchorData{vInputWitnesses[0], inputAnchor}; - } - } - - /** - * SCENARIO #3 - * - * zaddrs -> zaddr - * taddrs -> - * - * zaddrs -> - * taddrs -> taddr - * - * Send to zaddr by chaining JoinSplits together and immediately consuming any change - * Send to taddr by creating dummy z outputs and accumulating value in a change note - * which is used to set vpub_new in the last chained joinsplit. - */ - UniValue obj(UniValue::VOBJ); - CAmount jsChange = 0; // this is updated after each joinsplit - int changeOutputIndex = -1; // this is updated after each joinsplit if jsChange > 0 - bool vpubOldProcessed = false; // updated when vpub_old for taddr inputs is set in first joinsplit - bool vpubNewProcessed = false; // updated when vpub_new for miner fee and taddr outputs is set in last joinsplit - - // At this point, we are guaranteed to have at least one input note. - // Use address of first input note as the temporary change address. - SproutSpendingKey changeKey = std::get<3>(zInputsDeque.front()); - SproutPaymentAddress changeAddress = changeKey.address(); - - CAmount vpubOldTarget = 0; - CAmount vpubNewTarget = 0; - if (isToTaddr_) { - vpubNewTarget = z_inputs_total; - } else { - if (utxoInputs_.empty()) { - vpubNewTarget = minersFee; - } else { - vpubOldTarget = t_inputs_total - minersFee; - } - } - - // Keep track of treestate within this transaction - boost::unordered_map intermediates; - std::vector previousCommitments; - - while (!vpubNewProcessed) { - MergeToAddressJSInfo info; - info.vpub_old = 0; - info.vpub_new = 0; - - // Set vpub_old in the first joinsplit - if (!vpubOldProcessed) { - if (t_inputs_total < vpubOldTarget) { - throw JSONRPCError(RPC_WALLET_ERROR, - strprintf("Insufficient transparent funds for vpub_old %s (miners fee %s, taddr inputs %s)", - FormatMoney(vpubOldTarget), FormatMoney(minersFee), FormatMoney(t_inputs_total))); - } - info.vpub_old += vpubOldTarget; // funds flowing from public pool - vpubOldProcessed = true; - } - - CAmount jsInputValue = 0; - uint256 jsAnchor; - std::vector> witnesses; - - JSDescription prevJoinSplit; - - // Keep track of previous JoinSplit and its commitments - if (tx_.vjoinsplit.size() > 0) { - prevJoinSplit = tx_.vjoinsplit.back(); - } - - // If there is no change, the chain has terminated so we can reset the tracked treestate. - if (jsChange == 0 && tx_.vjoinsplit.size() > 0) { - intermediates.clear(); - previousCommitments.clear(); - } - - // - // Consume change as the first input of the JoinSplit. - // - if (jsChange > 0) { - LOCK2(cs_main, pwalletMain->cs_wallet); - - // Update tree state with previous joinsplit - SproutMerkleTree tree; - auto it = intermediates.find(prevJoinSplit.anchor); - if (it != intermediates.end()) { - tree = it->second; - } else if (!pcoinsTip->GetSproutAnchorAt(prevJoinSplit.anchor, tree)) { - throw JSONRPCError(RPC_WALLET_ERROR, "Could not find previous JoinSplit anchor"); - } - - assert(changeOutputIndex != -1); - boost::optional changeWitness; - int n = 0; - for (const uint256& commitment : prevJoinSplit.commitments) { - tree.append(commitment); - previousCommitments.push_back(commitment); - if (!changeWitness && changeOutputIndex == n++) { - changeWitness = tree.witness(); - } else if (changeWitness) { - changeWitness.get().append(commitment); - } - } - if (changeWitness) { - witnesses.push_back(changeWitness); - } - jsAnchor = tree.root(); - intermediates.insert(std::make_pair(tree.root(), tree)); // chained js are interstitial (found in between block boundaries) - - // Decrypt the change note's ciphertext to retrieve some data we need - ZCNoteDecryption decryptor(changeKey.receiving_key()); - auto hSig = prevJoinSplit.h_sig(*pzcashParams, tx_.joinSplitPubKey); - try { - SproutNotePlaintext plaintext = SproutNotePlaintext::decrypt( - decryptor, - prevJoinSplit.ciphertexts[changeOutputIndex], - prevJoinSplit.ephemeralKey, - hSig, - (unsigned char)changeOutputIndex); - - SproutNote note = plaintext.note(changeAddress); - info.notes.push_back(note); - info.zkeys.push_back(changeKey); - - jsInputValue += plaintext.value(); - - LogPrint("zrpcunsafe", "%s: spending change (amount=%s)\n", - getId(), - FormatMoney(plaintext.value())); - - } catch (const std::exception& e) { - throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Error decrypting output note of previous JoinSplit: %s", e.what())); - } - } - - - // - // Consume spendable non-change notes - // - std::vector vInputNotes; - std::vector vInputZKeys; - std::vector vOutPoints; - std::vector> vInputWitnesses; - uint256 inputAnchor; - int numInputsNeeded = (jsChange > 0) ? 1 : 0; - while (numInputsNeeded++ < ZC_NUM_JS_INPUTS && zInputsDeque.size() > 0) { - MergeToAddressInputSproutNote t = zInputsDeque.front(); - JSOutPoint jso = std::get<0>(t); - SproutNote note = std::get<1>(t); - CAmount noteFunds = std::get<2>(t); - SproutSpendingKey zkey = std::get<3>(t); - zInputsDeque.pop_front(); - - MergeToAddressWitnessAnchorData wad = jsopWitnessAnchorMap[jso.ToString()]; - vInputWitnesses.push_back(wad.witness); - if (inputAnchor.IsNull()) { - inputAnchor = wad.anchor; - } else if (inputAnchor != wad.anchor) { - throw JSONRPCError(RPC_WALLET_ERROR, "Selected input notes do not share the same anchor"); - } - - vOutPoints.push_back(jso); - vInputNotes.push_back(note); - vInputZKeys.push_back(zkey); - - jsInputValue += noteFunds; - - int wtxHeight = -1; - int wtxDepth = -1; - { - LOCK2(cs_main, pwalletMain->cs_wallet); - const CWalletTx& wtx = pwalletMain->mapWallet[jso.hash]; - // Zero confirmation notes belong to transactions which have not yet been mined - if (mapBlockIndex.find(wtx.hashBlock) == mapBlockIndex.end()) { - throw JSONRPCError(RPC_WALLET_ERROR, strprintf("mapBlockIndex does not contain block hash %s", wtx.hashBlock.ToString())); - } - wtxHeight = komodo_blockheight(wtx.hashBlock); - wtxDepth = wtx.GetDepthInMainChain(); - } - LogPrint("zrpcunsafe", "%s: spending note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s, height=%d, confirmations=%d)\n", - getId(), - jso.hash.ToString().substr(0, 10), - jso.js, - int(jso.n), // uint8_t - FormatMoney(noteFunds), - wtxHeight, - wtxDepth); - } - - // Add history of previous commitments to witness - if (vInputNotes.size() > 0) { - if (vInputWitnesses.size() == 0) { - throw JSONRPCError(RPC_WALLET_ERROR, "Could not find witness for note commitment"); - } - - for (auto& optionalWitness : vInputWitnesses) { - if (!optionalWitness) { - throw JSONRPCError(RPC_WALLET_ERROR, "Witness for note commitment is null"); - } - SproutWitness w = *optionalWitness; // could use .get(); - if (jsChange > 0) { - for (const uint256& commitment : previousCommitments) { - w.append(commitment); - } - if (jsAnchor != w.root()) { - throw JSONRPCError(RPC_WALLET_ERROR, "Witness for spendable note does not have same anchor as change input"); - } - } - witnesses.push_back(w); - } - - // The jsAnchor is null if this JoinSplit is at the start of a new chain - if (jsAnchor.IsNull()) { - jsAnchor = inputAnchor; - } - - // Add spendable notes as inputs - std::copy(vInputNotes.begin(), vInputNotes.end(), std::back_inserter(info.notes)); - std::copy(vInputZKeys.begin(), vInputZKeys.end(), std::back_inserter(info.zkeys)); - } - - // Accumulate change - jsChange = jsInputValue + info.vpub_old; - - // Set vpub_new in the last joinsplit (when there are no more notes to spend) - if (zInputsDeque.empty()) { - assert(!vpubNewProcessed); - if (jsInputValue < vpubNewTarget) { - throw JSONRPCError(RPC_WALLET_ERROR, - strprintf("Insufficient funds for vpub_new %s (miners fee %s, taddr inputs %s)", - FormatMoney(vpubNewTarget), FormatMoney(minersFee), FormatMoney(t_inputs_total))); - } - info.vpub_new += vpubNewTarget; // funds flowing back to public pool - vpubNewProcessed = true; - jsChange -= vpubNewTarget; - // If we are merging to a t-addr, there should be no change - if (isToTaddr_) assert(jsChange == 0); - } - - // create dummy output - info.vjsout.push_back(JSOutput()); // dummy output while we accumulate funds into a change note for vpub_new - - // create output for any change - if (jsChange > 0) { - std::string outputType = "change"; - auto jso = JSOutput(changeAddress, jsChange); - // If this is the final output, set the target and memo - if (isToZaddr_ && vpubNewProcessed) { - outputType = "target"; - jso.addr = boost::get(toPaymentAddress_); - if (!hexMemo.empty()) { - jso.memo = get_memo_from_hex_string(hexMemo); - } - } - info.vjsout.push_back(jso); - - LogPrint("zrpcunsafe", "%s: generating note for %s (amount=%s)\n", - getId(), - outputType, - FormatMoney(jsChange)); - } - - obj = perform_joinsplit(info, witnesses, jsAnchor); - - if (jsChange > 0) { - changeOutputIndex = mta_find_output(obj, 1); - } - } - - // Sanity check in case changes to code block above exits loop by invoking 'break' - assert(zInputsDeque.size() == 0); - assert(vpubNewProcessed); - - sign_send_raw_transaction(obj); - return true; + return false; } @@ -848,191 +486,6 @@ void AsyncRPCOperation_mergetoaddress::sign_send_raw_transaction(UniValue obj) tx_ = tx; } - -UniValue AsyncRPCOperation_mergetoaddress::perform_joinsplit(MergeToAddressJSInfo& info) -{ - std::vector> witnesses; - uint256 anchor; - { - LOCK(cs_main); - anchor = pcoinsTip->GetBestAnchor(SPROUT); // As there are no inputs, ask the wallet for the best anchor - } - return perform_joinsplit(info, witnesses, anchor); -} - - -UniValue AsyncRPCOperation_mergetoaddress::perform_joinsplit(MergeToAddressJSInfo& info, std::vector& outPoints) -{ - std::vector> witnesses; - uint256 anchor; - { - LOCK(cs_main); - pwalletMain->GetSproutNoteWitnesses(outPoints, witnesses, anchor); - } - return perform_joinsplit(info, witnesses, anchor); -} - -UniValue AsyncRPCOperation_mergetoaddress::perform_joinsplit( - MergeToAddressJSInfo& info, - std::vector> witnesses, - uint256 anchor) -{ - if (anchor.IsNull()) { - throw std::runtime_error("anchor is null"); - } - - if (witnesses.size() != info.notes.size()) { - throw runtime_error("number of notes and witnesses do not match"); - } - - if (info.notes.size() != info.zkeys.size()) { - throw runtime_error("number of notes and spending keys do not match"); - } - - for (size_t i = 0; i < witnesses.size(); i++) { - if (!witnesses[i]) { - throw runtime_error("joinsplit input could not be found in tree"); - } - info.vjsin.push_back(JSInput(*witnesses[i], info.notes[i], info.zkeys[i])); - } - - // Make sure there are two inputs and two outputs - while (info.vjsin.size() < ZC_NUM_JS_INPUTS) { - info.vjsin.push_back(JSInput()); - } - - while (info.vjsout.size() < ZC_NUM_JS_OUTPUTS) { - info.vjsout.push_back(JSOutput()); - } - - if (info.vjsout.size() != ZC_NUM_JS_INPUTS || info.vjsin.size() != ZC_NUM_JS_OUTPUTS) { - throw runtime_error("unsupported joinsplit input/output counts"); - } - - CMutableTransaction mtx(tx_); - - LogPrint("zrpcunsafe", "%s: creating joinsplit at index %d (vpub_old=%s, vpub_new=%s, in[0]=%s, in[1]=%s, out[0]=%s, out[1]=%s)\n", - getId(), - tx_.vjoinsplit.size(), - FormatMoney(info.vpub_old), FormatMoney(info.vpub_new), - FormatMoney(info.vjsin[0].note.value()), FormatMoney(info.vjsin[1].note.value()), - FormatMoney(info.vjsout[0].value), FormatMoney(info.vjsout[1].value)); - - // Generate the proof, this can take over a minute. - std::array inputs{info.vjsin[0], info.vjsin[1]}; - std::array outputs{info.vjsout[0], info.vjsout[1]}; - std::array inputMap; - std::array outputMap; - - uint256 esk; // payment disclosure - secret - - JSDescription jsdesc = JSDescription::Randomized( - mtx.fOverwintered && (mtx.nVersion >= SAPLING_TX_VERSION), - *pzcashParams, - joinSplitPubKey_, - anchor, - inputs, - outputs, - inputMap, - outputMap, - info.vpub_old, - info.vpub_new, - !this->testmode, - &esk); // parameter expects pointer to esk, so pass in address - { - auto verifier = libzcash::ProofVerifier::Strict(); - if (!(jsdesc.Verify(*pzcashParams, verifier, joinSplitPubKey_))) { - throw std::runtime_error("error verifying joinsplit"); - } - } - - mtx.vjoinsplit.push_back(jsdesc); - - // Empty output script. - CScript scriptCode; - CTransaction signTx(mtx); - uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId_); - - // Add the signature - if (!(crypto_sign_detached(&mtx.joinSplitSig[0], NULL, - dataToBeSigned.begin(), 32, - joinSplitPrivKey_) == 0)) { - throw std::runtime_error("crypto_sign_detached failed"); - } - - // Sanity check - if (!(crypto_sign_verify_detached(&mtx.joinSplitSig[0], - dataToBeSigned.begin(), 32, - mtx.joinSplitPubKey.begin()) == 0)) { - throw std::runtime_error("crypto_sign_verify_detached failed"); - } - - CTransaction rawTx(mtx); - tx_ = rawTx; - - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << rawTx; - - std::string encryptedNote1; - std::string encryptedNote2; - { - CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION); - ss2 << ((unsigned char)0x00); - ss2 << jsdesc.ephemeralKey; - ss2 << jsdesc.ciphertexts[0]; - ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey_); - - encryptedNote1 = HexStr(ss2.begin(), ss2.end()); - } - { - CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION); - ss2 << ((unsigned char)0x01); - ss2 << jsdesc.ephemeralKey; - ss2 << jsdesc.ciphertexts[1]; - ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey_); - - encryptedNote2 = HexStr(ss2.begin(), ss2.end()); - } - - UniValue arrInputMap(UniValue::VARR); - UniValue arrOutputMap(UniValue::VARR); - for (size_t i = 0; i < ZC_NUM_JS_INPUTS; i++) { - arrInputMap.push_back(static_cast(inputMap[i])); - } - for (size_t i = 0; i < ZC_NUM_JS_OUTPUTS; i++) { - arrOutputMap.push_back(static_cast(outputMap[i])); - } - - - // !!! Payment disclosure START - unsigned char buffer[32] = {0}; - memcpy(&buffer[0], &joinSplitPrivKey_[0], 32); // private key in first half of 64 byte buffer - std::vector vch(&buffer[0], &buffer[0] + 32); - uint256 joinSplitPrivKey = uint256(vch); - size_t js_index = tx_.vjoinsplit.size() - 1; - uint256 placeholder; - for (int i = 0; i < ZC_NUM_JS_OUTPUTS; i++) { - uint8_t mapped_index = outputMap[i]; - // placeholder for txid will be filled in later when tx has been finalized and signed. - PaymentDisclosureKey pdKey = {placeholder, js_index, mapped_index}; - JSOutput output = outputs[mapped_index]; - libzcash::SproutPaymentAddress zaddr = output.addr; // randomized output - PaymentDisclosureInfo pdInfo = {PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL, esk, joinSplitPrivKey, zaddr}; - paymentDisclosureData_.push_back(PaymentDisclosureKeyInfo(pdKey, pdInfo)); - - LogPrint("paymentdisclosure", "%s: Payment Disclosure: js=%d, n=%d, zaddr=%s\n", getId(), js_index, int(mapped_index), EncodePaymentAddress(zaddr)); - } - // !!! Payment disclosure END - - UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("encryptednote1", encryptedNote1)); - obj.push_back(Pair("encryptednote2", encryptedNote2)); - obj.push_back(Pair("rawtxn", HexStr(ss.begin(), ss.end()))); - obj.push_back(Pair("inputmap", arrInputMap)); - obj.push_back(Pair("outputmap", arrOutputMap)); - return obj; -} - std::array AsyncRPCOperation_mergetoaddress::get_memo_from_hex_string(std::string s) { std::array memo = {{0x00}}; @@ -1099,9 +552,6 @@ void AsyncRPCOperation_mergetoaddress::unlock_utxos() { */ void AsyncRPCOperation_mergetoaddress::lock_notes() { LOCK2(cs_main, pwalletMain->cs_wallet); - for (auto note : sproutNoteInputs_) { - pwalletMain->LockNote(std::get<0>(note)); - } for (auto note : saplingNoteInputs_) { pwalletMain->LockNote(std::get<0>(note)); } @@ -1112,9 +562,6 @@ void AsyncRPCOperation_mergetoaddress::lock_notes() { */ void AsyncRPCOperation_mergetoaddress::unlock_notes() { LOCK2(cs_main, pwalletMain->cs_wallet); - for (auto note : sproutNoteInputs_) { - pwalletMain->UnlockNote(std::get<0>(note)); - } for (auto note : saplingNoteInputs_) { pwalletMain->UnlockNote(std::get<0>(note)); } diff --git a/src/wallet/asyncrpcoperation_mergetoaddress.h b/src/wallet/asyncrpcoperation_mergetoaddress.h index be49baff0..69150161e 100644 --- a/src/wallet/asyncrpcoperation_mergetoaddress.h +++ b/src/wallet/asyncrpcoperation_mergetoaddress.h @@ -1,4 +1,6 @@ // Copyright (c) 2017 The Zcash 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. @@ -22,7 +24,6 @@ #include "amount.h" #include "asyncrpcoperation.h" -#include "paymentdisclosure.h" #include "primitives/transaction.h" #include "transaction_builder.h" #include "wallet.h" @@ -43,29 +44,11 @@ using namespace libzcash; // Input UTXO is a tuple of txid, vout, amount, script typedef std::tuple MergeToAddressInputUTXO; -// Input JSOP is a tuple of JSOutpoint, note, amount, spending key -typedef std::tuple MergeToAddressInputSproutNote; - typedef std::tuple MergeToAddressInputSaplingNote; // A recipient is a tuple of address, memo (optional if zaddr) typedef std::tuple MergeToAddressRecipient; -// Package of info which is passed to perform_joinsplit methods. -struct MergeToAddressJSInfo { - std::vector vjsin; - std::vector vjsout; - std::vector notes; - std::vector zkeys; - CAmount vpub_old = 0; - CAmount vpub_new = 0; -}; - -// A struct to help us track the witness and anchor for a given JSOutPoint -struct MergeToAddressWitnessAnchorData { - boost::optional witness; - uint256 anchor; -}; class AsyncRPCOperation_mergetoaddress : public AsyncRPCOperation { @@ -74,7 +57,6 @@ public: boost::optional builder, CMutableTransaction contextualTx, std::vector utxoInputs, - std::vector sproutNoteInputs, std::vector saplingNoteInputs, MergeToAddressRecipient recipient, CAmount fee = MERGE_TO_ADDRESS_OPERATION_DEFAULT_MINERS_FEE, @@ -93,8 +75,6 @@ public: bool testmode = false; // Set to true to disable sending txs and generating proofs - bool paymentDisclosureMode = true; // Set to true to save esk for encrypted notes in payment disclosure database. - private: friend class TEST_FRIEND_AsyncRPCOperation_mergetoaddress; // class for unit testing @@ -113,11 +93,7 @@ private: uint256 joinSplitPubKey_; unsigned char joinSplitPrivKey_[crypto_sign_SECRETKEYBYTES]; - // The key is the result string from calling JSOutPoint::ToString() - std::unordered_map jsopWitnessAnchorMap; - std::vector utxoInputs_; - std::vector sproutNoteInputs_; std::vector saplingNoteInputs_; TransactionBuilder builder_; @@ -126,18 +102,6 @@ private: std::array get_memo_from_hex_string(std::string s); bool main_impl(); - // JoinSplit without any input notes to spend - UniValue perform_joinsplit(MergeToAddressJSInfo&); - - // JoinSplit with input notes to spend (JSOutPoints)) - UniValue perform_joinsplit(MergeToAddressJSInfo&, std::vector&); - - // JoinSplit where you have the witnesses and anchor - UniValue perform_joinsplit( - MergeToAddressJSInfo& info, - std::vector> witnesses, - uint256 anchor); - void sign_send_raw_transaction(UniValue obj); // throws exception if there was an error void lock_utxos(); @@ -148,8 +112,6 @@ private: void unlock_notes(); - // payment disclosure! - std::vector paymentDisclosureData_; }; @@ -183,24 +145,6 @@ public: return delegate->main_impl(); } - UniValue perform_joinsplit(MergeToAddressJSInfo& info) - { - return delegate->perform_joinsplit(info); - } - - UniValue perform_joinsplit(MergeToAddressJSInfo& info, std::vector& v) - { - return delegate->perform_joinsplit(info, v); - } - - UniValue perform_joinsplit( - MergeToAddressJSInfo& info, - std::vector> witnesses, - uint256 anchor) - { - return delegate->perform_joinsplit(info, witnesses, anchor); - } - void sign_send_raw_transaction(UniValue obj) { delegate->sign_send_raw_transaction(obj); diff --git a/src/wallet/asyncrpcoperation_saplingconsolidation.cpp b/src/wallet/asyncrpcoperation_saplingconsolidation.cpp new file mode 100644 index 000000000..0c6cae7c1 --- /dev/null +++ b/src/wallet/asyncrpcoperation_saplingconsolidation.cpp @@ -0,0 +1,279 @@ +// Copyright (c) 2019-2020 The Hush developers +// Copyright (c) 2019 CryptoForge +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "assert.h" +#include "boost/variant/static_visitor.hpp" +#include "asyncrpcoperation_saplingconsolidation.h" +#include "init.h" +#include "key_io.h" +#include "rpc/protocol.h" +#include "random.h" +#include "sync.h" +#include "tinyformat.h" +#include "transaction_builder.h" +#include "util.h" +#include "utilmoneystr.h" +#include "wallet.h" + +CAmount fConsolidationTxFee = DEFAULT_CONSOLIDATION_FEE; +bool fConsolidationMapUsed = false; +const int CONSOLIDATION_EXPIRY_DELTA = 15; + +extern string randomSietchZaddr(); + +AsyncRPCOperation_saplingconsolidation::AsyncRPCOperation_saplingconsolidation(int targetHeight) : targetHeight_(targetHeight) {} + +AsyncRPCOperation_saplingconsolidation::~AsyncRPCOperation_saplingconsolidation() {} + +void AsyncRPCOperation_saplingconsolidation::main() { + if (isCancelled()) + return; + + set_state(OperationStatus::EXECUTING); + start_execution_clock(); + + bool success = false; + + try { + success = main_impl(); + } catch (const UniValue& objError) { + int code = find_value(objError, "code").get_int(); + std::string message = find_value(objError, "message").get_str(); + set_error_code(code); + set_error_message(message); + } catch (const runtime_error& e) { + set_error_code(-1); + set_error_message("runtime error: " + string(e.what())); + } catch (const logic_error& e) { + set_error_code(-1); + set_error_message("logic error: " + string(e.what())); + } catch (const exception& e) { + set_error_code(-1); + set_error_message("general exception: " + string(e.what())); + } catch (...) { + set_error_code(-2); + set_error_message("unknown error"); + } + + stop_execution_clock(); + + if (success) { + set_state(OperationStatus::SUCCESS); + } else { + set_state(OperationStatus::FAILED); + } + + std::string s = strprintf("%s: Sapling Consolidation transaction created. (status=%s", getId(), getStateAsString()); + if (success) { + s += strprintf(", success)\n"); + } else { + s += strprintf(", error=%s)\n", getErrorMessage()); + } + + LogPrintf("%s", s); +} + +bool AsyncRPCOperation_saplingconsolidation::main_impl() { + bool status=true; + auto opid=getId(); + LogPrint("zrpcunsafe", "%s: Beginning AsyncRPCOperation_saplingconsolidation.\n", opid); + auto consensusParams = Params().GetConsensus(); + auto nextActivationHeight = NextActivationHeight(targetHeight_, consensusParams); + if (nextActivationHeight && targetHeight_ + CONSOLIDATION_EXPIRY_DELTA >= nextActivationHeight.get()) { + LogPrint("zrpcunsafe", "%s: Consolidation txs would be created before a NU activation but may expire after. Skipping this round.\n",opid); + setConsolidationResult(0, 0, std::vector()); + return status; + } + + std::vector saplingEntries; + std::set addresses; + { + LOCK2(cs_main, pwalletMain->cs_wallet); + // We set minDepth to 11 to avoid unconfirmed notes and in anticipation of specifying + // an anchor at height N-10 for each SpendDescription + // Consider, should notes be sorted? + pwalletMain->GetFilteredNotes(saplingEntries, "", 11); + + if(saplingEntries.size() == 0) { + LogPrint("zrpcunsafe", "%s: Nothing to consolidate, done.\n",opid); + return true; + } + + if (fConsolidationMapUsed) { + const vector& v = mapMultiArgs["-consolidatesaplingaddress"]; + for(int i = 0; i < v.size(); i++) { + auto zAddress = DecodePaymentAddress(v[i]); + if (boost::get(&zAddress) != nullptr) { + libzcash::SaplingPaymentAddress saplingAddress = boost::get(zAddress); + addresses.insert(saplingAddress); + } else { + LogPrint("zrpcunsafe", "%s: Invalid zaddr, exiting\n", opid); + return false; + } + } + } else { + pwalletMain->GetSaplingPaymentAddresses(addresses); + } + } + + int numTxCreated = 0; + std::vector consolidationTxIds; + CAmount amountConsolidated = 0; + CCoinsViewCache coinsView(pcoinsTip); + + for (auto addr : addresses) { + libzcash::SaplingExtendedSpendingKey extsk; + if (pwalletMain->GetSaplingExtendedSpendingKey(addr, extsk)) { + + std::vector fromNotes; + CAmount amountToSend = 0; + // max of 8 zins means the tx cannot reduce the anonset, + // since there will be 8 zins and 8 zouts at worst case + // This also helps reduce ztx creation time + int maxQuantity = rand() % 8 + 1; + for (const SaplingNoteEntry& saplingEntry : saplingEntries) { + + libzcash::SaplingIncomingViewingKey ivk; + pwalletMain->GetSaplingIncomingViewingKey(boost::get(saplingEntry.address), ivk); + + //Select Notes from that same address we will be sending to. + if (ivk == extsk.expsk.full_viewing_key().in_viewing_key()) { + amountToSend += CAmount(saplingEntry.note.value()); + fromNotes.push_back(saplingEntry); + } + + //Only use a randomly determined number of notes + if (fromNotes.size() >= maxQuantity) + break; + + } + + // minimum required + // We use 3 so that addresses can spent one zutxo and still have another zutxo to use while that + // tx is confirming + int minQuantity = 3; + if (fromNotes.size() < minQuantity) + continue; + + amountConsolidated += amountToSend; + auto builder = TransactionBuilder(consensusParams, targetHeight_, pwalletMain); + //builder.SetExpiryHeight(targetHeight_ + CONSOLIDATION_EXPIRY_DELTA); + auto actualAmountToSend = amountToSend < fConsolidationTxFee ? 0 : amountToSend - fConsolidationTxFee; + LogPrint("zrpcunsafe", "%s: Beginning to create transaction with Sapling output amount=%s\n", opid, FormatMoney(actualAmountToSend)); + + // Select Sapling notes + std::vector ops; + std::vector notes; + for (auto fromNote : fromNotes) { + ops.push_back(fromNote.op); + notes.push_back(fromNote.note); + } + + // Fetch Sapling anchor and witnesses + uint256 anchor; + std::vector> witnesses; + { + LOCK2(cs_main, pwalletMain->cs_wallet); + LogPrint("zrpcunsafe", "%s: Fetching note witnesses\n", opid); + pwalletMain->GetSaplingNoteWitnesses(ops, witnesses, anchor); + } + + // Add Sapling spends + for (size_t i = 0; i < notes.size(); i++) { + if (!witnesses[i]) { + LogPrint("zrpcunsafe", "%s: Missing Witnesses. Stopping.\n", opid); + status=false; + break; + } + builder.AddSaplingSpend(extsk.expsk, notes[i], anchor, witnesses[i].get()); + LogPrint("zrpcunsafe", "%s: Added consolidation input %d\n", opid, i); + } + + CAmount thisTxFee = amountToSend < fConsolidationTxFee ? 0 : fConsolidationTxFee; + LogPrint("zrpcunsafe", "%s: Using fee=%d\n", opid, thisTxFee); + builder.SetFee(thisTxFee); + + // Add the actual consolidation tx + builder.AddSaplingOutput(extsk.expsk.ovk, addr, actualAmountToSend); + LogPrint("zrpcunsafe", "%s: Added consolidation output %s with amount=%li\n", opid, addr.GetHash().ToString().c_str(), actualAmountToSend); + + // Add sietch zouts + int MIN_ZOUTS = 7; + for(size_t i = 0; i < MIN_ZOUTS; i++) { + // In Privacy Zdust We Trust -- Duke + string zdust = randomSietchZaddr(); + auto zaddr = DecodePaymentAddress(zdust); + if (IsValidPaymentAddress(zaddr)) { + CAmount amount=0; + auto sietchZoutput = boost::get(zaddr); + LogPrint("zrpcunsafe", "%s: Adding Sietch zdust output %d %s amount=%li\n", opid, i, zdust, amount); + + // actually add our sietch zoutput, the new way + builder.AddSaplingOutput(extsk.expsk.ovk, sietchZoutput, amount); + } else { + LogPrint("zrpcunsafe", "%s: Invalid payment address %s! Stopping.\n", opid, zdust); + status = false; + break; + } + } + LogPrint("zrpcunsafe", "%s: Done adding %d sietch zouts\n", opid, MIN_ZOUTS); + //CTransaction tx = builder.Build(); + + auto maybe_tx = builder.Build(); + if (!maybe_tx) { + LogPrint("zrpcunsafe", "%s: Failed to build transaction.\n",opid); + status=false; + break; + } + CTransaction tx = maybe_tx.get(); + + if (isCancelled()) { + LogPrint("zrpcunsafe", "%s: Canceled. Stopping.\n", opid); + status=false; + break; + } + + if(pwalletMain->CommitConsolidationTx(tx)) { + LogPrint("zrpcunsafe", "%s: Committed consolidation transaction with txid=%s\n",opid, tx.GetHash().ToString()); + amountConsolidated += actualAmountToSend; + consolidationTxIds.push_back(tx.GetHash().ToString()); + numTxCreated++; + } else { + LogPrint("zrpcunsafe", "%s: Consolidation transaction FAILED in CommitTransaction, txid=%s\n",opid , tx.GetHash().ToString()); + setConsolidationResult(numTxCreated, amountConsolidated, consolidationTxIds); + status = false; + break; + } + } + } + + LogPrint("zrpcunsafe", "%s: Created %d transactions with total Sapling output amount=%s,status=%d\n",opid , numTxCreated, FormatMoney(amountConsolidated), (int)status); + setConsolidationResult(numTxCreated, amountConsolidated, consolidationTxIds); + return status; +} + +void AsyncRPCOperation_saplingconsolidation::setConsolidationResult(int numTxCreated, const CAmount& amountConsolidated, const std::vector& consolidationTxIds) { + UniValue res(UniValue::VOBJ); + res.push_back(Pair("num_tx_created", numTxCreated)); + res.push_back(Pair("amount_consolidated", FormatMoney(amountConsolidated))); + UniValue txIds(UniValue::VARR); + for (const std::string& txId : consolidationTxIds) { + txIds.push_back(txId); + } + res.push_back(Pair("consolidation_txids", txIds)); + set_result(res); +} + +void AsyncRPCOperation_saplingconsolidation::cancel() { + set_state(OperationStatus::CANCELLED); +} + +UniValue AsyncRPCOperation_saplingconsolidation::getStatus() const { + UniValue v = AsyncRPCOperation::getStatus(); + UniValue obj = v.get_obj(); + obj.push_back(Pair("method", "saplingconsolidation")); + obj.push_back(Pair("target_height", targetHeight_)); + return obj; +} diff --git a/src/wallet/asyncrpcoperation_saplingconsolidation.h b/src/wallet/asyncrpcoperation_saplingconsolidation.h new file mode 100644 index 000000000..5d14b9335 --- /dev/null +++ b/src/wallet/asyncrpcoperation_saplingconsolidation.h @@ -0,0 +1,42 @@ +// Copyright (c) 2020 The Hush developers +// Copyright (c) 2019 CryptoForge +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "amount.h" +#include "asyncrpcoperation.h" +#include "univalue.h" +#include "zcash/Address.hpp" +#include "zcash/zip32.h" + +//Default fee used for consolidation transactions, in puposhis +static const CAmount DEFAULT_CONSOLIDATION_FEE = 10000; +extern CAmount fConsolidationTxFee; +extern bool fConsolidationMapUsed; + +class AsyncRPCOperation_saplingconsolidation : public AsyncRPCOperation +{ +public: + AsyncRPCOperation_saplingconsolidation(int targetHeight); + virtual ~AsyncRPCOperation_saplingconsolidation(); + + // We don't want to be copied or moved around + AsyncRPCOperation_saplingconsolidation(AsyncRPCOperation_saplingconsolidation const&) = delete; // Copy construct + AsyncRPCOperation_saplingconsolidation(AsyncRPCOperation_saplingconsolidation&&) = delete; // Move construct + AsyncRPCOperation_saplingconsolidation& operator=(AsyncRPCOperation_saplingconsolidation const&) = delete; // Copy assign + AsyncRPCOperation_saplingconsolidation& operator=(AsyncRPCOperation_saplingconsolidation&&) = delete; // Move assign + + virtual void main(); + + virtual void cancel(); + + virtual UniValue getStatus() const; + +private: + int targetHeight_; + + bool main_impl(); + + void setConsolidationResult(int numTxCreated, const CAmount& amountConsolidated, const std::vector& consolidationTxIds); + +}; diff --git a/src/wallet/asyncrpcoperation_sendmany.cpp b/src/wallet/asyncrpcoperation_sendmany.cpp index 82a7c9212..1b709b142 100644 --- a/src/wallet/asyncrpcoperation_sendmany.cpp +++ b/src/wallet/asyncrpcoperation_sendmany.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2016 The Zcash 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. +// file COPYING or https://www.opensource.org/licenses/mit-license.php /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * @@ -49,7 +49,6 @@ #include #include -#include "paymentdisclosuredb.h" #include using namespace libzcash; @@ -141,10 +140,6 @@ AsyncRPCOperation_sendmany::AsyncRPCOperation_sendmany( } else { LogPrint("zrpc", "%s: z_sendmany initialized\n", getId()); } - - - // Enable payment disclosure if requested - paymentDisclosureMode = fExperimentalMode && GetBoolArg("-paymentdisclosure", true); } AsyncRPCOperation_sendmany::~AsyncRPCOperation_sendmany() { @@ -211,25 +206,10 @@ void AsyncRPCOperation_sendmany::main() { s += strprintf(", error=%s)\n", getErrorMessage()); } LogPrintf("%s",s); - - // !!! Payment disclosure START - if (success && paymentDisclosureMode && paymentDisclosureData_.size()>0) { - uint256 txidhash = tx_.GetHash(); - std::shared_ptr db = PaymentDisclosureDB::sharedInstance(); - for (PaymentDisclosureKeyInfo p : paymentDisclosureData_) { - p.first.hash = txidhash; - if (!db->Put(p.first, p.second)) { - LogPrint("paymentdisclosure", "%s: Payment Disclosure: Error writing entry to database for key %s\n", getId(), p.first.ToString()); - } else { - LogPrint("paymentdisclosure", "%s: Payment Disclosure: Successfully added entry to database for key %s\n", getId(), p.first.ToString()); - } - } - } - // !!! Payment disclosure END } // Notes: -// 1. #1159 Currently there is no limit set on the number of joinsplits, so size of tx could be invalid. +// 1. #1159 Currently there is no limit set on the number of shielded spends, so size of tx could be invalid. // 2. #1360 Note selection is not optimal // 3. #1277 Spendable notes are not locked, so an operation running in parallel could also try to use them bool AsyncRPCOperation_sendmany::main_impl() { @@ -265,18 +245,12 @@ bool AsyncRPCOperation_sendmany::main_impl() { throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds, no unspent notes found for zaddr from address."); } - // At least one of z_sprout_inputs_ and z_sapling_inputs_ must be empty by design - assert(z_sprout_inputs_.empty() || z_sapling_inputs_.empty()); - CAmount t_inputs_total = 0; for (SendManyInputUTXO & t : t_inputs_) { t_inputs_total += std::get<2>(t); } CAmount z_inputs_total = 0; - for (SendManyInputJSOP & t : z_sprout_inputs_) { - z_inputs_total += std::get<2>(t); - } for (auto t : z_sapling_inputs_) { z_inputs_total += t.note.value(); } @@ -566,430 +540,7 @@ bool AsyncRPCOperation_sendmany::main_impl() { * END SCENARIO #0 */ - - // Grab the current consensus branch ID - { - LOCK(cs_main); - consensusBranchId_ = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); - } - - /** - * SCENARIO #1 - * - * taddr -> taddrs - * - * There are no zaddrs or joinsplits involved. - */ - if (isPureTaddrOnlyTx) { - add_taddr_outputs_to_tx(); - - CAmount funds = selectedUTXOAmount; - CAmount fundsSpent = t_outputs_total + minersFee; - CAmount change = funds - fundsSpent; - - if (change > 0) { - add_taddr_change_output_to_tx(0,change); - - LogPrint("zrpc", "%s: transparent change in transaction output (amount=%s)\n", - getId(), - FormatMoney(change) - ); - } - - UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("rawtxn", EncodeHexTx(tx_))); - sign_send_raw_transaction(obj); - return true; - } - /** - * END SCENARIO #1 - */ - - - // Prepare raw transaction to handle JoinSplits - CMutableTransaction mtx(tx_); - crypto_sign_keypair(joinSplitPubKey_.begin(), joinSplitPrivKey_); - mtx.joinSplitPubKey = joinSplitPubKey_; - //if ((uint32_t)chainActive.LastTip()->nTime < ASSETCHAINS_STAKED_HF_TIMESTAMP) - if ( !hush_hardfork_active((uint32_t)chainActive.LastTip()->nTime) ) - mtx.nLockTime = (uint32_t)time(NULL) - 60; // jl777 - else - mtx.nLockTime = (uint32_t)chainActive.Tip()->GetMedianTimePast(); - - tx_ = CTransaction(mtx); - - // Copy zinputs and zoutputs to more flexible containers - std::deque zInputsDeque; // zInputsDeque stores minimum numbers of notes for target amount - CAmount tmp = 0; - for (auto o : z_sprout_inputs_) { - zInputsDeque.push_back(o); - tmp += std::get<2>(o); - if (tmp >= targetAmount) { - break; - } - } - std::deque zOutputsDeque; - for (auto o : z_outputs_) { - zOutputsDeque.push_back(o); - } - - // When spending notes, take a snapshot of note witnesses and anchors as the treestate will - // change upon arrival of new blocks which contain joinsplit transactions. This is likely - // to happen as creating a chained joinsplit transaction can take longer than the block interval. - if (z_sprout_inputs_.size() > 0) { - LOCK2(cs_main, pwalletMain->cs_wallet); - for (auto t : z_sprout_inputs_) { - JSOutPoint jso = std::get<0>(t); - std::vector vOutPoints = { jso }; - uint256 inputAnchor; - std::vector> vInputWitnesses; - pwalletMain->GetSproutNoteWitnesses(vOutPoints, vInputWitnesses, inputAnchor); - jsopWitnessAnchorMap[ jso.ToString() ] = WitnessAnchorData{ vInputWitnesses[0], inputAnchor }; - } - } - - - /** - * SCENARIO #2 - * - * taddr -> taddrs - * -> zaddrs - * - * Note: Consensus rule states that coinbase utxos can only be sent to a zaddr. TODO: Do they? - * Local wallet rule does not allow any change when sending coinbase utxos - * since there is currently no way to specify a change address and we don't - * want users accidentally sending excess funds to a recipient. - */ - if (isfromtaddr_) { - add_taddr_outputs_to_tx(); - - CAmount funds = selectedUTXOAmount; - CAmount fundsSpent = t_outputs_total + minersFee + z_outputs_total; - CAmount change = funds - fundsSpent; - - if (change > 0) { - if (selectedUTXOCoinbase) { - assert(isSingleZaddrOutput); - throw JSONRPCError(RPC_WALLET_ERROR, strprintf( - "Change %s not allowed. When shielding coinbase funds, the wallet does not " - "allow any change as there is currently no way to specify a change address " - "in z_sendmany.", FormatMoney(change))); - } else { - CBitcoinAddress ba = CBitcoinAddress(fromtaddr_); - add_taddr_change_output_to_tx(&ba,change); - LogPrint("zrpc", "%s: transparent change in transaction output (amount=%s)\n", - getId(), - FormatMoney(change) - ); - } - } - - // Create joinsplits, where each output represents a zaddr recipient. - UniValue obj(UniValue::VOBJ); - while (zOutputsDeque.size() > 0) { - AsyncJoinSplitInfo info; - info.vpub_old = 0; - info.vpub_new = 0; - int n = 0; - while (n++ 0) { - SendManyRecipient smr = zOutputsDeque.front(); - std::string address = std::get<0>(smr); - CAmount value = std::get<1>(smr); - std::string hexMemo = std::get<2>(smr); - zOutputsDeque.pop_front(); - - PaymentAddress pa = DecodePaymentAddress(address); - JSOutput jso = JSOutput(boost::get(pa), value); - if (hexMemo.size() > 0) { - jso.memo = get_memo_from_hex_string(hexMemo); - } - info.vjsout.push_back(jso); - - // Funds are removed from the value pool and enter the private pool - info.vpub_old += value; - } - obj = perform_joinsplit(info); - } - sign_send_raw_transaction(obj); - return true; - } - /** - * END SCENARIO #2 - */ - - - - /** - * SCENARIO #3 - * - * zaddr -> taddrs - * -> zaddrs - * - * Send to zaddrs by chaining JoinSplits together and immediately consuming any change - * Send to taddrs by creating dummy z outputs and accumulating value in a change note - * which is used to set vpub_new in the last chained joinsplit. - */ - UniValue obj(UniValue::VOBJ); - CAmount jsChange = 0; // this is updated after each joinsplit - int changeOutputIndex = -1; // this is updated after each joinsplit if jsChange > 0 - bool vpubNewProcessed = false; // updated when vpub_new for miner fee and taddr outputs is set in last joinsplit - CAmount vpubNewTarget = minersFee; - if (t_outputs_total > 0) { - add_taddr_outputs_to_tx(); - vpubNewTarget += t_outputs_total; - } - - // Keep track of treestate within this transaction - boost::unordered_map intermediates; - std::vector previousCommitments; - - while (!vpubNewProcessed) { - AsyncJoinSplitInfo info; - info.vpub_old = 0; - info.vpub_new = 0; - - CAmount jsInputValue = 0; - uint256 jsAnchor; - std::vector> witnesses; - - JSDescription prevJoinSplit; - - // Keep track of previous JoinSplit and its commitments - if (tx_.vjoinsplit.size() > 0) { - prevJoinSplit = tx_.vjoinsplit.back(); - } - - // If there is no change, the chain has terminated so we can reset the tracked treestate. - if (jsChange==0 && tx_.vjoinsplit.size() > 0) { - intermediates.clear(); - previousCommitments.clear(); - } - - // - // Consume change as the first input of the JoinSplit. - // - if (jsChange > 0) { - LOCK2(cs_main, pwalletMain->cs_wallet); - - // Update tree state with previous joinsplit - SproutMerkleTree tree; - auto it = intermediates.find(prevJoinSplit.anchor); - if (it != intermediates.end()) { - tree = it->second; - } else if (!pcoinsTip->GetSproutAnchorAt(prevJoinSplit.anchor, tree)) { - throw JSONRPCError(RPC_WALLET_ERROR, "Could not find previous JoinSplit anchor"); - } - - assert(changeOutputIndex != -1); - boost::optional changeWitness; - int n = 0; - for (const uint256& commitment : prevJoinSplit.commitments) { - tree.append(commitment); - previousCommitments.push_back(commitment); - if (!changeWitness && changeOutputIndex == n++) { - changeWitness = tree.witness(); - } else if (changeWitness) { - changeWitness.get().append(commitment); - } - } - if (changeWitness) { - witnesses.push_back(changeWitness); - } - jsAnchor = tree.root(); - intermediates.insert(std::make_pair(tree.root(), tree)); // chained js are interstitial (found in between block boundaries) - - // Decrypt the change note's ciphertext to retrieve some data we need - ZCNoteDecryption decryptor(boost::get(spendingkey_).receiving_key()); - auto hSig = prevJoinSplit.h_sig(*pzcashParams, tx_.joinSplitPubKey); - try { - SproutNotePlaintext plaintext = SproutNotePlaintext::decrypt( - decryptor, - prevJoinSplit.ciphertexts[changeOutputIndex], - prevJoinSplit.ephemeralKey, - hSig, - (unsigned char) changeOutputIndex); - - SproutNote note = plaintext.note(boost::get(frompaymentaddress_)); - info.notes.push_back(note); - - jsInputValue += plaintext.value(); - - LogPrint("zrpcunsafe", "%s: spending change (amount=%s)\n", - getId(), - FormatMoney(plaintext.value()) - ); - - } catch (const std::exception& e) { - throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Error decrypting output note of previous JoinSplit: %s", e.what())); - } - } - - - // - // Consume spendable non-change notes - // - std::vector vInputNotes; - std::vector vOutPoints; - std::vector> vInputWitnesses; - uint256 inputAnchor; - int numInputsNeeded = (jsChange>0) ? 1 : 0; - while (numInputsNeeded++ < ZC_NUM_JS_INPUTS && zInputsDeque.size() > 0) { - SendManyInputJSOP t = zInputsDeque.front(); - JSOutPoint jso = std::get<0>(t); - SproutNote note = std::get<1>(t); - CAmount noteFunds = std::get<2>(t); - zInputsDeque.pop_front(); - - WitnessAnchorData wad = jsopWitnessAnchorMap[ jso.ToString() ]; - vInputWitnesses.push_back(wad.witness); - if (inputAnchor.IsNull()) { - inputAnchor = wad.anchor; - } else if (inputAnchor != wad.anchor) { - throw JSONRPCError(RPC_WALLET_ERROR, "Selected input notes do not share the same anchor"); - } - - vOutPoints.push_back(jso); - vInputNotes.push_back(note); - - jsInputValue += noteFunds; - - int wtxHeight = -1; - int wtxDepth = -1; - { - LOCK2(cs_main, pwalletMain->cs_wallet); - const CWalletTx& wtx = pwalletMain->mapWallet[jso.hash]; - // Zero-confirmation notes belong to transactions which have not yet been mined - if (mapBlockIndex.find(wtx.hashBlock) == mapBlockIndex.end()) { - throw JSONRPCError(RPC_WALLET_ERROR, strprintf("mapBlockIndex does not contain block hash %s", wtx.hashBlock.ToString())); - } - wtxHeight = komodo_blockheight(wtx.hashBlock); - wtxDepth = wtx.GetDepthInMainChain(); - } - LogPrint("zrpcunsafe", "%s: spending note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s, height=%d, confirmations=%d)\n", - getId(), - jso.hash.ToString().substr(0, 10), - jso.js, - int(jso.n), // uint8_t - FormatMoney(noteFunds), - wtxHeight, - wtxDepth - ); - } - - // Add history of previous commitments to witness - if (vInputNotes.size() > 0) { - - if (vInputWitnesses.size()==0) { - throw JSONRPCError(RPC_WALLET_ERROR, "Could not find witness for note commitment"); - } - - for (auto & optionalWitness : vInputWitnesses) { - if (!optionalWitness) { - throw JSONRPCError(RPC_WALLET_ERROR, "Witness for note commitment is null"); - } - SproutWitness w = *optionalWitness; // could use .get(); - if (jsChange > 0) { - for (const uint256& commitment : previousCommitments) { - w.append(commitment); - } - if (jsAnchor != w.root()) { - throw JSONRPCError(RPC_WALLET_ERROR, "Witness for spendable note does not have same anchor as change input"); - } - } - witnesses.push_back(w); - } - - // The jsAnchor is null if this JoinSplit is at the start of a new chain - if (jsAnchor.IsNull()) { - jsAnchor = inputAnchor; - } - - // Add spendable notes as inputs - std::copy(vInputNotes.begin(), vInputNotes.end(), std::back_inserter(info.notes)); - } - - // Find recipient to transfer funds to - std::string address, hexMemo; - CAmount value = 0; - if (zOutputsDeque.size() > 0) { - SendManyRecipient smr = zOutputsDeque.front(); - address = std::get<0>(smr); - value = std::get<1>(smr); - hexMemo = std::get<2>(smr); - zOutputsDeque.pop_front(); - } - - // Reset change - jsChange = 0; - CAmount outAmount = value; - - // Set vpub_new in the last joinsplit (when there are no more notes to spend or zaddr outputs to satisfy) - if (zOutputsDeque.size() == 0 && zInputsDeque.size() == 0) { - assert(!vpubNewProcessed); - if (jsInputValue < vpubNewTarget) { - throw JSONRPCError(RPC_WALLET_ERROR, - strprintf("Insufficient funds for vpub_new %s (miners fee %s, taddr outputs %s)", - FormatMoney(vpubNewTarget), FormatMoney(minersFee), FormatMoney(t_outputs_total))); - } - outAmount += vpubNewTarget; - info.vpub_new += vpubNewTarget; // funds flowing back to public pool - vpubNewProcessed = true; - jsChange = jsInputValue - outAmount; - assert(jsChange >= 0); - } - else { - // This is not the last joinsplit, so compute change and any amount still due to the recipient - if (jsInputValue > outAmount) { - jsChange = jsInputValue - outAmount; - } else if (outAmount > jsInputValue) { - // Any amount due is owed to the recipient. Let the miners fee get paid first. - CAmount due = outAmount - jsInputValue; - SendManyRecipient r = SendManyRecipient(address, due, hexMemo); - zOutputsDeque.push_front(r); - - // reduce the amount being sent right now to the value of all inputs - value = jsInputValue; - } - } - - // create output for recipient - if (address.empty()) { - assert(value==0); - info.vjsout.push_back(JSOutput()); // dummy output while we accumulate funds into a change note for vpub_new - } else { - PaymentAddress pa = DecodePaymentAddress(address); - // If we are here, we know we have no Sapling outputs. - JSOutput jso = JSOutput(boost::get(pa), value); - if (hexMemo.size() > 0) { - jso.memo = get_memo_from_hex_string(hexMemo); - } - info.vjsout.push_back(jso); - } - - // create output for any change - if (jsChange>0) { - info.vjsout.push_back(JSOutput(boost::get(frompaymentaddress_), jsChange)); - - LogPrint("zrpcunsafe", "%s: generating note for change (amount=%s)\n", - getId(), - FormatMoney(jsChange) - ); - } - - obj = perform_joinsplit(info, witnesses, jsAnchor); - - if (jsChange > 0) { - changeOutputIndex = find_output(obj, 1); - } - } - - // Sanity check in case changes to code block above exits loop by invoking 'break' - assert(zInputsDeque.size() == 0); - assert(zOutputsDeque.size() == 0); - assert(vpubNewProcessed); - - sign_send_raw_transaction(obj); - return true; + return false; } @@ -1127,33 +678,10 @@ bool AsyncRPCOperation_sendmany::find_utxos(bool fAcceptCoinbase=false) { bool AsyncRPCOperation_sendmany::find_unspent_notes() { - std::vector sproutEntries; std::vector saplingEntries; { LOCK2(cs_main, pwalletMain->cs_wallet); - pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, fromaddress_, mindepth_); - } - - // If using the TransactionBuilder, we only want Sapling notes. - // If not using it, we only want Sprout notes. - // TODO: Refactor `GetFilteredNotes()` so we only fetch what we need. - if (isUsingBuilder_) { - sproutEntries.clear(); - } else { - saplingEntries.clear(); - } - - for (CSproutNotePlaintextEntry & entry : sproutEntries) { - z_sprout_inputs_.push_back(SendManyInputJSOP(entry.jsop, entry.plaintext.note(boost::get(frompaymentaddress_)), CAmount(entry.plaintext.value()))); - std::string data(entry.plaintext.memo().begin(), entry.plaintext.memo().end()); - LogPrint("zrpcunsafe", "%s: found unspent Sprout note (txid=%s, vjoinsplit=%d, ciphertext=%d, amount=%s, memo=%s)\n", - getId(), - entry.jsop.hash.ToString().substr(0, 10), - entry.jsop.js, - int(entry.jsop.n), // uint8_t - FormatMoney(entry.plaintext.value()), - HexStr(data).substr(0, 10) - ); + pwalletMain->GetFilteredNotes(saplingEntries, fromaddress_, mindepth_); } for (auto entry : saplingEntries) { @@ -1167,15 +695,7 @@ bool AsyncRPCOperation_sendmany::find_unspent_notes() { HexStr(data).substr(0, 10)); } - if (z_sprout_inputs_.empty() && z_sapling_inputs_.empty()) { - return false; - } - // sort in descending order, so big notes appear first - std::sort(z_sprout_inputs_.begin(), z_sprout_inputs_.end(), - [](SendManyInputJSOP i, SendManyInputJSOP j) -> bool { - return std::get<2>(i) > std::get<2>(j); - }); std::sort(z_sapling_inputs_.begin(), z_sapling_inputs_.end(), [](SaplingNoteEntry i, SaplingNoteEntry j) -> bool { return i.note.value() > j.note.value(); @@ -1184,190 +704,6 @@ bool AsyncRPCOperation_sendmany::find_unspent_notes() { return true; } -UniValue AsyncRPCOperation_sendmany::perform_joinsplit(AsyncJoinSplitInfo & info) { - std::vector> witnesses; - uint256 anchor; - { - LOCK(cs_main); - anchor = pcoinsTip->GetBestAnchor(SPROUT); // As there are no inputs, ask the wallet for the best anchor - } - return perform_joinsplit(info, witnesses, anchor); -} - - -UniValue AsyncRPCOperation_sendmany::perform_joinsplit(AsyncJoinSplitInfo & info, std::vector & outPoints) { - std::vector> witnesses; - uint256 anchor; - { - LOCK(cs_main); - pwalletMain->GetSproutNoteWitnesses(outPoints, witnesses, anchor); - } - return perform_joinsplit(info, witnesses, anchor); -} - -UniValue AsyncRPCOperation_sendmany::perform_joinsplit( - AsyncJoinSplitInfo & info, - std::vector> witnesses, - uint256 anchor) -{ - if (anchor.IsNull()) { - throw std::runtime_error("anchor is null"); - } - - if (!(witnesses.size() == info.notes.size())) { - throw runtime_error("number of notes and witnesses do not match"); - } - - for (size_t i = 0; i < witnesses.size(); i++) { - if (!witnesses[i]) { - throw runtime_error("joinsplit input could not be found in tree"); - } - info.vjsin.push_back(JSInput(*witnesses[i], info.notes[i], boost::get(spendingkey_))); - } - - // Make sure there are two inputs and two outputs - while (info.vjsin.size() < ZC_NUM_JS_INPUTS) { - info.vjsin.push_back(JSInput()); - } - - while (info.vjsout.size() < ZC_NUM_JS_OUTPUTS) { - info.vjsout.push_back(JSOutput()); - } - - if (info.vjsout.size() != ZC_NUM_JS_INPUTS || info.vjsin.size() != ZC_NUM_JS_OUTPUTS) { - throw runtime_error("unsupported joinsplit input/output counts"); - } - - CMutableTransaction mtx(tx_); - - LogPrint("zrpcunsafe", "%s: creating joinsplit at index %d (vpub_old=%s, vpub_new=%s, in[0]=%s, in[1]=%s, out[0]=%s, out[1]=%s)\n", - getId(), - tx_.vjoinsplit.size(), - FormatMoney(info.vpub_old), FormatMoney(info.vpub_new), - FormatMoney(info.vjsin[0].note.value()), FormatMoney(info.vjsin[1].note.value()), - FormatMoney(info.vjsout[0].value), FormatMoney(info.vjsout[1].value) - ); - - // Generate the proof, this can take over a minute. - std::array inputs - {info.vjsin[0], info.vjsin[1]}; - std::array outputs - {info.vjsout[0], info.vjsout[1]}; - std::array inputMap; - std::array outputMap; - uint256 esk; // payment disclosure - secret - - JSDescription jsdesc = JSDescription::Randomized( - mtx.fOverwintered && (mtx.nVersion >= SAPLING_TX_VERSION), - *pzcashParams, - joinSplitPubKey_, - anchor, - inputs, - outputs, - inputMap, - outputMap, - info.vpub_old, - info.vpub_new, - !this->testmode, - &esk); // parameter expects pointer to esk, so pass in address - { - auto verifier = libzcash::ProofVerifier::Strict(); - if (!(jsdesc.Verify(*pzcashParams, verifier, joinSplitPubKey_))) { - throw std::runtime_error("error verifying joinsplit"); - } - } - - mtx.vjoinsplit.push_back(jsdesc); - - // Empty output script. - CScript scriptCode; - CTransaction signTx(mtx); - uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId_); - - // Add the signature - if (!(crypto_sign_detached(&mtx.joinSplitSig[0], NULL, - dataToBeSigned.begin(), 32, - joinSplitPrivKey_ - ) == 0)) - { - throw std::runtime_error("crypto_sign_detached failed"); - } - - // Sanity check - if (!(crypto_sign_verify_detached(&mtx.joinSplitSig[0], - dataToBeSigned.begin(), 32, - mtx.joinSplitPubKey.begin() - ) == 0)) - { - throw std::runtime_error("crypto_sign_verify_detached failed"); - } - - CTransaction rawTx(mtx); - tx_ = rawTx; - - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << rawTx; - - std::string encryptedNote1; - std::string encryptedNote2; - { - CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION); - ss2 << ((unsigned char) 0x00); - ss2 << jsdesc.ephemeralKey; - ss2 << jsdesc.ciphertexts[0]; - ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey_); - - encryptedNote1 = HexStr(ss2.begin(), ss2.end()); - } - { - CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION); - ss2 << ((unsigned char) 0x01); - ss2 << jsdesc.ephemeralKey; - ss2 << jsdesc.ciphertexts[1]; - ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey_); - - encryptedNote2 = HexStr(ss2.begin(), ss2.end()); - } - - UniValue arrInputMap(UniValue::VARR); - UniValue arrOutputMap(UniValue::VARR); - for (size_t i = 0; i < ZC_NUM_JS_INPUTS; i++) { - arrInputMap.push_back(static_cast(inputMap[i])); - } - for (size_t i = 0; i < ZC_NUM_JS_OUTPUTS; i++) { - arrOutputMap.push_back(static_cast(outputMap[i])); - } - - - // !!! Payment disclosure START - unsigned char buffer[32] = {0}; - memcpy(&buffer[0], &joinSplitPrivKey_[0], 32); // private key in first half of 64 byte buffer - std::vector vch(&buffer[0], &buffer[0] + 32); - uint256 joinSplitPrivKey = uint256(vch); - size_t js_index = tx_.vjoinsplit.size() - 1; - uint256 placeholder; - for (int i = 0; i < ZC_NUM_JS_OUTPUTS; i++) { - uint8_t mapped_index = outputMap[i]; - // placeholder for txid will be filled in later when tx has been finalized and signed. - PaymentDisclosureKey pdKey = {placeholder, js_index, mapped_index}; - JSOutput output = outputs[mapped_index]; - libzcash::SproutPaymentAddress zaddr = output.addr; // randomized output - PaymentDisclosureInfo pdInfo = {PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL, esk, joinSplitPrivKey, zaddr}; - paymentDisclosureData_.push_back(PaymentDisclosureKeyInfo(pdKey, pdInfo)); - - LogPrint("paymentdisclosure", "%s: Payment Disclosure: js=%d, n=%d, zaddr=%s\n", getId(), js_index, int(mapped_index), EncodePaymentAddress(zaddr)); - } - // !!! Payment disclosure END - - UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("encryptednote1", encryptedNote1)); - obj.push_back(Pair("encryptednote2", encryptedNote2)); - obj.push_back(Pair("rawtxn", HexStr(ss.begin(), ss.end()))); - obj.push_back(Pair("inputmap", arrInputMap)); - obj.push_back(Pair("outputmap", arrOutputMap)); - return obj; -} - void AsyncRPCOperation_sendmany::add_taddr_outputs_to_tx() { CMutableTransaction rawTx(tx_); diff --git a/src/wallet/asyncrpcoperation_sendmany.h b/src/wallet/asyncrpcoperation_sendmany.h index 8e39f341a..86e6ef775 100644 --- a/src/wallet/asyncrpcoperation_sendmany.h +++ b/src/wallet/asyncrpcoperation_sendmany.h @@ -1,4 +1,5 @@ // Copyright (c) 2016 The Zcash 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. @@ -27,7 +28,6 @@ #include "zcash/JoinSplit.hpp" #include "zcash/Address.hpp" #include "wallet.h" -#include "paymentdisclosure.h" #include #include @@ -46,19 +46,6 @@ typedef std::tuple SendManyRecipient; // Input UTXO is a tuple (quadruple) of txid, vout, amount, coinbase) typedef std::tuple SendManyInputUTXO; -// Input JSOP is a tuple of JSOutpoint, note and amount -typedef std::tuple SendManyInputJSOP; - -// Package of info which is passed to perform_joinsplit methods. -struct AsyncJoinSplitInfo -{ - std::vector vjsin; - std::vector vjsout; - std::vector notes; - CAmount vpub_old = 0; - CAmount vpub_new = 0; -}; - // A struct to help us track the witness and anchor for a given JSOutPoint struct WitnessAnchorData { boost::optional witness; @@ -90,8 +77,6 @@ public: bool testmode = false; // Set to true to disable sending txs and generating proofs - bool paymentDisclosureMode = true; // Set to true to save esk for encrypted notes in payment disclosure database. - private: friend class TEST_FRIEND_AsyncRPCOperation_sendmany; // class for unit testing @@ -117,7 +102,7 @@ private: std::vector t_outputs_; std::vector z_outputs_; std::vector t_inputs_; - std::vector z_sprout_inputs_; + //std::vector z_sprout_inputs_; std::vector z_sapling_inputs_; TransactionBuilder builder_; @@ -130,22 +115,7 @@ private: std::array get_memo_from_hex_string(std::string s); bool main_impl(); - // JoinSplit without any input notes to spend - UniValue perform_joinsplit(AsyncJoinSplitInfo &); - - // JoinSplit with input notes to spend (JSOutPoints)) - UniValue perform_joinsplit(AsyncJoinSplitInfo &, std::vector & ); - - // JoinSplit where you have the witnesses and anchor - UniValue perform_joinsplit( - AsyncJoinSplitInfo & info, - std::vector> witnesses, - uint256 anchor); - void sign_send_raw_transaction(UniValue obj); // throws exception if there was an error - - // payment disclosure! - std::vector paymentDisclosureData_; }; @@ -190,22 +160,6 @@ public: return delegate->main_impl(); } - UniValue perform_joinsplit(AsyncJoinSplitInfo &info) { - return delegate->perform_joinsplit(info); - } - - UniValue perform_joinsplit(AsyncJoinSplitInfo &info, std::vector &v ) { - return delegate->perform_joinsplit(info, v); - } - - UniValue perform_joinsplit( - AsyncJoinSplitInfo & info, - std::vector> witnesses, - uint256 anchor) - { - return delegate->perform_joinsplit(info, witnesses, anchor); - } - void sign_send_raw_transaction(UniValue obj) { delegate->sign_send_raw_transaction(obj); } diff --git a/src/wallet/asyncrpcoperation_shieldcoinbase.cpp b/src/wallet/asyncrpcoperation_shieldcoinbase.cpp index 6db4eb6c0..de56ba3bc 100644 --- a/src/wallet/asyncrpcoperation_shieldcoinbase.cpp +++ b/src/wallet/asyncrpcoperation_shieldcoinbase.cpp @@ -1,4 +1,5 @@ // Copyright (c) 2017 The Zcash 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. @@ -47,9 +48,6 @@ #include "asyncrpcoperation_shieldcoinbase.h" -#include "paymentdisclosure.h" -#include "paymentdisclosuredb.h" - using namespace libzcash; extern uint64_t ASSETCHAINS_TIMELOCKGTE; @@ -107,8 +105,6 @@ AsyncRPCOperation_shieldcoinbase::AsyncRPCOperation_shieldcoinbase( // Lock UTXOs lock_utxos(); - // Enable payment disclosure if requested - paymentDisclosureMode = fExperimentalMode && GetBoolArg("-paymentdisclosure", true); } AsyncRPCOperation_shieldcoinbase::~AsyncRPCOperation_shieldcoinbase() { @@ -180,20 +176,6 @@ void AsyncRPCOperation_shieldcoinbase::main() { unlock_utxos(); // clean up - // !!! Payment disclosure START - if (success && paymentDisclosureMode && paymentDisclosureData_.size()>0) { - uint256 txidhash = tx_.GetHash(); - std::shared_ptr db = PaymentDisclosureDB::sharedInstance(); - for (PaymentDisclosureKeyInfo p : paymentDisclosureData_) { - p.first.hash = txidhash; - if (!db->Put(p.first, p.second)) { - LogPrint("paymentdisclosure", "%s: Payment Disclosure: Error writing entry to database for key %s\n", getId(), p.first.ToString()); - } else { - LogPrint("paymentdisclosure", "%s: Payment Disclosure: Successfully added entry to database for key %s\n", getId(), p.first.ToString()); - } - } - } - // !!! Payment disclosure END } bool AsyncRPCOperation_shieldcoinbase::main_impl() { @@ -234,37 +216,6 @@ bool AsyncRPCOperation_shieldcoinbase::main_impl() { return boost::apply_visitor(ShieldToAddress(this, sendAmount), tozaddr_); } -bool ShieldToAddress::operator()(const libzcash::SproutPaymentAddress &zaddr) const { - // update the transaction with these inputs - CMutableTransaction rawTx(m_op->tx_); - for (ShieldCoinbaseUTXO & t : m_op->inputs_) { - CTxIn in(COutPoint(t.txid, t.vout)); - if (t.amount >= ASSETCHAINS_TIMELOCKGTE) - in.nSequence = 0xfffffffe; - rawTx.vin.push_back(in); - } - m_op->tx_ = CTransaction(rawTx); - - // Prepare raw transaction to handle JoinSplits - CMutableTransaction mtx(m_op->tx_); - crypto_sign_keypair(m_op->joinSplitPubKey_.begin(), m_op->joinSplitPrivKey_); - mtx.joinSplitPubKey = m_op->joinSplitPubKey_; - m_op->tx_ = CTransaction(mtx); - - // Create joinsplit - UniValue obj(UniValue::VOBJ); - ShieldCoinbaseJSInfo info; - info.vpub_old = sendAmount; - info.vpub_new = 0; - JSOutput jso = JSOutput(zaddr, sendAmount); - info.vjsout.push_back(jso); - obj = m_op->perform_joinsplit(info); - - m_op->sign_send_raw_transaction(obj); - return true; -} - - extern UniValue signrawtransaction(const UniValue& params, bool fHelp, const CPubKey& mypk); extern UniValue sendrawtransaction(const UniValue& params, bool fHelp, const CPubKey& mypk); @@ -406,164 +357,6 @@ void AsyncRPCOperation_shieldcoinbase::sign_send_raw_transaction(UniValue obj) } -UniValue AsyncRPCOperation_shieldcoinbase::perform_joinsplit(ShieldCoinbaseJSInfo & info) { - uint32_t consensusBranchId; - uint256 anchor; - { - LOCK(cs_main); - consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); - anchor = pcoinsTip->GetBestAnchor(SPROUT); - } - - - if (anchor.IsNull()) { - throw std::runtime_error("anchor is null"); - } - - // Make sure there are two inputs and two outputs - while (info.vjsin.size() < ZC_NUM_JS_INPUTS) { - info.vjsin.push_back(JSInput()); - } - - while (info.vjsout.size() < ZC_NUM_JS_OUTPUTS) { - info.vjsout.push_back(JSOutput()); - } - - if (info.vjsout.size() != ZC_NUM_JS_INPUTS || info.vjsin.size() != ZC_NUM_JS_OUTPUTS) { - throw runtime_error("unsupported joinsplit input/output counts"); - } - - CMutableTransaction mtx(tx_); - - LogPrint("zrpcunsafe", "%s: creating joinsplit at index %d (vpub_old=%s, vpub_new=%s, in[0]=%s, in[1]=%s, out[0]=%s, out[1]=%s)\n", - getId(), - tx_.vjoinsplit.size(), - FormatMoney(info.vpub_old), FormatMoney(info.vpub_new), - FormatMoney(info.vjsin[0].note.value()), FormatMoney(info.vjsin[1].note.value()), - FormatMoney(info.vjsout[0].value), FormatMoney(info.vjsout[1].value) - ); - - // Generate the proof, this can take over a minute. - std::array inputs - {info.vjsin[0], info.vjsin[1]}; - std::array outputs - {info.vjsout[0], info.vjsout[1]}; - - std::array inputMap; - std::array outputMap; - - uint256 esk; // payment disclosure - secret - - JSDescription jsdesc = JSDescription::Randomized( - mtx.fOverwintered && (mtx.nVersion >= SAPLING_TX_VERSION), - *pzcashParams, - joinSplitPubKey_, - anchor, - inputs, - outputs, - inputMap, - outputMap, - info.vpub_old, - info.vpub_new, - !this->testmode, - &esk); // parameter expects pointer to esk, so pass in address - { - auto verifier = libzcash::ProofVerifier::Strict(); - if (!(jsdesc.Verify(*pzcashParams, verifier, joinSplitPubKey_))) { - throw std::runtime_error("error verifying joinsplit"); - } - } - - mtx.vjoinsplit.push_back(jsdesc); - - // Empty output script. - CScript scriptCode; - CTransaction signTx(mtx); - uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); - - // Add the signature - if (!(crypto_sign_detached(&mtx.joinSplitSig[0], NULL, - dataToBeSigned.begin(), 32, - joinSplitPrivKey_ - ) == 0)) - { - throw std::runtime_error("crypto_sign_detached failed"); - } - - // Sanity check - if (!(crypto_sign_verify_detached(&mtx.joinSplitSig[0], - dataToBeSigned.begin(), 32, - mtx.joinSplitPubKey.begin() - ) == 0)) - { - throw std::runtime_error("crypto_sign_verify_detached failed"); - } - - CTransaction rawTx(mtx); - tx_ = rawTx; - - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << rawTx; - - std::string encryptedNote1; - std::string encryptedNote2; - { - CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION); - ss2 << ((unsigned char) 0x00); - ss2 << jsdesc.ephemeralKey; - ss2 << jsdesc.ciphertexts[0]; - ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey_); - - encryptedNote1 = HexStr(ss2.begin(), ss2.end()); - } - { - CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION); - ss2 << ((unsigned char) 0x01); - ss2 << jsdesc.ephemeralKey; - ss2 << jsdesc.ciphertexts[1]; - ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey_); - - encryptedNote2 = HexStr(ss2.begin(), ss2.end()); - } - - UniValue arrInputMap(UniValue::VARR); - UniValue arrOutputMap(UniValue::VARR); - for (size_t i = 0; i < ZC_NUM_JS_INPUTS; i++) { - arrInputMap.push_back(static_cast(inputMap[i])); - } - for (size_t i = 0; i < ZC_NUM_JS_OUTPUTS; i++) { - arrOutputMap.push_back(static_cast(outputMap[i])); - } - - // !!! Payment disclosure START - unsigned char buffer[32] = {0}; - memcpy(&buffer[0], &joinSplitPrivKey_[0], 32); // private key in first half of 64 byte buffer - std::vector vch(&buffer[0], &buffer[0] + 32); - uint256 joinSplitPrivKey = uint256(vch); - size_t js_index = tx_.vjoinsplit.size() - 1; - uint256 placeholder; - for (int i = 0; i < ZC_NUM_JS_OUTPUTS; i++) { - uint8_t mapped_index = outputMap[i]; - // placeholder for txid will be filled in later when tx has been finalized and signed. - PaymentDisclosureKey pdKey = {placeholder, js_index, mapped_index}; - JSOutput output = outputs[mapped_index]; - libzcash::SproutPaymentAddress zaddr = output.addr; // randomized output - PaymentDisclosureInfo pdInfo = {PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL, esk, joinSplitPrivKey, zaddr}; - paymentDisclosureData_.push_back(PaymentDisclosureKeyInfo(pdKey, pdInfo)); - - LogPrint("paymentdisclosure", "%s: Payment Disclosure: js=%d, n=%d, zaddr=%s\n", getId(), js_index, int(mapped_index), EncodePaymentAddress(zaddr)); - } - // !!! Payment disclosure END - - UniValue obj(UniValue::VOBJ); - obj.push_back(Pair("encryptednote1", encryptedNote1)); - obj.push_back(Pair("encryptednote2", encryptedNote2)); - obj.push_back(Pair("rawtxn", HexStr(ss.begin(), ss.end()))); - obj.push_back(Pair("inputmap", arrInputMap)); - obj.push_back(Pair("outputmap", arrOutputMap)); - return obj; -} - /** * Override getStatus() to append the operation's context object to the default status object. */ diff --git a/src/wallet/asyncrpcoperation_shieldcoinbase.h b/src/wallet/asyncrpcoperation_shieldcoinbase.h index b3fef0fc1..3eb1a6cfc 100644 --- a/src/wallet/asyncrpcoperation_shieldcoinbase.h +++ b/src/wallet/asyncrpcoperation_shieldcoinbase.h @@ -1,4 +1,5 @@ // Copyright (c) 2017 The Zcash 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. @@ -33,8 +34,6 @@ #include -#include "paymentdisclosure.h" - // Default transaction fee if caller does not specify one. #define SHIELD_COINBASE_DEFAULT_MINERS_FEE 10000 @@ -80,8 +79,6 @@ public: bool testmode = false; // Set to true to disable sending txs and generating proofs bool cheatSpend = false; // set when this is shielding a cheating coinbase - bool paymentDisclosureMode = true; // Set to true to save esk for encrypted notes in payment disclosure database. - private: friend class ShieldToAddress; friend class TEST_FRIEND_AsyncRPCOperation_shieldcoinbase; // class for unit testing @@ -109,9 +106,6 @@ private: void lock_utxos(); void unlock_utxos(); - - // payment disclosure! - std::vector paymentDisclosureData_; }; class ShieldToAddress : public boost::static_visitor @@ -123,7 +117,6 @@ public: ShieldToAddress(AsyncRPCOperation_shieldcoinbase *op, CAmount sendAmount) : m_op(op), sendAmount(sendAmount) {} - bool operator()(const libzcash::SproutPaymentAddress &zaddr) const; bool operator()(const libzcash::SaplingPaymentAddress &zaddr) const; bool operator()(const libzcash::InvalidEncoding& no) const; }; diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp index 38aff1a04..9d11a55fe 100644 --- a/src/wallet/crypter.cpp +++ b/src/wallet/crypter.cpp @@ -1,6 +1,7 @@ // Copyright (c) 2009-2013 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. +// file COPYING or https://www.opensource.org/licenses/mit-license.php /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * @@ -168,22 +169,6 @@ static bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector& vchCryptedSecret, - const libzcash::SproutPaymentAddress& address, - libzcash::SproutSpendingKey& sk) -{ - CKeyingMaterial vchSecret; - if (!DecryptSecret(vMasterKey, vchCryptedSecret, address.GetHash(), vchSecret)) - return false; - - if (vchSecret.size() != libzcash::SerializedSproutSpendingKeySize) - return false; - - CSecureDataStream ss(vchSecret, SER_NETWORK, PROTOCOL_VERSION); - ss >> sk; - return sk.address() == address; -} static bool DecryptSaplingSpendingKey(const CKeyingMaterial& vMasterKey, const std::vector& vchCryptedSecret, @@ -207,7 +192,7 @@ bool CCryptoKeyStore::SetCrypted() LOCK2(cs_KeyStore, cs_SpendingKeyStore); if (fUseCrypto) return true; - if (!(mapKeys.empty() && mapSproutSpendingKeys.empty() && mapSaplingSpendingKeys.empty())) + if (!(mapKeys.empty() && mapSaplingSpendingKeys.empty())) return false; fUseCrypto = true; return true; @@ -260,21 +245,6 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn) if (fDecryptionThoroughlyChecked) break; } - CryptedSproutSpendingKeyMap::const_iterator miSprout = mapCryptedSproutSpendingKeys.begin(); - for (; miSprout != mapCryptedSproutSpendingKeys.end(); ++miSprout) - { - const libzcash::SproutPaymentAddress &address = (*miSprout).first; - const std::vector &vchCryptedSecret = (*miSprout).second; - libzcash::SproutSpendingKey sk; - if (!DecryptSproutSpendingKey(vMasterKeyIn, vchCryptedSecret, address, sk)) - { - keyFail = true; - break; - } - keyPass = true; - if (fDecryptionThoroughlyChecked) - break; - } CryptedSaplingSpendingKeyMap::const_iterator miSapling = mapCryptedSaplingSpendingKeys.begin(); for (; miSapling != mapCryptedSaplingSpendingKeys.end(); ++miSapling) { @@ -292,7 +262,7 @@ bool CCryptoKeyStore::Unlock(const CKeyingMaterial& vMasterKeyIn) } if (keyPass && keyFail) { - LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n"); + LogPrintf("Oh shit! The wallet is probably corrupted: Some keys decrypt but not all.\n"); assert(false); } if (keyFail || !keyPass) @@ -440,30 +410,6 @@ bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) co return false; } -bool CCryptoKeyStore::AddSproutSpendingKey(const libzcash::SproutSpendingKey &sk) -{ - { - LOCK(cs_SpendingKeyStore); - if (!IsCrypted()) - return CBasicKeyStore::AddSproutSpendingKey(sk); - - if (IsLocked()) - return false; - - std::vector vchCryptedSecret; - CSecureDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << sk; - CKeyingMaterial vchSecret(ss.begin(), ss.end()); - auto address = sk.address(); - if (!EncryptSecret(vMasterKey, vchSecret, address.GetHash(), vchCryptedSecret)) - return false; - - if (!AddCryptedSproutSpendingKey(address, sk.receiving_key(), vchCryptedSecret)) - return false; - } - return true; -} - bool CCryptoKeyStore::AddSaplingSpendingKey( const libzcash::SaplingExtendedSpendingKey &sk, const libzcash::SaplingPaymentAddress &defaultAddr) @@ -494,22 +440,6 @@ bool CCryptoKeyStore::AddSaplingSpendingKey( return true; } -bool CCryptoKeyStore::AddCryptedSproutSpendingKey( - const libzcash::SproutPaymentAddress &address, - const libzcash::ReceivingKey &rk, - const std::vector &vchCryptedSecret) -{ - { - LOCK(cs_SpendingKeyStore); - if (!SetCrypted()) - return false; - - mapCryptedSproutSpendingKeys[address] = vchCryptedSecret; - mapNoteDecryptors.insert(std::make_pair(address, ZCNoteDecryption(rk))); - } - return true; -} - bool CCryptoKeyStore::AddCryptedSaplingSpendingKey( const libzcash::SaplingExtendedFullViewingKey &extfvk, const std::vector &vchCryptedSecret, @@ -531,23 +461,6 @@ bool CCryptoKeyStore::AddCryptedSaplingSpendingKey( return true; } -bool CCryptoKeyStore::GetSproutSpendingKey(const libzcash::SproutPaymentAddress &address, libzcash::SproutSpendingKey &skOut) const -{ - { - LOCK(cs_SpendingKeyStore); - if (!IsCrypted()) - return CBasicKeyStore::GetSproutSpendingKey(address, skOut); - - CryptedSproutSpendingKeyMap::const_iterator mi = mapCryptedSproutSpendingKeys.find(address); - if (mi != mapCryptedSproutSpendingKeys.end()) - { - const std::vector &vchCryptedSecret = (*mi).second; - return DecryptSproutSpendingKey(vMasterKey, vchCryptedSecret, address, skOut); - } - } - return false; -} - bool CCryptoKeyStore::GetSaplingSpendingKey(const libzcash::SaplingFullViewingKey &fvk, libzcash::SaplingExtendedSpendingKey &skOut) const { { @@ -603,22 +516,6 @@ bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn) } } mapKeys.clear(); - BOOST_FOREACH(SproutSpendingKeyMap::value_type& mSproutSpendingKey, mapSproutSpendingKeys) - { - const libzcash::SproutSpendingKey &sk = mSproutSpendingKey.second; - CSecureDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << sk; - CKeyingMaterial vchSecret(ss.begin(), ss.end()); - libzcash::SproutPaymentAddress address = sk.address(); - std::vector vchCryptedSecret; - if (!EncryptSecret(vMasterKeyIn, vchSecret, address.GetHash(), vchCryptedSecret)) { - return false; - } - if (!AddCryptedSproutSpendingKey(address, sk.receiving_key(), vchCryptedSecret)) { - return false; - } - } - mapSproutSpendingKeys.clear(); //! Sapling key support BOOST_FOREACH(SaplingSpendingKeyMap::value_type& mSaplingSpendingKey, mapSaplingSpendingKeys) { diff --git a/src/wallet/crypter.h b/src/wallet/crypter.h index f42a762af..8a7de32b4 100644 --- a/src/wallet/crypter.h +++ b/src/wallet/crypter.h @@ -1,4 +1,5 @@ // 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. @@ -145,7 +146,7 @@ class CCryptoKeyStore : public CBasicKeyStore private: std::pair> cryptedHDSeed; CryptedKeyMap mapCryptedKeys; - CryptedSproutSpendingKeyMap mapCryptedSproutSpendingKeys; + //CryptedSproutSpendingKeyMap mapCryptedSproutSpendingKeys; CryptedSaplingSpendingKeyMap mapCryptedSaplingSpendingKeys; CKeyingMaterial vMasterKey; @@ -223,37 +224,6 @@ public: mi++; } } - virtual bool AddCryptedSproutSpendingKey( - const libzcash::SproutPaymentAddress &address, - const libzcash::ReceivingKey &rk, - const std::vector &vchCryptedSecret); - bool AddSproutSpendingKey(const libzcash::SproutSpendingKey &sk); - bool HaveSproutSpendingKey(const libzcash::SproutPaymentAddress &address) const - { - { - LOCK(cs_SpendingKeyStore); - if (!IsCrypted()) - return CBasicKeyStore::HaveSproutSpendingKey(address); - return mapCryptedSproutSpendingKeys.count(address) > 0; - } - return false; - } - bool GetSproutSpendingKey(const libzcash::SproutPaymentAddress &address, libzcash::SproutSpendingKey &skOut) const; - void GetSproutPaymentAddresses(std::set &setAddress) const - { - if (!IsCrypted()) - { - CBasicKeyStore::GetSproutPaymentAddresses(setAddress); - return; - } - setAddress.clear(); - CryptedSproutSpendingKeyMap::const_iterator mi = mapCryptedSproutSpendingKeys.begin(); - while (mi != mapCryptedSproutSpendingKeys.end()) - { - setAddress.insert((*mi).first); - mi++; - } - } //! Sapling virtual bool AddCryptedSaplingSpendingKey( const libzcash::SaplingExtendedFullViewingKey &extfvk, diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index dd0880b75..1814e9209 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -105,7 +105,7 @@ bool CDBEnv::Open(const boost::filesystem::path& pathIn) nEnvFlags |= DB_PRIVATE; dbenv->set_lg_dir(pathLogDir.string().c_str()); - dbenv->set_cachesize(0, 0x100000, 1); // 1 MiB should be enough for just the wallet + dbenv->set_cachesize(1, 0x100000, 1); // 1 MiB should be enough for just the wallet, Increased by 1 GB dbenv->set_lg_bsize(0x10000); dbenv->set_lg_max(1048576); dbenv->set_lk_max_locks(40000); @@ -181,6 +181,55 @@ CDBEnv::VerifyResult CDBEnv::Verify(const std::string& strFile, bool (*recoverFu return (fRecovered ? RECOVER_OK : RECOVER_FAIL); } +bool CDBEnv::Compact(const std::string& strFile) +{ + LOCK(cs_db); + + DB_COMPACT dbcompact; + dbcompact.compact_fillpercent = 80; + dbcompact.compact_pages = DB_MAX_PAGES; + dbcompact.compact_timeout = 0; + + DB_COMPACT *pdbcompact; + pdbcompact = &dbcompact; + + int result = 1; + if (mapDb[strFile] != NULL) { + Db* pdb = mapDb[strFile]; + result = pdb->compact(NULL, NULL, NULL, pdbcompact, DB_FREE_SPACE, NULL); + delete pdb; + mapDb[strFile] = NULL; + + switch (result) + { + case DB_LOCK_DEADLOCK: + LogPrint("db","Deadlock %i\n", result); + break; + case DB_LOCK_NOTGRANTED: + LogPrint("db","Lock Not Granted %i\n", result); + break; + case DB_REP_HANDLE_DEAD: + LogPrint("db","Handle Dead %i\n", result); + break; + case DB_REP_LOCKOUT: + LogPrint("db","Rep Lockout %i\n", result); + break; + case EACCES: + LogPrint("db","Eacces %i\n", result); + break; + case EINVAL: + LogPrint("db","Error Invalid %i\n", result); + break; + case 0: + LogPrint("db","Wallet Compact Sucessful\n"); + break; + default: + LogPrint("db","Compact result int %i\n", result); + } + } + return (result == 0); +} + bool CDBEnv::Salvage(const std::string& strFile, bool fAggressive, std::vector& vResult) { LOCK(cs_db); diff --git a/src/wallet/db.h b/src/wallet/db.h index 8ad246de4..31ba88f11 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -88,6 +88,7 @@ public: * NOTE: reads the entire database into memory, so cannot be used * for huge databases. */ + bool Compact(const std::string& strFile); typedef std::pair, std::vector > KeyValPair; bool Salvage(const std::string& strFile, bool fAggressive, std::vector& vResult); diff --git a/src/wallet/gtest/test_wallet.cpp b/src/wallet/gtest/test_wallet.cpp index 676239d0b..6373b6e9f 100644 --- a/src/wallet/gtest/test_wallet.cpp +++ b/src/wallet/gtest/test_wallet.cpp @@ -53,12 +53,10 @@ public: return CCryptoKeyStore::Unlock(vMasterKeyIn); } - void IncrementNoteWitnesses(const CBlockIndex* pindex, - const CBlock* pblock, - SproutMerkleTree& sproutTree, - SaplingMerkleTree& saplingTree) { - CWallet::IncrementNoteWitnesses(pindex, pblock, sproutTree, saplingTree); + void BuildWitnessCache(const CBlockIndex* pindex, bool witnessOnly) { + CWallet::BuildWitnessCache(pindex, witnessOnly); } + void DecrementNoteWitnesses(const CBlockIndex* pindex) { CWallet::DecrementNoteWitnesses(pindex); } @@ -77,11 +75,6 @@ CWalletTx GetValidReceive(const libzcash::SproutSpendingKey& sk, CAmount value, return GetValidReceive(*params, sk, value, randomInputs, version); } -libzcash::SproutNote GetNote(const libzcash::SproutSpendingKey& sk, - const CTransaction& tx, size_t js, size_t n) { - return GetNote(*params, sk, tx, js, n); -} - CWalletTx GetValidSpend(const libzcash::SproutSpendingKey& sk, const libzcash::SproutNote& note, CAmount value) { return GetValidSpend(*params, sk, note, value); @@ -116,7 +109,7 @@ std::pair CreateValidBlock(TestWallet& wallet, wallet.AddToWallet(wtx, true, NULL); block.vtx.push_back(wtx); - wallet.IncrementNoteWitnesses(&index, &block, sproutTree, saplingTree); + wallet.BuildWitnessCache(&index, false); return std::make_pair(jsoutpt, saplingNotes[0]); } @@ -141,341 +134,8 @@ TEST(WalletTests, SetupDatadirLocationRunAsFirstTest) { boost::filesystem::create_directories(pathTemp); mapArgs["-datadir"] = pathTemp.string(); } +/* -TEST(WalletTests, SproutNoteDataSerialisation) { - auto sk = libzcash::SproutSpendingKey::random(); - auto wtx = GetValidReceive(sk, 10, true); - auto note = GetNote(sk, wtx, 0, 1); - auto nullifier = note.nullifier(sk); - - mapSproutNoteData_t noteData; - JSOutPoint jsoutpt {wtx.GetHash(), 0, 1}; - SproutNoteData nd {sk.address(), nullifier}; - SproutMerkleTree tree; - nd.witnesses.push_front(tree.witness()); - noteData[jsoutpt] = nd; - - CDataStream ss(SER_DISK, CLIENT_VERSION); - ss << noteData; - - mapSproutNoteData_t noteData2; - ss >> noteData2; - - EXPECT_EQ(noteData, noteData2); - EXPECT_EQ(noteData[jsoutpt].witnesses, noteData2[jsoutpt].witnesses); -} - - -TEST(WalletTests, FindUnspentSproutNotes) { - SelectParams(CBaseChainParams::TESTNET); - CWallet wallet; - auto sk = libzcash::SproutSpendingKey::random(); - wallet.AddSproutSpendingKey(sk); - - auto wtx = GetValidReceive(sk, 10, true); - auto note = GetNote(sk, wtx, 0, 1); - auto nullifier = note.nullifier(sk); - - mapSproutNoteData_t noteData; - JSOutPoint jsoutpt {wtx.GetHash(), 0, 1}; - SproutNoteData nd {sk.address(), nullifier}; - noteData[jsoutpt] = nd; - - wtx.SetSproutNoteData(noteData); - wallet.AddToWallet(wtx, true, NULL); - EXPECT_FALSE(wallet.IsSproutSpent(nullifier)); - - // We currently have an unspent and unconfirmed note in the wallet (depth of -1) - std::vector sproutEntries; - std::vector saplingEntries; - wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 0); - EXPECT_EQ(0, sproutEntries.size()); - sproutEntries.clear(); - saplingEntries.clear(); - wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", -1); - EXPECT_EQ(1, sproutEntries.size()); - sproutEntries.clear(); - saplingEntries.clear(); - - // Fake-mine the transaction - EXPECT_EQ(-1, chainActive.Height()); - CBlock block; - block.vtx.push_back(wtx); - block.hashMerkleRoot = block.BuildMerkleTree(); - auto blockHash = block.GetHash(); - CBlockIndex fakeIndex {block}; - mapBlockIndex.insert(std::make_pair(blockHash, &fakeIndex)); - chainActive.SetTip(&fakeIndex); - EXPECT_TRUE(chainActive.Contains(&fakeIndex)); - EXPECT_EQ(0, chainActive.Height()); - - wtx.SetMerkleBranch(block); - wallet.AddToWallet(wtx, true, NULL); - EXPECT_FALSE(wallet.IsSproutSpent(nullifier)); - - - // We now have an unspent and confirmed note in the wallet (depth of 1) - wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 0); - EXPECT_EQ(1, sproutEntries.size()); - sproutEntries.clear(); - saplingEntries.clear(); - wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 1); - EXPECT_EQ(1, sproutEntries.size()); - sproutEntries.clear(); - saplingEntries.clear(); - wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 2); - EXPECT_EQ(0, sproutEntries.size()); - sproutEntries.clear(); - saplingEntries.clear(); - - - // Let's spend the note. - auto wtx2 = GetValidSpend(sk, note, 5); - wallet.AddToWallet(wtx2, true, NULL); - EXPECT_FALSE(wallet.IsSproutSpent(nullifier)); - - // Fake-mine a spend transaction - EXPECT_EQ(0, chainActive.Height()); - CBlock block2; - block2.vtx.push_back(wtx2); - block2.hashMerkleRoot = block2.BuildMerkleTree(); - block2.hashPrevBlock = blockHash; - auto blockHash2 = block2.GetHash(); - CBlockIndex fakeIndex2 {block2}; - mapBlockIndex.insert(std::make_pair(blockHash2, &fakeIndex2)); - fakeIndex2.SetHeight(1); - chainActive.SetTip(&fakeIndex2); - EXPECT_TRUE(chainActive.Contains(&fakeIndex2)); - EXPECT_EQ(1, chainActive.Height()); - - wtx2.SetMerkleBranch(block2); - wallet.AddToWallet(wtx2, true, NULL); - EXPECT_TRUE(wallet.IsSproutSpent(nullifier)); - - // The note has been spent. By default, GetFilteredNotes() ignores spent notes. - wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 0); - EXPECT_EQ(0, sproutEntries.size()); - sproutEntries.clear(); - saplingEntries.clear(); - // Let's include spent notes to retrieve it. - wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 0, false); - EXPECT_EQ(1, sproutEntries.size()); - sproutEntries.clear(); - saplingEntries.clear(); - // The spent note has two confirmations. - wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 2, false); - EXPECT_EQ(1, sproutEntries.size()); - sproutEntries.clear(); - saplingEntries.clear(); - // It does not have 3 confirmations. - wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 3, false); - EXPECT_EQ(0, sproutEntries.size()); - sproutEntries.clear(); - saplingEntries.clear(); - - - // Let's receive a new note - CWalletTx wtx3; - { - auto wtx = GetValidReceive(sk, 20, true); - auto note = GetNote(sk, wtx, 0, 1); - auto nullifier = note.nullifier(sk); - - mapSproutNoteData_t noteData; - JSOutPoint jsoutpt {wtx.GetHash(), 0, 1}; - SproutNoteData nd {sk.address(), nullifier}; - noteData[jsoutpt] = nd; - - wtx.SetSproutNoteData(noteData); - wallet.AddToWallet(wtx, true, NULL); - EXPECT_FALSE(wallet.IsSproutSpent(nullifier)); - - wtx3 = wtx; - } - - // Fake-mine the new transaction - EXPECT_EQ(1, chainActive.Height()); - CBlock block3; - block3.vtx.push_back(wtx3); - block3.hashMerkleRoot = block3.BuildMerkleTree(); - block3.hashPrevBlock = blockHash2; - auto blockHash3 = block3.GetHash(); - CBlockIndex fakeIndex3 {block3}; - mapBlockIndex.insert(std::make_pair(blockHash3, &fakeIndex3)); - fakeIndex3.SetHeight(2); - chainActive.SetTip(&fakeIndex3); - EXPECT_TRUE(chainActive.Contains(&fakeIndex3)); - EXPECT_EQ(2, chainActive.Height()); - - wtx3.SetMerkleBranch(block3); - wallet.AddToWallet(wtx3, true, NULL); - - // We now have an unspent note which has one confirmation, in addition to our spent note. - wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 1); - EXPECT_EQ(1, sproutEntries.size()); - sproutEntries.clear(); - saplingEntries.clear(); - // Let's return the spent note too. - wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 1, false); - EXPECT_EQ(2, sproutEntries.size()); - sproutEntries.clear(); - saplingEntries.clear(); - // Increasing number of confirmations will exclude our new unspent note. - wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 2, false); - EXPECT_EQ(1, sproutEntries.size()); - sproutEntries.clear(); - saplingEntries.clear(); - // If we also ignore spent notes at this depth, we won't find any notes. - wallet.GetFilteredNotes(sproutEntries, saplingEntries, "", 2, true); - EXPECT_EQ(0, sproutEntries.size()); - sproutEntries.clear(); - saplingEntries.clear(); - - // Tear down - chainActive.SetTip(NULL); - mapBlockIndex.erase(blockHash); - mapBlockIndex.erase(blockHash2); - mapBlockIndex.erase(blockHash3); -} - - -TEST(WalletTests, SetSproutNoteAddrsInCWalletTx) { - auto sk = libzcash::SproutSpendingKey::random(); - auto wtx = GetValidReceive(sk, 10, true); - auto note = GetNote(sk, wtx, 0, 1); - auto nullifier = note.nullifier(sk); - EXPECT_EQ(0, wtx.mapSproutNoteData.size()); - - mapSproutNoteData_t noteData; - JSOutPoint jsoutpt {wtx.GetHash(), 0, 1}; - SproutNoteData nd {sk.address(), nullifier}; - noteData[jsoutpt] = nd; - - wtx.SetSproutNoteData(noteData); - EXPECT_EQ(noteData, wtx.mapSproutNoteData); -} - -TEST(WalletTests, SetSaplingNoteAddrsInCWalletTx) { - SelectParams(CBaseChainParams::REGTEST); - UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); - UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); - auto consensusParams = Params().GetConsensus(); - - TestWallet wallet; - - std::vector> rawSeed(32); - HDSeed seed(rawSeed); - auto sk = libzcash::SaplingExtendedSpendingKey::Master(seed); - auto expsk = sk.expsk; - auto fvk = expsk.full_viewing_key(); - auto ivk = fvk.in_viewing_key(); - auto pk = sk.DefaultAddress(); - - libzcash::SaplingNote note(pk, 50000); - auto cm = note.cm().get(); - SaplingMerkleTree tree; - tree.append(cm); - auto anchor = tree.root(); - auto witness = tree.witness(); - - auto nf = note.nullifier(fvk, witness.position()); - ASSERT_TRUE(nf); - uint256 nullifier = nf.get(); - - auto builder = TransactionBuilder(consensusParams, 1); - ASSERT_TRUE(builder.AddSaplingSpend(expsk, note, anchor, witness)); - builder.AddSaplingOutput(fvk.ovk, pk, 50000, {}); - builder.SetFee(0); - auto maybe_tx = builder.Build(); - ASSERT_EQ(static_cast(maybe_tx), true); - auto tx = maybe_tx.get(); - - CWalletTx wtx {&wallet, tx}; - - EXPECT_EQ(0, wtx.mapSaplingNoteData.size()); - mapSaplingNoteData_t noteData; - - SaplingOutPoint op {wtx.GetHash(), 0}; - SaplingNoteData nd; - nd.nullifier = nullifier; - nd.ivk = ivk; - nd.witnesses.push_front(witness); - nd.witnessHeight = 123; - noteData.insert(std::make_pair(op, nd)); - - wtx.SetSaplingNoteData(noteData); - EXPECT_EQ(noteData, wtx.mapSaplingNoteData); - - // Test individual fields in case equality operator is defined/changed. - EXPECT_EQ(ivk, wtx.mapSaplingNoteData[op].ivk); - EXPECT_EQ(nullifier, wtx.mapSaplingNoteData[op].nullifier); - EXPECT_EQ(nd.witnessHeight, wtx.mapSaplingNoteData[op].witnessHeight); - EXPECT_TRUE(witness == wtx.mapSaplingNoteData[op].witnesses.front()); - - // Revert to default - UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); - UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); -} - -TEST(WalletTests, SetSproutInvalidNoteAddrsInCWalletTx) { - CWalletTx wtx; - EXPECT_EQ(0, wtx.mapSproutNoteData.size()); - - mapSproutNoteData_t noteData; - auto sk = libzcash::SproutSpendingKey::random(); - JSOutPoint jsoutpt {wtx.GetHash(), 0, 1}; - SproutNoteData nd {sk.address(), uint256()}; - noteData[jsoutpt] = nd; - - EXPECT_THROW(wtx.SetSproutNoteData(noteData), std::logic_error); -} - -// The following test is the same as SetInvalidSaplingNoteDataInCWalletTx -// TEST(WalletTests, SetSaplingInvalidNoteAddrsInCWalletTx) - -// Cannot add note data for an index which does not exist in tx.vShieldedOutput -TEST(WalletTests, SetInvalidSaplingNoteDataInCWalletTx) { - CWalletTx wtx; - EXPECT_EQ(0, wtx.mapSaplingNoteData.size()); - - mapSaplingNoteData_t noteData; - SaplingOutPoint op {uint256(), 1}; - SaplingNoteData nd; - noteData.insert(std::make_pair(op, nd)); - - EXPECT_THROW(wtx.SetSaplingNoteData(noteData), std::logic_error); -} - -TEST(WalletTests, GetSproutNoteNullifier) { - CWallet wallet; - - auto sk = libzcash::SproutSpendingKey::random(); - auto address = sk.address(); - auto dec = ZCNoteDecryption(sk.receiving_key()); - - auto wtx = GetValidReceive(sk, 10, true); - auto note = GetNote(sk, wtx, 0, 1); - auto nullifier = note.nullifier(sk); - - auto hSig = wtx.vjoinsplit[0].h_sig( - *params, wtx.joinSplitPubKey); - - auto ret = wallet.GetSproutNoteNullifier( - wtx.vjoinsplit[0], - address, - dec, - hSig, 1); - EXPECT_NE(nullifier, ret); - - wallet.AddSproutSpendingKey(sk); - - ret = wallet.GetSproutNoteNullifier( - wtx.vjoinsplit[0], - address, - dec, - hSig, 1); - EXPECT_EQ(nullifier, ret); -} TEST(WalletTests, FindMySaplingNotes) { SelectParams(CBaseChainParams::REGTEST); @@ -579,92 +239,6 @@ TEST(WalletTests, FindMySaplingNotesWithIvkOnly) { UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); } -TEST(WalletTests, FindMySproutNotes) { - CWallet wallet; - - auto sk = libzcash::SproutSpendingKey::random(); - auto sk2 = libzcash::SproutSpendingKey::random(); - wallet.AddSproutSpendingKey(sk2); - - auto wtx = GetValidReceive(sk, 10, true); - auto note = GetNote(sk, wtx, 0, 1); - auto nullifier = note.nullifier(sk); - - auto noteMap = wallet.FindMySproutNotes(wtx); - EXPECT_EQ(0, noteMap.size()); - - wallet.AddSproutSpendingKey(sk); - - noteMap = wallet.FindMySproutNotes(wtx); - EXPECT_EQ(2, noteMap.size()); - - JSOutPoint jsoutpt {wtx.GetHash(), 0, 1}; - SproutNoteData nd {sk.address(), nullifier}; - EXPECT_EQ(1, noteMap.count(jsoutpt)); - EXPECT_EQ(nd, noteMap[jsoutpt]); -} - -TEST(WalletTests, FindMySproutNotesInEncryptedWallet) { - TestWallet wallet; - uint256 r {GetRandHash()}; - CKeyingMaterial vMasterKey (r.begin(), r.end()); - - auto sk = libzcash::SproutSpendingKey::random(); - wallet.AddSproutSpendingKey(sk); - - ASSERT_TRUE(wallet.EncryptKeys(vMasterKey)); - - auto wtx = GetValidReceive(sk, 10, true); - auto note = GetNote(sk, wtx, 0, 1); - auto nullifier = note.nullifier(sk); - - auto noteMap = wallet.FindMySproutNotes(wtx); - EXPECT_EQ(2, noteMap.size()); - - JSOutPoint jsoutpt {wtx.GetHash(), 0, 1}; - SproutNoteData nd {sk.address(), nullifier}; - EXPECT_EQ(1, noteMap.count(jsoutpt)); - EXPECT_NE(nd, noteMap[jsoutpt]); - - ASSERT_TRUE(wallet.Unlock(vMasterKey)); - - noteMap = wallet.FindMySproutNotes(wtx); - EXPECT_EQ(2, noteMap.size()); - EXPECT_EQ(1, noteMap.count(jsoutpt)); - EXPECT_EQ(nd, noteMap[jsoutpt]); -} - -TEST(WalletTests, GetConflictedSproutNotes) { - CWallet wallet; - - auto sk = libzcash::SproutSpendingKey::random(); - wallet.AddSproutSpendingKey(sk); - - auto wtx = GetValidReceive(sk, 10, true); - auto note = GetNote(sk, wtx, 0, 1); - auto nullifier = note.nullifier(sk); - - auto wtx2 = GetValidSpend(sk, note, 5); - auto wtx3 = GetValidSpend(sk, note, 10); - auto hash2 = wtx2.GetHash(); - auto hash3 = wtx3.GetHash(); - - // No conflicts for no spends - EXPECT_EQ(0, wallet.GetConflicts(hash2).size()); - wallet.AddToWallet(wtx, true, NULL); - EXPECT_EQ(0, wallet.GetConflicts(hash2).size()); - - // No conflicts for one spend - wallet.AddToWallet(wtx2, true, NULL); - EXPECT_EQ(0, wallet.GetConflicts(hash2).size()); - - // Conflicts for two spends - wallet.AddToWallet(wtx3, true, NULL); - auto c3 = wallet.GetConflicts(hash2); - EXPECT_EQ(2, c3.size()); - EXPECT_EQ(std::set({hash2, hash3}), c3); -} - // Generate note A and spend to create note B, from which we spend to create two conflicting transactions TEST(WalletTests, GetConflictedSaplingNotes) { SelectParams(CBaseChainParams::REGTEST); @@ -724,8 +298,8 @@ TEST(WalletTests, GetConflictedSaplingNotes) { wallet.AddToWallet(wtx, true, NULL); // Simulate receiving new block and ChainTip signal - wallet.IncrementNoteWitnesses(&fakeIndex, &block, sproutTree, saplingTree); - wallet.UpdateSaplingNullifierNoteMapForBlock(&block); + wallet.BuildWitnessCache(&fakeIndex, false); + wallet.UpdateNullifierNoteMapForBlock(&block); // Retrieve the updated wtx from wallet uint256 hash = wtx.GetHash(); @@ -1008,8 +582,8 @@ TEST(WalletTests, NavigateFromSaplingNullifierToNote) { } // Simulate receiving new block and ChainTip signal - wallet.IncrementNoteWitnesses(&fakeIndex, &block, sproutTree, saplingTree); - wallet.UpdateSaplingNullifierNoteMapForBlock(&block); + wallet.BuildWitnessCache(&fakeIndex, false); + wallet.UpdateNullifierNoteMapForBlock(&block); // Retrieve the updated wtx from wallet uint256 hash = wtx.GetHash(); @@ -1126,8 +700,8 @@ TEST(WalletTests, SpentSaplingNoteIsFromMe) { // Simulate receiving new block and ChainTip signal. // This triggers calculation of nullifiers for notes belonging to this wallet // in the output descriptions of wtx. - wallet.IncrementNoteWitnesses(&fakeIndex, &block, sproutTree, saplingTree); - wallet.UpdateSaplingNullifierNoteMapForBlock(&block); + wallet.BuildWitnessCache(&fakeIndex, false); + wallet.UpdateNullifierNoteMapForBlock(&block); // Retrieve the updated wtx from wallet wtx = wallet.mapWallet[wtx.GetHash()]; @@ -1263,7 +837,7 @@ TEST(WalletTests, CachedWitnessesEmptyChain) { CBlockIndex index(block); SproutMerkleTree sproutTree; SaplingMerkleTree saplingTree; - wallet.IncrementNoteWitnesses(&index, &block, sproutTree, saplingTree); + wallet.BuildWitnessCache(&index, false); ::GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses); @@ -1354,7 +928,7 @@ TEST(WalletTests, CachedWitnessesChainTip) { EXPECT_NE(anchors1.second, anchors3.second); // Re-incrementing with the same block should give the same result - wallet.IncrementNoteWitnesses(&index2, &block2, sproutTree, saplingTree); + wallet.BuildWitnessCache(&index2, false); auto anchors4 = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses); EXPECT_NE(anchors4.first, anchors4.second); @@ -1364,7 +938,7 @@ TEST(WalletTests, CachedWitnessesChainTip) { EXPECT_EQ(anchors2.second, anchors4.second); // Incrementing with the same block again should not change the cache - wallet.IncrementNoteWitnesses(&index2, &block2, sproutTree, saplingTree); + wallet.BuildWitnessCache(&index2, false); std::vector> sproutWitnesses5; std::vector> saplingWitnesses5; @@ -1447,7 +1021,7 @@ TEST(WalletTests, CachedWitnessesDecrementFirst) { EXPECT_NE(anchors2.second, anchors4.second); // Re-incrementing with the same block should give the same result - wallet.IncrementNoteWitnesses(&index2, &block2, sproutTree, saplingTree); + wallet.BuildWitnessCache(&index2, false); auto anchors5 = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses); @@ -1504,7 +1078,7 @@ TEST(WalletTests, CachedWitnessesCleanIndex) { for (size_t i = 0; i < numBlocks; i++) { SproutMerkleTree sproutRiPrevTree {sproutRiTree}; SaplingMerkleTree saplingRiPrevTree {saplingRiTree}; - wallet.IncrementNoteWitnesses(&(indices[i]), &(blocks[i]), sproutRiTree, saplingRiTree); + wallet.BuildWitnessCache(&indices[i], false); auto anchors = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses); for (size_t j = 0; j < numBlocks; j++) { @@ -1531,7 +1105,7 @@ TEST(WalletTests, CachedWitnessesCleanIndex) { } { - wallet.IncrementNoteWitnesses(&(indices[i]), &(blocks[i]), sproutRiPrevTree, saplingRiPrevTree); + wallet.BuildWitnessCache(&indices[i], false); auto anchors = GetWitnessesAndAnchors(wallet, sproutNotes, saplingNotes, sproutWitnesses, saplingWitnesses); for (size_t j = 0; j < numBlocks; j++) { EXPECT_TRUE((bool) sproutWitnesses[j]); @@ -1737,88 +1311,6 @@ TEST(WalletTests, SetBestChainIgnoresTxsWithoutShieldedData) { wallet.SetBestChain(walletdb, loc); } -TEST(WalletTests, UpdateSproutNullifierNoteMap) { - TestWallet wallet; - uint256 r {GetRandHash()}; - CKeyingMaterial vMasterKey (r.begin(), r.end()); - - auto sk = libzcash::SproutSpendingKey::random(); - wallet.AddSproutSpendingKey(sk); - - ASSERT_TRUE(wallet.EncryptKeys(vMasterKey)); - - auto wtx = GetValidReceive(sk, 10, true); - auto note = GetNote(sk, wtx, 0, 1); - auto nullifier = note.nullifier(sk); - - // Pretend that we called FindMySproutNotes while the wallet was locked - mapSproutNoteData_t noteData; - JSOutPoint jsoutpt {wtx.GetHash(), 0, 1}; - SproutNoteData nd {sk.address()}; - noteData[jsoutpt] = nd; - wtx.SetSproutNoteData(noteData); - - wallet.AddToWallet(wtx, true, NULL); - EXPECT_EQ(0, wallet.mapSproutNullifiersToNotes.count(nullifier)); - - EXPECT_FALSE(wallet.UpdateNullifierNoteMap()); - - ASSERT_TRUE(wallet.Unlock(vMasterKey)); - - EXPECT_TRUE(wallet.UpdateNullifierNoteMap()); - EXPECT_EQ(1, wallet.mapSproutNullifiersToNotes.count(nullifier)); - EXPECT_EQ(wtx.GetHash(), wallet.mapSproutNullifiersToNotes[nullifier].hash); - EXPECT_EQ(0, wallet.mapSproutNullifiersToNotes[nullifier].js); - EXPECT_EQ(1, wallet.mapSproutNullifiersToNotes[nullifier].n); -} - -TEST(WalletTests, UpdatedSproutNoteData) { - TestWallet wallet; - - auto sk = libzcash::SproutSpendingKey::random(); - wallet.AddSproutSpendingKey(sk); - - auto wtx = GetValidReceive(sk, 10, true); - auto note = GetNote(sk, wtx, 0, 0); - auto note2 = GetNote(sk, wtx, 0, 1); - auto nullifier = note.nullifier(sk); - auto nullifier2 = note2.nullifier(sk); - auto wtx2 = wtx; - - // First pretend we added the tx to the wallet and - // we don't have the key for the second note - mapSproutNoteData_t noteData; - JSOutPoint jsoutpt {wtx.GetHash(), 0, 0}; - SproutNoteData nd {sk.address(), nullifier}; - noteData[jsoutpt] = nd; - wtx.SetSproutNoteData(noteData); - - // Pretend we mined the tx by adding a fake witness - SproutMerkleTree tree; - wtx.mapSproutNoteData[jsoutpt].witnesses.push_front(tree.witness()); - wtx.mapSproutNoteData[jsoutpt].witnessHeight = 100; - - // Now pretend we added the key for the second note, and - // the tx was "added" to the wallet again to update it. - // This happens via the 'z_importkey' RPC method. - JSOutPoint jsoutpt2 {wtx2.GetHash(), 0, 1}; - SproutNoteData nd2 {sk.address(), nullifier2}; - noteData[jsoutpt2] = nd2; - wtx2.SetSproutNoteData(noteData); - - // The txs should initially be different - EXPECT_NE(wtx.mapSproutNoteData, wtx2.mapSproutNoteData); - EXPECT_EQ(1, wtx.mapSproutNoteData[jsoutpt].witnesses.size()); - EXPECT_EQ(100, wtx.mapSproutNoteData[jsoutpt].witnessHeight); - - // After updating, they should be the same - EXPECT_TRUE(wallet.UpdatedNoteData(wtx2, wtx)); - EXPECT_EQ(wtx.mapSproutNoteData, wtx2.mapSproutNoteData); - EXPECT_EQ(1, wtx.mapSproutNoteData[jsoutpt].witnesses.size()); - EXPECT_EQ(100, wtx.mapSproutNoteData[jsoutpt].witnessHeight); - // TODO: The new note should get witnessed (but maybe not here) (#1350) -} - TEST(WalletTests, UpdatedSaplingNoteData) { SelectParams(CBaseChainParams::REGTEST); UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); @@ -1886,8 +1378,8 @@ TEST(WalletTests, UpdatedSaplingNoteData) { wallet.AddToWallet(wtx, true, NULL); // Simulate receiving new block and ChainTip signal - wallet.IncrementNoteWitnesses(&fakeIndex, &block, sproutTree, saplingTree); - wallet.UpdateSaplingNullifierNoteMapForBlock(&block); + wallet.BuildWitnessCache(&fakeIndex, false); + wallet.UpdateNullifierNoteMapForBlock(&block); // Retrieve the updated wtx from wallet uint256 hash = wtx.GetHash(); @@ -1915,7 +1407,7 @@ TEST(WalletTests, UpdatedSaplingNoteData) { EXPECT_EQ(2, wtx2.mapSaplingNoteData.size()); EXPECT_EQ(1, wtx2.mapSaplingNoteData[sop0].witnesses.size()); // wtx2 has fake witness for payment output - EXPECT_EQ(0, wtx2.mapSaplingNoteData[sop1].witnesses.size()); // wtx2 never had incrementnotewitness called + EXPECT_EQ(0, wtx2.mapSaplingNoteData[sop1].witnesses.size()); // wtx2 never had BuildWitnessCache called // After updating, they should be the same EXPECT_TRUE(wallet.UpdatedNoteData(wtx2, wtx)); @@ -1943,37 +1435,6 @@ TEST(WalletTests, UpdatedSaplingNoteData) { UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); } -TEST(WalletTests, MarkAffectedSproutTransactionsDirty) { - TestWallet wallet; - - auto sk = libzcash::SproutSpendingKey::random(); - wallet.AddSproutSpendingKey(sk); - - auto wtx = GetValidReceive(sk, 10, true); - auto hash = wtx.GetHash(); - auto note = GetNote(sk, wtx, 0, 1); - auto nullifier = note.nullifier(sk); - auto wtx2 = GetValidSpend(sk, note, 5); - - mapSproutNoteData_t noteData; - JSOutPoint jsoutpt {hash, 0, 1}; - SproutNoteData nd {sk.address(), nullifier}; - noteData[jsoutpt] = nd; - - wtx.SetSproutNoteData(noteData); - wallet.AddToWallet(wtx, true, NULL); - wallet.MarkAffectedTransactionsDirty(wtx); - - // After getting a cached value, the first tx should be clean - wallet.mapWallet[hash].GetDebit(ISMINE_ALL); - EXPECT_TRUE(wallet.mapWallet[hash].fDebitCached); - - // After adding the note spend, the first tx should be dirty - wallet.AddToWallet(wtx2, true, NULL); - wallet.MarkAffectedTransactionsDirty(wtx2); - EXPECT_FALSE(wallet.mapWallet[hash].fDebitCached); -} - TEST(WalletTests, MarkAffectedSaplingTransactionsDirty) { SelectParams(CBaseChainParams::REGTEST); UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); @@ -2001,7 +1462,7 @@ TEST(WalletTests, MarkAffectedSaplingTransactionsDirty) { auto scriptPubKey = GetScriptForDestination(tsk.GetPubKey().GetID()); // Generate shielding tx from transparent to Sapling - // 0.0005 t-ZEC in, 0.0004 z-ZEC out, 0.0001 t-ZEC fee + // 0.0005 t-HUSH in, 0.0004 z-HUSH out, 0.0001 t-HUSH fee auto builder = TransactionBuilder(consensusParams, 1, &keystore); builder.AddTransparentInput(COutPoint(), scriptPubKey, 50000); builder.AddSaplingOutput(fvk.ovk, pk, 40000, {}); @@ -2040,8 +1501,8 @@ TEST(WalletTests, MarkAffectedSaplingTransactionsDirty) { wallet.AddToWallet(wtx, true, NULL); // Simulate receiving new block and ChainTip signal - wallet.IncrementNoteWitnesses(&fakeIndex, &block, sproutTree, saplingTree); - wallet.UpdateSaplingNullifierNoteMapForBlock(&block); + wallet.BuildWitnessCache(&fakeIndex, false); + wallet.UpdateNullifierNoteMapForBlock(&block); // Retrieve the updated wtx from wallet uint256 hash = wtx.GetHash(); @@ -2095,39 +1556,7 @@ TEST(WalletTests, MarkAffectedSaplingTransactionsDirty) { UpdateNetworkUpgradeParameters(Consensus::UPGRADE_SAPLING, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); UpdateNetworkUpgradeParameters(Consensus::UPGRADE_OVERWINTER, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); } - -TEST(WalletTests, SproutNoteLocking) { - TestWallet wallet; - - auto sk = libzcash::SproutSpendingKey::random(); - wallet.AddSproutSpendingKey(sk); - - auto wtx = GetValidReceive(sk, 10, true); - auto wtx2 = GetValidReceive(sk, 10, true); - - JSOutPoint jsoutpt {wtx.GetHash(), 0, 0}; - JSOutPoint jsoutpt2 {wtx2.GetHash(),0, 0}; - - // Test selective locking - wallet.LockNote(jsoutpt); - EXPECT_TRUE(wallet.IsLockedNote(jsoutpt)); - EXPECT_FALSE(wallet.IsLockedNote(jsoutpt2)); - - // Test selective unlocking - wallet.UnlockNote(jsoutpt); - EXPECT_FALSE(wallet.IsLockedNote(jsoutpt)); - - // Test multiple locking - wallet.LockNote(jsoutpt); - wallet.LockNote(jsoutpt2); - EXPECT_TRUE(wallet.IsLockedNote(jsoutpt)); - EXPECT_TRUE(wallet.IsLockedNote(jsoutpt2)); - - // Test unlock all - wallet.UnlockAllSproutNotes(); - EXPECT_FALSE(wallet.IsLockedNote(jsoutpt)); - EXPECT_FALSE(wallet.IsLockedNote(jsoutpt2)); -} +*/ TEST(WalletTests, SaplingNoteLocking) { TestWallet wallet; diff --git a/src/wallet/gtest/test_wallet_zkeys.cpp b/src/wallet/gtest/test_wallet_zkeys.cpp index 365533b6c..7811c9c8a 100644 --- a/src/wallet/gtest/test_wallet_zkeys.cpp +++ b/src/wallet/gtest/test_wallet_zkeys.cpp @@ -106,303 +106,6 @@ TEST(wallet_zkeys_tests, StoreAndLoadSaplingZkeys) { EXPECT_TRUE(wallet.HaveSaplingIncomingViewingKey(dpa2)); } -/** - * This test covers methods on CWallet - * GenerateNewSproutZKey() - * AddSproutZKey() - * LoadZKey() - * LoadZKeyMetadata() - */ -TEST(wallet_zkeys_tests, store_and_load_zkeys) { - SelectParams(CBaseChainParams::MAIN); - - CWallet wallet; - - // wallet should be empty - std::set addrs; - wallet.GetSproutPaymentAddresses(addrs); - ASSERT_EQ(0, addrs.size()); - - // wallet should have one key - auto addr = wallet.GenerateNewSproutZKey(); - wallet.GetSproutPaymentAddresses(addrs); - ASSERT_EQ(1, addrs.size()); - - // verify wallet has spending key for the address - ASSERT_TRUE(wallet.HaveSproutSpendingKey(addr)); - - // manually add new spending key to wallet - auto sk = libzcash::SproutSpendingKey::random(); - ASSERT_TRUE(wallet.AddSproutZKey(sk)); - - // verify wallet did add it - addr = sk.address(); - ASSERT_TRUE(wallet.HaveSproutSpendingKey(addr)); - - // verify spending key stored correctly - libzcash::SproutSpendingKey keyOut; - wallet.GetSproutSpendingKey(addr, keyOut); - ASSERT_EQ(sk, keyOut); - - // verify there are two keys - wallet.GetSproutPaymentAddresses(addrs); - ASSERT_EQ(2, addrs.size()); - ASSERT_EQ(1, addrs.count(addr)); - - // Load a third key into the wallet - sk = libzcash::SproutSpendingKey::random(); - ASSERT_TRUE(wallet.LoadZKey(sk)); - - // attach metadata to this third key - addr = sk.address(); - int64_t now = GetTime(); - CKeyMetadata meta(now); - ASSERT_TRUE(wallet.LoadZKeyMetadata(addr, meta)); - - // check metadata is the same - CKeyMetadata m= wallet.mapSproutZKeyMetadata[addr]; - ASSERT_EQ(m.nCreateTime, now); -} - -/** - * This test covers methods on CWallet - * AddSproutViewingKey() - * RemoveSproutViewingKey() - * LoadSproutViewingKey() - */ -TEST(wallet_zkeys_tests, StoreAndLoadViewingKeys) { - SelectParams(CBaseChainParams::MAIN); - - CWallet wallet; - - // wallet should be empty - std::set addrs; - wallet.GetSproutPaymentAddresses(addrs); - ASSERT_EQ(0, addrs.size()); - - // manually add new viewing key to wallet - auto sk = libzcash::SproutSpendingKey::random(); - auto vk = sk.viewing_key(); - ASSERT_TRUE(wallet.AddSproutViewingKey(vk)); - - // verify wallet did add it - auto addr = sk.address(); - ASSERT_TRUE(wallet.HaveSproutViewingKey(addr)); - // and that we don't have the corresponding spending key - ASSERT_FALSE(wallet.HaveSproutSpendingKey(addr)); - - // verify viewing key stored correctly - libzcash::SproutViewingKey vkOut; - wallet.GetSproutViewingKey(addr, vkOut); - ASSERT_EQ(vk, vkOut); - - // Load a second viewing key into the wallet - auto sk2 = libzcash::SproutSpendingKey::random(); - ASSERT_TRUE(wallet.LoadSproutViewingKey(sk2.viewing_key())); - - // verify wallet did add it - auto addr2 = sk2.address(); - ASSERT_TRUE(wallet.HaveSproutViewingKey(addr2)); - ASSERT_FALSE(wallet.HaveSproutSpendingKey(addr2)); - - // Remove the first viewing key - ASSERT_TRUE(wallet.RemoveSproutViewingKey(vk)); - ASSERT_FALSE(wallet.HaveSproutViewingKey(addr)); - ASSERT_TRUE(wallet.HaveSproutViewingKey(addr2)); -} - -/** - * This test covers methods on CWalletDB - * WriteZKey() - */ -TEST(wallet_zkeys_tests, write_zkey_direct_to_db) { - SelectParams(CBaseChainParams::TESTNET); - - // Get temporary and unique path for file. - // Note: / operator to append paths - boost::filesystem::path pathTemp = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); - boost::filesystem::create_directories(pathTemp); - mapArgs["-datadir"] = pathTemp.string(); - - bool fFirstRun; - CWallet wallet("wallet.dat"); - ASSERT_EQ(DB_LOAD_OK, wallet.LoadWallet(fFirstRun)); - - // No default CPubKey set - ASSERT_TRUE(fFirstRun); - - // wallet should be empty - std::set addrs; - wallet.GetSproutPaymentAddresses(addrs); - ASSERT_EQ(0, addrs.size()); - - // Add random key to the wallet - auto paymentAddress = wallet.GenerateNewSproutZKey(); - - // wallet should have one key - wallet.GetSproutPaymentAddresses(addrs); - ASSERT_EQ(1, addrs.size()); - - // create random key and add it to database directly, bypassing wallet - auto sk = libzcash::SproutSpendingKey::random(); - auto addr = sk.address(); - int64_t now = GetTime(); - CKeyMetadata meta(now); - CWalletDB db("wallet.dat"); - db.WriteZKey(addr, sk, meta); - - // wallet should not be aware of key - ASSERT_FALSE(wallet.HaveSproutSpendingKey(addr)); - - // wallet sees one key - wallet.GetSproutPaymentAddresses(addrs); - ASSERT_EQ(1, addrs.size()); - - // wallet should have default metadata for addr with null createtime - CKeyMetadata m = wallet.mapSproutZKeyMetadata[addr]; - ASSERT_EQ(m.nCreateTime, 0); - ASSERT_NE(m.nCreateTime, now); - - // load the wallet again - ASSERT_EQ(DB_LOAD_OK, wallet.LoadWallet(fFirstRun)); - - // wallet can now see the spending key - ASSERT_TRUE(wallet.HaveSproutSpendingKey(addr)); - - // check key is the same - libzcash::SproutSpendingKey keyOut; - wallet.GetSproutSpendingKey(addr, keyOut); - ASSERT_EQ(sk, keyOut); - - // wallet should have two keys - wallet.GetSproutPaymentAddresses(addrs); - ASSERT_EQ(2, addrs.size()); - - // check metadata is now the same - m = wallet.mapSproutZKeyMetadata[addr]; - ASSERT_EQ(m.nCreateTime, now); -} - -/** - * This test covers methods on CWalletDB - * WriteSproutViewingKey() - */ -TEST(wallet_zkeys_tests, WriteViewingKeyDirectToDB) { - SelectParams(CBaseChainParams::TESTNET); - - // Get temporary and unique path for file. - // Note: / operator to append paths - boost::filesystem::path pathTemp = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); - boost::filesystem::create_directories(pathTemp); - mapArgs["-datadir"] = pathTemp.string(); - - bool fFirstRun; - CWallet wallet("wallet-vkey.dat"); - ASSERT_EQ(DB_LOAD_OK, wallet.LoadWallet(fFirstRun)); - - // No default CPubKey set - ASSERT_TRUE(fFirstRun); - - // create random viewing key and add it to database directly, bypassing wallet - auto sk = libzcash::SproutSpendingKey::random(); - auto vk = sk.viewing_key(); - auto addr = sk.address(); - int64_t now = GetTime(); - CKeyMetadata meta(now); - CWalletDB db("wallet-vkey.dat"); - db.WriteSproutViewingKey(vk); - - // wallet should not be aware of viewing key - ASSERT_FALSE(wallet.HaveSproutViewingKey(addr)); - - // load the wallet again - ASSERT_EQ(DB_LOAD_OK, wallet.LoadWallet(fFirstRun)); - - // wallet can now see the viewing key - ASSERT_TRUE(wallet.HaveSproutViewingKey(addr)); - - // check key is the same - libzcash::SproutViewingKey vkOut; - wallet.GetSproutViewingKey(addr, vkOut); - ASSERT_EQ(vk, vkOut); -} - - - -/** - * This test covers methods on CWalletDB to load/save crypted z keys. - */ -TEST(wallet_zkeys_tests, write_cryptedzkey_direct_to_db) { - SelectParams(CBaseChainParams::TESTNET); - - // Get temporary and unique path for file. - // Note: / operator to append paths - boost::filesystem::path pathTemp = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); - boost::filesystem::create_directories(pathTemp); - mapArgs["-datadir"] = pathTemp.string(); - - bool fFirstRun; - CWallet wallet("wallet_crypted.dat"); - ASSERT_EQ(DB_LOAD_OK, wallet.LoadWallet(fFirstRun)); - - // No default CPubKey set - ASSERT_TRUE(fFirstRun); - - // wallet should be empty - std::set addrs; - wallet.GetSproutPaymentAddresses(addrs); - ASSERT_EQ(0, addrs.size()); - - // Add random key to the wallet - auto paymentAddress = wallet.GenerateNewSproutZKey(); - - // wallet should have one key - wallet.GetSproutPaymentAddresses(addrs); - ASSERT_EQ(1, addrs.size()); - - // encrypt wallet - SecureString strWalletPass; - strWalletPass.reserve(100); - strWalletPass = "hello"; - ASSERT_TRUE(wallet.EncryptWallet(strWalletPass)); - - // adding a new key will fail as the wallet is locked - EXPECT_ANY_THROW(wallet.GenerateNewSproutZKey()); - - // unlock wallet and then add - wallet.Unlock(strWalletPass); - auto paymentAddress2 = wallet.GenerateNewSproutZKey(); - - // Create a new wallet from the existing wallet path - CWallet wallet2("wallet_crypted.dat"); - ASSERT_EQ(DB_LOAD_OK, wallet2.LoadWallet(fFirstRun)); - - // Confirm it's not the same as the other wallet - ASSERT_TRUE(&wallet != &wallet2); - - // wallet should have two keys - wallet2.GetSproutPaymentAddresses(addrs); - ASSERT_EQ(2, addrs.size()); - - // check we have entries for our payment addresses - ASSERT_TRUE(addrs.count(paymentAddress)); - ASSERT_TRUE(addrs.count(paymentAddress2)); - - // spending key is crypted, so we can't extract valid payment address - libzcash::SproutSpendingKey keyOut; - wallet2.GetSproutSpendingKey(paymentAddress, keyOut); - ASSERT_FALSE(paymentAddress == keyOut.address()); - - // unlock wallet to get spending keys and verify payment addresses - wallet2.Unlock(strWalletPass); - - wallet2.GetSproutSpendingKey(paymentAddress, keyOut); - ASSERT_EQ(paymentAddress, keyOut.address()); - - wallet2.GetSproutSpendingKey(paymentAddress2, keyOut); - ASSERT_EQ(paymentAddress2, keyOut.address()); -} - /** * This test covers methods on CWalletDB to load/save crypted sapling z keys. */ diff --git a/src/wallet/rpcdisclosure.cpp b/src/wallet/rpcdisclosure.cpp deleted file mode 100644 index cd0cc42a6..000000000 --- a/src/wallet/rpcdisclosure.cpp +++ /dev/null @@ -1,319 +0,0 @@ -// Copyright (c) 2017 The Zcash developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -/****************************************************************************** - * Copyright © 2014-2019 The SuperNET Developers. * - * * - * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * - * the top-level directory of this distribution for the individual copyright * - * holder information and the developer policies on copyright and licensing. * - * * - * Unless otherwise agreed in a custom licensing agreement, no part of the * - * SuperNET software, including this file may be copied, modified, propagated * - * or distributed except according to the terms contained in the LICENSE file * - * * - * Removal or modification of this copyright notice is prohibited. * - * * - ******************************************************************************/ - -#include "rpc/server.h" -#include "init.h" -#include "key_io.h" -#include "main.h" -#include "script/script.h" -#include "script/standard.h" -#include "sync.h" -#include "util.h" -#include "utiltime.h" -#include "wallet.h" - -#include -#include - -#include -#include - -#include - -#include "paymentdisclosure.h" -#include "paymentdisclosuredb.h" - -#include "zcash/Note.hpp" -#include "zcash/NoteEncryption.hpp" - -using namespace std; -using namespace libzcash; - -// Function declaration for function implemented in wallet/rpcwallet.cpp -bool EnsureWalletIsAvailable(bool avoidException); - -/** - * RPC call to generate a payment disclosure - */ -UniValue z_getpaymentdisclosure(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - if (!EnsureWalletIsAvailable(fHelp)) - return NullUniValue; - - string enableArg = "paymentdisclosure"; - auto fEnablePaymentDisclosure = fExperimentalMode && GetBoolArg("-" + enableArg, true); - string strPaymentDisclosureDisabledMsg = ""; - if (!fEnablePaymentDisclosure) { - strPaymentDisclosureDisabledMsg = experimentalDisabledHelpMsg("z_getpaymentdisclosure", enableArg); - } - - if (fHelp || params.size() < 3 || params.size() > 4 ) - throw runtime_error( - "z_getpaymentdisclosure \"txid\" \"js_index\" \"output_index\" (\"message\") \n" - "\nGenerate a payment disclosure for a given joinsplit output.\n" - "\nEXPERIMENTAL FEATURE\n" - + strPaymentDisclosureDisabledMsg + - "\nArguments:\n" - "1. \"txid\" (string, required) \n" - "2. \"js_index\" (string, required) \n" - "3. \"output_index\" (string, required) \n" - "4. \"message\" (string, optional) \n" - "\nResult:\n" - "\"paymentdisclosure\" (string) Hex data string, with \"zpd:\" prefix.\n" - "\nExamples:\n" - + HelpExampleCli("z_getpaymentdisclosure", "96f12882450429324d5f3b48630e3168220e49ab7b0f066e5c2935a6b88bb0f2 0 0 \"refund\"") - + HelpExampleRpc("z_getpaymentdisclosure", "\"96f12882450429324d5f3b48630e3168220e49ab7b0f066e5c2935a6b88bb0f2\", 0, 0, \"refund\"") - ); - - if (!fEnablePaymentDisclosure) { - throw JSONRPCError(RPC_WALLET_ERROR, "Error: payment disclosure is disabled."); - } - - LOCK2(cs_main, pwalletMain->cs_wallet); - - EnsureWalletIsUnlocked(); - - // Check wallet knows about txid - string txid = params[0].get_str(); - uint256 hash; - hash.SetHex(txid); - - CTransaction tx; - uint256 hashBlock; - - // Check txid has been seen - if (!GetTransaction(hash, tx, hashBlock, true)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); - } - - // Check tx has been confirmed - if (hashBlock.IsNull()) { - throw JSONRPCError(RPC_MISC_ERROR, "Transaction has not been confirmed yet"); - } - - // Check is mine - if (!pwalletMain->mapWallet.count(hash)) { - throw JSONRPCError(RPC_MISC_ERROR, "Transaction does not belong to the wallet"); - } - const CWalletTx& wtx = pwalletMain->mapWallet[hash]; - - // Check if shielded tx - if (wtx.vjoinsplit.empty()) { - throw JSONRPCError(RPC_MISC_ERROR, "Transaction is not a shielded transaction"); - } - - // Check js_index - int js_index = params[1].get_int(); - if (js_index < 0 || js_index >= wtx.vjoinsplit.size()) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid js_index"); - } - - // Check output_index - int output_index = params[2].get_int(); - if (output_index < 0 || output_index >= ZC_NUM_JS_OUTPUTS) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid output_index"); - } - - // Get message if it exists - string msg; - if (params.size() == 4) { - msg = params[3].get_str(); - } - - // Create PaymentDisclosureKey - PaymentDisclosureKey key = {hash, (size_t)js_index, (uint8_t)output_index }; - - // TODO: In future, perhaps init the DB in init.cpp - shared_ptr db = PaymentDisclosureDB::sharedInstance(); - PaymentDisclosureInfo info; - if (!db->Get(key, info)) { - throw JSONRPCError(RPC_DATABASE_ERROR, "Could not find payment disclosure info for the given joinsplit output"); - } - - PaymentDisclosure pd( wtx.joinSplitPubKey, key, info, msg ); - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << pd; - string strHex = HexStr(ss.begin(), ss.end()); - return PAYMENT_DISCLOSURE_BLOB_STRING_PREFIX + strHex; -} - - - -/** - * RPC call to validate a payment disclosure data blob. - */ -UniValue z_validatepaymentdisclosure(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - if (!EnsureWalletIsAvailable(fHelp)) - return NullUniValue; - - string enableArg = "paymentdisclosure"; - auto fEnablePaymentDisclosure = fExperimentalMode && GetBoolArg("-" + enableArg, true); - string strPaymentDisclosureDisabledMsg = ""; - if (!fEnablePaymentDisclosure) { - strPaymentDisclosureDisabledMsg = experimentalDisabledHelpMsg("z_validatepaymentdisclosure", enableArg); - } - - if (fHelp || params.size() != 1) - throw runtime_error( - "z_validatepaymentdisclosure \"paymentdisclosure\"\n" - "\nValidates a payment disclosure.\n" - "\nEXPERIMENTAL FEATURE\n" - + strPaymentDisclosureDisabledMsg + - "\nArguments:\n" - "1. \"paymentdisclosure\" (string, required) Hex data string, with \"zpd:\" prefix.\n" - "\nExamples:\n" - + HelpExampleCli("z_validatepaymentdisclosure", "\"zpd:706462ff004c561a0447ba2ec51184e6c204...\"") - + HelpExampleRpc("z_validatepaymentdisclosure", "\"zpd:706462ff004c561a0447ba2ec51184e6c204...\"") - ); - - if (!fEnablePaymentDisclosure) { - throw JSONRPCError(RPC_WALLET_ERROR, "Error: payment disclosure is disabled."); - } - - LOCK2(cs_main, pwalletMain->cs_wallet); - - EnsureWalletIsUnlocked(); - - // Verify the payment disclosure input begins with "zpd:" prefix. - string strInput = params[0].get_str(); - size_t pos = strInput.find(PAYMENT_DISCLOSURE_BLOB_STRING_PREFIX); - if (pos != 0) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, payment disclosure prefix not found."); - } - string hexInput = strInput.substr(strlen(PAYMENT_DISCLOSURE_BLOB_STRING_PREFIX)); - if (!IsHex(hexInput)) - { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected payment disclosure data in hexadecimal format."); - } - - // Unserialize the payment disclosure data into an object - PaymentDisclosure pd; - CDataStream ss(ParseHex(hexInput), SER_NETWORK, PROTOCOL_VERSION); - try { - ss >> pd; - // too much data is ignored, but if not enough data, exception of type ios_base::failure is thrown, - // CBaseDataStream::read(): end of data: iostream error - } catch (const std::exception &e) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, payment disclosure data is malformed."); - } - - if (pd.payload.marker != PAYMENT_DISCLOSURE_PAYLOAD_MAGIC_BYTES) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, payment disclosure marker not found."); - } - - if (pd.payload.version != PAYMENT_DISCLOSURE_VERSION_EXPERIMENTAL) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Payment disclosure version is unsupported."); - } - - uint256 hash = pd.payload.txid; - CTransaction tx; - uint256 hashBlock; - // Check if we have seen the transaction - if (!GetTransaction(hash, tx, hashBlock, true)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); - } - - // Check if the transaction has been confirmed - if (hashBlock.IsNull()) { - throw JSONRPCError(RPC_MISC_ERROR, "Transaction has not been confirmed yet"); - } - - // Check if shielded tx - if (tx.vjoinsplit.empty()) { - throw JSONRPCError(RPC_MISC_ERROR, "Transaction is not a shielded transaction"); - } - - UniValue errs(UniValue::VARR); - UniValue o(UniValue::VOBJ); - o.push_back(Pair("txid", pd.payload.txid.ToString())); - - // Check js_index - if (pd.payload.js >= tx.vjoinsplit.size()) { - errs.push_back("Payment disclosure refers to an invalid joinsplit index"); - } - o.push_back(Pair("jsIndex", pd.payload.js)); - - if (pd.payload.n < 0 || pd.payload.n >= ZC_NUM_JS_OUTPUTS) { - errs.push_back("Payment disclosure refers to an invalid output index"); - } - o.push_back(Pair("outputIndex", pd.payload.n)); - o.push_back(Pair("version", pd.payload.version)); - o.push_back(Pair("onetimePrivKey", pd.payload.esk.ToString())); - o.push_back(Pair("message", pd.payload.message)); - o.push_back(Pair("joinSplitPubKey", tx.joinSplitPubKey.ToString())); - - // Verify the payment disclosure was signed using the same key as the transaction i.e. the joinSplitPrivKey. - uint256 dataToBeSigned = SerializeHash(pd.payload, SER_GETHASH, 0); - bool sigVerified = (crypto_sign_verify_detached(pd.payloadSig.data(), - dataToBeSigned.begin(), 32, - tx.joinSplitPubKey.begin()) == 0); - o.push_back(Pair("signatureVerified", sigVerified)); - if (!sigVerified) { - errs.push_back("Payment disclosure signature does not match transaction signature"); - } - - // Check the payment address is valid - SproutPaymentAddress zaddr = pd.payload.zaddr; - { - o.push_back(Pair("paymentAddress", EncodePaymentAddress(zaddr))); - - try { - // Decrypt the note to get value and memo field - JSDescription jsdesc = tx.vjoinsplit[pd.payload.js]; - uint256 h_sig = jsdesc.h_sig(*pzcashParams, tx.joinSplitPubKey); - - ZCPaymentDisclosureNoteDecryption decrypter; - - ZCNoteEncryption::Ciphertext ciphertext = jsdesc.ciphertexts[pd.payload.n]; - - uint256 pk_enc = zaddr.pk_enc; - auto plaintext = decrypter.decryptWithEsk(ciphertext, pk_enc, pd.payload.esk, h_sig, pd.payload.n); - - CDataStream ssPlain(SER_NETWORK, PROTOCOL_VERSION); - ssPlain << plaintext; - SproutNotePlaintext npt; - ssPlain >> npt; - - string memoHexString = HexStr(npt.memo().data(), npt.memo().data() + npt.memo().size()); - o.push_back(Pair("memo", memoHexString)); - o.push_back(Pair("value", ValueFromAmount(npt.value()))); - - // Check the blockchain commitment matches decrypted note commitment - uint256 cm_blockchain = jsdesc.commitments[pd.payload.n]; - SproutNote note = npt.note(zaddr); - uint256 cm_decrypted = note.cm(); - bool cm_match = (cm_decrypted == cm_blockchain); - o.push_back(Pair("commitmentMatch", cm_match)); - if (!cm_match) { - errs.push_back("Commitment derived from payment disclosure does not match blockchain commitment"); - } - } catch (const std::exception &e) { - errs.push_back(string("Error while decrypting payment disclosure note: ") + string(e.what()) ); - } - } - - bool isValid = errs.empty(); - o.push_back(Pair("valid", isValid)); - if (!isValid) { - o.push_back(Pair("errors", errs)); - } - - return o; -} diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index b87672dc3..72af5d930 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -149,6 +149,43 @@ UniValue convertpassphrase(const UniValue& params, bool fHelp, const CPubKey& my return ret; } +UniValue rescan(const UniValue& params, bool fHelp, const CPubKey& mypk) +{ + //LOCK2(cs_main, pwalletMain->cs_wallet); + + if (!EnsureWalletIsAvailable(fHelp)) + return NullUniValue; + + if (fHelp || params.size() > 1) + throw runtime_error( + "rescan \"height\"\n" + "\nRescan all transactions from genesis or given block height.\n" + "\nArguments:\n" + "1. \"height\" (integer, optional) The block height to rescan from\n" + "\nExamples:\n" + "\nRescan from block height 555\n" + + HelpExampleCli("rescan", "\"555\"") + + "\nRescan from genesis block\n" + + HelpExampleCli("rescan","") + ); + + // Height to rescan from + int nRescanHeight = 0; + if (params.size() > 0) + nRescanHeight = params[0].get_int(); + if (nRescanHeight < 0 || nRescanHeight > chainActive.Height()) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range"); + } + + LogPrintf("Rescanning from height=%d\n", nRescanHeight); + //pwalletMain->ScanForWalletTransactions(chainActive[nRescanHeight],true); + bool update = false; + pwalletMain->ScanForWalletTransactions(chainActive.Genesis(),update); + //TODO: can we return something more useful? + return NullUniValue; +} + + UniValue importprivkey(const UniValue& params, bool fHelp, const CPubKey& mypk) { if (!EnsureWalletIsAvailable(fHelp)) @@ -666,18 +703,10 @@ UniValue dumpwallet_impl(const UniValue& params, bool fHelp, bool fDumpZKeys) file << "\n"; if (fDumpZKeys) { - std::set sproutAddresses; - pwalletMain->GetSproutPaymentAddresses(sproutAddresses); file << "\n"; file << "# Zkeys\n"; file << "\n"; - for (auto addr : sproutAddresses) { - libzcash::SproutSpendingKey key; - if (pwalletMain->GetSproutSpendingKey(addr, key)) { - std::string strTime = EncodeDumpTime(pwalletMain->mapSproutZKeyMetadata[addr].nCreateTime); - file << strprintf("%s %s # zaddr=%s\n", EncodeSpendingKey(key), strTime, EncodePaymentAddress(addr)); - } - } + std::set saplingAddresses; pwalletMain->GetSaplingPaymentAddresses(saplingAddresses); file << "\n"; @@ -864,48 +893,27 @@ UniValue z_importviewingkey(const UniValue& params, bool fHelp, const CPubKey& m throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid viewing key"); } - if (boost::get(&viewingkey) == nullptr) { - if (params.size() < 4) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Missing zaddr for Sapling viewing key."); - } - string strAddress = params[3].get_str(); - auto address = DecodePaymentAddress(strAddress); - if (!IsValidPaymentAddress(address)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr"); - } + if (params.size() < 4) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Missing zaddr for Sapling viewing key."); + } + string strAddress = params[3].get_str(); + auto address = DecodePaymentAddress(strAddress); + if (!IsValidPaymentAddress(address)) { + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr"); + } - auto addr = boost::get(address); - auto ivk = boost::get(viewingkey); + auto addr = boost::get(address); + auto ivk = boost::get(viewingkey); - if (pwalletMain->HaveSaplingIncomingViewingKey(addr)) { - if (fIgnoreExistingKey) { - return NullUniValue; - } - } else { - pwalletMain->MarkDirty(); - - if (!pwalletMain->AddSaplingIncomingViewingKey(ivk, addr)) { - throw JSONRPCError(RPC_WALLET_ERROR, "Error adding viewing key to wallet"); - } + if (pwalletMain->HaveSaplingIncomingViewingKey(addr)) { + if (fIgnoreExistingKey) { + return NullUniValue; } } else { - auto vkey = boost::get(viewingkey); - auto addr = vkey.address(); - if (pwalletMain->HaveSproutSpendingKey(addr)) { - throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this viewing key"); - } + pwalletMain->MarkDirty(); - // Don't throw error in case a viewing key is already there - if (pwalletMain->HaveSproutViewingKey(addr)) { - if (fIgnoreExistingKey) { - return NullUniValue; - } - } else { - pwalletMain->MarkDirty(); - - if (!pwalletMain->AddSproutViewingKey(vkey)) { - throw JSONRPCError(RPC_WALLET_ERROR, "Error adding viewing key to wallet"); - } + if (!pwalletMain->AddSaplingIncomingViewingKey(ivk, addr)) { + throw JSONRPCError(RPC_WALLET_ERROR, "Error adding viewing key to wallet"); } } @@ -985,26 +993,12 @@ UniValue z_exportviewingkey(const UniValue& params, bool fHelp, const CPubKey& m throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr"); } - if (boost::get(&address) == nullptr) { - auto addr = boost::get(address); - libzcash::SaplingIncomingViewingKey ivk; - if(!pwalletMain->GetSaplingIncomingViewingKey(addr, ivk)) { - throw JSONRPCError(RPC_WALLET_ERROR, "Wallet does not hold viewing key for this zaddr"); - } - return EncodeViewingKey(ivk); + auto addr = boost::get(address); + libzcash::SaplingIncomingViewingKey ivk; + if(!pwalletMain->GetSaplingIncomingViewingKey(addr, ivk)) { + throw JSONRPCError(RPC_WALLET_ERROR, "Wallet does not hold viewing key for this zaddr"); } - - auto addr = boost::get(address); - libzcash::SproutViewingKey vk; - if (!pwalletMain->GetSproutViewingKey(addr, vk)) { - libzcash::SproutSpendingKey k; - if (!pwalletMain->GetSproutSpendingKey(addr, k)) { - throw JSONRPCError(RPC_WALLET_ERROR, "Wallet does not hold private key or viewing key for this zaddr"); - } - vk = k.viewing_key(); - } - - return EncodeViewingKey(vk); + return EncodeViewingKey(ivk); } extern int32_t KOMODO_NSPV; diff --git a/src/wallet/rpchushwallet.cpp b/src/wallet/rpchushwallet.cpp new file mode 100644 index 000000000..64cd0e4a5 --- /dev/null +++ b/src/wallet/rpchushwallet.cpp @@ -0,0 +1,478 @@ +// Copyright (c) 2019-2020 The Hush developers +// Copyright (c) 2019 Cryptoforge +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "init.h" +#include "key_io.h" +#include "rpc/server.h" +#include "wallet.h" +#include "rpchushwallet.h" +#include "utilmoneystr.h" +#include + +using namespace std; +using namespace libzcash; + +bool EnsureWalletIsAvailable(bool avoidException); + +void zsTxSpendsToJSON(const CWalletTx& wtx, UniValue& spends, CAmount& totalSpends, CAmount& filteredSpends, const std::string& strAddress, bool filterByAddress) { + + LOCK2(cs_main, pwalletMain->cs_wallet); + + //Used to identify incomplete key sets + int vinCount = 0; + int vinSpendCount = 0; + int shieldedSpendCount = 0; + int shieldedSpendsSpentCount = 0; + + //Check address + bool isTAddress = false; + bool isZsAddress = false; + + CTxDestination tAddress = DecodeDestination(strAddress); + auto zAddress = DecodePaymentAddress(strAddress); + SaplingPaymentAddress zsAddress; + + if (filterByAddress) { + + if (IsValidDestination(tAddress)) + isTAddress = true; + + if (IsValidPaymentAddress(zAddress)) { + if (boost::get(&zAddress) != nullptr) { + zsAddress = boost::get(zAddress); + isZsAddress = true; + } + } + } + + + // Transparent Inputs belonging to the wallet + UniValue tSpends(UniValue::VARR); + if (isTAddress || !filterByAddress) { + for (int i = 0; i < wtx.vin.size(); i++) { + vinCount++; + const CTxIn& txin = wtx.vin[i]; + UniValue obj(UniValue::VOBJ); + CTxDestination address; + const CWalletTx* parent = pwalletMain->GetWalletTx(txin.prevout.hash); + if (parent != NULL) { + const CTxOut& parentOut = parent->vout[txin.prevout.n]; + ExtractDestination(parentOut.scriptPubKey, address); + if(IsMine(*pwalletMain, address)){ + vinSpendCount++; + totalSpends += CAmount(-parentOut.nValue); + obj.push_back(Pair("address",EncodeDestination(address))); + obj.push_back(Pair("scriptPubKey",HexStr(parentOut.scriptPubKey.begin(), parentOut.scriptPubKey.end()))); + obj.push_back(Pair("amount",ValueFromAmount(-parentOut.nValue))); + obj.push_back(Pair("spendTxid",parent->GetHash().ToString())); + obj.push_back(Pair("spendVout",(int)txin.prevout.n)); + CTxDestination filterAddress = DecodeDestination(strAddress); + if (address == tAddress || !filterByAddress) { + filteredSpends += CAmount(-parentOut.nValue); + tSpends.push_back(obj); + } + } + } + } + } + spends.push_back(Pair("transparentSpends",tSpends)); + + // Sapling Inputs belonging to the wallet + UniValue zsSpends(UniValue::VARR); + if (isZsAddress || !filterByAddress) { + for (int i = 0; i < wtx.vShieldedSpend.size(); i++) { + shieldedSpendCount++; + const SpendDescription& spendDesc = wtx.vShieldedSpend[i]; + UniValue obj(UniValue::VOBJ); + + SaplingOutPoint op = pwalletMain->mapSaplingNullifiersToNotes[spendDesc.nullifier]; + + if (pwalletMain->IsSaplingNullifierFromMe(spendDesc.nullifier)) { + const CWalletTx* parent = pwalletMain->GetWalletTx(pwalletMain->mapSaplingNullifiersToNotes[spendDesc.nullifier].hash); + const OutputDescription& output = parent->vShieldedOutput[op.n]; + auto nd = pwalletMain->mapWallet[pwalletMain->mapSaplingNullifiersToNotes[spendDesc.nullifier].hash].mapSaplingNoteData[op]; + auto pt = libzcash::SaplingNotePlaintext::decrypt(output.encCiphertext,nd.ivk,output.ephemeralKey,output.cm); + + if (pt) { + auto note = pt.get(); + auto pa = nd.ivk.address(note.d); + auto address = pa.get(); + shieldedSpendsSpentCount++; + totalSpends += CAmount(-note.value()); + obj.push_back(Pair("address",EncodePaymentAddress(address))); + obj.push_back(Pair("amount", ValueFromAmount(CAmount(-note.value())))); + obj.push_back(Pair("spendTxid",parent->GetHash().ToString())); + obj.push_back(Pair("spendshieldedOutputIndex",(int)op.n)); + if (address == zsAddress || !filterByAddress) { + filteredSpends += CAmount(-note.value()); + zsSpends.push_back(obj); + } + } + } + } + } + spends.push_back(Pair("saplingSpends",zsSpends)); + + + spends.push_back(Pair("totalSpends",ValueFromAmount(filteredSpends))); + + if (!filterByAddress) { + if (filteredSpends != 0 && (vinCount != vinSpendCount || shieldedSpendCount != shieldedSpendsSpentCount)) { + spends.push_back(Pair("missingSpendingKeys", true)); + spends.push_back(Pair("vinCount", vinCount)); + spends.push_back(Pair("vinSpendCount", vinSpendCount)); + spends.push_back(Pair("shieldedSpendCount", shieldedSpendCount)); + spends.push_back(Pair("shieldedSpendsSpentCount", shieldedSpendsSpentCount)); + } else { + spends.push_back(Pair("missingSpendingKeys", false)); + } + } +} + + +void zsTxReceivedToJSON(const CWalletTx& wtx, UniValue& received, CAmount& totalReceived, const std::string& strAddress, bool filterByAddress) { + + LOCK2(cs_main, pwalletMain->cs_wallet); + + //Check address + bool isTAddress = false; + bool isZsAddress = false; + + CTxDestination tAddress = DecodeDestination(strAddress); + auto zAddress = DecodePaymentAddress(strAddress); + SaplingPaymentAddress zsAddress; + + if (filterByAddress) { + + if (IsValidDestination(tAddress)) + isTAddress = true; + + if (IsValidPaymentAddress(zAddress)) { + if (boost::get(&zAddress) != nullptr) { + zsAddress = boost::get(zAddress); + isZsAddress = true; + } + } + } + + + //Transparent Received txos belonging to the wallet + UniValue tReceived(UniValue::VARR); + if (isTAddress || !filterByAddress) { + for (int i = 0; i < wtx.vout.size(); i++) { + const CTxOut& txout = wtx.vout[i]; + UniValue obj(UniValue::VOBJ); + CTxDestination address; + ExtractDestination(txout.scriptPubKey, address); + if(IsMine(*pwalletMain, address)){ + obj.push_back(Pair("address",EncodeDestination(address))); + obj.push_back(Pair("scriptPubKey",HexStr(txout.scriptPubKey.begin(), txout.scriptPubKey.end()))); + obj.push_back(Pair("amount",ValueFromAmount(txout.nValue))); + obj.push_back(Pair("vout", i)); + if (address == tAddress || !filterByAddress) { + totalReceived += CAmount(txout.nValue); + tReceived.push_back(obj); + } + } + } + } + received.push_back(Pair("transparentReceived",tReceived)); + + + //Sapling Sends belonging to the wallet + UniValue zsReceived(UniValue::VARR); + if (isZsAddress || !filterByAddress) { + for (int i = 0; i < wtx.vShieldedOutput.size(); i++) { + const OutputDescription& outputDesc = wtx.vShieldedOutput[i]; + UniValue obj(UniValue::VOBJ); + bool changeTx = false; + //Decrypt sapling incoming commitments using IVK + std::set addresses; + pwalletMain->GetSaplingPaymentAddresses(addresses); + for (auto addr : addresses) { + libzcash::SaplingExtendedSpendingKey extsk; + if (pwalletMain->GetSaplingExtendedSpendingKey(addr, extsk)) { + auto pt = libzcash::SaplingNotePlaintext::decrypt( + outputDesc.encCiphertext, extsk.expsk.full_viewing_key().in_viewing_key(), outputDesc.ephemeralKey, outputDesc.cm); + + if (pt) { + auto note = pt.get(); + obj.push_back(Pair("address",EncodePaymentAddress(addr))); + obj.push_back(Pair("amount", ValueFromAmount(CAmount(note.value())))); + obj.push_back(Pair("shieldedOutputIndex",i)); + + //Check Change Status + if (wtx.vShieldedSpend.size()!=0) { + std::set> nullifierSet; + nullifierSet = pwalletMain->GetNullifiersForAddresses({addr}); + BOOST_FOREACH(const SpendDescription& spendDesc, wtx.vShieldedSpend) { + if (nullifierSet.count(std::make_pair(addr, spendDesc.nullifier))) { + changeTx = true; + } + } + } + obj.push_back(Pair("change",changeTx)); + if (addr == zsAddress || !filterByAddress) { + totalReceived += CAmount(note.value()); + zsReceived.push_back(obj); + } + } + } + } + } + } + received.push_back(Pair("saplingReceived",zsReceived)); + + received.push_back(Pair("totalReceived",ValueFromAmount(totalReceived))); +} + + +void zsTxSendsToJSON(const CWalletTx& wtx, UniValue& sends, CAmount& totalSends, const std::string& strAddress, bool filterByAddress) { + + LOCK2(cs_main, pwalletMain->cs_wallet); + + //Used to identify incomplete key sets + int shieldedOutputCount = 0; + int shieldedOutputDecryptedCount = 0; + + //Check address + bool isTAddress = false; + bool isZsAddress = false; + + CTxDestination tAddress = DecodeDestination(strAddress); + auto zAddress = DecodePaymentAddress(strAddress); + SaplingPaymentAddress zsAddress; + + if (filterByAddress) { + + if (IsValidDestination(tAddress)) + isTAddress = true; + + if (IsValidPaymentAddress(zAddress)) { + if (boost::get(&zAddress) != nullptr) { + zsAddress = boost::get(zAddress); + isZsAddress = true; + } + } + } + + //All Transparent Sends in the transaction + + UniValue tSends(UniValue::VARR); + if (isTAddress || !filterByAddress) { + for (int i = 0; i < wtx.vout.size(); i++) { + const CTxOut& txout = wtx.vout[i]; + UniValue obj(UniValue::VOBJ); + CTxDestination address; + ExtractDestination(txout.scriptPubKey, address); + obj.push_back(Pair("address",EncodeDestination(address))); + obj.push_back(Pair("scriptPubKey",HexStr(txout.scriptPubKey.begin(), txout.scriptPubKey.end()))); + obj.push_back(Pair("amount",ValueFromAmount(-txout.nValue))); + obj.push_back(Pair("vout", i)); + if (address == tAddress || !filterByAddress) { + totalSends += CAmount(-txout.nValue); + tSends.push_back(obj); + } + } + } + sends.push_back(Pair("transparentSends",tSends)); + + //All Shielded Sends in the transaction + UniValue zsSends(UniValue::VARR); + if (isZsAddress || !filterByAddress) { + for (int i = 0; i < wtx.vShieldedOutput.size(); i++) { + const OutputDescription& outputDesc = wtx.vShieldedOutput[i]; + shieldedOutputCount++; + UniValue obj(UniValue::VOBJ); + bool changeTx = false; + + //Decrypt sapling outgoing t to z transaction using HDseed + if (wtx.vShieldedSpend.size()==0) { + HDSeed seed; + if (pwalletMain->GetHDSeed(seed)) { + auto opt = libzcash::SaplingOutgoingPlaintext::decrypt( + outputDesc.outCiphertext,ovkForShieldingFromTaddr(seed),outputDesc.cv,outputDesc.cm,outputDesc.ephemeralKey); + + if (opt) { + auto opt_unwrapped = opt.get(); + auto pt = libzcash::SaplingNotePlaintext::decrypt( + outputDesc.encCiphertext,outputDesc.ephemeralKey,opt_unwrapped.esk,opt_unwrapped.pk_d,outputDesc.cm); + + if (pt) { + shieldedOutputDecryptedCount++; + auto pt_unwrapped = pt.get(); + libzcash::SaplingPaymentAddress sentAddr(pt_unwrapped.d, opt_unwrapped.pk_d); + obj.push_back(Pair("address",EncodePaymentAddress(sentAddr))); + obj.push_back(Pair("amount", ValueFromAmount(CAmount(pt_unwrapped.value())))); + obj.push_back(Pair("shieldedOutputIndex",i)); + obj.push_back(Pair("change",false)); + if (sentAddr == zsAddress || !filterByAddress) { + totalSends += CAmount(-pt_unwrapped.value()); + zsSends.push_back(obj); + } + } + } + } + + //attempt Decryption of Outgoing Sapling using wallet extended spending keys + } else { + std::set addresses; + pwalletMain->GetSaplingPaymentAddresses(addresses); + for (auto addr : addresses) { + libzcash::SaplingExtendedSpendingKey extsk; + if (pwalletMain->GetSaplingExtendedSpendingKey(addr, extsk)) { + auto opt = libzcash::SaplingOutgoingPlaintext::decrypt( + outputDesc.outCiphertext,extsk.expsk.full_viewing_key().ovk,outputDesc.cv,outputDesc.cm,outputDesc.ephemeralKey); + + if (opt) { + auto opt_unwrapped = opt.get(); + auto pt = libzcash::SaplingNotePlaintext::decrypt( + outputDesc.encCiphertext,outputDesc.ephemeralKey,opt_unwrapped.esk,opt_unwrapped.pk_d,outputDesc.cm); + + if (pt) { + auto pt_unwrapped = pt.get(); + auto memo = pt_unwrapped.memo(); + shieldedOutputDecryptedCount++; + libzcash::SaplingPaymentAddress sentAddr(pt_unwrapped.d, opt_unwrapped.pk_d); + obj.push_back(Pair("address",EncodePaymentAddress(sentAddr))); + obj.push_back(Pair("amount", ValueFromAmount(CAmount(-pt_unwrapped.value())))); + obj.push_back(Pair("memo", HexStr(memo))); + + if (memo[0] <= 0xf4) { + auto end = std::find_if(memo.rbegin(), memo.rend(), [](unsigned char v) { return v != 0; }); + std::string memoStr(memo.begin(), end.base()); + if (utf8::is_valid(memoStr)) { + obj.push_back(Pair("memoStr", memoStr)); + } + } + obj.push_back(Pair("shieldedOutputIndex",i)); + + //Check Change Status + if (wtx.vShieldedSpend.size()!=0) { + std::set> nullifierSet; + nullifierSet = pwalletMain->GetNullifiersForAddresses({sentAddr}); + BOOST_FOREACH(const SpendDescription& spendDesc, wtx.vShieldedSpend) { + if (nullifierSet.count(std::make_pair(sentAddr, spendDesc.nullifier))) { + changeTx = true; + } + } + } + obj.push_back(Pair("change",changeTx)); + if (sentAddr == zsAddress || !filterByAddress) { + totalSends += CAmount(-pt_unwrapped.value()); + zsSends.push_back(obj); + } + } + } + } + } + } + } + } + sends.push_back(Pair("saplingSends",zsSends)); + + if (shieldedOutputCount != shieldedOutputDecryptedCount) { + sends.push_back(Pair("missingSaplingOVK", true)); + } else { + sends.push_back(Pair("missingSaplingOVK", false)); + } + + sends.push_back(Pair("totalSends",ValueFromAmount(totalSends))); +} + + +void zsWalletTxJSON(const CWalletTx& wtx, UniValue& ret, const std::string strAddress, bool fBool, const int returnType) { + + LOCK2(cs_main, pwalletMain->cs_wallet); + + //Track total wallet spend and received + CAmount totalSpends = 0; + CAmount filteredSpends = 0; + CAmount totalReceived = 0; + CAmount totalSends = 0; + + //Various Univalue to be added to the final transaction + UniValue spends(UniValue::VOBJ); + UniValue received(UniValue::VOBJ); + UniValue sends(UniValue::VOBJ); + UniValue tx(UniValue::VOBJ); + + //Begin Compiling the Decrypted Transaction + tx.push_back(Pair("txid", wtx.GetHash().ToString())); + if (wtx.IsCoinBase()) + { + tx.push_back(Pair("coinbase", true)); + if (wtx.GetDepthInMainChain() < 1) + tx.push_back(Pair("category", "orphan")); + else if (wtx.GetBlocksToMaturity() > 0) + tx.push_back(Pair("category", "immature")); + else + tx.push_back(Pair("category", "generate")); + } else { + tx.push_back(Pair("coinbase", false)); + tx.push_back(Pair("category", "standard")); + } + + tx.push_back(Pair("blockhash", wtx.hashBlock.GetHex())); + tx.push_back(Pair("blockindex", wtx.nIndex)); + int confirms = wtx.GetDepthInMainChain(); + if(confirms > 0) + { + tx.push_back(Pair("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime())); + } else { + tx.push_back(Pair("blocktime", 0)); + } + tx.push_back(Pair("expiryheight", (int64_t)wtx.nExpiryHeight)); + tx.push_back(Pair("confirmations", confirms)); + tx.push_back(Pair("time", wtx.GetTxTime())); + tx.push_back(Pair("size", static_cast(GetSerializeSize(static_cast(wtx), SER_NETWORK, PROTOCOL_VERSION)))); + + //Wallet Conflicts + UniValue conflicts(UniValue::VARR); + BOOST_FOREACH(const uint256& conflict, wtx.GetConflicts()) + conflicts.push_back(conflict.GetHex()); + tx.push_back(Pair("walletconflicts", conflicts)); + + // Return Type used to determine what is included in the transaction + // 0 Spends, Received and spends + // 1 Sends + // 2 Received + // 3 Spends + // TODO - Setup Enum, maybe... + + // Add Spends retrieved earlier + if (returnType != 2) { + zsTxSpendsToJSON(wtx, spends, totalSpends, filteredSpends, strAddress, fBool); + if ((!fBool || filteredSpends != 0) && (returnType == 0 || returnType == 1)) { + tx.push_back(Pair("spends",spends)); + } + } + // Get Received + if (returnType == 0 || returnType == 2) { + zsTxReceivedToJSON(wtx, received, totalReceived, strAddress, fBool); + if (!fBool || totalReceived != 0) { + tx.push_back(Pair("received",received)); + } + } + + // Get Sends + if (returnType == 0 || returnType == 3) { + //Only include sends if there are spends that belong to the wallet. + if (totalSpends != 0 || fBool) { + zsTxSendsToJSON(wtx, sends, totalSends, strAddress, fBool); + } + if (!fBool || totalSends != 0) { + tx.push_back(Pair("sends",sends)); + } + } + + if ((returnType == 0 && (!fBool || filteredSpends != 0 || totalReceived != 0 || totalSends != 0)) + || (returnType == 1 && (!fBool || filteredSpends != 0)) + || (returnType == 2 && (!fBool || totalReceived != 0)) + || (returnType == 3 && (!fBool || totalSends != 0))) { + ret.push_back(tx); + } + +} diff --git a/src/wallet/rpchushwallet.h b/src/wallet/rpchushwallet.h new file mode 100644 index 000000000..b9a6d6f6f --- /dev/null +++ b/src/wallet/rpchushwallet.h @@ -0,0 +1,22 @@ +// Copyright (c) 2020 The Hush developers +// Copyright (c) 2016 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_WALLET_RPCHUSHWALLET_H +#define BITCOIN_WALLET_RPCHUSHWALLET_H + +struct balancestruct { + CAmount confirmed; + CAmount unconfirmed; + CAmount locked; + CAmount immature; +}; + +void zsTxSpendsToJSON(const CWalletTx& wtx, UniValue& spends, CAmount& totalSpends, CAmount& filteredSpends, const std::string& strAddress, bool filterByAddress); +void zsTxReceivedToJSON(const CWalletTx& wtx, UniValue& received, CAmount& totalReceived, const std::string& strAddress, bool filterByAddress); +void zsTxSendsToJSON(const CWalletTx& wtx, UniValue& sends, CAmount& totalSends, const std::string& strAddress, bool filterByAddress); +void zsWalletTxJSON(const CWalletTx& wtx, UniValue& ret, const std::string strAddress, bool fBool, const int returnType); + + +#endif //BITCOIN_WALLET_RPCWALLET_H diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 2acd06b22..3425de1a8 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -38,6 +38,7 @@ #include "zcbenchmarks.h" #include "script/interpreter.h" #include "zcash/zip32.h" +#include "zcash/Note.hpp" #include "notaries_staked.h" #include "utiltime.h" @@ -62,7 +63,7 @@ #include "komodo_defs.h" #include -#include "sietch.h" +#include "rpchushwallet.h" using namespace std; @@ -70,14 +71,16 @@ using namespace libzcash; extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; extern std::string ASSETCHAINS_OVERRIDE_PUBKEY; -const std::string ADDR_TYPE_SAPLING = "sapling"; -const std::string ADDR_TYPE_DONOTREMEMBER = "donotremember"; +const std::string ADDR_TYPE_SAPLING = "sapling"; extern UniValue TxJoinSplitToJSON(const CTransaction& tx); extern int32_t KOMODO_INSYNC; uint32_t komodo_segid32(char *coinaddr); int32_t komodo_dpowconfs(int32_t height,int32_t numconfs); int32_t komodo_isnotaryvout(char *coinaddr,uint32_t tiptime); // from ac_private chains only CBlockIndex *komodo_getblockindex(uint256 hash); +extern string randomSietchZaddr(); +extern CAmount fConsolidationTxFee; +extern bool fZindex; int64_t nWalletUnlockTime; static CCriticalSection cs_nWalletUnlockTime; @@ -1342,7 +1345,7 @@ UniValue movecmd(const UniValue& params, bool fHelp, const CPubKey& mypk) if (!walletdb.TxnBegin()) throw JSONRPCError(RPC_DATABASE_ERROR, "database error"); - int64_t nNow = GetAdjustedTime(); + int64_t nNow = GetTime(); // Debit CAccountingEntry debit; @@ -3027,6 +3030,651 @@ uint64_t komodo_interestsum() return(0); } +/** + *Return current blockchain status, wallet balance, address balance and the last 200 transactions +**/ +UniValue getalldata(const UniValue& params, bool fHelp,const CPubKey&) +{ + if (fHelp || params.size() > 3) + throw runtime_error( + "getalldata \"datatype transactiontype \"\n" + "\n" + "This function only returns information on wallet addresses with full spending keys." + "\n" + "\nArguments:\n" + "1. \"datatype\" (integer, required) \n" + " Value of 0: Return address, balance, transactions and blockchain info\n" + " Value of 1: Return address, balance, blockchain info\n" + " Value of 2: Return transactions and blockchain info\n" + "2. \"transactiontype\" (integer, optional) \n" + " Value of 1: Return all transactions in the last 24 hours\n" + " Value of 2: Return all transactions in the last 7 days\n" + " Value of 3: Return all transactions in the last 30 days\n" + " Other number: Return all transactions in the last 24 hours\n" + "3. \"transactioncount\" (integer, optional) \n" + "\nResult:\n" + "\nExamples:\n" + + HelpExampleCli("getalldata", "0") + + HelpExampleRpc("getalldata", "0") + ); + + LOCK(cs_main); + + UniValue returnObj(UniValue::VOBJ); + int connectionCount = 0; + { + LOCK2(cs_main, cs_vNodes); + connectionCount = (int)vNodes.size(); + } + + LOCK2(cs_main, pwalletMain->cs_wallet); + int nMinDepth = 1; + + CAmount confirmed = 0; + CAmount unconfirmed = 0; + CAmount locked = 0; + CAmount immature = 0; + + CAmount privateConfirmed = 0; + CAmount privateUnconfirmed = 0; + CAmount privateLocked = 0; + CAmount privateImmature = 0; + + balancestruct txAmounts; + txAmounts.confirmed = 0; + txAmounts.unconfirmed = 0; + txAmounts.locked = 0; + txAmounts.immature = 0; + + + //Create map of addresses + //Add all Transaparent addresses to list + map addressBalances; + BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& item, pwalletMain->mapAddressBook) + { + string addressString = EncodeDestination(item.first); + if (addressBalances.count(addressString) == 0) + addressBalances.insert(make_pair(addressString,txAmounts)); + } + + //Add all Sapling addresses to map + std::set zs_addresses; + pwalletMain->GetSaplingPaymentAddresses(zs_addresses); + for (auto addr : zs_addresses) { + string addressString = EncodePaymentAddress(addr); + if (addressBalances.count(addressString) == 0) + addressBalances.insert(make_pair(addressString,txAmounts)); + } + + //Create Ordered List + map orderedTxs; + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { + const uint256& wtxid = it->first; + const CWalletTx& wtx = (*it).second; + orderedTxs.insert(std::pair(wtx.nOrderPos, wtx)); + + unsigned int txType = 0; + // 0 Unassigend + // 1 Immature + // 2 Unconfirmed + // 3 Locked + + if (!CheckFinalTx(wtx)) + continue; + + if (wtx.GetDepthInMainChain() < 0) + continue; + + if (wtx.mapSaplingNoteData.size() == 0 && !wtx.IsTrusted()) + continue; + + //Assign Immature + if (txType == 0 && wtx.IsCoinBase() && wtx.GetBlocksToMaturity() > 0) + txType = 1; + + //Assign Unconfirmed + if (txType == 0 && wtx.GetDepthInMainChain() == 0) + txType = 2; + + for (unsigned int i = 0; i < wtx.vout.size(); i++) { + + CTxDestination address; + if (!ExtractDestination(wtx.vout[i].scriptPubKey, address)) + continue; + + //excluded coins that we dont have the spending keys for + isminetype mine = IsMine(*pwalletMain,address); + if (mine != ISMINE_SPENDABLE) + continue; + + //Exclude spent coins + if (pwalletMain->IsSpent(wtxid, i)) + continue; + + //Assign locked + if (txType == 0 && pwalletMain->IsLockedCoin((*it).first, i)) + txType = 3; + + //Assign Locked to 10000 Zer inputs for Zeronodes + //if (txType == 0 && fZeroNode && wtx.vout[i].nValue == 10000 * COIN) + // txType = 3; + + string addressString = EncodeDestination(address); + if (addressBalances.count(addressString) == 0) + addressBalances.insert(make_pair(addressString,txAmounts)); + + if (txType == 0) { + addressBalances.at(addressString).confirmed += wtx.vout[i].nValue; + confirmed += wtx.vout[i].nValue; + } else if (txType == 1) { + addressBalances.at(addressString).immature+= wtx.vout[i].nValue; + immature += wtx.vout[i].nValue; + } else if (txType == 2) { + addressBalances.at(addressString).unconfirmed += wtx.vout[i].nValue; + unconfirmed += wtx.vout[i].nValue; + } else if (txType == 3) { + addressBalances.at(addressString).locked += wtx.vout[i].nValue; + locked += wtx.vout[i].nValue; + } + } + + for (auto & pair : wtx.mapSaplingNoteData) { + SaplingOutPoint op = pair.first; + SaplingNoteData nd = pair.second; + + //Skip Spent + if (nd.nullifier && pwalletMain->IsSaplingSpent(*nd.nullifier)) + continue; + + //Decrypt sapling incoming commitments using IVK + for (auto addr : zs_addresses) { + libzcash::SaplingExtendedSpendingKey extsk; + if (pwalletMain->GetSaplingExtendedSpendingKey(addr, extsk)) { + auto pt = libzcash::SaplingNotePlaintext::decrypt( + wtx.vShieldedOutput[op.n].encCiphertext,extsk.expsk.full_viewing_key().in_viewing_key(),wtx.vShieldedOutput[op.n].ephemeralKey,wtx.vShieldedOutput[op.n].cm); + + if (txType == 0 && pwalletMain->IsLockedNote(op)) + txType == 3; + + if (pt) { + auto note = pt.get(); + string addressString = EncodePaymentAddress(addr); + if (addressBalances.count(addressString) == 0) + addressBalances.insert(make_pair(addressString,txAmounts)); + + if (txType == 0) { + addressBalances.at(addressString).confirmed += note.value(); + privateConfirmed += note.value(); + } else if (txType == 1) { + addressBalances.at(addressString).immature += note.value(); + privateImmature += note.value(); + } else if (txType == 2) { + addressBalances.at(addressString).unconfirmed += note.value(); + privateUnconfirmed += note.value(); + } else if (txType == 3) { + addressBalances.at(addressString).locked += note.value(); + privateLocked += note.value(); + } + + continue; + + } + } + } + } + } + + + CAmount nBalance = 0; + CAmount nBalanceUnconfirmed = 0; + CAmount nBalanceTotal = 0; + CAmount totalBalance= confirmed + privateConfirmed; + CAmount totalUnconfirmed = unconfirmed + privateUnconfirmed; + + + returnObj.push_back(Pair("connectionCount", connectionCount)); + returnObj.push_back(Pair("besttime", chainActive.Tip()->GetBlockTime())); + returnObj.push_back(Pair("bestblockhash", chainActive.Tip()->GetBlockHash().GetHex())); + returnObj.push_back(Pair("transparentbalance", FormatMoney(confirmed))); + returnObj.push_back(Pair("transparentbalanceunconfirmed", FormatMoney(unconfirmed))); + returnObj.push_back(Pair("privatebalance", FormatMoney(privateConfirmed))); + returnObj.push_back(Pair("privatebalanceunconfirmed", FormatMoney(privateUnconfirmed))); + returnObj.push_back(Pair("totalbalance", FormatMoney(totalBalance))); + returnObj.push_back(Pair("totalunconfirmed", FormatMoney(totalUnconfirmed))); + returnObj.push_back(Pair("lockedbalance", FormatMoney(locked))); + returnObj.push_back(Pair("immaturebalance", FormatMoney(immature))); + + //get all t address + UniValue addressbalance(UniValue::VARR); + UniValue addrlist(UniValue::VOBJ); + + if (params.size() > 0 && (params[0].get_int() == 1 || params[0].get_int() == 0)) + { + for (map::iterator it = addressBalances.begin(); it != addressBalances.end(); ++it) { + UniValue addr(UniValue::VOBJ); + addr.push_back(Pair("amount", ValueFromAmount(it->second.confirmed))); + addr.push_back(Pair("unconfirmed", ValueFromAmount(it->second.unconfirmed))); + addr.push_back(Pair("locked", ValueFromAmount(it->second.locked))); + addr.push_back(Pair("immature", ValueFromAmount(it->second.immature))); + addr.push_back(Pair("ismine", true)); + addrlist.push_back(Pair(it->first, addr)); + } + } + + addressbalance.push_back(addrlist); + returnObj.push_back(Pair("addressbalance", addressbalance)); + + + //get transactions + int nCount = 200; + UniValue trans(UniValue::VARR); + UniValue transTime(UniValue::VARR); + + if (params.size() == 3) + { + nCount = params[2].get_int(); + } + + if (params.size() > 0 && (params[0].get_int() == 2 || params[0].get_int() == 0)) + { + int day = 365 * 30; //30 Years + if(params.size() > 1) + { + if(params[1].get_int() == 1) + { + day = 1; + } + else if(params[1].get_int() == 2) + { + day = 7; + } + else if(params[1].get_int() == 3) + { + day = 30; + } + else if(params[1].get_int() == 4) + { + day = 90; + } + else if(params[1].get_int() == 5) + { + day = 365; + } + } + + + uint64_t t = GetTime(); + for (map::reverse_iterator it = orderedTxs.rbegin(); it != orderedTxs.rend(); ++it) + { + const CWalletTx& wtx = (*it).second; + + if (!CheckFinalTx(wtx)) + continue; + + if (wtx.mapSaplingNoteData.size() == 0 && !wtx.IsTrusted()) + continue; + + //Excude transactions with less confirmations than required + if (wtx.GetDepthInMainChain() < 0 ) + continue; + + //Exclude Transactions older that max days old + if (wtx.GetDepthInMainChain() > 0 && mapBlockIndex[wtx.hashBlock]->GetBlockTime() < (t - (day * 60 * 60 * 24))) { + continue; + } + + zsWalletTxJSON(wtx, trans, "*", false, 0); + if (trans.size() >= nCount) break; + + } + + vector arrTmp = trans.getValues(); + + std::reverse(arrTmp.begin(), arrTmp.end()); // Return oldest to newest + + trans.clear(); + trans.setArray(); + trans.push_backV(arrTmp); + } + + returnObj.push_back(Pair("listtransactions", trans)); + return returnObj; +} + +UniValue z_listreceivedaddress(const UniValue& params, bool fHelp,const CPubKey&) +{ + if (!EnsureWalletIsAvailable(fHelp)) + return NullUniValue; + + if (fHelp || params.size() > 5 || params.size() == 3) + throw runtime_error( + "z_listreceivedbyaddress\n" + "\nReturns received outputs for a single address.\n" + "\n" + "This function only returns information on addresses with full spending keys." + "\n" + "\nArguments:\n" + "1. \"hushaddress:\" (string, required) \n" + "\n" + "2. \"Minimum Confimations:\" (numeric, optional, default=0) \n" + "\n" + "3. \"Filter Type:\" (numeric, optional, default=0) \n" + " Value of 0: Returns all transactions in the wallet\n" + " Value of 1: Returns the last x days of transactions\n" + " Value of 2: Returns transactions with confimations less than x\n" + "\n" + "4. \"Filter:\" (numeric, optional, default=999999) \n" + " Filter Type equal 0: paramater ignored\n" + " Filter Type equal 1: number represents the number of days returned\n" + " Filter Type equal 2: number represents the max confirmations for transaction to be returned\n" + "\n" + "5. \"Count:\" (numeric, optional, default=9999999) \n" + " Last n number of transactions returned\n" + "\n" + "Default Parameters:\n" + "2. 0 - O confimations required\n" + "3. 0 - Returns all transactions\n" + "4. 9999999 - Ignored\n" + "5. 9999999 - Return the last 9,999,999 transactions.\n" + "\n" + "\nResult:\n" + " \"txid\": \"transactionid\", (string) The transaction id.\n" + " \"coinbase\": \"coinbase\", (string) Coinbase transaction, true or false\n" + " \"category\": \"category\", (string) orphan (coinbase), immature (coinbase), generate (coinbase), regular\n" + " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction\n" + " \"blockindex\": n, (numeric) The block index containing the transaction\n" + " \"blocktime\": n, (numeric) The block time in seconds of the block containing the transaction, 0 for unconfirmed transactions\n" + " \"expiryheight\": n, (numeric) The expiry height of the transaction\n" + " \"confirmations\": n, (numeric) The number of confirmations for the transaction\n" + " \"time\": xxx, (numeric) The transaction time in seconds of the transaction\n" + " \"size\": xxx, (numeric) The transaction size\n" + " \"walletconflicts\": [conflicts], An array of wallet conflicts\n" + " \"recieved\": { A list of receives from the transaction\n" + " \"transparentReceived\": [{ An Array of txos received for transparent addresses\n" + " \"address\": \"zeroaddress\", (string) Hush transparent address (t-address)\n" + " \"scriptPubKey\": \"script\", (string) Script for the transparent address (t-address)\n" + " \"amount\": x.xxxx, (numeric) Value of output being received " + CURRENCY_UNIT + ", positive for receives\n" + " \"vout\": : n, (numeric) the vout value\n" + " }],\n" + " \"saplingReceived\": [{ An Array of utxos/notes received for sapling addresses\n" + " \"address\": \"zeroaddress\", (string) Shielded address (z-address)\n" + " \"amount\": x.xxxx, (numeric) Value of output being received " + CURRENCY_UNIT + ", positive for receives\n" + " \"sheildedOutputIndex\": n, (numeric) The index of the ShieledOutput\n" + " \"change\": true/false (string) The note is change. This can result from sending funds\n" + " to the same address they came from, or incomplete useage\n" + " resulting in the remainder of the note used being sent back to the\n" + " same z-address.\n" + " }],\n" + " },\n" + "\nExamples:\n" + + HelpExampleCli("z_listreceivedbyaddress", "R...") + + HelpExampleRpc("z_listreceivedbyaddress", "R...") + ); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + UniValue ret(UniValue::VARR); + + //param values` + int64_t nMinConfirms = 0; + int64_t nFilterType = 0; + int64_t nFilter = 999999; + int64_t nCount = 9999999; + + if (params.size() >= 2) + nMinConfirms = params[1].get_int64(); + + if (params.size() >= 4) { + nFilterType = params[2].get_int64(); + nFilter = params[3].get_int64(); + } + + if (params.size() == 5) { + nCount = params[4].get_int64(); + } + + if (nMinConfirms < 0) + throw runtime_error("Minimum confimations must be greater that 0"); + + if (nFilterType < 0 || nFilterType > 2) + throw runtime_error("Filter type must be 0, 1 or 2."); + + if (nFilter < 0) + throw runtime_error("Filter must be greater that 0."); + + //Created Ordered Transaction Map + map orderedTxs; + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { + const CWalletTx& wtx = (*it).second; + orderedTxs.insert(std::pair(wtx.nOrderPos, wtx)); + } + + + uint64_t t = GetTime(); + //Reverse Iterate thru transactions + for (map::reverse_iterator it = orderedTxs.rbegin(); it != orderedTxs.rend(); ++it) { + const CWalletTx& wtx = (*it).second; + bool includeTransaction = true; + + //Excude transactions with less confirmations than required + if (wtx.GetDepthInMainChain() < nMinConfirms) { + includeTransaction = false; + } + + //Exclude Transactions older that max days old + if (wtx.GetDepthInMainChain() > 0) { + if (nFilterType == 1 && mapBlockIndex[wtx.hashBlock]->GetBlockTime() < (t - (nFilter * 60 * 60 * 24))) { + includeTransaction = false; + } + } + + //Exclude transactions with greater than max confirmations + if (nFilterType == 2 && wtx.GetDepthInMainChain() > nFilter){ + includeTransaction = false; + } + + if (includeTransaction) { + zsWalletTxJSON(wtx, ret, params[0].get_str() , true, 2); + } + + if (ret.size() > nCount) break; + } + + return ret; +} + +UniValue z_getinfo(const UniValue& params, bool fHelp,const CPubKey&) +{ + if (!EnsureWalletIsAvailable(fHelp)) + return NullUniValue; + + if (fHelp || params.size() > 0) { + throw runtime_error( + "z_getinfo\n" + "\nReturns various information about shielded operations, such as sapling consolidation details.\n" + "\nExamples:\n" + + HelpExampleCli("z_getinfo", "") + + HelpExampleRpc("z_getinfo", "") + ); + } + + LOCK2(cs_main, pwalletMain->cs_wallet); + + UniValue result(UniValue::VOBJ); + result.push_back(Pair("zindex",(bool)fZindex)); + result.push_back(Pair("consolidation",(bool)pwalletMain->fSaplingConsolidationEnabled )); + result.push_back(Pair("consolidationtxfee",(int)fConsolidationTxFee)); + result.push_back(Pair("deletetx",(bool)fTxDeleteEnabled)); + result.push_back(Pair("delete_interval",(int)fDeleteInterval)); + result.push_back(Pair("keeptxnum",(int)fKeepLastNTransactions)); + result.push_back(Pair("keeptxfornblocks",(int)fDeleteTransactionsAfterNBlocks)); + + std::set saplingzaddrs = {}; + pwalletMain->GetSaplingPaymentAddresses(saplingzaddrs); + result.push_back(Pair("num_sapling_zaddrs",(int)saplingzaddrs.size())); + + std::shared_ptr q = getAsyncRPCQueue(); + std::vector ids = q->getAllOperationIds(); + result.push_back(Pair("num_op_ids",(int)ids.size())); + + return result; +} + +UniValue z_listsentbyaddress(const UniValue& params, bool fHelp,const CPubKey&) +{ + if (!EnsureWalletIsAvailable(fHelp)) + return NullUniValue; + + if (fHelp || params.size() > 5 || params.size() == 3) + throw runtime_error( + "z_listsentbyaddress\n" + "\nReturns decrypted Hush outputs sent to a single address.\n" + "\n" + "This function only returns information on addresses sent from wallet addresses with full spending keys." + "\n" + "\nArguments:\n" + "1. \"hushaddress:\" (string, required) \n" + "\n" + "2. \"Minimum Confimations:\" (numeric, optional, default=0) \n" + "\n" + "3. \"Filter Type:\" (numeric, optional, default=0) \n" + " Value of 0: Returns all transactions in the wallet\n" + " Value of 1: Returns the last x days of transactions\n" + " Value of 2: Returns transactions with confimations less than x\n" + "\n" + "4. \"Filter:\" (numeric, optional, default=999999) \n" + " Filter Type equal 0: paramater ignored\n" + " Filter Type equal 1: number represents the number of days returned\n" + " Filter Type equal 2: number represents the max confirmations for transaction to be returned\n" + "\n" + "5. \"Count:\" (numeric, optional, default=9999999) \n" + " Last n number of transactions returned\n" + "\n" + "Default Parameters:\n" + "2. 0 - O confimations required\n" + "3. 0 - Returns all transactions\n" + "4. 9999999 - Ignored\n" + "5. 9999999 - Return the last 9,999,999 transactions.\n" + "\n" + "\nResult:\n" + " \"txid\": \"transactionid\", (string) The transaction id.\n" + " \"coinbase\": \"coinbase\", (string) Coinbase transaction, true or false\n" + " \"category\": \"category\", (string) orphan (coinbase), immature (coinbase), generate (coinbase), regular\n" + " \"blockhash\": \"hashvalue\", (string) The block hash containing the transaction\n" + " \"blockindex\": n, (numeric) The block index containing the transaction\n" + " \"blocktime\": n, (numeric) The block time in seconds of the block containing the transaction, 0 for unconfirmed transactions\n" + " \"expiryheight\": n, (numeric) The expiry height of the transaction\n" + " \"confirmations\": n, (numeric) The number of confirmations for the transaction\n" + " \"time\": xxx, (numeric) The transaction time in seconds of the transaction\n" + " \"size\": xxx, (numeric) The transaction size\n" + " \"walletconflicts\": [conflicts], An array of wallet conflicts\n" + " \"sends\": { A list of outputs of where funds were sent to in the transaction,\n" + " only available if the transaction has valid sends (inputs) belonging to the wallet\n" + " \"transparentSends\": [{ An Array of spends (outputs) for transparent addresses of the receipient\n" + " \"address\": \"hushaddress\", (string) Hush transparent address (t-address)\n" + " \"scriptPubKey\": \"script\", (string) Script for the Hush transparent address (t-address)\n" + " \"amount\": x.xxxx, (numeric) Value of output being sent " + CURRENCY_UNIT + ", negative for sends\n" + " \"vout\": : n, (numeric) the vout value\n" + " }],\n" + " \"saplingSends\": [{ An Array of spends (outputs) for sapling addresses\n" + " \"address\": \"hushaddress\", (string) Hush sapling address (z-address) of the receipient\n" + " \"amount\": x.xxxx, (numeric) Value of output being sent" + CURRENCY_UNIT + ", negative for sends\n" + " \"memo\": xxxxx, (string) hexademical string representation of memo field\n" + " \"memoStr\" : \"memo\", (string) Only returned if memo contains valid UTF-8 text.\n" + " \"shieldedOutputIndex\": n, (numeric) The index of the ShieledOutput\n" + " \"change\": true/false (string) The note is change. This can result from sending funds\n" + " to the same address they came from, or incomplete useage\n" + " resulting in the remainder of the note used being sent back to the\n" + " same z-address.\n" + " }],\n" + " \"missingSaplingOVK\": true/false (string) True if the sapling outputs are not decryptable\n" + " }\n" + "\nExamples:\n" + + HelpExampleCli("z_listsentbyaddress", "t1KzZ5n2TPEGYXTZ3WYGL1AYEumEQaRoHaL") + + HelpExampleRpc("z_listsentbyaddress", "t1KzZ5n2TPEGYXTZ3WYGL1AYEumEQaRoHaL") + ); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + UniValue ret(UniValue::VARR); + + //param values` + int64_t nMinConfirms = 0; + int64_t nFilterType = 0; + int64_t nFilter = 9999999; + int64_t nCount = 9999999; + + if (params.size() >= 2) + nMinConfirms = params[1].get_int64(); + + if (params.size() >= 4) { + nFilterType = params[2].get_int64(); + nFilter = params[3].get_int64(); + } + + if (params.size() == 5) { + nCount = params[4].get_int64(); + } + + if (nMinConfirms < 0) + throw runtime_error("Minimum confimations must be greater that 0"); + + if (nFilterType < 0 || nFilterType > 2) + throw runtime_error("Filter type must be 0, 1 or 2."); + + if (nFilter < 0) + throw runtime_error("Filter must be greater that 0."); + + //Created Ordered Transaction Map + map orderedTxs; + for (map::iterator it = pwalletMain->mapWallet.begin(); it != pwalletMain->mapWallet.end(); ++it) { + const CWalletTx& wtx = (*it).second; + orderedTxs.insert(std::pair(wtx.nOrderPos, wtx)); + } + + + uint64_t t = GetTime(); + //Reverse Iterate thru transactions + for (map::reverse_iterator it = orderedTxs.rbegin(); it != orderedTxs.rend(); ++it) { + const CWalletTx& wtx = (*it).second; + + if (!CheckFinalTx(wtx)) + continue; + + if (wtx.GetDepthInMainChain() < 0) + continue; + + if (wtx.mapSaplingNoteData.size() == 0 && !wtx.IsTrusted()) + continue; + + //Excude transactions with less confirmations than required + if (wtx.GetDepthInMainChain() < nMinConfirms) + continue; + + //Exclude Transactions older that max days old + if (wtx.GetDepthInMainChain() > 0 && nFilterType == 1 && mapBlockIndex[wtx.hashBlock]->GetBlockTime() < (t - (nFilter * 60 * 60 * 24))) + continue; + + //Exclude transactions with greater than max confirmations + if (nFilterType == 2 && wtx.GetDepthInMainChain() > nFilter) + continue; + + zsWalletTxJSON(wtx, ret, "*", false, 0); + + + if (ret.size() >= nCount) break; + } + + vector arrTmp = ret.getValues(); + + std::reverse(arrTmp.begin(), arrTmp.end()); // Return oldest to newest + + ret.clear(); + ret.setArray(); + ret.push_backV(arrTmp); + + return ret; +} UniValue z_listunspent(const UniValue& params, bool fHelp, const CPubKey& mypk) { @@ -3141,9 +3789,8 @@ UniValue z_listunspent(const UniValue& params, bool fHelp, const CPubKey& mypk) UniValue results(UniValue::VARR); if (zaddrs.size() > 0) { - std::vector sproutEntries; std::vector saplingEntries; - pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, zaddrs, nMinDepth, nMaxDepth, true, !fIncludeWatchonly, false); + pwalletMain->GetFilteredNotes(saplingEntries, zaddrs, nMinDepth, nMaxDepth, true, !fIncludeWatchonly, false); std::set> nullifierSet = pwalletMain->GetNullifiersForAddresses(zaddrs); for (auto & entry : saplingEntries) { @@ -3233,479 +3880,6 @@ UniValue fundrawtransaction(const UniValue& params, bool fHelp, const CPubKey& m return result; } -UniValue zc_sample_joinsplit(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - if (fHelp) { - throw runtime_error( - "zcsamplejoinsplit\n" - "\n" - "Perform a joinsplit and return the JSDescription.\n" - ); - } - - LOCK(cs_main); - - uint256 joinSplitPubKey; - uint256 anchor = SproutMerkleTree().root(); - JSDescription samplejoinsplit(true, - *pzcashParams, - joinSplitPubKey, - anchor, - {JSInput(), JSInput()}, - {JSOutput(), JSOutput()}, - 0, - 0); - - CDataStream ss(SER_NETWORK, SAPLING_TX_VERSION | (1 << 31)); - ss << samplejoinsplit; - - return HexStr(ss.begin(), ss.end()); -} - -UniValue zc_benchmark(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - if (!EnsureWalletIsAvailable(fHelp)) { - return NullUniValue; - } - - if (fHelp || params.size() < 2) { - throw runtime_error( - "zcbenchmark benchmarktype samplecount\n" - "\n" - "Runs a benchmark of the selected type samplecount times,\n" - "returning the running times of each sample.\n" - "\n" - "Output: [\n" - " {\n" - " \"runningtime\": runningtime\n" - " },\n" - " {\n" - " \"runningtime\": runningtime\n" - " }\n" - " ...\n" - "]\n" - ); - } - - LOCK(cs_main); - - std::string benchmarktype = params[0].get_str(); - int samplecount = params[1].get_int(); - - if (samplecount <= 0) { - throw JSONRPCError(RPC_TYPE_ERROR, "Invalid samplecount"); - } - - std::vector sample_times; - - JSDescription samplejoinsplit; - - if (benchmarktype == "verifyjoinsplit") { - CDataStream ss(ParseHexV(params[2].get_str(), "js"), SER_NETWORK, SAPLING_TX_VERSION | (1 << 31)); - ss >> samplejoinsplit; - } - - for (int i = 0; i < samplecount; i++) { - if (benchmarktype == "sleep") { - sample_times.push_back(benchmark_sleep()); - } else if (benchmarktype == "parameterloading") { - sample_times.push_back(benchmark_parameter_loading()); - } else if (benchmarktype == "createjoinsplit") { - if (params.size() < 3) { - sample_times.push_back(benchmark_create_joinsplit()); - } else { - int nThreads = params[2].get_int(); - std::vector vals = benchmark_create_joinsplit_threaded(nThreads); - // Divide by nThreads^2 to get average seconds per JoinSplit because - // we are running one JoinSplit per thread. - sample_times.push_back(std::accumulate(vals.begin(), vals.end(), 0.0) / (nThreads*nThreads)); - } - } else if (benchmarktype == "verifyjoinsplit") { - sample_times.push_back(benchmark_verify_joinsplit(samplejoinsplit)); -#ifdef ENABLE_MINING - } else if (benchmarktype == "solveequihash") { - if (params.size() < 3) { - sample_times.push_back(benchmark_solve_equihash()); - } else { - int nThreads = params[2].get_int(); - std::vector vals = benchmark_solve_equihash_threaded(nThreads); - sample_times.insert(sample_times.end(), vals.begin(), vals.end()); - } -#endif - } else if (benchmarktype == "verifyequihash") { - sample_times.push_back(benchmark_verify_equihash()); - } else if (benchmarktype == "validatelargetx") { - // Number of inputs in the spending transaction that we will simulate - int nInputs = 11130; - if (params.size() >= 3) { - nInputs = params[2].get_int(); - } - sample_times.push_back(benchmark_large_tx(nInputs)); - } else if (benchmarktype == "trydecryptnotes") { - int nAddrs = params[2].get_int(); - sample_times.push_back(benchmark_try_decrypt_notes(nAddrs)); - } else if (benchmarktype == "incnotewitnesses") { - int nTxs = params[2].get_int(); - sample_times.push_back(benchmark_increment_note_witnesses(nTxs)); - } else if (benchmarktype == "connectblockslow") { - if (Params().NetworkIDString() != "regtest") { - throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode"); - } - sample_times.push_back(benchmark_connectblock_slow()); - } else if (benchmarktype == "sendtoaddress") { - if (Params().NetworkIDString() != "regtest") { - throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode"); - } - auto amount = AmountFromValue(params[2]); - sample_times.push_back(benchmark_sendtoaddress(amount)); - } else if (benchmarktype == "loadwallet") { - if (Params().NetworkIDString() != "regtest") { - throw JSONRPCError(RPC_TYPE_ERROR, "Benchmark must be run in regtest mode"); - } - sample_times.push_back(benchmark_loadwallet()); - } else if (benchmarktype == "listunspent") { - sample_times.push_back(benchmark_listunspent()); - } else if (benchmarktype == "createsaplingspend") { - sample_times.push_back(benchmark_create_sapling_spend()); - } else if (benchmarktype == "createsaplingoutput") { - sample_times.push_back(benchmark_create_sapling_output()); - } else if (benchmarktype == "verifysaplingspend") { - sample_times.push_back(benchmark_verify_sapling_spend()); - } else if (benchmarktype == "verifysaplingoutput") { - sample_times.push_back(benchmark_verify_sapling_output()); - } else { - throw JSONRPCError(RPC_TYPE_ERROR, "Invalid benchmarktype"); - } - } - - UniValue results(UniValue::VARR); - for (auto time : sample_times) { - UniValue result(UniValue::VOBJ); - result.push_back(Pair("runningtime", time)); - results.push_back(result); - } - - return results; -} - -UniValue zc_raw_receive(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - if (!EnsureWalletIsAvailable(fHelp)) { - return NullUniValue; - } - - if (fHelp || params.size() != 2) { - throw runtime_error( - "zcrawreceive zcsecretkey encryptednote\n" - "\n" - "DEPRECATED. Decrypts encryptednote and checks if the coin commitments\n" - "are in the blockchain as indicated by the \"exists\" result.\n" - "\n" - "Output: {\n" - " \"amount\": value,\n" - " \"note\": noteplaintext,\n" - " \"exists\": exists\n" - "}\n" - ); - } - - RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VSTR)); - - LOCK(cs_main); - - auto spendingkey = DecodeSpendingKey(params[0].get_str()); - if (!IsValidSpendingKey(spendingkey)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key"); - } - if (boost::get(&spendingkey) == nullptr) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Only works with Sprout spending keys"); - } - SproutSpendingKey k = boost::get(spendingkey); - - uint256 epk; - unsigned char nonce; - ZCNoteEncryption::Ciphertext ct; - uint256 h_sig; - - { - CDataStream ssData(ParseHexV(params[1], "encrypted_note"), SER_NETWORK, PROTOCOL_VERSION); - try { - ssData >> nonce; - ssData >> epk; - ssData >> ct; - ssData >> h_sig; - } catch(const std::exception &) { - throw runtime_error( - "encrypted_note could not be decoded" - ); - } - } - - ZCNoteDecryption decryptor(k.receiving_key()); - - SproutNotePlaintext npt = SproutNotePlaintext::decrypt( - decryptor, - ct, - epk, - h_sig, - nonce - ); - SproutPaymentAddress payment_addr = k.address(); - SproutNote decrypted_note = npt.note(payment_addr); - - assert(pwalletMain != NULL); - std::vector> witnesses; - uint256 anchor; - uint256 commitment = decrypted_note.cm(); - pwalletMain->WitnessNoteCommitment( - {commitment}, - witnesses, - anchor - ); - - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << npt; - - UniValue result(UniValue::VOBJ); - result.push_back(Pair("amount", ValueFromAmount(decrypted_note.value()))); - result.push_back(Pair("note", HexStr(ss.begin(), ss.end()))); - result.push_back(Pair("exists", (bool) witnesses[0])); - return result; -} - - - -UniValue zc_raw_joinsplit(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - if (!EnsureWalletIsAvailable(fHelp)) { - return NullUniValue; - } - - if (fHelp || params.size() != 5) { - throw runtime_error( - "zcrawjoinsplit rawtx inputs outputs vpub_old vpub_new\n" - " inputs: a JSON object mapping {note: zcsecretkey, ...}\n" - " outputs: a JSON object mapping {zcaddr: value, ...}\n" - "\n" - "DEPRECATED. Splices a joinsplit into rawtx. Inputs are unilaterally confidential.\n" - "Outputs are confidential between sender/receiver. The vpub_old and\n" - "vpub_new values are globally public and move transparent value into\n" - "or out of the confidential value store, respectively.\n" - "\n" - "Note: The caller is responsible for delivering the output enc1 and\n" - "enc2 to the appropriate recipients, as well as signing rawtxout and\n" - "ensuring it is mined. (A future RPC call will deliver the confidential\n" - "payments in-band on the blockchain.)\n" - "\n" - "Output: {\n" - " \"encryptednote1\": enc1,\n" - " \"encryptednote2\": enc2,\n" - " \"rawtxn\": rawtxout\n" - "}\n" - ); - } - - LOCK(cs_main); - - CTransaction tx; - if (!DecodeHexTx(tx, params[0].get_str())) - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); - - UniValue inputs = params[1].get_obj(); - UniValue outputs = params[2].get_obj(); - - CAmount vpub_old(0); - CAmount vpub_new(0); - - if (params[3].get_real() != 0.0) - vpub_old = AmountFromValue(params[3]); - - if (params[4].get_real() != 0.0) - vpub_new = AmountFromValue(params[4]); - - std::vector vjsin; - std::vector vjsout; - std::vector notes; - std::vector keys; - std::vector commitments; - - for (const string& name_ : inputs.getKeys()) { - auto spendingkey = DecodeSpendingKey(inputs[name_].get_str()); - if (!IsValidSpendingKey(spendingkey)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key"); - } - if (boost::get(&spendingkey) == nullptr) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Only works with Sprout spending keys"); - } - SproutSpendingKey k = boost::get(spendingkey); - - keys.push_back(k); - - SproutNotePlaintext npt; - - { - CDataStream ssData(ParseHexV(name_, "note"), SER_NETWORK, PROTOCOL_VERSION); - ssData >> npt; - } - - SproutPaymentAddress addr = k.address(); - SproutNote note = npt.note(addr); - notes.push_back(note); - commitments.push_back(note.cm()); - } - - uint256 anchor; - std::vector> witnesses; - pwalletMain->WitnessNoteCommitment(commitments, witnesses, anchor); - - assert(witnesses.size() == notes.size()); - assert(notes.size() == keys.size()); - - { - for (size_t i = 0; i < witnesses.size(); i++) { - if (!witnesses[i]) { - throw runtime_error( - "joinsplit input could not be found in tree" - ); - } - - vjsin.push_back(JSInput(*witnesses[i], notes[i], keys[i])); - } - } - - while (vjsin.size() < ZC_NUM_JS_INPUTS) { - vjsin.push_back(JSInput()); - } - - for (const string& name_ : outputs.getKeys()) { - auto addrTo = DecodePaymentAddress(name_); - if (!IsValidPaymentAddress(addrTo)) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid recipient address."); - } - if (boost::get(&addrTo) == nullptr) { - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Only works with Sprout payment addresses"); - } - CAmount nAmount = AmountFromValue(outputs[name_]); - - vjsout.push_back(JSOutput(boost::get(addrTo), nAmount)); - } - - while (vjsout.size() < ZC_NUM_JS_OUTPUTS) { - vjsout.push_back(JSOutput()); - } - - // TODO - if (vjsout.size() != ZC_NUM_JS_INPUTS || vjsin.size() != ZC_NUM_JS_OUTPUTS) { - throw runtime_error("unsupported joinsplit input/output counts"); - } - - uint256 joinSplitPubKey; - unsigned char joinSplitPrivKey[crypto_sign_SECRETKEYBYTES]; - crypto_sign_keypair(joinSplitPubKey.begin(), joinSplitPrivKey); - - CMutableTransaction mtx(tx); - mtx.nVersion = 2; - mtx.joinSplitPubKey = joinSplitPubKey; - - JSDescription jsdesc(false, - *pzcashParams, - joinSplitPubKey, - anchor, - {vjsin[0], vjsin[1]}, - {vjsout[0], vjsout[1]}, - vpub_old, - vpub_new); - - { - auto verifier = libzcash::ProofVerifier::Strict(); - assert(jsdesc.Verify(*pzcashParams, verifier, joinSplitPubKey)); - } - - mtx.vjoinsplit.push_back(jsdesc); - - // Empty output script. - CScript scriptCode; - CTransaction signTx(mtx); - auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); - uint256 dataToBeSigned = SignatureHash(scriptCode, signTx, NOT_AN_INPUT, SIGHASH_ALL, 0, consensusBranchId); - - // Add the signature - assert(crypto_sign_detached(&mtx.joinSplitSig[0], NULL, - dataToBeSigned.begin(), 32, - joinSplitPrivKey - ) == 0); - - // Sanity check - assert(crypto_sign_verify_detached(&mtx.joinSplitSig[0], - dataToBeSigned.begin(), 32, - mtx.joinSplitPubKey.begin() - ) == 0); - - CTransaction rawTx(mtx); - - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << rawTx; - - std::string encryptedNote1; - std::string encryptedNote2; - { - CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION); - ss2 << ((unsigned char) 0x00); - ss2 << jsdesc.ephemeralKey; - ss2 << jsdesc.ciphertexts[0]; - ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey); - - encryptedNote1 = HexStr(ss2.begin(), ss2.end()); - } - { - CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION); - ss2 << ((unsigned char) 0x01); - ss2 << jsdesc.ephemeralKey; - ss2 << jsdesc.ciphertexts[1]; - ss2 << jsdesc.h_sig(*pzcashParams, joinSplitPubKey); - - encryptedNote2 = HexStr(ss2.begin(), ss2.end()); - } - - UniValue result(UniValue::VOBJ); - result.push_back(Pair("encryptednote1", encryptedNote1)); - result.push_back(Pair("encryptednote2", encryptedNote2)); - result.push_back(Pair("rawtxn", HexStr(ss.begin(), ss.end()))); - return result; -} - -UniValue zc_raw_keygen(const UniValue& params, bool fHelp, const CPubKey& mypk) -{ - if (!EnsureWalletIsAvailable(fHelp)) { - return NullUniValue; - } - - if (fHelp || params.size() != 0) { - throw runtime_error( - "zcrawkeygen\n" - "\n" - "DEPRECATED. Generate a zcaddr which can send and receive confidential values.\n" - "\n" - "Output: {\n" - " \"zcaddress\": zcaddr,\n" - " \"zcsecretkey\": zcsecretkey,\n" - " \"zcviewingkey\": zcviewingkey,\n" - "}\n" - ); - } - - auto k = SproutSpendingKey::random(); - auto addr = k.address(); - auto viewing_key = k.viewing_key(); - - UniValue result(UniValue::VOBJ); - result.push_back(Pair("zcaddress", EncodePaymentAddress(addr))); - result.push_back(Pair("zcsecretkey", EncodeSpendingKey(k))); - result.push_back(Pair("zcviewingkey", EncodeViewingKey(viewing_key))); - return result; -} - - UniValue z_getnewaddress(const UniValue& params, bool fHelp, const CPubKey& mypk) { if (!EnsureWalletIsAvailable(fHelp)) @@ -3881,10 +4055,9 @@ CAmount getBalanceTaddr(std::string transparentAddress, int minDepth=1, bool ign CAmount getBalanceZaddr(std::string address, int minDepth = 1, bool ignoreUnspendable=true) { CAmount balance = 0; - std::vector sproutEntries; std::vector saplingEntries; LOCK2(cs_main, pwalletMain->cs_wallet); - pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, address, minDepth, true, ignoreUnspendable); + pwalletMain->GetFilteredNotes(saplingEntries, address, minDepth, true, ignoreUnspendable); for (auto & entry : saplingEntries) { balance += CAmount(entry.note.value()); } @@ -3936,16 +4109,14 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp, const CPubK throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid zaddr."); } - // Visitor to support Sprout and Sapling addrs if (!boost::apply_visitor(PaymentAddressBelongsToWallet(pwalletMain), zaddr) && !boost::apply_visitor(IncomingViewingKeyBelongsToWallet(pwalletMain), zaddr)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key or viewing key not found."); } UniValue result(UniValue::VARR); - std::vector sproutEntries; std::vector saplingEntries; - pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, fromaddress, nMinDepth, false, false); + pwalletMain->GetFilteredNotes(saplingEntries, fromaddress, nMinDepth, false, false); std::set> nullifierSet; auto hasSpendingKey = boost::apply_visitor(HaveSpendingKeyForPaymentAddress(pwalletMain), zaddr); @@ -3966,6 +4137,15 @@ UniValue z_listreceivedbyaddress(const UniValue& params, bool fHelp, const CPubK obj.push_back(Pair("txid", entry.op.hash.ToString())); obj.push_back(Pair("amount", ValueFromAmount(CAmount(entry.note.value())))); obj.push_back(Pair("memo", HexStr(entry.memo))); + // give a string representation if valid utf8 + auto memo = entry.memo; + if (memo[0] <= 0xf4) { + auto end = std::find_if(memo.rbegin(), memo.rend(), [](unsigned char v) { return v != 0; }); + std::string memoStr(memo.begin(), end.base()); + if (utf8::is_valid(memoStr)) { + obj.push_back(Pair("memoStr", memoStr)); + } + } obj.push_back(Pair("outindex", (int)entry.op.n)); obj.push_back(Pair("rawconfirmations", entry.confirmations)); obj.push_back(Pair("confirmations", dpowconfs)); @@ -4038,6 +4218,42 @@ UniValue z_getbalance(const UniValue& params, bool fHelp, const CPubKey& mypk) return ValueFromAmount(nBalance); } +UniValue z_getnotescount(const UniValue& params, bool fHelp,const CPubKey& mypk) +{ + if (!EnsureWalletIsAvailable(fHelp)) + return NullUniValue; + + if (fHelp || params.size() > 1) + throw runtime_error( + "z_getnotescount\n" + "\nArguments:\n" + "1. minconf (numeric, optional, default=1) Only include notes in transactions confirmed at least this many times.\n" + "\nReturns the number of sapling notes available in the wallet.\n" + "\nResult:\n" + "{\n" + " \"sapling\" (numeric) the number of sapling notes in the wallet\n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("z_getnotescount", "0") + ); + + LOCK2(cs_main, pwalletMain->cs_wallet); + + int nMinDepth = 1; + if (params.size() > 0) + nMinDepth = params[0].get_int(); + + int sapling = 0; + for (auto& wtx : pwalletMain->mapWallet) { + if (wtx.second.GetDepthInMainChain() >= nMinDepth) { + sapling += wtx.second.mapSaplingNoteData.size(); + } + } + UniValue ret(UniValue::VOBJ); + ret.push_back(Pair("sapling", sapling)); + + return ret; +} UniValue z_gettotalbalance(const UniValue& params, bool fHelp, const CPubKey& mypk) { @@ -4058,6 +4274,7 @@ UniValue z_gettotalbalance(const UniValue& params, bool fHelp, const CPubKey& my "{\n" " \"transparent\": xxxxx, (numeric) the total balance of transparent funds\n" " \"private\": xxxxx, (numeric) the total balance of shielded funds\n" + " \"private\": xxxxx, (numeric) the total balance of private funds\n" " \"total\": xxxxx, (numeric) the total balance of both transparent and private funds\n" "}\n" "\nExamples:\n" @@ -4177,7 +4394,9 @@ UniValue z_viewtransaction(const UniValue& params, bool fHelp, const CPubKey& my // Fetch the note that is being spent auto res = pwalletMain->mapSaplingNullifiersToNotes.find(spend.nullifier); if (res == pwalletMain->mapSaplingNullifiersToNotes.end()) { - fprintf(stderr,"Could not find spending note %s", uint256_str(str, spend.nullifier)); + if(fZdebug) { + fprintf(stderr,"Could not find spending note %s\n", uint256_str(str, spend.nullifier)); + } continue; } auto op = res->second; @@ -4231,8 +4450,10 @@ UniValue z_viewtransaction(const UniValue& params, bool fHelp, const CPubKey& my pa = recovered->second; isOutgoing = true; } else { - // Unreadable - fprintf(stderr,"Could not recover Sapling note!"); + // Unreadable or unconfirmed? + if(fZdebug) { + fprintf(stderr,"Could not recover Sapling note!\n"); + } continue; } } @@ -4435,14 +4656,9 @@ UniValue z_sendmany(const UniValue& params, bool fHelp, const CPubKey& mypk) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "From address does not belong to this node, zaddr spending key not found."); } - // Remember whether this is a Sprout or Sapling address + // Remember whether this is a Sapling address fromSapling = boost::get(&res) != nullptr; } - // This logic will need to be updated if we add a new shielded pool - bool fromSprout = !(fromTaddr || fromSapling); - - if (fromSprout) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot send from a Sprout zaddr, only Sapling zaddrs supported."); UniValue outputs = params[1].get_array(); @@ -4452,15 +4668,11 @@ UniValue z_sendmany(const UniValue& params, bool fHelp, const CPubKey& mypk) // Keep track of addresses to spot duplicates set setAddress; - // Track whether we see any Sprout addresses - bool noSproutAddrs = !fromSprout; - // Recipients std::vector taddrRecipients; std::vector zaddrRecipients; CAmount nTotalOut = 0; - bool containsSproutOutput = false; bool containsSaplingOutput = false; for (const UniValue& o : outputs.getValues()) { @@ -4481,35 +4693,6 @@ UniValue z_sendmany(const UniValue& params, bool fHelp, const CPubKey& mypk) auto res = DecodePaymentAddress(address); if (IsValidPaymentAddress(res, branchId)) { isZaddr = true; - - bool toSapling = boost::get(&res) != nullptr; - bool toSprout = !toSapling; - noSproutAddrs = noSproutAddrs && toSapling; - - containsSproutOutput |= toSprout; - containsSaplingOutput |= toSapling; - - // Sending to both Sprout and Sapling is currently unsupported using z_sendmany - if (containsSproutOutput && containsSaplingOutput) { - throw JSONRPCError( - RPC_INVALID_PARAMETER, - "Cannot send to both Sprout and Sapling addresses using z_sendmany"); - } - if ( GetTime() > KOMODO_SAPLING_DEADLINE ) - { - if ( fromSprout || toSprout ) - throw JSONRPCError(RPC_INVALID_PARAMETER,"Sprout usage has expired"); - } - if ( toSapling && ASSETCHAINS_SYMBOL[0] == 0 ) - throw JSONRPCError(RPC_INVALID_PARAMETER,"Sprout usage will expire soon"); - - // If we are sending from a shielded address, all recipient - // shielded addresses must be of the same type. - if ((fromSprout && toSapling) || (fromSapling && toSprout)) { - throw JSONRPCError( - RPC_INVALID_PARAMETER, - "Cannot send between Sprout and Sapling addresses using z_sendmany"); - } } else { throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ")+address ); } @@ -4699,9 +4882,7 @@ UniValue z_sendmany(const UniValue& params, bool fHelp, const CPubKey& mypk) // Builder (used if Sapling addresses are involved) boost::optional builder; - if (noSproutAddrs) { - builder = TransactionBuilder(Params().GetConsensus(), nextBlockHeight, pwalletMain); - } + builder = TransactionBuilder(Params().GetConsensus(), nextBlockHeight, pwalletMain); // Contextual transaction we will build on // (used if no Sapling addresses are involved) @@ -4964,7 +5145,6 @@ UniValue z_shieldcoinbase(const UniValue& params, bool fHelp, const CPubKey& myp #define MERGE_TO_ADDRESS_DEFAULT_SPROUT_LIMIT 10 #define MERGE_TO_ADDRESS_DEFAULT_SAPLING_LIMIT 90 -#define JOINSPLIT_SIZE GetSerializeSize(JSDescription(), SER_NETWORK, PROTOCOL_VERSION) #define OUTPUTDESCRIPTION_SIZE GetSerializeSize(OutputDescription(), SER_NETWORK, PROTOCOL_VERSION) #define SPENDDESCRIPTION_SIZE GetSerializeSize(SpendDescription(), SER_NETWORK, PROTOCOL_VERSION) @@ -4974,16 +5154,15 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp return NullUniValue; string enableArg = "zmergetoaddress"; - auto fEnableMergeToAddress = fExperimentalMode && GetBoolArg("-" + enableArg, true); - std::string strDisabledMsg = ""; - if (!fEnableMergeToAddress) { - strDisabledMsg = experimentalDisabledHelpMsg("z_mergetoaddress", enableArg); - } + //auto fEnableMergeToAddress = fExperimentalMode && GetBoolArg("-" + enableArg, true); + //std::string strDisabledMsg = ""; + //if (!fEnableMergeToAddress) { + // strDisabledMsg = experimentalDisabledHelpMsg("z_mergetoaddress", enableArg); + //} if (fHelp || params.size() < 2 || params.size() > 7) throw runtime_error( "z_mergetoaddress [\"fromaddress\", ... ] \"toaddress\" ( fee ) ( transparent_limit ) ( shielded_limit ) ( memo )\n" - + strDisabledMsg + "\nMerge multiple UTXOs and notes into a single UTXO or note. Coinbase UTXOs are ignored; use `z_shieldcoinbase`" "\nto combine those into a single note." "\n\nThis is an asynchronous operation, and UTXOs selected for merging will be locked. If there is an error, they" @@ -5010,7 +5189,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp "4. transparent_limit (numeric, optional, default=" + strprintf("%d", MERGE_TO_ADDRESS_DEFAULT_TRANSPARENT_LIMIT) + ") Limit on the maximum number of UTXOs to merge. Set to 0 to use node option -mempooltxinputlimit (before Overwinter), or as many as will fit in the transaction (after Overwinter).\n" "4. shielded_limit (numeric, optional, default=" - + strprintf("%d Sprout or %d Sapling Notes", MERGE_TO_ADDRESS_DEFAULT_SPROUT_LIMIT, MERGE_TO_ADDRESS_DEFAULT_SAPLING_LIMIT) + ") Limit on the maximum number of notes to merge. Set to 0 to merge as many as will fit in the transaction.\n" + + strprintf("%d Sapling Notes", MERGE_TO_ADDRESS_DEFAULT_SAPLING_LIMIT) + ") Limit on the maximum number of notes to merge. Set to 0 to merge as many as will fit in the transaction.\n" "5. maximum_utxo_size (numeric, optional) eg, 0.0001 anything under 10000 satoshies will be merged, ignores 10,000 sat p2pk utxo that iguana uses, and merges coinbase utxo.\n" "6. \"memo\" (string, optional) Encoded as hex. When toaddress is a z-addr, this will be stored in the memo field of the new note.\n" @@ -5027,20 +5206,15 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp " \"opid\": xxx (string) An operationid to pass to z_getoperationstatus to get the result of the operation.\n" "}\n" "\nExamples:\n" - + HelpExampleCli("z_mergetoaddress", "'[\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"]' ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf") - + HelpExampleRpc("z_mergetoaddress", "[\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"], \"ztfaW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"") + + HelpExampleCli("z_mergetoaddress", "'[\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"]' zs1aW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf") + + HelpExampleRpc("z_mergetoaddress", "[\"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPV\"], \"zs1aW34Gj9FrnGUEf833ywDVL62NWXBM81u6EQnM6VR45eYnXhwztecW1SjxA7JrmAXKJhxhj3vDNEpVCQoSvVoSpmbhtjf\"") ); - if (!fEnableMergeToAddress) { - throw JSONRPCError(RPC_WALLET_ERROR, "Error: z_mergetoaddress is disabled."); - } - LOCK2(cs_main, pwalletMain->cs_wallet); THROW_IF_SYNCING(KOMODO_INSYNC); bool useAnyUTXO = false; - bool useAnySprout = false; bool useAnySapling = false; std::set taddrs = {}; std::set zaddrs = {}; @@ -5061,8 +5235,6 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp if (address == "ANY_TADDR") { useAnyUTXO = true; - } else if (address == "ANY_SPROUT") { - useAnySprout = true; } else if (address == "ANY_SAPLING") { useAnySapling = true; } else { @@ -5087,8 +5259,8 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp if (useAnyUTXO && taddrs.size() > 0) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify specific t-addrs when using \"ANY_TADDR\""); } - if ((useAnySprout || useAnySapling) && zaddrs.size() > 0) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify specific z-addrs when using \"ANY_SPROUT\" or \"ANY_SAPLING\""); + if ((useAnySapling) && zaddrs.size() > 0) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify specific z-addrs when using \"ANY_SAPLING\""); } const int nextBlockHeight = chainActive.Height() + 1; @@ -5097,7 +5269,6 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp // Validate the destination address auto destaddress = params[1].get_str(); - bool isToSproutZaddr = false; bool isToSaplingZaddr = false; CTxDestination taddr = DecodeDestination(destaddress); if (!IsValidDestination(taddr)) { @@ -5110,7 +5281,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, Sapling has not activated"); } } else { - isToSproutZaddr = true; + throw JSONRPCError(RPC_INVALID_PARAMETER, "Only Sapling zaddrs allowed!"); } } else { throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, unknown address format: ") + destaddress ); @@ -5135,14 +5306,12 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp } } - int sproutNoteLimit = MERGE_TO_ADDRESS_DEFAULT_SPROUT_LIMIT; int saplingNoteLimit = MERGE_TO_ADDRESS_DEFAULT_SAPLING_LIMIT; if (params.size() > 4) { int nNoteLimit = params[4].get_int(); if (nNoteLimit < 0) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Limit on maximum number of notes cannot be negative"); } - sproutNoteLimit = nNoteLimit; saplingNoteLimit = nNoteLimit; } @@ -5159,7 +5328,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp std::string memo; if (params.size() > 6) { memo = params[6].get_str(); - if (!(isToSproutZaddr || isToSaplingZaddr)) { + if (!isToSaplingZaddr) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Memo can not be used with a taddr. It can only be used with a zaddr."); } else if (!IsHex(memo)) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected memo data in hexadecimal format."); @@ -5173,7 +5342,6 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp // Prepare to get UTXOs and notes std::vector utxoInputs; - std::vector sproutNoteInputs; std::vector saplingNoteInputs; CAmount mergedUTXOValue = 0; CAmount mergedNoteValue = 0; @@ -5187,9 +5355,8 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp unsigned int max_tx_size = saplingActive ? MAX_TX_SIZE_AFTER_SAPLING : MAX_TX_SIZE_BEFORE_SAPLING; size_t estimatedTxSize = 200; // tx overhead + wiggle room - if (isToSproutZaddr) { - estimatedTxSize += JOINSPLIT_SIZE; - } else if (isToSaplingZaddr) { + + if (isToSaplingZaddr) { estimatedTxSize += OUTPUTDESCRIPTION_SIZE; } @@ -5247,57 +5414,10 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp } } - if (useAnySprout || useAnySapling || zaddrs.size() > 0) { + if (useAnySapling || zaddrs.size() > 0) { // Get available notes - std::vector sproutEntries; - //std::vector saplingEntries; - //pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, zaddrs); - std::vector saplingEntries,skipsapling; - pwalletMain->GetFilteredNotes(sproutEntries, useAnySprout == 0 ? saplingEntries : skipsapling, zaddrs); - // If Sapling is not active, do not allow sending from a sapling addresses. - if (!saplingActive && saplingEntries.size() > 0) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, Sapling has not activated"); - } - // Sending from both Sprout and Sapling is currently unsupported using z_mergetoaddress - if (sproutEntries.size() > 0 && saplingEntries.size() > 0) { - throw JSONRPCError( - RPC_INVALID_PARAMETER, - "Cannot send from both Sprout and Sapling addresses using z_mergetoaddress"); - } - // If sending between shielded addresses, they must be the same type - if ((saplingEntries.size() > 0 && isToSproutZaddr) || (sproutEntries.size() > 0 && isToSaplingZaddr)) { - throw JSONRPCError( - RPC_INVALID_PARAMETER, - "Cannot send between Sprout and Sapling addresses using z_mergetoaddress"); - } - - // Find unspent notes and update estimated size - for (const CSproutNotePlaintextEntry& entry : sproutEntries) { - noteCounter++; - CAmount nValue = entry.plaintext.value(); - - if (!maxedOutNotesFlag) { - // If we haven't added any notes yet and the merge is to a - // z-address, we have already accounted for the first JoinSplit. - size_t increase = (sproutNoteInputs.empty() && !isToSproutZaddr) || (sproutNoteInputs.size() % 2 == 0) ? JOINSPLIT_SIZE : 0; - if (estimatedTxSize + increase >= max_tx_size || - (sproutNoteLimit > 0 && noteCounter > sproutNoteLimit)) - { - maxedOutNotesFlag = true; - } else { - estimatedTxSize += increase; - auto zaddr = entry.address; - SproutSpendingKey zkey; - pwalletMain->GetSproutSpendingKey(zaddr, zkey); - sproutNoteInputs.emplace_back(entry.jsop, entry.plaintext.note(zaddr), nValue, zkey); - mergedNoteValue += nValue; - } - } - - if (maxedOutNotesFlag) { - remainingNoteValue += nValue; - } - } + std::vector saplingEntries; + pwalletMain->GetFilteredNotes(saplingEntries, zaddrs); for (const SaplingNoteEntry& entry : saplingEntries) { noteCounter++; @@ -5326,7 +5446,7 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp } size_t numUtxos = utxoInputs.size(); - size_t numNotes = sproutNoteInputs.size() + saplingNoteInputs.size(); + size_t numNotes = saplingNoteInputs.size(); //fprintf(stderr, "num utxos.%li\n", numUtxos); if (numUtxos < 2 && numNotes == 0) { @@ -5364,22 +5484,19 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp, const CPubKey& myp CMutableTransaction contextualTx = CreateNewContextualCMutableTransaction( Params().GetConsensus(), nextBlockHeight); - bool isSproutShielded = sproutNoteInputs.size() > 0 || isToSproutZaddr; - if (contextualTx.nVersion == 1 && isSproutShielded) { - contextualTx.nVersion = 2; // Tx format should support vjoinsplit - } // Builder (used if Sapling addresses are involved) boost::optional builder; if (isToSaplingZaddr || saplingNoteInputs.size() > 0) { builder = TransactionBuilder(Params().GetConsensus(), nextBlockHeight, pwalletMain); - } else + } else { contextualTx.nExpiryHeight = 0; // set non z-tx to have no expiry height. + } // Create operation and add to global queue std::shared_ptr q = getAsyncRPCQueue(); std::shared_ptr operation( - new AsyncRPCOperation_mergetoaddress(builder, contextualTx, utxoInputs, sproutNoteInputs, saplingNoteInputs, recipient, nFee, contextInfo) ); + new AsyncRPCOperation_mergetoaddress(builder, contextualTx, utxoInputs, saplingNoteInputs, recipient, nFee, contextInfo) ); q->addOperation(operation); AsyncRPCOperationId operationId = operation->getId(); @@ -8120,9 +8237,8 @@ extern UniValue z_exportviewingkey(const UniValue& params, bool fHelp, const CPu extern UniValue z_importviewingkey(const UniValue& params, bool fHelp, const CPubKey& mypk); extern UniValue z_exportwallet(const UniValue& params, bool fHelp, const CPubKey& mypk); extern UniValue z_importwallet(const UniValue& params, bool fHelp, const CPubKey& mypk); +extern UniValue rescan(const UniValue& params, bool fHelp, const CPubKey& mypk); -extern UniValue z_getpaymentdisclosure(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcdisclosure.cpp -extern UniValue z_validatepaymentdisclosure(const UniValue& params, bool fHelp, const CPubKey& mypk); static const CRPCCommand commands[] = { // category name actor (function) okSafeMode @@ -8136,6 +8252,7 @@ static const CRPCCommand commands[] = { "wallet", "encryptwallet", &encryptwallet, true }, { "wallet", "getaccountaddress", &getaccountaddress, true }, { "wallet", "getaccount", &getaccount, true }, + { "wallet", "getalldata", &getalldata, true }, { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, true }, { "wallet", "getbalance", &getbalance, false }, { "wallet", "getnewaddress", &getnewaddress, true }, @@ -8160,6 +8277,7 @@ static const CRPCCommand commands[] = { "wallet", "listunspent", &listunspent, false }, { "wallet", "lockunspent", &lockunspent, true }, { "wallet", "move", &movecmd, false }, + { "wallet", "rescan", &rescan, false }, { "wallet", "sendfrom", &sendfrom, false }, { "wallet", "sendmany", &sendmany, false }, { "wallet", "sendtoaddress", &sendtoaddress, false }, @@ -8169,11 +8287,6 @@ static const CRPCCommand commands[] = { "wallet", "walletlock", &walletlock, true }, { "wallet", "walletpassphrasechange", &walletpassphrasechange, true }, { "wallet", "walletpassphrase", &walletpassphrase, true }, - { "wallet", "zcbenchmark", &zc_benchmark, true }, - { "wallet", "zcrawkeygen", &zc_raw_keygen, true }, - { "wallet", "zcrawjoinsplit", &zc_raw_joinsplit, true }, - { "wallet", "zcrawreceive", &zc_raw_receive, true }, - { "wallet", "zcsamplejoinsplit", &zc_sample_joinsplit, true }, { "wallet", "z_listreceivedbyaddress", &z_listreceivedbyaddress, false }, { "wallet", "z_listunspent", &z_listunspent, false }, { "wallet", "z_getbalance", &z_getbalance, false }, @@ -8193,11 +8306,13 @@ static const CRPCCommand commands[] = { "wallet", "z_exportwallet", &z_exportwallet, true }, { "wallet", "z_importwallet", &z_importwallet, true }, { "wallet", "z_viewtransaction", &z_viewtransaction, true }, - // TODO: rearrange into another category - { "disclosure", "z_getpaymentdisclosure", &z_getpaymentdisclosure, true }, - { "disclosure", "z_validatepaymentdisclosure", &z_validatepaymentdisclosure, true } + { "wallet", "z_getinfo", &z_getinfo, true }, + { "wallet", "z_listsentbyaddress", &z_listsentbyaddress, true }, + { "wallet", "z_listreceivedbyaddress", &z_listreceivedbyaddress, true }, + { "wallet", "z_getnotescount", &z_getnotescount, false } }; + void RegisterWalletRPCCommands(CRPCTable &tableRPC) { for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index a9e79a3a3..e10065de4 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -20,6 +20,7 @@ ******************************************************************************/ #include "wallet/wallet.h" +#include "asyncrpcqueue.h" #include "checkpoints.h" #include "coincontrol.h" @@ -38,6 +39,7 @@ #include "zcash/Note.hpp" #include "crypter.h" #include "coins.h" +#include "wallet/asyncrpcoperation_saplingconsolidation.h" #include "zcash/zip32.h" #include "cc/CCinclude.h" @@ -47,6 +49,10 @@ #include #include +#if defined(__GLIBC__) +#include +#endif + using namespace std; using namespace libzcash; @@ -65,6 +71,11 @@ CBlockIndex *komodo_chainactive(int32_t height); extern std::string DONATION_PUBKEY; int32_t komodo_dpowconfs(int32_t height,int32_t numconfs); int tx_height( const uint256 &hash ); +bool fTxDeleteEnabled = false; +bool fTxConflictDeleteEnabled = false; +int fDeleteInterval = DEFAULT_TX_DELETE_INTERVAL; +unsigned int fDeleteTransactionsAfterNBlocks = DEFAULT_TX_RETENTION_BLOCKS; +unsigned int fKeepLastNTransactions = DEFAULT_TX_RETENTION_LASTTX; /** * Fees smaller than this (in satoshi) are considered zero fee (for transaction creation) @@ -105,26 +116,6 @@ const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const return &(it->second); } -// Generate a new spending key and return its public payment address -libzcash::SproutPaymentAddress CWallet::GenerateNewSproutZKey() -{ - AssertLockHeld(cs_wallet); // mapSproutZKeyMetadata - - auto k = SproutSpendingKey::random(); - auto addr = k.address(); - - // Check for collision, even though it is unlikely to ever occur - if (CCryptoKeyStore::HaveSproutSpendingKey(addr)) - throw std::runtime_error("CWallet::GenerateNewSproutZKey(): Collision detected"); - - // Create new metadata - int64_t nCreationTime = GetTime(); - mapSproutZKeyMetadata[addr] = CKeyMetadata(nCreationTime); - - if (!AddSproutZKey(k)) - throw std::runtime_error("CWallet::GenerateNewSproutZKey(): AddSproutZKey failed"); - return addr; -} // Generate a new Sapling spending key and return its public payment address SaplingPaymentAddress CWallet::GenerateNewSaplingZKey(bool addToWallet) @@ -222,30 +213,6 @@ bool CWallet::AddSaplingIncomingViewingKey( } -// Add spending key to keystore and persist to disk -bool CWallet::AddSproutZKey(const libzcash::SproutSpendingKey &key) -{ - AssertLockHeld(cs_wallet); // mapSproutZKeyMetadata - auto addr = key.address(); - - if (!CCryptoKeyStore::AddSproutSpendingKey(key)) - return false; - - // check if we need to remove from viewing keys - if (HaveSproutViewingKey(addr)) - RemoveSproutViewingKey(key.viewing_key()); - - if (!fFileBacked) - return true; - - if (!IsCrypted()) { - return CWalletDB(strWalletFile).WriteZKey(addr, - key, - mapSproutZKeyMetadata[addr]); - } - return true; -} - CPubKey CWallet::GenerateNewKey() { AssertLockHeld(cs_wallet); // mapKeyMetadata @@ -316,33 +283,6 @@ bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, return false; } - -bool CWallet::AddCryptedSproutSpendingKey( - const libzcash::SproutPaymentAddress &address, - const libzcash::ReceivingKey &rk, - const std::vector &vchCryptedSecret) -{ - if (!CCryptoKeyStore::AddCryptedSproutSpendingKey(address, rk, vchCryptedSecret)) - return false; - if (!fFileBacked) - return true; - { - LOCK(cs_wallet); - if (pwalletdbEncryption) { - return pwalletdbEncryption->WriteCryptedZKey(address, - rk, - vchCryptedSecret, - mapSproutZKeyMetadata[address]); - } else { - return CWalletDB(strWalletFile).WriteCryptedZKey(address, - rk, - vchCryptedSecret, - mapSproutZKeyMetadata[address]); - } - } - return false; -} - bool CWallet::AddCryptedSaplingSpendingKey(const libzcash::SaplingExtendedFullViewingKey &extfvk, const std::vector &vchCryptedSecret, const libzcash::SaplingPaymentAddress &defaultAddr) @@ -376,22 +316,11 @@ bool CWallet::LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &meta) return true; } -bool CWallet::LoadZKeyMetadata(const SproutPaymentAddress &addr, const CKeyMetadata &meta) -{ - AssertLockHeld(cs_wallet); // mapSproutZKeyMetadata - mapSproutZKeyMetadata[addr] = meta; - return true; -} - bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret) { return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret); } -bool CWallet::LoadCryptedZKey(const libzcash::SproutPaymentAddress &addr, const libzcash::ReceivingKey &rk, const std::vector &vchCryptedSecret) -{ - return CCryptoKeyStore::AddCryptedSproutSpendingKey(addr, rk, vchCryptedSecret); -} bool CWallet::LoadCryptedSaplingZKey( const libzcash::SaplingExtendedFullViewingKey &extfvk, @@ -419,43 +348,6 @@ bool CWallet::LoadSaplingPaymentAddress( return CCryptoKeyStore::AddSaplingIncomingViewingKey(ivk, addr); } -bool CWallet::LoadZKey(const libzcash::SproutSpendingKey &key) -{ - return CCryptoKeyStore::AddSproutSpendingKey(key); -} - -bool CWallet::AddSproutViewingKey(const libzcash::SproutViewingKey &vk) -{ - if (!CCryptoKeyStore::AddSproutViewingKey(vk)) { - return false; - } - nTimeFirstKey = 1; // No birthday information for viewing keys. - if (!fFileBacked) { - return true; - } - return CWalletDB(strWalletFile).WriteSproutViewingKey(vk); -} - -bool CWallet::RemoveSproutViewingKey(const libzcash::SproutViewingKey &vk) -{ - AssertLockHeld(cs_wallet); - if (!CCryptoKeyStore::RemoveSproutViewingKey(vk)) { - return false; - } - if (fFileBacked) { - if (!CWalletDB(strWalletFile).EraseSproutViewingKey(vk)) { - return false; - } - } - - return true; -} - -bool CWallet::LoadSproutViewingKey(const libzcash::SproutViewingKey &vk) -{ - return CCryptoKeyStore::AddSproutViewingKey(vk); -} - bool CWallet::AddCScript(const CScript& redeemScript) { if (!CCryptoKeyStore::AddCScript(redeemScript)) @@ -579,16 +471,61 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, void CWallet::ChainTip(const CBlockIndex *pindex, const CBlock *pblock, - SproutMerkleTree sproutTree, - SaplingMerkleTree saplingTree, - bool added) + boost::optional> added) { if (added) { - IncrementNoteWitnesses(pindex, pblock, sproutTree, saplingTree); + bool initialDownloadCheck = IsInitialBlockDownload(); + // Prevent witness cache building && consolidation transactions + // from being created when node is syncing after launch, + // and also when node wakes up from suspension/hibernation and incoming blocks are old. + // 144 blocks = 3hrs @ 75s blocktime + if (!initialDownloadCheck && + pblock->GetBlockTime() > GetTime() - 144*ASSETCHAINS_BLOCKTIME) + { + BuildWitnessCache(pindex, false); + RunSaplingConsolidation(pindex->GetHeight()); + DeleteWalletTransactions(pindex); + } else { + //Build intial witnesses on every block + BuildWitnessCache(pindex, true); + if (initialDownloadCheck && pindex->GetHeight() % fDeleteInterval == 0) { + DeleteWalletTransactions(pindex); + } + } } else { DecrementNoteWitnesses(pindex); + UpdateNullifierNoteMapForBlock(pblock); } - UpdateSaplingNullifierNoteMapForBlock(pblock); +} + +void CWallet::RunSaplingConsolidation(int blockHeight) { + if (!NetworkUpgradeActive(blockHeight, Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) { + return; + } + LOCK(cs_wallet); + if (!fSaplingConsolidationEnabled) { + return; + } + + int consolidateInterval = rand() % 5 + 5; + if (blockHeight % consolidateInterval == 0) { + std::shared_ptr q = getAsyncRPCQueue(); + std::shared_ptr lastOperation = q->getOperationForId(saplingConsolidationOperationId); + if (lastOperation != nullptr) { + lastOperation->cancel(); + } + pendingSaplingConsolidationTxs.clear(); + std::shared_ptr operation(new AsyncRPCOperation_saplingconsolidation(blockHeight + 5)); + saplingConsolidationOperationId = operation->getId(); + q->addOperation(operation); + } +} + +bool CWallet::CommitConsolidationTx(const CTransaction& tx) { + CWalletTx wtx(this, tx); + CReserveKey reservekey(pwalletMain); + fprintf(stderr,"%s: %s\n",__func__,tx.ToString().c_str()); + return CommitTransaction(wtx, reservekey); } void CWallet::SetBestChain(const CBlockLocator& loc) @@ -628,29 +565,6 @@ std::set> CWallet::GetNullifiersFor return nullifierSet; } -bool CWallet::IsNoteSproutChange( - const std::set> & nullifierSet, - const PaymentAddress & address, - const JSOutPoint & jsop) -{ - // A Note is marked as "change" if the address that received it - // also spent Notes in the same transaction. This will catch, - // for instance: - // - Change created by spending fractions of Notes (because - // z_sendmany sends change to the originating z-address). - // - "Chaining Notes" used to connect JoinSplits together. - // - Notes created by consolidation transactions (e.g. using - // z_mergetoaddress). - // - Notes sent from one address to itself. - for (const JSDescription & jsd : mapWallet[jsop.hash].vjoinsplit) { - for (const uint256 & nullifier : jsd.nullifiers) { - if (nullifierSet.count(std::make_pair(address, nullifier))) { - return true; - } - } - } - return false; -} bool CWallet::IsNoteSaplingChange(const std::set> & nullifierSet, const libzcash::PaymentAddress & address, @@ -732,20 +646,6 @@ set CWallet::GetConflicts(const uint256& txid) const result.insert(it->second); } - std::pair range_n; - - for (const JSDescription& jsdesc : wtx.vjoinsplit) { - for (const uint256& nullifier : jsdesc.nullifiers) { - if (mapTxSproutNullifiers.count(nullifier) <= 1) { - continue; // No conflict if zero or one spends - } - range_n = mapTxSproutNullifiers.equal_range(nullifier); - for (TxNullifiers::const_iterator it = range_n.first; it != range_n.second; ++it) { - result.insert(it->second); - } - } - } - std::pair range_o; for (const SpendDescription &spend : wtx.vShieldedSpend) { @@ -872,22 +772,20 @@ bool CWallet::IsSpent(const uint256& hash, unsigned int n) const return false; } -/** - * Note is spent if any non-conflicted transaction - * spends it: - */ -bool CWallet::IsSproutSpent(const uint256& nullifier) const { - pair range; - range = mapTxSproutNullifiers.equal_range(nullifier); +unsigned int CWallet::GetSpendDepth(const uint256& hash, unsigned int n) const +{ + const COutPoint outpoint(hash, n); + pair range; + range = mapTxSpends.equal_range(outpoint); - for (TxNullifiers::const_iterator it = range.first; it != range.second; ++it) { + for (TxSpends::const_iterator it = range.first; it != range.second; ++it) + { const uint256& wtxid = it->second; std::map::const_iterator mit = mapWallet.find(wtxid); - if (mit != mapWallet.end() && mit->second.GetDepthInMainChain() >= 0) { - return true; // Spent - } + if (mit != mapWallet.end() && mit->second.GetDepthInMainChain() >= 0) + return mit->second.GetDepthInMainChain(); // Spent } - return false; + return 0; } bool CWallet::IsSaplingSpent(const uint256& nullifier) const { @@ -904,6 +802,20 @@ bool CWallet::IsSaplingSpent(const uint256& nullifier) const { return false; } +unsigned int CWallet::GetSaplingSpendDepth(const uint256& nullifier) const { + pair range; + range = mapTxSaplingNullifiers.equal_range(nullifier); + + for (TxNullifiers::const_iterator it = range.first; it != range.second; ++it) { + const uint256& wtxid = it->second; + std::map::const_iterator mit = mapWallet.find(wtxid); + if (mit != mapWallet.end() && mit->second.GetDepthInMainChain() >= 0) { + return mit->second.GetDepthInMainChain(); // Spent + } + } + return 0; +} + void CWallet::AddToTransparentSpends(const COutPoint& outpoint, const uint256& wtxid) { mapTxSpends.insert(make_pair(outpoint, wtxid)); @@ -913,15 +825,6 @@ void CWallet::AddToTransparentSpends(const COutPoint& outpoint, const uint256& w SyncMetaData(range); } -void CWallet::AddToSproutSpends(const uint256& nullifier, const uint256& wtxid) -{ - mapTxSproutNullifiers.insert(make_pair(nullifier, wtxid)); - - pair range; - range = mapTxSproutNullifiers.equal_range(nullifier); - SyncMetaData(range); -} - void CWallet::AddToSaplingSpends(const uint256& nullifier, const uint256& wtxid) { mapTxSaplingNullifiers.insert(make_pair(nullifier, wtxid)); @@ -941,11 +844,6 @@ void CWallet::AddToSpends(const uint256& wtxid) for (const CTxIn& txin : thisTx.vin) { AddToTransparentSpends(txin.prevout, wtxid); } - for (const JSDescription& jsdesc : thisTx.vjoinsplit) { - for (const uint256& nullifier : jsdesc.nullifiers) { - AddToSproutSpends(nullifier, wtxid); - } - } for (const SpendDescription &spend : thisTx.vShieldedSpend) { AddToSaplingSpends(spend.nullifier, wtxid); } @@ -992,241 +890,227 @@ void CWallet::ClearNoteWitnessCache() item.second.witnessHeight = -1; } } - nWitnessCacheSize = 0; - //fprintf(stderr,"Clear witness cache\n"); } -template -void CopyPreviousWitnesses(NoteDataMap& noteDataMap, int indexHeight, int64_t nWitnessCacheSize) -{ - for (auto& item : noteDataMap) { - auto* nd = &(item.second); - // Only increment witnesses that are behind the current height - if (nd->witnessHeight < indexHeight) { - // Check the validity of the cache - // The only time a note witnessed above the current height - // would be invalid here is during a reindex when blocks - // have been decremented, and we are incrementing the blocks - // immediately after. - assert(nWitnessCacheSize >= nd->witnesses.size()); - // Witnesses being incremented should always be either -1 - // (never incremented or decremented) or one below indexHeight - assert((nd->witnessHeight == -1) || (nd->witnessHeight == indexHeight - 1)); - // Copy the witness for the previous block if we have one - if (nd->witnesses.size() > 0) { - nd->witnesses.push_front(nd->witnesses.front()); - } - if (nd->witnesses.size() > WITNESS_CACHE_SIZE) { - nd->witnesses.pop_back(); - } - } - } -} - -template -void AppendNoteCommitment(NoteDataMap& noteDataMap, int indexHeight, int64_t nWitnessCacheSize, const uint256& note_commitment) -{ - for (auto& item : noteDataMap) { - auto* nd = &(item.second); - if (nd->witnessHeight < indexHeight && nd->witnesses.size() > 0) { - // Check the validity of the cache - // See comment in CopyPreviousWitnesses about validity. - assert(nWitnessCacheSize >= nd->witnesses.size()); - nd->witnesses.front().append(note_commitment); - } - } -} - -template -void WitnessNoteIfMine(std::map& noteDataMap, int indexHeight, int64_t nWitnessCacheSize, const OutPoint& key, const Witness& witness) -{ - if (noteDataMap.count(key) && noteDataMap[key].witnessHeight < indexHeight) { - auto* nd = &(noteDataMap[key]); - if (nd->witnesses.size() > 0) { - // We think this can happen because we write out the - // witness cache state after every block increment or - // decrement, but the block index itself is written in - // batches. So if the node crashes in between these two - // operations, it is possible for IncrementNoteWitnesses - // to be called again on previously-cached blocks. This - // doesn't affect existing cached notes because of the - // NoteData::witnessHeight checks. See #1378 for details. - LogPrintf("Inconsistent witness cache state found for %s\n- Cache size: %d\n- Top (height %d): %s\n- New (height %d): %s\n", - key.ToString(), nd->witnesses.size(), - nd->witnessHeight, - nd->witnesses.front().root().GetHex(), - indexHeight, - witness.root().GetHex()); - nd->witnesses.clear(); - } - nd->witnesses.push_front(witness); - // Set height to one less than pindex so it gets incremented - nd->witnessHeight = indexHeight - 1; - // Check the validity of the cache - assert(nWitnessCacheSize >= nd->witnesses.size()); - } -} - - -template -void UpdateWitnessHeights(NoteDataMap& noteDataMap, int indexHeight, int64_t nWitnessCacheSize) -{ - for (auto& item : noteDataMap) { - auto* nd = &(item.second); - if (nd->witnessHeight < indexHeight) { - nd->witnessHeight = indexHeight; - // Check the validity of the cache - // See comment in CopyPreviousWitnesses about validity. - assert(nWitnessCacheSize >= nd->witnesses.size()); - } - } -} - -void CWallet::IncrementNoteWitnesses(const CBlockIndex* pindex, - const CBlock* pblockIn, - SproutMerkleTree& sproutTree, - SaplingMerkleTree& saplingTree) -{ - LOCK(cs_wallet); - for (std::pair& wtxItem : mapWallet) { - ::CopyPreviousWitnesses(wtxItem.second.mapSproutNoteData, pindex->GetHeight(), nWitnessCacheSize); - ::CopyPreviousWitnesses(wtxItem.second.mapSaplingNoteData, pindex->GetHeight(), nWitnessCacheSize); - } - - if (nWitnessCacheSize < WITNESS_CACHE_SIZE) { - nWitnessCacheSize += 1; - } - - const CBlock* pblock {pblockIn}; - CBlock block; - if (!pblock) { - ReadBlockFromDisk(block, pindex, false); - pblock = █ - } - - for (const CTransaction& tx : pblock->vtx) { - auto hash = tx.GetHash(); - bool txIsOurs = mapWallet.count(hash); - // Sprout - for (size_t i = 0; i < tx.vjoinsplit.size(); i++) { - const JSDescription& jsdesc = tx.vjoinsplit[i]; - for (uint8_t j = 0; j < jsdesc.commitments.size(); j++) { - const uint256& note_commitment = jsdesc.commitments[j]; - sproutTree.append(note_commitment); - - // Increment existing witnesses - for (std::pair& wtxItem : mapWallet) { - ::AppendNoteCommitment(wtxItem.second.mapSproutNoteData, pindex->GetHeight(), nWitnessCacheSize, note_commitment); - } - - // If this is our note, witness it - if (txIsOurs) { - JSOutPoint jsoutpt {hash, i, j}; - ::WitnessNoteIfMine(mapWallet[hash].mapSproutNoteData, pindex->GetHeight(), nWitnessCacheSize, jsoutpt, sproutTree.witness()); - } - } - } - // Sapling - for (uint32_t i = 0; i < tx.vShieldedOutput.size(); i++) { - const uint256& note_commitment = tx.vShieldedOutput[i].cm; - saplingTree.append(note_commitment); - - // Increment existing witnesses - for (std::pair& wtxItem : mapWallet) { - ::AppendNoteCommitment(wtxItem.second.mapSaplingNoteData, pindex->GetHeight(), nWitnessCacheSize, note_commitment); - } - - // If this is our note, witness it - if (txIsOurs) { - SaplingOutPoint outPoint {hash, i}; - ::WitnessNoteIfMine(mapWallet[hash].mapSaplingNoteData, pindex->GetHeight(), nWitnessCacheSize, outPoint, saplingTree.witness()); - } - } - } - - // Update witness heights - for (std::pair& wtxItem : mapWallet) { - ::UpdateWitnessHeights(wtxItem.second.mapSproutNoteData, pindex->GetHeight(), nWitnessCacheSize); - ::UpdateWitnessHeights(wtxItem.second.mapSaplingNoteData, pindex->GetHeight(), nWitnessCacheSize); - } - - // For performance reasons, we write out the witness cache in - // CWallet::SetBestChain() (which also ensures that overall consistency - // of the wallet.dat is maintained). -} - -template -bool DecrementNoteWitnesses(NoteDataMap& noteDataMap, int indexHeight, int64_t nWitnessCacheSize) -{ - extern int32_t KOMODO_REWIND; - - for (auto& item : noteDataMap) { - auto* nd = &(item.second); - // Only decrement witnesses that are not above the current height - if (nd->witnessHeight <= indexHeight) { - // Check the validity of the cache - // See comment below (this would be invalid if there were a - // prior decrement). - assert(nWitnessCacheSize >= nd->witnesses.size()); - // Witnesses being decremented should always be either -1 - // (never incremented or decremented) or equal to the height - // of the block being removed (indexHeight) - if (!((nd->witnessHeight == -1) || (nd->witnessHeight == indexHeight))) - { - printf("at height %d\n", indexHeight); - return false; - } - if (nd->witnesses.size() > 0) { - nd->witnesses.pop_front(); - } - // indexHeight is the height of the block being removed, so - // the new witness cache height is one below it. - nd->witnessHeight = indexHeight - 1; - } - // Check the validity of the cache - // Technically if there are notes witnessed above the current - // height, their cache will now be invalid (relative to the new - // value of nWitnessCacheSize). However, this would only occur - // during a reindex, and by the time the reindex reaches the tip - // of the chain again, the existing witness caches will be valid - // again. - // We don't set nWitnessCacheSize to zero at the start of the - // reindex because the on-disk blocks had already resulted in a - // chain that didn't trigger the assertion below. - if (nd->witnessHeight < indexHeight) { - // Subtract 1 to compare to what nWitnessCacheSize will be after - // decrementing. - assert((nWitnessCacheSize - 1) >= nd->witnesses.size()); - } - } - assert(KOMODO_REWIND != 0 || nWitnessCacheSize > 0 || WITNESS_CACHE_SIZE != _COINBASE_MATURITY+10); - return true; -} - - void CWallet::DecrementNoteWitnesses(const CBlockIndex* pindex) { LOCK(cs_wallet); + + extern int32_t KOMODO_REWIND; + for (std::pair& wtxItem : mapWallet) { - if (!::DecrementNoteWitnesses(wtxItem.second.mapSproutNoteData, pindex->GetHeight(), nWitnessCacheSize)) - needsRescan = true; - if (!::DecrementNoteWitnesses(wtxItem.second.mapSaplingNoteData, pindex->GetHeight(), nWitnessCacheSize)) - needsRescan = true; + //Sapling + for (auto& item : wtxItem.second.mapSaplingNoteData) { + auto* nd = &(item.second); + if (nd->nullifier && pwalletMain->GetSaplingSpendDepth(*item.second.nullifier) <= WITNESS_CACHE_SIZE) { + // Only decrement witnesses that are not above the current height + if (nd->witnessHeight <= pindex->GetHeight()) { + if (nd->witnesses.size() > 1) { + // indexHeight is the height of the block being removed, so + // the new witness cache height is one below it. + nd->witnesses.pop_front(); + nd->witnessHeight = pindex->GetHeight() - 1; + } + } + } + } } - if ( WITNESS_CACHE_SIZE == _COINBASE_MATURITY+10 ) - { - nWitnessCacheSize -= 1; - // TODO: If nWitnessCache is zero, we need to regenerate the caches (#1302) - assert(nWitnessCacheSize > 0); + assert(KOMODO_REWIND != 0 || WITNESS_CACHE_SIZE != _COINBASE_MATURITY+10); +} + +template +void ClearSingleNoteWitnessCache(NoteData* nd) +{ + nd->witnesses.clear(); + nd->witnessHeight = -1; + nd->witnessRootValidated = false; +} + +int CWallet::SaplingWitnessMinimumHeight(const uint256& nullifier, int nWitnessHeight, int nMinimumHeight) +{ + if (GetSaplingSpendDepth(nullifier) <= WITNESS_CACHE_SIZE) { + nMinimumHeight = min(nWitnessHeight, nMinimumHeight); } - else - { - if ( nWitnessCacheSize > 0 ) - nWitnessCacheSize--; + return nMinimumHeight; +} + +int CWallet::VerifyAndSetInitialWitness(const CBlockIndex* pindex, bool witnessOnly) +{ + LOCK2(cs_main, cs_wallet); + + int nWitnessTxIncrement = 0; + int nWitnessTotalTxCount = mapWallet.size(); + int nMinimumHeight = pindex->GetHeight(); + + for (std::pair& wtxItem : mapWallet) { + nWitnessTxIncrement += 1; + + if (wtxItem.second.mapSaplingNoteData.empty()) + continue; + + if (wtxItem.second.GetDepthInMainChain() > 0) { + auto wtxHash = wtxItem.second.GetHash(); + int wtxHeight = mapBlockIndex[wtxItem.second.hashBlock]->GetHeight(); + + for (mapSaplingNoteData_t::value_type& item : wtxItem.second.mapSaplingNoteData) { + + auto op = item.first; + auto* nd = &(item.second); + CBlockIndex* pblockindex; + uint256 blockRoot; + uint256 witnessRoot; + + if (!nd->nullifier) + ::ClearSingleNoteWitnessCache(nd); + + if (!nd->witnesses.empty() && nd->witnessHeight > 0) { + + //Skip all functions for validated witness while witness only = true + if (nd->witnessRootValidated && witnessOnly) + continue; + + //Skip Validation when witness root has been validated + if (nd->witnessRootValidated) { + nMinimumHeight = SaplingWitnessMinimumHeight(*item.second.nullifier, nd->witnessHeight, nMinimumHeight); + continue; + } + + //Skip Validation when witness height is greater that block height + if (nd->witnessHeight > pindex->GetHeight() - 1) { + nMinimumHeight = SaplingWitnessMinimumHeight(*item.second.nullifier, nd->witnessHeight, nMinimumHeight); + continue; + } + + //Validate the witness at the witness height + witnessRoot = nd->witnesses.front().root(); + pblockindex = chainActive[nd->witnessHeight]; + blockRoot = pblockindex->hashFinalSaplingRoot; + if (witnessRoot == blockRoot) { + nd->witnessRootValidated = true; + nMinimumHeight = SaplingWitnessMinimumHeight(*item.second.nullifier, nd->witnessHeight, nMinimumHeight); + continue; + } + } + + //Clear witness Cache for all other scenarios + pblockindex = chainActive[wtxHeight]; + ::ClearSingleNoteWitnessCache(nd); + + LogPrintf("Setting Initial Sapling Witness for tx %s, %i of %i\n", wtxHash.ToString(), nWitnessTxIncrement, nWitnessTotalTxCount); + + SaplingMerkleTree saplingTree; + blockRoot = pblockindex->pprev->hashFinalSaplingRoot; + pcoinsTip->GetSaplingAnchorAt(blockRoot, saplingTree); + + //Cycle through blocks and transactions building sapling tree until the commitment needed is reached + const CBlock* pblock; + CBlock block; + ReadBlockFromDisk(block, pblockindex, 1); + pblock = █ + + for (const CTransaction& tx : block.vtx) { + auto hash = tx.GetHash(); + + // Sapling + for (uint32_t i = 0; i < tx.vShieldedOutput.size(); i++) { + const uint256& note_commitment = tx.vShieldedOutput[i].cm; + + // Increment existing witness until the end of the block + if (!nd->witnesses.empty()) { + nd->witnesses.front().append(note_commitment); + } + + //Only needed for intial witness + if (nd->witnesses.empty()) { + saplingTree.append(note_commitment); + + // If this is our note, witness it + if (hash == wtxHash) { + SaplingOutPoint outPoint {hash, i}; + if (op == outPoint) { + nd->witnesses.push_front(saplingTree.witness()); + } + } + } + } + } + nd->witnessHeight = pblockindex->GetHeight(); + UpdateSaplingNullifierNoteMapWithTx(wtxItem.second); + nMinimumHeight = SaplingWitnessMinimumHeight(*item.second.nullifier, nd->witnessHeight, nMinimumHeight); + } } - // For performance reasons, we write out the witness cache in - // CWallet::SetBestChain() (which also ensures that overall consistency - // of the wallet.dat is maintained). + } + + return nMinimumHeight; +} + +void CWallet::BuildWitnessCache(const CBlockIndex* pindex, bool witnessOnly) +{ + + LOCK2(cs_main, cs_wallet); + + int startHeight = VerifyAndSetInitialWitness(pindex, witnessOnly) + 1; + + if (startHeight > pindex->GetHeight() || witnessOnly) { + return; + } + + uint256 sproutRoot; + uint256 saplingRoot; + CBlockIndex* pblockindex = chainActive[startHeight]; + int height = chainActive.Height(); + + while (pblockindex) { + + if (pblockindex->GetHeight() % 100 == 0 && pblockindex->GetHeight() < height - 5) { + LogPrintf("Building Witnesses for block %i %.4f complete\n", pblockindex->GetHeight(), pblockindex->GetHeight() / double(height)); + } + + SaplingMerkleTree saplingTree; + saplingRoot = pblockindex->pprev->hashFinalSaplingRoot; + pcoinsTip->GetSaplingAnchorAt(saplingRoot, saplingTree); + + //Cycle through blocks and transactions building sapling tree until the commitment needed is reached + CBlock block; + ReadBlockFromDisk(block, pblockindex, 1); + + for (std::pair& wtxItem : mapWallet) { + + if (wtxItem.second.mapSaplingNoteData.empty()) + continue; + + if (wtxItem.second.GetDepthInMainChain() > 0) { + + //Sapling + for (mapSaplingNoteData_t::value_type& item : wtxItem.second.mapSaplingNoteData) { + auto* nd = &(item.second); + if (nd->nullifier && nd->witnessHeight == pblockindex->GetHeight() - 1 + && GetSaplingSpendDepth(*item.second.nullifier) <= WITNESS_CACHE_SIZE) { + + nd->witnesses.push_front(nd->witnesses.front()); + while (nd->witnesses.size() > WITNESS_CACHE_SIZE) { + nd->witnesses.pop_back(); + } + + for (const CTransaction& tx : block.vtx) { + for (uint32_t i = 0; i < tx.vShieldedOutput.size(); i++) { + const uint256& note_commitment = tx.vShieldedOutput[i].cm; + nd->witnesses.front().append(note_commitment); + } + } + nd->witnessHeight = pblockindex->GetHeight(); + } + } + } + } + + if (pblockindex == pindex) + break; + + pblockindex = chainActive.Next(pblockindex); + + } + } bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) @@ -1382,22 +1266,6 @@ bool CWallet::UpdateNullifierNoteMap() ZCNoteDecryption dec; for (std::pair& wtxItem : mapWallet) { - for (mapSproutNoteData_t::value_type& item : wtxItem.second.mapSproutNoteData) { - if (!item.second.nullifier) { - if (GetNoteDecryptor(item.second.address, dec)) { - auto i = item.first.js; - auto hSig = wtxItem.second.vjoinsplit[i].h_sig( - *pzcashParams, wtxItem.second.joinSplitPubKey); - item.second.nullifier = GetSproutNoteNullifier( - wtxItem.second.vjoinsplit[i], - item.second.address, - dec, - hSig, - item.first.n); - } - } - } - // TODO: Sapling. This method is only called from RPC walletpassphrase, which is currently unsupported // as RPC encryptwallet is hidden behind two flags: -developerencryptwallet -experimentalfeatures @@ -1408,18 +1276,13 @@ bool CWallet::UpdateNullifierNoteMap() } /** - * Update mapSproutNullifiersToNotes and mapSaplingNullifiersToNotes + * Update mapSaplingNullifiersToNotes * with the cached nullifiers in this tx. */ void CWallet::UpdateNullifierNoteMapWithTx(const CWalletTx& wtx) { { LOCK(cs_wallet); - for (const mapSproutNoteData_t::value_type& item : wtx.mapSproutNoteData) { - if (item.second.nullifier) { - mapSproutNullifiersToNotes[*item.second.nullifier] = item.first; - } - } for (const mapSaplingNoteData_t::value_type& item : wtx.mapSaplingNoteData) { if (item.second.nullifier) { @@ -1479,7 +1342,7 @@ void CWallet::UpdateSaplingNullifierNoteMapWithTx(CWalletTx& wtx) { * Iterate over transactions in a block and update the cached Sapling nullifiers * for transactions which belong to the wallet. */ -void CWallet::UpdateSaplingNullifierNoteMapForBlock(const CBlock *pblock) { +void CWallet::UpdateNullifierNoteMapForBlock(const CBlock *pblock) { LOCK(cs_wallet); for (const CTransaction& tx : pblock->vtx) { @@ -1513,10 +1376,9 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD bool fInsertedNew = ret.second; if (fInsertedNew) { - wtx.nTimeReceived = GetAdjustedTime(); - wtx.nOrderPos = IncOrderPosNext(pwalletdb); - - wtx.nTimeSmart = wtx.nTimeReceived; + wtx.nTimeReceived = GetTime(); + wtx.nOrderPos = IncOrderPosNext(pwalletdb); + wtx.nTimeSmart = wtx.nTimeReceived; if (!wtxIn.hashBlock.IsNull()) { if (mapBlockIndex.count(wtxIn.hashBlock)) @@ -1618,21 +1480,6 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletD bool CWallet::UpdatedNoteData(const CWalletTx& wtxIn, CWalletTx& wtx) { - bool unchangedSproutFlag = (wtxIn.mapSproutNoteData.empty() || wtxIn.mapSproutNoteData == wtx.mapSproutNoteData); - if (!unchangedSproutFlag) { - auto tmp = wtxIn.mapSproutNoteData; - // Ensure we keep any cached witnesses we may already have - for (const std::pair nd : wtx.mapSproutNoteData) { - if (tmp.count(nd.first) && nd.second.witnesses.size() > 0) { - tmp.at(nd.first).witnesses.assign( - nd.second.witnesses.cbegin(), nd.second.witnesses.cend()); - } - tmp.at(nd.first).witnessHeight = nd.second.witnessHeight; - } - // Now copy over the updated note data - wtx.mapSproutNoteData = tmp; - } - bool unchangedSaplingFlag = (wtxIn.mapSaplingNoteData.empty() || wtxIn.mapSaplingNoteData == wtx.mapSaplingNoteData); if (!unchangedSaplingFlag) { auto tmp = wtxIn.mapSaplingNoteData; @@ -1650,7 +1497,7 @@ bool CWallet::UpdatedNoteData(const CWalletTx& wtxIn, CWalletTx& wtx) wtx.mapSaplingNoteData = tmp; } - return !unchangedSproutFlag || !unchangedSaplingFlag; + return !unchangedSaplingFlag; } /** @@ -1667,7 +1514,6 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl return false; bool fExisted = mapWallet.count(tx.GetHash()) != 0; if (fExisted && !fUpdate) return false; - auto sproutNoteData = FindMySproutNotes(tx); auto saplingNoteDataAndAddressesToAdd = FindMySaplingNotes(tx); auto saplingNoteData = saplingNoteDataAndAddressesToAdd.first; auto addressesToAdd = saplingNoteDataAndAddressesToAdd.second; @@ -1691,7 +1537,7 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl fprintf(stderr, " %s\n", wladdr.c_str()); } } - if (fExisted || IsMine(tx) || IsFromMe(tx) || sproutNoteData.size() > 0 || saplingNoteData.size() > 0) + if (fExisted || IsMine(tx) || IsFromMe(tx) || saplingNoteData.size() > 0) { // wallet filter for notary nodes. Enables by setting -whitelistaddress= as startup param or in conf file (works same as -addnode byut with R-address's) if ( !tx.IsCoinBase() && !vWhiteListAddress.empty() && !NotaryAddress.empty() ) @@ -1723,10 +1569,6 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pbl CWalletTx wtx(this,tx); - if (sproutNoteData.size() > 0) { - wtx.SetSproutNoteData(sproutNoteData); - } - if (saplingNoteData.size() > 0) { wtx.SetSaplingNoteData(saplingNoteData); } @@ -1764,14 +1606,6 @@ void CWallet::MarkAffectedTransactionsDirty(const CTransaction& tx) if (mapWallet.count(txin.prevout.hash)) mapWallet[txin.prevout.hash].MarkDirty(); } - for (const JSDescription& jsdesc : tx.vjoinsplit) { - for (const uint256& nullifier : jsdesc.nullifiers) { - if (mapSproutNullifiersToNotes.count(nullifier) && - mapWallet.count(mapSproutNullifiersToNotes[nullifier].hash)) { - mapWallet[mapSproutNullifiersToNotes[nullifier].hash].MarkDirty(); - } - } - } for (const SpendDescription &spend : tx.vShieldedSpend) { uint256 nullifier = spend.nullifier; @@ -1806,82 +1640,6 @@ void CWallet::RescanWallet() } -/** - * Returns a nullifier if the SpendingKey is available - * Throws std::runtime_error if the decryptor doesn't match this note - */ -boost::optional CWallet::GetSproutNoteNullifier(const JSDescription &jsdesc, - const libzcash::SproutPaymentAddress &address, - const ZCNoteDecryption &dec, - const uint256 &hSig, - uint8_t n) const -{ - boost::optional ret; - auto note_pt = libzcash::SproutNotePlaintext::decrypt( - dec, - jsdesc.ciphertexts[n], - jsdesc.ephemeralKey, - hSig, - (unsigned char) n); - auto note = note_pt.note(address); - // SpendingKeys are only available if: - // - We have them (this isn't a viewing key) - // - The wallet is unlocked - libzcash::SproutSpendingKey key; - if (GetSproutSpendingKey(address, key)) { - ret = note.nullifier(key); - } - return ret; -} - -/** - * Finds all output notes in the given transaction that have been sent to - * PaymentAddresses in this wallet. - * - * It should never be necessary to call this method with a CWalletTx, because - * the result of FindMySproutNotes (for the addresses available at the time) will - * already have been cached in CWalletTx.mapSproutNoteData. - */ -mapSproutNoteData_t CWallet::FindMySproutNotes(const CTransaction &tx) const -{ - LOCK(cs_SpendingKeyStore); - uint256 hash = tx.GetHash(); - - mapSproutNoteData_t noteData; - for (size_t i = 0; i < tx.vjoinsplit.size(); i++) { - auto hSig = tx.vjoinsplit[i].h_sig(*pzcashParams, tx.joinSplitPubKey); - for (uint8_t j = 0; j < tx.vjoinsplit[i].ciphertexts.size(); j++) { - for (const NoteDecryptorMap::value_type& item : mapNoteDecryptors) { - try { - auto address = item.first; - JSOutPoint jsoutpt {hash, i, j}; - auto nullifier = GetSproutNoteNullifier( - tx.vjoinsplit[i], - address, - item.second, - hSig, j); - if (nullifier) { - SproutNoteData nd {address, *nullifier}; - noteData.insert(std::make_pair(jsoutpt, nd)); - } else { - SproutNoteData nd {address}; - noteData.insert(std::make_pair(jsoutpt, nd)); - } - break; - } catch (const note_decryption_failed &err) { - // Couldn't decrypt with this decryptor - } catch (const std::exception &exc) { - // Unexpected failure - LogPrintf("FindMySproutNotes(): Unexpected error while testing decrypt:\n"); - LogPrintf("%s\n", exc.what()); - } - } - } - } - return noteData; -} - - /** * Finds all output notes in the given transaction that have been sent to * SaplingPaymentAddresses in this wallet. @@ -1941,18 +1699,6 @@ std::pair CWallet::FindMySap return std::make_pair(noteData, viewingKeysToAdd); } -bool CWallet::IsSproutNullifierFromMe(const uint256& nullifier) const -{ - { - LOCK(cs_wallet); - if (mapSproutNullifiersToNotes.count(nullifier) && - mapWallet.count(mapSproutNullifiersToNotes.at(nullifier).hash)) { - return true; - } - } - return false; -} - bool CWallet::IsSaplingNullifierFromMe(const uint256& nullifier) const { { @@ -1965,33 +1711,6 @@ bool CWallet::IsSaplingNullifierFromMe(const uint256& nullifier) const return false; } -void CWallet::GetSproutNoteWitnesses(std::vector notes, - std::vector>& witnesses, - uint256 &final_anchor) -{ - LOCK(cs_wallet); - witnesses.resize(notes.size()); - boost::optional rt; - int i = 0; - for (JSOutPoint note : notes) { - if (mapWallet.count(note.hash) && - mapWallet[note.hash].mapSproutNoteData.count(note) && - mapWallet[note.hash].mapSproutNoteData[note].witnesses.size() > 0) { - witnesses[i] = mapWallet[note.hash].mapSproutNoteData[note].witnesses.front(); - if (!rt) { - rt = witnesses[i]->root(); - } else { - assert(*rt == witnesses[i]->root()); - } - } - i++; - } - // All returned witnesses have the same anchor - if (rt) { - final_anchor = *rt; - } -} - void CWallet::GetSaplingNoteWitnesses(std::vector notes, std::vector>& witnesses, uint256 &final_anchor) @@ -2001,14 +1720,26 @@ void CWallet::GetSaplingNoteWitnesses(std::vector notes, boost::optional rt; int i = 0; for (SaplingOutPoint note : notes) { - if (mapWallet.count(note.hash) && - mapWallet[note.hash].mapSaplingNoteData.count(note) && - mapWallet[note.hash].mapSaplingNoteData[note].witnesses.size() > 0) { - witnesses[i] = mapWallet[note.hash].mapSaplingNoteData[note].witnesses.front(); + //fprintf(stderr,"%s: i=%d\n", __func__,i); + auto noteData = mapWallet[note.hash].mapSaplingNoteData; + auto nWitnesses = noteData[note].witnesses.size(); + if (mapWallet.count(note.hash) && noteData.count(note) && nWitnesses > 0) { + fprintf(stderr,"%s: Found %lu witnesses for note %s\n", __func__, nWitnesses, note.hash.ToString().c_str() ); + witnesses[i] = noteData[note].witnesses.front(); if (!rt) { + //fprintf(stderr,"%s: Setting witness root\n",__func__); rt = witnesses[i]->root(); } else { - assert(*rt == witnesses[i]->root()); + if(*rt == witnesses[i]->root()) { + //fprintf(stderr,"%s: rt=%s\n",__func__,rt.GetHash().ToString().c_str()); + //fprintf(stderr,"%s: witnesses[%d]->root()=%s\n",__func__,i,witnesses[i]->root().GetHash().ToString().c_str()); + // Something is fucky + std::string err = string("CWallet::GetSaplingNoteWitnesses: Invalid witness root! rt=") + rt.get().ToString(); + err += string("\n!= witness[i]->root()=") + witnesses[i]->root().ToString(); + //throw std::logic_error(err); + fprintf(stderr,"%s: IGNORING %s\n", __func__,err.c_str()); + } + } } i++; @@ -2016,6 +1747,7 @@ void CWallet::GetSaplingNoteWitnesses(std::vector notes, // All returned witnesses have the same anchor if (rt) { final_anchor = *rt; + //fprintf(stderr,"%s: final_anchor=%s\n", __func__, rt.get().ToString().c_str() ); } } @@ -2224,13 +1956,6 @@ bool CWallet::IsFromMe(const CTransaction& tx) const if (GetDebit(tx, ISMINE_ALL) > 0) { return true; } - for (const JSDescription& jsdesc : tx.vjoinsplit) { - for (const uint256& nullifier : jsdesc.nullifiers) { - if (IsSproutNullifierFromMe(nullifier)) { - return true; - } - } - } for (const SpendDescription &spend : tx.vShieldedSpend) { if (IsSaplingNullifierFromMe(spend.nullifier)) { return true; @@ -2366,22 +2091,6 @@ bool CWallet::LoadCryptedHDSeed(const uint256& seedFp, const std::vector nd : noteData) { - if (nd.first.js < vjoinsplit.size() && - nd.first.n < vjoinsplit[nd.first.js].ciphertexts.size()) { - // Store the address and nullifier for the Note - mapSproutNoteData[nd.first] = nd.second; - } else { - // If FindMySproutNotes() was used to obtain noteData, - // this should never happen - throw std::logic_error("CWalletTx::SetSproutNoteData(): Invalid note"); - } - } -} - void CWalletTx::SetSaplingNoteData(mapSaplingNoteData_t ¬eData) { mapSaplingNoteData.clear(); @@ -2525,36 +2234,6 @@ void CWalletTx::GetAmounts(list& listReceived, if (isFromMyTaddr) { CAmount myVpubOld = 0; CAmount myVpubNew = 0; - for (const JSDescription& js : vjoinsplit) { - bool fMyJSDesc = false; - - // Check input side - for (const uint256& nullifier : js.nullifiers) { - if (pwallet->IsSproutNullifierFromMe(nullifier)) { - fMyJSDesc = true; - break; - } - } - - // Check output side - if (!fMyJSDesc) { - for (const std::pair nd : this->mapSproutNoteData) { - if (nd.first.js < vjoinsplit.size() && nd.first.n < vjoinsplit[nd.first.js].ciphertexts.size()) { - fMyJSDesc = true; - break; - } - } - } - - if (fMyJSDesc) { - myVpubOld += js.vpub_old; - myVpubNew += js.vpub_new; - } - - if (!MoneyRange(js.vpub_old) || !MoneyRange(js.vpub_new) || !MoneyRange(myVpubOld) || !MoneyRange(myVpubNew)) { - throw std::runtime_error("CWalletTx::GetAmounts: value out of range"); - } - } // Create an output for the value taken from or added to the transparent value pool by JoinSplits if (myVpubOld > myVpubNew) { @@ -2672,57 +2351,277 @@ void CWallet::WitnessNoteCommitment(std::vector commitments, std::vector>& witnesses, uint256 &final_anchor) { - witnesses.resize(commitments.size()); - CBlockIndex* pindex = chainActive.Genesis(); - SproutMerkleTree tree; +} - while (pindex) { - CBlock block; - ReadBlockFromDisk(block, pindex,1); +/** + * Reorder the transactions based on block hieght and block index. + * Transactions can get out of order when they are deleted and subsequently + * re-added during intial load rescan. + */ - BOOST_FOREACH(const CTransaction& tx, block.vtx) +void CWallet::ReorderWalletTransactions(std::map, CWalletTx*> &mapSorted, int64_t &maxOrderPos) +{ + LOCK2(cs_main, cs_wallet); + + int maxSortNumber = chainActive.Tip()->GetHeight() + 1; + + for (map::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) + { + CWalletTx* pwtx = &(it->second); + int confirms = pwtx->GetDepthInMainChain(); + maxOrderPos = max(maxOrderPos, pwtx->nOrderPos); + + if (confirms > 0) { + int wtxHeight = mapBlockIndex[pwtx->hashBlock]->GetHeight(); + auto key = std::make_pair(wtxHeight, pwtx->nIndex); + mapSorted.insert(make_pair(key, pwtx)); + } + else { + auto key = std::make_pair(maxSortNumber, 0); + mapSorted.insert(std::make_pair(key, pwtx)); + maxSortNumber++; + } + } +} + /**Update the nOrderPos with passed in ordered map. + */ + +void CWallet::UpdateWalletTransactionOrder(std::map, CWalletTx*> &mapSorted, bool resetOrder) { + LOCK2(cs_main, cs_wallet); + + int64_t previousPosition = 0; + std::map mapUpdatedTxs; + + //Check the postion of each transaction relative to the previous one. +for (map, CWalletTx*>::iterator it = mapSorted.begin(); it != mapSorted.end(); ++it) { + CWalletTx* pwtx = it->second; + const uint256 wtxid = pwtx->GetHash(); + + if (pwtx->nOrderPos <= previousPosition || resetOrder) { + previousPosition++; + pwtx->nOrderPos = previousPosition; + mapUpdatedTxs.insert(std::make_pair(wtxid, pwtx)); + } + else { + previousPosition = pwtx->nOrderPos; + } + } + + //Update transactions nOrderPos for transactions that changed + CWalletDB walletdb(strWalletFile, "r+", false); + for (map::iterator it = mapUpdatedTxs.begin(); it != mapUpdatedTxs.end(); ++it) { + CWalletTx* pwtx = it->second; + LogPrint("deletetx","Reorder Tx - Updating Positon to %i for Tx %s\n ", pwtx->nOrderPos, pwtx->GetHash().ToString()); + pwtx->WriteToDisk(&walletdb); + mapWallet[pwtx->GetHash()].nOrderPos = pwtx->nOrderPos; + } + + //Update Next Wallet Tx Positon + nOrderPosNext = previousPosition++; + CWalletDB(strWalletFile).WriteOrderPosNext(nOrderPosNext); + LogPrint("deletetx","Reorder Tx - Total Transactions Reordered %i, Next Position %i\n ", mapUpdatedTxs.size(), nOrderPosNext); + +} + +/** + * Delete transactions from the Wallet + */ +void CWallet::DeleteTransactions(std::vector &removeTxs) { + LOCK(cs_wallet); + + CWalletDB walletdb(strWalletFile, "r+", false); + + for (int i = 0; i< removeTxs.size(); i++) { + if (mapWallet.erase(removeTxs[i])) { + walletdb.EraseTx(removeTxs[i]); + LogPrint("deletetx","Delete Tx - Deleting tx %s, %i.\n", removeTxs[i].ToString(),i); + } else { + LogPrint("deletetx","Delete Tx - Deleting tx %failed.\n", removeTxs[i].ToString()); + return; + } + } +#if defined(__GLIBC__) + malloc_trim(0); +#else + // On Mac and Win memory isn't kept back upon vector or list member erase, different garbage collector strategy. No need to force trimming. +#endif +} + +void CWallet::DeleteWalletTransactions(const CBlockIndex* pindex) { + + LOCK2(cs_main, cs_wallet); + + int nDeleteAfter = (int)fDeleteTransactionsAfterNBlocks; + bool runCompact = false; + + if (pindex && fTxDeleteEnabled) { + + //Check for acentries - exit function if found { - BOOST_FOREACH(const JSDescription& jsdesc, tx.vjoinsplit) - { - BOOST_FOREACH(const uint256 ¬e_commitment, jsdesc.commitments) - { - tree.append(note_commitment); - - BOOST_FOREACH(boost::optional& wit, witnesses) { - if (wit) { - wit->append(note_commitment); - } - } - - size_t i = 0; - BOOST_FOREACH(uint256& commitment, commitments) { - if (note_commitment == commitment) { - witnesses.at(i) = tree.witness(); - } - i++; - } - } + std::list acentries; + CWalletDB walletdb(strWalletFile); + walletdb.ListAccountCreditDebit("*", acentries); + if (acentries.size() > 0) { + LogPrintf("deletetx not compatible to account entries\n"); + return; } } + //delete transactions - uint256 current_anchor = tree.root(); - - // Consistency check: we should be able to find the current tree - // in our CCoins view. - SproutMerkleTree dummy_tree; - assert(pcoinsTip->GetSproutAnchorAt(current_anchor, dummy_tree)); - - pindex = chainActive.Next(pindex); - } - - // TODO: #93; Select a root via some heuristic. - final_anchor = tree.root(); - - BOOST_FOREACH(boost::optional& wit, witnesses) { - if (wit) { - assert(final_anchor == wit->root()); + //Sort Transactions by block and block index + int64_t maxOrderPos = 0; + std::map, CWalletTx*> mapSorted; + ReorderWalletTransactions(mapSorted, maxOrderPos); + if (maxOrderPos > int64_t(mapSorted.size())*10) { + //reset the postion when the max postion is 10x bigger than the + //number of transactions in the wallet + LogPrint("deletetx","Reorder Tx - maxOrderPos %i mapSorted Size %i\n", maxOrderPos, int64_t(mapSorted.size())*10); + UpdateWalletTransactionOrder(mapSorted, true); } - } + else { + UpdateWalletTransactionOrder(mapSorted, false); + } + + //Process Transactions in sorted order + int txConflictCount = 0; + int txUnConfirmed = 0; + int txCount = 0; + int txSaveCount = 0; + std::vector removeTxs; + + for (auto & item : mapSorted) + { + + CWalletTx* pwtx = item.second; + const uint256& wtxid = pwtx->GetHash(); + bool deleteTx = true; + txCount += 1; + int wtxDepth = pwtx->GetDepthInMainChain(); + + //Keep anything newer than N Blocks + if (wtxDepth == 0) + txUnConfirmed++; + + if (wtxDepth < nDeleteAfter && wtxDepth >= 0) { + LogPrint("deletetx","DeleteTx - Transaction above minimum depth, tx %s\n", pwtx->GetHash().ToString()); + deleteTx = false; + txSaveCount++; + continue; + } else if (wtxDepth == -1) { + //Enabled by default + if (!fTxConflictDeleteEnabled) { + LogPrint("deletetx","DeleteTx - Conflict delete is not enabled tx %s\n", pwtx->GetHash().ToString()); + deleteTx = false; + txSaveCount++; + continue; + } else { + txConflictCount++; + } + } else { + + //Check for unspent inputs or spend less than N Blocks ago. (Sapling) + for (auto & pair : pwtx->mapSaplingNoteData) { + SaplingNoteData nd = pair.second; + if (!nd.nullifier || pwalletMain->GetSaplingSpendDepth(*nd.nullifier) <= fDeleteTransactionsAfterNBlocks) { + LogPrint("deletetx","DeleteTx - Unspent sapling input tx %s\n", pwtx->GetHash().ToString()); + deleteTx = false; + continue; + } + } + + if (!deleteTx) { + txSaveCount++; + continue; + } + + //Check for outputs that no longer have parents in the wallet. Exclude parents that are in the same transaction. (Sapling) + for (int i = 0; i < pwtx->vShieldedSpend.size(); i++) { + const SpendDescription& spendDesc = pwtx->vShieldedSpend[i]; + if (pwalletMain->IsSaplingNullifierFromMe(spendDesc.nullifier)) { + const uint256& parentHash = pwalletMain->mapSaplingNullifiersToNotes[spendDesc.nullifier].hash; + const CWalletTx* parent = pwalletMain->GetWalletTx(parentHash); + if (parent != NULL && parentHash != wtxid) { + LogPrint("deletetx","DeleteTx - Parent of sapling tx %s found\n", pwtx->GetHash().ToString()); + deleteTx = false; + continue; + } + } + } + + if (!deleteTx) { + txSaveCount++; + continue; + } + + if (!deleteTx) { + txSaveCount++; + continue; + } + + if (!deleteTx) { + txSaveCount++; + continue; + } + + //Check for unspent inputs or spend less than N Blocks ago. (Transparent) + for (unsigned int i = 0; i < pwtx->vout.size(); i++) { + CTxDestination address; + ExtractDestination(pwtx->vout[i].scriptPubKey, address); + if(IsMine(pwtx->vout[i])) { + if (pwalletMain->GetSpendDepth(pwtx->GetHash(), i) <= fDeleteTransactionsAfterNBlocks) { + LogPrint("deletetx","DeleteTx - Unspent transparent input tx %s\n", pwtx->GetHash().ToString()); + deleteTx = false; + continue; + } + } + } + + if (!deleteTx) { + txSaveCount++; + continue; + } + + //Chcek for output with that no longer have parents in the wallet. (Transparent) + for (int i = 0; i < pwtx->vin.size(); i++) { + const CTxIn& txin = pwtx->vin[i]; + const uint256& parentHash = txin.prevout.hash; + const CWalletTx* parent = pwalletMain->GetWalletTx(txin.prevout.hash); + if (parent != NULL && parentHash != wtxid) { + LogPrint("deletetx","DeleteTx - Parent of transparent tx %s found\n", pwtx->GetHash().ToString()); + deleteTx = false; + continue; + } + } + + if (!deleteTx) { + txSaveCount++; + continue; + } + + //Keep Last N Transactions + if (mapSorted.size() - txCount < fKeepLastNTransactions + txConflictCount + txUnConfirmed) { + LogPrint("deletetx","DeleteTx - Transaction set position %i, tx %s\n", mapSorted.size() - txCount, wtxid.ToString()); + deleteTx = false; + txSaveCount++; + continue; + } + } + + //Collect everything else for deletion + if (deleteTx && int(removeTxs.size()) < MAX_DELETE_TX_SIZE) { + removeTxs.push_back(wtxid); + runCompact = true; + } + } + + //Delete Transactions from wallet + DeleteTransactions(removeTxs); + LogPrintf("Delete Tx - Total Transaction Count %i, Transactions Deleted %i\n ", txCount, int(removeTxs.size())); + + //Compress Wallet + if (runCompact) + CWalletDB::Compact(bitdb,strWalletFile); + } } /** @@ -2738,8 +2637,6 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) CBlockIndex* pindex = pindexStart; - std::vector myTxHashes; - { LOCK2(cs_main, cs_wallet); @@ -2761,42 +2658,37 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) BOOST_FOREACH(CTransaction& tx, block.vtx) { if (AddToWalletIfInvolvingMe(tx, &block, fUpdate)) { - myTxHashes.push_back(tx.GetHash()); ret++; } } - SproutMerkleTree sproutTree; + //SproutMerkleTree sproutTree; SaplingMerkleTree saplingTree; // This should never fail: we should always be able to get the tree // state on the path to the tip of our chain - assert(pcoinsTip->GetSproutAnchorAt(pindex->hashSproutAnchor, sproutTree)); + //assert(pcoinsTip->GetSproutAnchorAt(pindex->hashSproutAnchor, sproutTree)); if (pindex->pprev) { if (NetworkUpgradeActive(pindex->pprev->GetHeight(), Params().GetConsensus(), Consensus::UPGRADE_SAPLING)) { assert(pcoinsTip->GetSaplingAnchorAt(pindex->pprev->hashFinalSaplingRoot, saplingTree)); } } - // Increment note witness caches - ChainTip(pindex, &block, sproutTree, saplingTree, true); - pindex = chainActive.Next(pindex); + // Build inital witness caches + BuildWitnessCache(pindex, true); + + //Delete Transactions + if (pindex->GetHeight() % fDeleteInterval == 0) + DeleteWalletTransactions(pindex); + if (GetTime() >= nNow + 60) { nNow = GetTime(); LogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->GetHeight(), Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), pindex)); } + pindex = chainActive.Next(pindex); } - - // After rescanning, persist Sapling note data that might have changed, e.g. nullifiers. - // Do not flush the wallet here for performance reasons. - CWalletDB walletdb(strWalletFile, "r+", false); - for (auto hash : myTxHashes) { - CWalletTx wtx = mapWallet[hash]; - if (!wtx.mapSaplingNoteData.empty()) { - if (!wtx.WriteToDisk(&walletdb)) { - LogPrintf("Rescanning... WriteToDisk failed to update Sapling note data for: %s\n", hash.ToString()); - } - } - } + + //Update all witness caches + BuildWitnessCache(chainActive.Tip(), false); ShowProgress(_("Rescanning..."), 100); // hide progress dialog in GUI } @@ -4589,38 +4481,6 @@ void CWallet::ListLockedCoins(std::vector& vOutpts) // Note Locking Operations -void CWallet::LockNote(const JSOutPoint& output) -{ - AssertLockHeld(cs_wallet); // setLockedSproutNotes - setLockedSproutNotes.insert(output); -} - -void CWallet::UnlockNote(const JSOutPoint& output) -{ - AssertLockHeld(cs_wallet); // setLockedSproutNotes - setLockedSproutNotes.erase(output); -} - -void CWallet::UnlockAllSproutNotes() -{ - AssertLockHeld(cs_wallet); // setLockedSproutNotes - setLockedSproutNotes.clear(); -} - -bool CWallet::IsLockedNote(const JSOutPoint& outpt) const -{ - AssertLockHeld(cs_wallet); // setLockedSproutNotes - - return (setLockedSproutNotes.count(outpt) > 0); -} - -std::vector CWallet::ListLockedSproutNotes() -{ - AssertLockHeld(cs_wallet); // setLockedSproutNotes - std::vector vOutpts(setLockedSproutNotes.begin(), setLockedSproutNotes.end()); - return vOutpts; -} - void CWallet::LockNote(const SaplingOutPoint& output) { AssertLockHeld(cs_wallet); @@ -4886,7 +4746,6 @@ bool CMerkleTx::AcceptToMemoryPool(bool fLimitFree, bool fRejectAbsurdFee) * These notes are decrypted and added to the output parameter vector, outEntries. */ void CWallet::GetFilteredNotes( - std::vector& sproutEntries, std::vector& saplingEntries, std::string address, int minDepth, @@ -4899,7 +4758,7 @@ void CWallet::GetFilteredNotes( filterAddresses.insert(DecodePaymentAddress(address)); } - GetFilteredNotes(sproutEntries, saplingEntries, filterAddresses, minDepth, INT_MAX, ignoreSpent, requireSpendingKey); + GetFilteredNotes(saplingEntries, filterAddresses, minDepth, INT_MAX, ignoreSpent, requireSpendingKey); } /** @@ -4908,7 +4767,6 @@ void CWallet::GetFilteredNotes( * These notes are decrypted and added to the output parameter vector, outEntries. */ void CWallet::GetFilteredNotes( - std::vector& sproutEntries, std::vector& saplingEntries, std::set& filterAddresses, int minDepth, @@ -4928,6 +4786,9 @@ void CWallet::GetFilteredNotes( if (minDepth > 1) { int nHeight = tx_height(wtx.GetHash()); + if ( nHeight == 0 ) { + continue; + } int nDepth = wtx.GetDepthInMainChain(); int dpowconfs = komodo_dpowconfs(nHeight,nDepth); if ( dpowconfs < minDepth || dpowconfs > maxDepth) { @@ -4940,62 +4801,6 @@ void CWallet::GetFilteredNotes( } } - for (auto & pair : wtx.mapSproutNoteData) { - JSOutPoint jsop = pair.first; - SproutNoteData nd = pair.second; - SproutPaymentAddress pa = nd.address; - - // skip notes which belong to a different payment address in the wallet - if (!(filterAddresses.empty() || filterAddresses.count(pa))) { - continue; - } - - // skip note which has been spent - if (ignoreSpent && nd.nullifier && IsSproutSpent(*nd.nullifier)) { - continue; - } - - // skip notes which cannot be spent - if (requireSpendingKey && !HaveSproutSpendingKey(pa)) { - continue; - } - - // skip locked notes - if (ignoreLocked && IsLockedNote(jsop)) { - continue; - } - - int i = jsop.js; // Index into CTransaction.vjoinsplit - int j = jsop.n; // Index into JSDescription.ciphertexts - - // Get cached decryptor - ZCNoteDecryption decryptor; - if (!GetNoteDecryptor(pa, decryptor)) { - // Note decryptors are created when the wallet is loaded, so it should always exist - throw std::runtime_error(strprintf("Could not find note decryptor for payment address %s", EncodePaymentAddress(pa))); - } - - // determine amount of funds in the note - auto hSig = wtx.vjoinsplit[i].h_sig(*pzcashParams, wtx.joinSplitPubKey); - try { - SproutNotePlaintext plaintext = SproutNotePlaintext::decrypt( - decryptor, - wtx.vjoinsplit[i].ciphertexts[j], - wtx.vjoinsplit[i].ephemeralKey, - hSig, - (unsigned char) j); - - sproutEntries.push_back(CSproutNotePlaintextEntry{jsop, pa, plaintext, wtx.GetDepthInMainChain()}); - - } catch (const note_decryption_failed &err) { - // Couldn't decrypt with this spending key - throw std::runtime_error(strprintf("Could not decrypt note for payment address %s", EncodePaymentAddress(pa))); - } catch (const std::exception &exc) { - // Unexpected failure - throw std::runtime_error(strprintf("Error while decrypting note for payment address %s: %s", EncodePaymentAddress(pa), exc.what())); - } - } - for (auto & pair : wtx.mapSaplingNoteData) { SaplingOutPoint op = pair.first; SaplingNoteData nd = pair.second; @@ -5050,11 +4855,6 @@ void CWallet::GetFilteredNotes( // Shielded key and address generalizations // -bool IncomingViewingKeyBelongsToWallet::operator()(const libzcash::SproutPaymentAddress &zaddr) const -{ - return m_wallet->HaveSproutViewingKey(zaddr); -} - bool IncomingViewingKeyBelongsToWallet::operator()(const libzcash::SaplingPaymentAddress &zaddr) const { libzcash::SaplingIncomingViewingKey ivk; @@ -5066,11 +4866,6 @@ bool IncomingViewingKeyBelongsToWallet::operator()(const libzcash::InvalidEncodi return false; } -bool PaymentAddressBelongsToWallet::operator()(const libzcash::SproutPaymentAddress &zaddr) const -{ - return m_wallet->HaveSproutSpendingKey(zaddr) || m_wallet->HaveSproutViewingKey(zaddr); -} - bool PaymentAddressBelongsToWallet::operator()(const libzcash::SaplingPaymentAddress &zaddr) const { libzcash::SaplingIncomingViewingKey ivk; @@ -5086,11 +4881,6 @@ bool PaymentAddressBelongsToWallet::operator()(const libzcash::InvalidEncoding& return false; } -bool HaveSpendingKeyForPaymentAddress::operator()(const libzcash::SproutPaymentAddress &zaddr) const -{ - return m_wallet->HaveSproutSpendingKey(zaddr); -} - bool HaveSpendingKeyForPaymentAddress::operator()(const libzcash::SaplingPaymentAddress &zaddr) const { libzcash::SaplingIncomingViewingKey ivk; @@ -5106,17 +4896,6 @@ bool HaveSpendingKeyForPaymentAddress::operator()(const libzcash::InvalidEncodin return false; } -boost::optional GetSpendingKeyForPaymentAddress::operator()( - const libzcash::SproutPaymentAddress &zaddr) const -{ - libzcash::SproutSpendingKey k; - if (m_wallet->GetSproutSpendingKey(zaddr, k)) { - return libzcash::SpendingKey(k); - } else { - return boost::none; - } -} - boost::optional GetSpendingKeyForPaymentAddress::operator()( const libzcash::SaplingPaymentAddress &zaddr) const { @@ -5135,20 +4914,6 @@ boost::optional GetSpendingKeyForPaymentAddress::operator return libzcash::SpendingKey(); } -SpendingKeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::SproutSpendingKey &sk) const { - auto addr = sk.address(); - if (log){ - LogPrint("zrpc", "Importing zaddr %s...\n", EncodePaymentAddress(addr)); - } - if (m_wallet->HaveSproutSpendingKey(addr)) { - return KeyAlreadyExists; - } else if (m_wallet-> AddSproutZKey(sk)) { - m_wallet->mapSproutZKeyMetadata[addr].nCreateTime = nTime; - return KeyAdded; - } else { - return KeyNotAdded; - } -} SpendingKeyAddResult AddSpendingKeyToWallet::operator()(const libzcash::SaplingExtendedSpendingKey &sk) const { auto fvk = sk.expsk.full_viewing_key(); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 223fecb7d..dd6100f97 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -23,6 +23,7 @@ #define BITCOIN_WALLET_WALLET_H #include "amount.h" +#include "asyncrpcoperation.h" #include "coins.h" #include "key.h" #include "keystore.h" @@ -60,6 +61,11 @@ extern unsigned int nTxConfirmTarget; extern bool bSpendZeroConfChange; extern bool fSendFreeTransactions; extern bool fPayAtLeastCustomFee; +extern bool fTxDeleteEnabled; +extern bool fTxConflictDeleteEnabled; +extern int fDeleteInterval; +extern unsigned int fDeleteTransactionsAfterNBlocks; +extern unsigned int fKeepLastNTransactions; //! -paytxfee default @@ -82,6 +88,18 @@ extern unsigned int WITNESS_CACHE_SIZE; //! Size of HD seed in bytes static const size_t HD_WALLET_SEED_LENGTH = 32; +//Default Transaction Rentention N-BLOCKS +static const int DEFAULT_TX_DELETE_INTERVAL = 1000; + +//Default Transaction Rentention N-BLOCKS +static const unsigned int DEFAULT_TX_RETENTION_BLOCKS = 10000; + +//Default Retention Last N-Transactions +static const unsigned int DEFAULT_TX_RETENTION_LASTTX = 200; + +//Amount of transactions to delete per run while syncing +static const int MAX_DELETE_TX_SIZE = 50000; + class CBlockIndex; class CCoinControl; class COutput; @@ -218,9 +236,10 @@ public: std::string ToString() const; }; +// NOTE: wallet.dat format depends on this data structure :( class SproutNoteData -{ -public: + { + public: libzcash::SproutPaymentAddress address; /** @@ -246,20 +265,14 @@ public: /** * Block height corresponding to the most current witness. * - * When we first create a SproutNoteData in CWallet::FindMySproutNotes, this is set to + * When we first create a SaplingNoteData in CWallet::FindMySaplingNotes, this is set to * -1 as a placeholder. The next time CWallet::ChainTip is called, we can * determine what height the witness cache for this note is valid for (even * if no witnesses were cached), and so can set the correct value in - * CWallet::IncrementNoteWitnesses and CWallet::DecrementNoteWitnesses. + * CWallet::BuildWitnessCache and CWallet::DecrementNoteWitnesses. */ int witnessHeight; - SproutNoteData() : address(), nullifier(), witnessHeight {-1} { } - SproutNoteData(libzcash::SproutPaymentAddress a) : - address {a}, nullifier(), witnessHeight {-1} { } - SproutNoteData(libzcash::SproutPaymentAddress a, uint256 n) : - address {a}, nullifier {n}, witnessHeight {-1} { } - ADD_SERIALIZE_METHODS; template @@ -270,27 +283,22 @@ public: READWRITE(witnessHeight); } - friend bool operator<(const SproutNoteData& a, const SproutNoteData& b) { - return (a.address < b.address || - (a.address == b.address && a.nullifier < b.nullifier)); - } - - friend bool operator==(const SproutNoteData& a, const SproutNoteData& b) { - return (a.address == b.address && a.nullifier == b.nullifier); - } - - friend bool operator!=(const SproutNoteData& a, const SproutNoteData& b) { - return !(a == b); - } }; + class SaplingNoteData { public: /** - * We initialize the height to -1 for the same reason as we do in SproutNoteData. - * See the comment in that class for a full description. + * Block height corresponding to the most current witness. + * + * When we first create a SaplingNoteData in CWallet::FindMySaplingNotes, this is set to + * -1 as a placeholder. The next time CWallet::ChainTip is called, we can + * determine what height the witness cache for this note is valid for (even + * if no witnesses were cached), and so can set the correct value in + * CWallet::BuildWitnessCache and CWallet::DecrementNoteWitnesses. */ + SaplingNoteData() : witnessHeight {-1}, nullifier() { } SaplingNoteData(libzcash::SaplingIncomingViewingKey ivk) : ivk {ivk}, witnessHeight {-1}, nullifier() { } SaplingNoteData(libzcash::SaplingIncomingViewingKey ivk, uint256 n) : ivk {ivk}, witnessHeight {-1}, nullifier(n) { } @@ -300,6 +308,9 @@ public: libzcash::SaplingIncomingViewingKey ivk; boost::optional nullifier; + //In Memory Only + bool witnessRootValidated; + ADD_SERIALIZE_METHODS; template @@ -323,18 +334,11 @@ public: } }; + +// NOTE: this sprout structure is serialized into wallet.dat, removing it would change wallet.dat format on disk :( typedef std::map mapSproutNoteData_t; typedef std::map mapSaplingNoteData_t; -/** Decrypted note, its location in a transaction, and number of confirmations. */ -struct CSproutNotePlaintextEntry -{ - JSOutPoint jsop; - libzcash::SproutPaymentAddress address; - libzcash::SproutNotePlaintext plaintext; - int confirmations; -}; - /** Sapling note, its location in a transaction, and number of confirmations. */ struct SaplingNoteEntry { @@ -565,11 +569,8 @@ public: MarkDirty(); } - void SetSproutNoteData(mapSproutNoteData_t ¬eData); void SetSaplingNoteData(mapSaplingNoteData_t ¬eData); - std::pair DecryptSproutNote( - JSOutPoint jsop) const; boost::optional> DecryptSaplingNote(SaplingOutPoint op) const; @@ -777,11 +778,12 @@ private: * detect and report conflicts (double-spends). */ typedef TxSpendMap TxNullifiers; - TxNullifiers mapTxSproutNullifiers; TxNullifiers mapTxSaplingNullifiers; + + std::vector pendingSaplingConsolidationTxs; + AsyncRPCOperationId saplingConsolidationOperationId; void AddToTransparentSpends(const COutPoint& outpoint, const uint256& wtxid); - void AddToSproutSpends(const uint256& nullifier, const uint256& wtxid); void AddToSaplingSpends(const uint256& nullifier, const uint256& wtxid); void AddToSpends(const uint256& wtxid); @@ -793,6 +795,7 @@ public: */ int64_t nWitnessCacheSize; bool needsRescan = false; + bool fSaplingConsolidationEnabled = false; void ClearNoteWitnessCache(); @@ -800,13 +803,15 @@ public: std::set GetNullifiers(); protected: + + int SaplingWitnessMinimumHeight(const uint256& nullifier, int nWitnessHeight, int nMinimumHeight); + /** * pindex is the new tip being connected. */ - void IncrementNoteWitnesses(const CBlockIndex* pindex, - const CBlock* pblock, - SproutMerkleTree& sproutTree, - SaplingMerkleTree& saplingTree); + int VerifyAndSetInitialWitness(const CBlockIndex* pindex, bool witnessOnly); + void BuildWitnessCache(const CBlockIndex* pindex, bool witnessOnly); + /** * pindex is the old tip being disconnected. */ @@ -822,11 +827,11 @@ protected: try { for (std::pair& wtxItem : mapWallet) { auto wtx = wtxItem.second; - // We skip transactions for which mapSproutNoteData and mapSaplingNoteData - // are empty. This covers transactions that have no Sprout or Sapling data + // We skip transactions for which mapSaplingNoteData + // is empty. This covers transactions that have no Sapling data // (i.e. are purely transparent), as well as shielding and unshielding // transactions in which we only have transparent addresses involved. - if (!(wtx.mapSproutNoteData.empty() && wtx.mapSaplingNoteData.empty())) { + if (!(wtx.mapSaplingNoteData.empty())) { if (!walletdb.WriteTx(wtxItem.first, wtx)) { LogPrintf("SetBestChain(): Failed to write CWalletTx, aborting atomic write\n"); walletdb.TxnAbort(); @@ -884,7 +889,6 @@ public: std::set setKeyPool; std::map mapKeyMetadata; - std::map mapSproutZKeyMetadata; std::map mapSaplingZKeyMetadata; typedef std::map MasterKeyMap; @@ -1001,8 +1005,9 @@ public: bool SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, std::vector vCoins, std::set >& setCoinsRet, CAmount& nValueRet) const; bool IsSpent(const uint256& hash, unsigned int n) const; - bool IsSproutSpent(const uint256& nullifier) const; + unsigned int GetSpendDepth(const uint256& hash, unsigned int n) const; bool IsSaplingSpent(const uint256& nullifier) const; + unsigned int GetSaplingSpendDepth(const uint256& nullifier) const; bool IsLockedCoin(uint256 hash, unsigned int n) const; void LockCoin(COutPoint& output); @@ -1013,8 +1018,6 @@ public: bool IsLockedNote(const JSOutPoint& outpt) const; void LockNote(const JSOutPoint& output); void UnlockNote(const JSOutPoint& output); - void UnlockAllSproutNotes(); - std::vector ListLockedSproutNotes(); bool IsLockedNote(const SaplingOutPoint& output) const; void LockNote(const SaplingOutPoint& output); @@ -1064,31 +1067,6 @@ public: void GetKeyBirthTimes(std::map &mapKeyBirth) const; - /** - * Sprout ZKeys - */ - //! Generates a new Sprout zaddr - libzcash::SproutPaymentAddress GenerateNewSproutZKey(); - //! Adds spending key to the store, and saves it to disk - bool AddSproutZKey(const libzcash::SproutSpendingKey &key); - //! Adds spending key to the store, without saving it to disk (used by LoadWallet) - bool LoadZKey(const libzcash::SproutSpendingKey &key); - //! Load spending key metadata (used by LoadWallet) - bool LoadZKeyMetadata(const libzcash::SproutPaymentAddress &addr, const CKeyMetadata &meta); - //! Adds an encrypted spending key to the store, without saving it to disk (used by LoadWallet) - bool LoadCryptedZKey(const libzcash::SproutPaymentAddress &addr, const libzcash::ReceivingKey &rk, const std::vector &vchCryptedSecret); - //! Adds an encrypted spending key to the store, and saves it to disk (virtual method, declared in crypter.h) - bool AddCryptedSproutSpendingKey( - const libzcash::SproutPaymentAddress &address, - const libzcash::ReceivingKey &rk, - const std::vector &vchCryptedSecret); - - //! Adds a Sprout viewing key to the store, and saves it to disk. - bool AddSproutViewingKey(const libzcash::SproutViewingKey &vk); - bool RemoveSproutViewingKey(const libzcash::SproutViewingKey &vk); - //! Adds a Sprout viewing key to the store, without saving it to disk (used by LoadWallet) - bool LoadSproutViewingKey(const libzcash::SproutViewingKey &dest); - /** * Sapling ZKeys */ @@ -1139,7 +1117,7 @@ public: bool UpdateNullifierNoteMap(); void UpdateNullifierNoteMapWithTx(const CWalletTx& wtx); void UpdateSaplingNullifierNoteMapWithTx(CWalletTx& wtx); - void UpdateSaplingNullifierNoteMapForBlock(const CBlock* pblock); + void UpdateNullifierNoteMapForBlock(const CBlock* pblock); bool AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletDB* pwalletdb); void EraseFromWallet(const uint256 &hash); void SyncTransaction(const CTransaction& tx, const CBlock* pblock); @@ -1149,6 +1127,10 @@ public: std::vector commitments, std::vector>& witnesses, uint256 &final_anchor); + void ReorderWalletTransactions(std::map, CWalletTx*> &mapSorted, int64_t &maxOrderPos); + void UpdateWalletTransactionOrder(std::map, CWalletTx*> &mapSorted, bool resetOrder); + void DeleteTransactions(std::vector &removeTxs); + void DeleteWalletTransactions(const CBlockIndex* pindex); int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false); void ReacceptWalletTransactions(); void ResendWalletTransactions(int64_t nBestBlockTime); @@ -1181,21 +1163,9 @@ public: std::set GetAccountAddresses(const std::string& strAccount) const; - boost::optional GetSproutNoteNullifier( - const JSDescription& jsdesc, - const libzcash::SproutPaymentAddress& address, - const ZCNoteDecryption& dec, - const uint256& hSig, - uint8_t n) const; - mapSproutNoteData_t FindMySproutNotes(const CTransaction& tx) const; std::pair FindMySaplingNotes(const CTransaction& tx) const; - bool IsSproutNullifierFromMe(const uint256& nullifier) const; bool IsSaplingNullifierFromMe(const uint256& nullifier) const; - void GetSproutNoteWitnesses( - std::vector notes, - std::vector>& witnesses, - uint256 &final_anchor); void GetSaplingNoteWitnesses( std::vector notes, std::vector>& witnesses, @@ -1215,7 +1185,12 @@ public: CAmount GetCredit(const CTransaction& tx, int32_t voutNum, const isminefilter& filter) const; CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const; CAmount GetChange(const CTransaction& tx) const; - void ChainTip(const CBlockIndex *pindex, const CBlock *pblock, SproutMerkleTree sproutTree, SaplingMerkleTree saplingTree, bool added); + void ChainTip( + const CBlockIndex *pindex, + const CBlock *pblock, + boost::optional> added); + void RunSaplingConsolidation(int blockHeight); + bool CommitConsolidationTx(const CTransaction& tx); /** Saves witness caches and best block locator to disk. */ void SetBestChain(const CBlockLocator& loc); std::set> GetNullifiersForAddresses(const std::set & addresses); @@ -1241,6 +1216,13 @@ public: } } + //void GetScriptForMining(boost::shared_ptr &script); + void ResetRequestCount(const uint256 &hash) + { + LOCK(cs_wallet); + mapRequestCount[hash] = 0; + }; + unsigned int GetKeyPoolSize() { AssertLockHeld(cs_wallet); // setKeyPool @@ -1317,8 +1299,7 @@ public: bool LoadCryptedHDSeed(const uint256& seedFp, const std::vector& seed); /* Find notes filtered by payment address, min depth, ability to spend */ - void GetFilteredNotes(std::vector& sproutEntries, - std::vector& saplingEntries, + void GetFilteredNotes(std::vector& saplingEntries, std::string address, int minDepth=1, bool ignoreSpent=true, @@ -1326,8 +1307,7 @@ public: /* Find notes filtered by payment addresses, min depth, max depth, if they are spent, if a spending key is required, and if they are locked */ - void GetFilteredNotes(std::vector& sproutEntries, - std::vector& saplingEntries, + void GetFilteredNotes(std::vector& saplingEntries, std::set& filterAddresses, int minDepth=1, int maxDepth=INT_MAX, @@ -1406,7 +1386,6 @@ private: public: PaymentAddressBelongsToWallet(CWallet *wallet) : m_wallet(wallet) {} - bool operator()(const libzcash::SproutPaymentAddress &zaddr) const; bool operator()(const libzcash::SaplingPaymentAddress &zaddr) const; bool operator()(const libzcash::InvalidEncoding& no) const; }; @@ -1419,7 +1398,6 @@ private: public: IncomingViewingKeyBelongsToWallet(CWallet *wallet) : m_wallet(wallet) {} - bool operator()(const libzcash::SproutPaymentAddress &zaddr) const; bool operator()(const libzcash::SaplingPaymentAddress &zaddr) const; bool operator()(const libzcash::InvalidEncoding& no) const; }; @@ -1431,7 +1409,6 @@ private: public: HaveSpendingKeyForPaymentAddress(CWallet *wallet) : m_wallet(wallet) {} - bool operator()(const libzcash::SproutPaymentAddress &zaddr) const; bool operator()(const libzcash::SaplingPaymentAddress &zaddr) const; bool operator()(const libzcash::InvalidEncoding& no) const; }; @@ -1443,7 +1420,6 @@ private: public: GetSpendingKeyForPaymentAddress(CWallet *wallet) : m_wallet(wallet) {} - boost::optional operator()(const libzcash::SproutPaymentAddress &zaddr) const; boost::optional operator()(const libzcash::SaplingPaymentAddress &zaddr) const; boost::optional operator()(const libzcash::InvalidEncoding& no) const; }; @@ -1515,7 +1491,6 @@ public: ) : m_wallet(wallet), params(params), nTime(_nTime), hdKeypath(_hdKeypath), seedFpStr(_seedFp), log(_log) {} - SpendingKeyAddResult operator()(const libzcash::SproutSpendingKey &sk) const; SpendingKeyAddResult operator()(const libzcash::SaplingExtendedSpendingKey &sk) const; SpendingKeyAddResult operator()(const libzcash::InvalidEncoding& no) const; }; diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index c29427b74..71331ed93 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -1,6 +1,6 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2014 The Bitcoin Core developers -// Copyright (c) 2019 The Hush 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. @@ -124,26 +124,6 @@ bool CWalletDB::WriteCryptedKey(const CPubKey& vchPubKey, return true; } -bool CWalletDB::WriteCryptedZKey(const libzcash::SproutPaymentAddress & addr, - const libzcash::ReceivingKey &rk, - const std::vector& vchCryptedSecret, - const CKeyMetadata &keyMeta) -{ - const bool fEraseUnencryptedKey = true; - nWalletDBUpdated++; - - if (!Write(std::make_pair(std::string("zkeymeta"), addr), keyMeta)) - return false; - - if (!Write(std::make_pair(std::string("czkey"), addr), std::make_pair(rk, vchCryptedSecret), false)) - return false; - if (fEraseUnencryptedKey) - { - Erase(std::make_pair(std::string("zkey"), addr)); - } - return true; -} - bool CWalletDB::WriteCryptedSaplingZKey( const libzcash::SaplingExtendedFullViewingKey &extfvk, const std::vector& vchCryptedSecret, @@ -172,16 +152,6 @@ bool CWalletDB::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey) return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true); } -bool CWalletDB::WriteZKey(const libzcash::SproutPaymentAddress& addr, const libzcash::SproutSpendingKey& key, const CKeyMetadata &keyMeta) -{ - nWalletDBUpdated++; - - if (!Write(std::make_pair(std::string("zkeymeta"), addr), keyMeta)) - return false; - - // pair is: tuple_key("zkey", paymentaddress) --> secretkey - return Write(std::make_pair(std::string("zkey"), addr), key, false); -} bool CWalletDB::WriteSaplingZKey(const libzcash::SaplingIncomingViewingKey &ivk, const libzcash::SaplingExtendedSpendingKey &key, const CKeyMetadata &keyMeta) @@ -203,18 +173,6 @@ bool CWalletDB::WriteSaplingPaymentAddress( return Write(std::make_pair(std::string("sapzaddr"), addr), ivk, false); } -bool CWalletDB::WriteSproutViewingKey(const libzcash::SproutViewingKey &vk) -{ - nWalletDBUpdated++; - return Write(std::make_pair(std::string("vkey"), vk), '1'); -} - -bool CWalletDB::EraseSproutViewingKey(const libzcash::SproutViewingKey &vk) -{ - nWalletDBUpdated++; - return Erase(std::make_pair(std::string("vkey"), vk)); -} - bool CWalletDB::WriteCScript(const uint160& hash, const CScript& redeemScript) { nWalletDBUpdated++; @@ -552,6 +510,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, } else if (strType == "vkey") { + /* libzcash::SproutViewingKey vk; ssKey >> vk; char fYes; @@ -559,24 +518,27 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, if (fYes == '1') pwallet->LoadSproutViewingKey(vk); - // Viewing keys have no birthday information for now, - // so set the wallet birthday to the beginning of time. + Viewing keys have no birthday information for now, + so set the wallet birthday to the beginning of time. pwallet->nTimeFirstKey = 1; + */ } else if (strType == "zkey") { + /* libzcash::SproutPaymentAddress addr; ssKey >> addr; libzcash::SproutSpendingKey key; ssValue >> key; - if (!pwallet->LoadZKey(key)) - { - strErr = "Error reading wallet database: LoadZKey failed"; - return false; - } + //if (!pwallet->LoadZKey(key)) + //{ + // strErr = "Error reading wallet database: LoadZKey failed"; + // return false; + //} wss.nZKeys++; + */ } else if (strType == "sapzkey") { @@ -691,6 +653,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, } else if (strType == "czkey") { + /* libzcash::SproutPaymentAddress addr; ssKey >> addr; // Deserialization of a pair is just one item after another @@ -707,6 +670,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, return false; } wss.fIsEncrypted = true; + */ } else if (strType == "csapzkey") { @@ -742,13 +706,15 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, } else if (strType == "zkeymeta") { + /* libzcash::SproutPaymentAddress addr; ssKey >> addr; CKeyMetadata keyMeta; ssValue >> keyMeta; wss.nZKeyMeta++; + */ - pwallet->LoadZKeyMetadata(addr, keyMeta); + // pwallet->LoadZKeyMetadata(addr, keyMeta); // ignore earliest key creation time as taddr will exist before any zaddr } @@ -1208,6 +1174,12 @@ bool BackupWallet(const CWallet& wallet, const string& strDest) return false; } +bool CWalletDB::Compact(CDBEnv& dbenv, const std::string& strFile) +{ + bool fSuccess = dbenv.Compact(strFile); + return fSuccess; +} + // // Try to (very carefully!) recover wallet.dat if there is a problem. // diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index 2c57ec1e8..64a4817d9 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -1,7 +1,8 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2013 The Bitcoin Core developers +// Copyright (c) 2009-2013 The Hush developers // Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. +// file COPYING or https://www.opensource.org/licenses/mit-license.php /****************************************************************************** * Copyright © 2014-2019 The SuperNET Developers. * @@ -189,6 +190,7 @@ public: DBErrors LoadWallet(CWallet* pwallet); DBErrors FindWalletTx(CWallet* pwallet, std::vector& vTxHash, std::vector& vWtx); DBErrors ZapWalletTx(CWallet* pwallet, std::vector& vWtx); + static bool Compact(CDBEnv& dbenv, const std::string& strFile); static bool Recover(CDBEnv& dbenv, const std::string& filename, bool fOnlyKeys); static bool Recover(CDBEnv& dbenv, const std::string& filename); @@ -198,23 +200,15 @@ public: bool WriteHDChain(const CHDChain& chain); /// Write spending key to wallet database, where key is payment address and value is spending key. - bool WriteZKey(const libzcash::SproutPaymentAddress& addr, const libzcash::SproutSpendingKey& key, const CKeyMetadata &keyMeta); bool WriteSaplingZKey(const libzcash::SaplingIncomingViewingKey &ivk, const libzcash::SaplingExtendedSpendingKey &key, const CKeyMetadata &keyMeta); bool WriteSaplingPaymentAddress(const libzcash::SaplingPaymentAddress &addr, const libzcash::SaplingIncomingViewingKey &ivk); - bool WriteCryptedZKey(const libzcash::SproutPaymentAddress & addr, - const libzcash::ReceivingKey & rk, - const std::vector& vchCryptedSecret, - const CKeyMetadata &keyMeta); bool WriteCryptedSaplingZKey(const libzcash::SaplingExtendedFullViewingKey &extfvk, const std::vector& vchCryptedSecret, const CKeyMetadata &keyMeta); - bool WriteSproutViewingKey(const libzcash::SproutViewingKey &vk); - bool EraseSproutViewingKey(const libzcash::SproutViewingKey &vk); - private: CWalletDB(const CWalletDB&); void operator=(const CWalletDB&); diff --git a/src/zcash/Address.cpp b/src/zcash/Address.cpp index 148cd321c..5ce66a82f 100644 --- a/src/zcash/Address.cpp +++ b/src/zcash/Address.cpp @@ -1,3 +1,7 @@ +// Copyright (c) 2019-2020 The Hush developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or https://www.opensource.org/licenses/mit-license.php + #include "Address.hpp" #include "NoteEncryption.hpp" #include "hash.h" @@ -13,36 +17,6 @@ const uint32_t SAPLING_BRANCH_ID = 0x76b809bb; namespace libzcash { -uint256 SproutPaymentAddress::GetHash() const { - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << *this; - return Hash(ss.begin(), ss.end()); -} - -uint256 ReceivingKey::pk_enc() const { - return ZCNoteEncryption::generate_pubkey(*this); -} - -SproutPaymentAddress SproutViewingKey::address() const { - return SproutPaymentAddress(a_pk, sk_enc.pk_enc()); -} - -ReceivingKey SproutSpendingKey::receiving_key() const { - return ReceivingKey(ZCNoteEncryption::generate_privkey(*this)); -} - -SproutViewingKey SproutSpendingKey::viewing_key() const { - return SproutViewingKey(PRF_addr_a_pk(*this), receiving_key()); -} - -SproutSpendingKey SproutSpendingKey::random() { - return SproutSpendingKey(random_uint252()); -} - -SproutPaymentAddress SproutSpendingKey::address() const { - return viewing_key().address(); -} - //! Sapling uint256 SaplingPaymentAddress::GetHash() const { CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); @@ -119,10 +93,6 @@ class IsValidAddressForNetwork : public boost::static_visitor { public: IsValidAddressForNetwork(uint32_t consensusBranchId) : branchId(consensusBranchId) {} - bool operator()(const libzcash::SproutPaymentAddress &addr) const { - return true; - } - bool operator()(const libzcash::InvalidEncoding &addr) const { return false; } diff --git a/src/zcash/Address.hpp b/src/zcash/Address.hpp index 42ee0031b..ac90120a5 100644 --- a/src/zcash/Address.hpp +++ b/src/zcash/Address.hpp @@ -1,3 +1,5 @@ +// Copyright (c) 2019-2020 The Hush developers + #ifndef ZC_ADDRESS_H_ #define ZC_ADDRESS_H_ @@ -26,6 +28,16 @@ const size_t SerializedSaplingSpendingKeySize = 32; typedef std::array diversifier_t; +class ReceivingKey : public uint256 { +public: + ReceivingKey() { } + ReceivingKey(uint256 sk_enc) : uint256(sk_enc) { } + + uint256 pk_enc() const; +}; + + +// NOTE: wallet.dat format depends on this class SproutPaymentAddress { public: uint256 a_pk; @@ -54,52 +66,6 @@ public: } }; -class ReceivingKey : public uint256 { -public: - ReceivingKey() { } - ReceivingKey(uint256 sk_enc) : uint256(sk_enc) { } - - uint256 pk_enc() const; -}; - -class SproutViewingKey { -public: - uint256 a_pk; - ReceivingKey sk_enc; - - SproutViewingKey() : a_pk(), sk_enc() { } - SproutViewingKey(uint256 a_pk, ReceivingKey sk_enc) : a_pk(a_pk), sk_enc(sk_enc) { } - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action) { - READWRITE(a_pk); - READWRITE(sk_enc); - } - - SproutPaymentAddress address() const; - - friend inline bool operator==(const SproutViewingKey& a, const SproutViewingKey& b) { - return a.a_pk == b.a_pk && a.sk_enc == b.sk_enc; - } - friend inline bool operator<(const SproutViewingKey& a, const SproutViewingKey& b) { - return (a.a_pk < b.a_pk || - (a.a_pk == b.a_pk && a.sk_enc < b.sk_enc)); - } -}; - -class SproutSpendingKey : public uint252 { -public: - SproutSpendingKey() : uint252() { } - SproutSpendingKey(uint252 a_sk) : uint252(a_sk) { } - - static SproutSpendingKey random(); - - ReceivingKey receiving_key() const; - SproutViewingKey viewing_key() const; - SproutPaymentAddress address() const; -}; //! Sapling functions. class SaplingPaymentAddress { @@ -218,8 +184,8 @@ public: SaplingPaymentAddress default_address() const; }; -typedef boost::variant PaymentAddress; -typedef boost::variant ViewingKey; +typedef boost::variant PaymentAddress; +typedef boost::variant ViewingKey; } diff --git a/src/zcash/CreateJoinSplit.cpp b/src/zcash/CreateJoinSplit.cpp deleted file mode 100644 index 06b76bb9b..000000000 --- a/src/zcash/CreateJoinSplit.cpp +++ /dev/null @@ -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 -} diff --git a/src/zcash/GenerateParams.cpp b/src/zcash/GenerateParams.cpp deleted file mode 100644 index 94f1c73c1..000000000 --- a/src/zcash/GenerateParams.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "zcash/JoinSplit.hpp" - -#include -#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; -} diff --git a/src/zcash/IncrementalMerkleTree.cpp b/src/zcash/IncrementalMerkleTree.cpp index f8d5fad61..d4411c11b 100644 --- a/src/zcash/IncrementalMerkleTree.cpp +++ b/src/zcash/IncrementalMerkleTree.cpp @@ -1,3 +1,5 @@ +// Copyright (c) 2019-2020 The Hush developers + #include #include @@ -35,6 +37,391 @@ PedersenHash PedersenHash::uncommitted() { return res; } +static const std::array pedersen_empty_roots = { + uint256(std::vector{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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 +438,409 @@ SHA256Compress SHA256Compress::combine( return res; } +static const std::array sha256_empty_roots = { + uint256(std::vector{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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{ + 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 class PathFiller { private: @@ -228,6 +1018,7 @@ size_t IncrementalMerkleTree::next_depth(size_t skip) const { template Hash IncrementalMerkleTree::root(size_t depth, std::deque filler_hashes) const { + //fprintf(stderr,"%s: depth=%d\n",__func__,depth); PathFiller filler(filler_hashes); Hash combine_left = left ? *left : filler.next(0); diff --git a/src/zcash/IncrementalMerkleTree.hpp b/src/zcash/IncrementalMerkleTree.hpp index 79a90bc5b..ab55e8ad4 100644 --- a/src/zcash/IncrementalMerkleTree.hpp +++ b/src/zcash/IncrementalMerkleTree.hpp @@ -1,3 +1,5 @@ +// Copyright (c) 2019-2020 The Hush developers + #ifndef ZC_INCREMENTALMERKLETREE_H_ #define ZC_INCREMENTALMERKLETREE_H_ @@ -57,14 +59,9 @@ public: template 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 friend bool operator==(const EmptyMerkleRoots& a, @@ -227,6 +224,7 @@ public: static SHA256Compress uncommitted() { return SHA256Compress(); } + static SHA256Compress EmptyRoot(size_t); }; class PedersenHash : public uint256 { @@ -241,6 +239,7 @@ public: ); static PedersenHash uncommitted(); + static PedersenHash EmptyRoot(size_t); }; template diff --git a/src/zcash/JoinSplit.cpp b/src/zcash/JoinSplit.cpp index ac59ccfa3..5cd7627dc 100644 --- a/src/zcash/JoinSplit.cpp +++ b/src/zcash/JoinSplit.cpp @@ -1,3 +1,4 @@ +// Copyright (c) 2019-2020 The Hush developers #include "JoinSplit.hpp" #include "prf.h" #include "sodium.h" @@ -10,434 +11,22 @@ #include #include #include -#include -#include -#include -#include #include "tinyformat.h" #include "sync.h" #include "amount.h" -extern int64_t MAX_MONEY; #include "librustzcash.h" #include "streams.h" #include "version.h" -using namespace libsnark; - namespace libzcash { -#include "zcash/circuit/gadget.tcc" - static CCriticalSection cs_ParamsIO; -template -void saveToFile(const std::string path, T& obj) { - LOCK(cs_ParamsIO); - - std::stringstream ss; - ss << obj; - std::ofstream fh; - fh.open(path, std::ios::binary); - ss.rdbuf()->pubseekpos(0, std::ios_base::out); - fh << ss.rdbuf(); - fh.flush(); - fh.close(); -} - -template -void loadFromFile(const std::string path, T& objIn) { - LOCK(cs_ParamsIO); - - std::stringstream ss; - std::ifstream fh(path, std::ios::binary); - - if(!fh.is_open()) { - throw std::runtime_error(strprintf("could not load param file at %s", path)); - } - - ss << fh.rdbuf(); - fh.close(); - - ss.rdbuf()->pubseekpos(0, std::ios_base::in); - - T obj; - ss >> obj; - - objIn = std::move(obj); -} - template class JoinSplitCircuit : public JoinSplit { public: - typedef default_r1cs_ppzksnark_pp ppzksnark_ppT; - typedef Fr FieldT; - - r1cs_ppzksnark_verification_key vk; - r1cs_ppzksnark_processed_verification_key vk_precomp; - std::string pkPath; - - JoinSplitCircuit(const std::string vkPath, const std::string pkPath) : pkPath(pkPath) { - loadFromFile(vkPath, vk); - vk_precomp = r1cs_ppzksnark_verifier_process_vk(vk); - } + JoinSplitCircuit() {} ~JoinSplitCircuit() {} - - static void generate(const std::string r1csPath, - const std::string vkPath, - const std::string pkPath) - { - protoboard pb; - - joinsplit_gadget g(pb); - g.generate_r1cs_constraints(); - - auto r1cs = pb.get_constraint_system(); - - saveToFile(r1csPath, r1cs); - - r1cs_ppzksnark_keypair keypair = r1cs_ppzksnark_generator(r1cs); - - saveToFile(vkPath, keypair.vk); - saveToFile(pkPath, keypair.pk); - } - - bool verify( - const PHGRProof& proof, - ProofVerifier& verifier, - const uint256& joinSplitPubKey, - const uint256& randomSeed, - const std::array& macs, - const std::array& nullifiers, - const std::array& commitments, - uint64_t vpub_old, - uint64_t vpub_new, - const uint256& rt - ) { - try { - auto r1cs_proof = proof.to_libsnark_proof>(); - - uint256 h_sig = this->h_sig(randomSeed, nullifiers, joinSplitPubKey); - - auto witness = joinsplit_gadget::witness_map( - rt, - h_sig, - macs, - nullifiers, - commitments, - vpub_old, - vpub_new - ); - - return verifier.check( - vk, - vk_precomp, - witness, - r1cs_proof - ); - } catch (...) { - return false; - } - } - - SproutProof prove( - bool makeGrothProof, - const std::array& inputs, - const std::array& outputs, - std::array& out_notes, - std::array& out_ciphertexts, - uint256& out_ephemeralKey, - const uint256& joinSplitPubKey, - uint256& out_randomSeed, - std::array& out_macs, - std::array& out_nullifiers, - std::array& out_commitments, - uint64_t vpub_old, - uint64_t vpub_new, - const uint256& rt, - bool computeProof, - uint256 *out_esk // Payment disclosure - ) { - if (vpub_old > MAX_MONEY) { - throw std::invalid_argument("nonsensical vpub_old value"); - } - - if (vpub_new > MAX_MONEY) { - throw std::invalid_argument("nonsensical vpub_new value"); - } - - uint64_t lhs_value = vpub_old; - uint64_t rhs_value = vpub_new; - - for (size_t i = 0; i < NumInputs; i++) { - // Sanity checks of input - { - // If note has nonzero value - if (inputs[i].note.value() != 0) { - // The witness root must equal the input root. - if (inputs[i].witness.root() != rt) { - throw std::invalid_argument("joinsplit not anchored to the correct root"); - } - - // The tree must witness the correct element - if (inputs[i].note.cm() != inputs[i].witness.element()) { - throw std::invalid_argument("witness of wrong element for joinsplit input"); - } - } - - // Ensure we have the key to this note. - if (inputs[i].note.a_pk != inputs[i].key.address().a_pk) { - throw std::invalid_argument("input note not authorized to spend with given key"); - } - - // Balance must be sensical - if (inputs[i].note.value() > MAX_MONEY) { - throw std::invalid_argument("nonsensical input note value"); - } - - lhs_value += inputs[i].note.value(); - - if (lhs_value > MAX_MONEY) { - throw std::invalid_argument("nonsensical left hand size of joinsplit balance"); - } - } - - // Compute nullifier of input - out_nullifiers[i] = inputs[i].nullifier(); - } - - // Sample randomSeed - out_randomSeed = random_uint256(); - - // Compute h_sig - uint256 h_sig = this->h_sig(out_randomSeed, out_nullifiers, joinSplitPubKey); - - // Sample phi - uint252 phi = random_uint252(); - - // Compute notes for outputs - for (size_t i = 0; i < NumOutputs; i++) { - // Sanity checks of output - { - if (outputs[i].value > MAX_MONEY) { - throw std::invalid_argument("nonsensical output value"); - } - - rhs_value += outputs[i].value; - - if (rhs_value > MAX_MONEY) { - throw std::invalid_argument("nonsensical right hand side of joinsplit balance"); - } - } - - // Sample r - uint256 r = random_uint256(); - - out_notes[i] = outputs[i].note(phi, r, i, h_sig); - } - - if (lhs_value != rhs_value) { - throw std::invalid_argument("invalid joinsplit balance"); - } - - // Compute the output commitments - for (size_t i = 0; i < NumOutputs; i++) { - out_commitments[i] = out_notes[i].cm(); - } - - // Encrypt the ciphertexts containing the note - // plaintexts to the recipients of the value. - { - ZCNoteEncryption encryptor(h_sig); - - for (size_t i = 0; i < NumOutputs; i++) { - SproutNotePlaintext pt(out_notes[i], outputs[i].memo); - - out_ciphertexts[i] = pt.encrypt(encryptor, outputs[i].addr.pk_enc); - } - - out_ephemeralKey = encryptor.get_epk(); - - // !!! Payment disclosure START - if (out_esk != nullptr) { - *out_esk = encryptor.get_esk(); - } - // !!! Payment disclosure END - } - - // Authenticate h_sig with each of the input - // spending keys, producing macs which protect - // against malleability. - for (size_t i = 0; i < NumInputs; i++) { - out_macs[i] = PRF_pk(inputs[i].key, i, h_sig); - } - - if (makeGrothProof) { - if (!computeProof) { - return GrothProof(); - } - - GrothProof proof; - - CDataStream ss1(SER_NETWORK, PROTOCOL_VERSION); - ss1 << inputs[0].witness.path(); - std::vector auth1(ss1.begin(), ss1.end()); - - CDataStream ss2(SER_NETWORK, PROTOCOL_VERSION); - ss2 << inputs[1].witness.path(); - std::vector auth2(ss2.begin(), ss2.end()); - - librustzcash_sprout_prove( - proof.begin(), - - phi.begin(), - rt.begin(), - h_sig.begin(), - - inputs[0].key.begin(), - inputs[0].note.value(), - inputs[0].note.rho.begin(), - inputs[0].note.r.begin(), - auth1.data(), - - inputs[1].key.begin(), - inputs[1].note.value(), - inputs[1].note.rho.begin(), - inputs[1].note.r.begin(), - auth2.data(), - - out_notes[0].a_pk.begin(), - out_notes[0].value(), - out_notes[0].r.begin(), - - out_notes[1].a_pk.begin(), - out_notes[1].value(), - out_notes[1].r.begin(), - - vpub_old, - vpub_new - ); - - return proof; - } - - if (!computeProof) { - return PHGRProof(); - } - - protoboard pb; - { - joinsplit_gadget g(pb); - g.generate_r1cs_constraints(); - g.generate_r1cs_witness( - phi, - rt, - h_sig, - inputs, - out_notes, - vpub_old, - vpub_new - ); - } - - // The constraint system must be satisfied or there is an unimplemented - // or incorrect sanity check above. Or the constraint system is broken! - assert(pb.is_satisfied()); - - // TODO: These are copies, which is not strictly necessary. - std::vector primary_input = pb.primary_input(); - std::vector aux_input = pb.auxiliary_input(); - - // Swap A and B if it's beneficial (less arithmetic in G2) - // In our circuit, we already know that it's beneficial - // to swap, but it takes so little time to perform this - // estimate that it doesn't matter if we check every time. - pb.constraint_system.swap_AB_if_beneficial(); - - std::ifstream fh(pkPath, std::ios::binary); - - if(!fh.is_open()) { - throw std::runtime_error(strprintf("could not load param file at %s", pkPath)); - } - - return PHGRProof(r1cs_ppzksnark_prover_streaming( - fh, - primary_input, - aux_input, - pb.constraint_system - )); - } }; - -template -void JoinSplit::Generate(const std::string r1csPath, - const std::string vkPath, - const std::string pkPath) -{ - initialize_curve_params(); - JoinSplitCircuit::generate(r1csPath, vkPath, pkPath); -} - -template -JoinSplit* JoinSplit::Prepared(const std::string vkPath, - const std::string pkPath) -{ - initialize_curve_params(); - return new JoinSplitCircuit(vkPath, pkPath); -} - -template -uint256 JoinSplit::h_sig( - const uint256& randomSeed, - const std::array& nullifiers, - const uint256& joinSplitPubKey -) { - const unsigned char personalization[crypto_generichash_blake2b_PERSONALBYTES] - = {'Z','c','a','s','h','C','o','m','p','u','t','e','h','S','i','g'}; - - std::vector block(randomSeed.begin(), randomSeed.end()); - - for (size_t i = 0; i < NumInputs; i++) { - block.insert(block.end(), nullifiers[i].begin(), nullifiers[i].end()); - } - - block.insert(block.end(), joinSplitPubKey.begin(), joinSplitPubKey.end()); - - uint256 output; - - if (crypto_generichash_blake2b_salt_personal(output.begin(), 32, - &block[0], block.size(), - NULL, 0, // No key. - NULL, // No salt. - personalization - ) != 0) - { - throw std::logic_error("hash function failure"); - } - - return output; -} - -SproutNote JSOutput::note(const uint252& phi, const uint256& r, size_t i, const uint256& h_sig) const { - uint256 rho = PRF_rho(phi, i, h_sig); - - return SproutNote(addr.a_pk, value, rho, r); -} - -JSOutput::JSOutput() : addr(uint256(), uint256()), value(0) { - SproutSpendingKey a_sk = SproutSpendingKey::random(); - addr = a_sk.address(); -} - -JSInput::JSInput() : witness(SproutMerkleTree().witness()), - key(SproutSpendingKey::random()) { - note = SproutNote(key.address().a_pk, 0, random_uint256(), random_uint256()); - SproutMerkleTree dummy_tree; - dummy_tree.append(note.cm()); - witness = dummy_tree.witness(); -} - -template class JoinSplit; - } diff --git a/src/zcash/JoinSplit.hpp b/src/zcash/JoinSplit.hpp index c37926ede..e7aded3c1 100644 --- a/src/zcash/JoinSplit.hpp +++ b/src/zcash/JoinSplit.hpp @@ -1,3 +1,5 @@ +// Copyright (c) 2019-2020 The Hush developers + #ifndef ZC_JOINSPLIT_H_ #define ZC_JOINSPLIT_H_ @@ -24,87 +26,13 @@ typedef std::array GrothProof; typedef boost::variant SproutProof; class JSInput { -public: - SproutWitness witness; - SproutNote note; - SproutSpendingKey key; - - JSInput(); - JSInput(SproutWitness witness, - SproutNote note, - SproutSpendingKey key) : witness(witness), note(note), key(key) { } - - uint256 nullifier() const { - return note.nullifier(key); - } }; class JSOutput { -public: - SproutPaymentAddress addr; - uint64_t value; - std::array memo = {{0xF6}}; // 0xF6 is invalid UTF8 as per spec, rest of array is 0x00 - - JSOutput(); - JSOutput(SproutPaymentAddress addr, uint64_t value) : addr(addr), value(value) { } - - SproutNote note(const uint252& phi, const uint256& r, size_t i, const uint256& h_sig) const; }; template class JoinSplit { -public: - virtual ~JoinSplit() {} - - static void Generate(const std::string r1csPath, - const std::string vkPath, - const std::string pkPath); - static JoinSplit* Prepared(const std::string vkPath, - const std::string pkPath); - - static uint256 h_sig(const uint256& randomSeed, - const std::array& nullifiers, - const uint256& joinSplitPubKey - ); - - // Compute nullifiers, macs, note commitments & encryptions, and SNARK proof - virtual SproutProof prove( - bool makeGrothProof, - const std::array& inputs, - const std::array& outputs, - std::array& out_notes, - std::array& out_ciphertexts, - uint256& out_ephemeralKey, - const uint256& joinSplitPubKey, - uint256& out_randomSeed, - std::array& out_hmacs, - std::array& out_nullifiers, - std::array& out_commitments, - uint64_t vpub_old, - uint64_t vpub_new, - const uint256& rt, - bool computeProof = true, - // For paymentdisclosure, we need to retrieve the esk. - // Reference as non-const parameter with default value leads to compile error. - // So use pointer for simplicity. - uint256 *out_esk = nullptr - ) = 0; - - virtual bool verify( - const PHGRProof& proof, - ProofVerifier& verifier, - const uint256& joinSplitPubKey, - const uint256& randomSeed, - const std::array& hmacs, - const std::array& nullifiers, - const std::array& commitments, - uint64_t vpub_old, - uint64_t vpub_new, - const uint256& rt - ) = 0; - -protected: - JoinSplit() {} }; } diff --git a/src/zcash/Note.cpp b/src/zcash/Note.cpp index 23210c784..e6d185a0e 100644 --- a/src/zcash/Note.cpp +++ b/src/zcash/Note.cpp @@ -1,3 +1,5 @@ +// Copyright (c) 2019-2020 The Hush developers + #include "Note.hpp" #include "prf.h" #include "crypto/sha256.h" @@ -11,35 +13,6 @@ using namespace libzcash; -SproutNote::SproutNote() { - a_pk = random_uint256(); - rho = random_uint256(); - r = random_uint256(); -} - -uint256 SproutNote::cm() const { - unsigned char discriminant = 0xb0; - - CSHA256 hasher; - hasher.Write(&discriminant, 1); - hasher.Write(a_pk.begin(), 32); - - auto value_vec = convertIntToVectorLE(value_); - - hasher.Write(&value_vec[0], value_vec.size()); - hasher.Write(rho.begin(), 32); - hasher.Write(r.begin(), 32); - - uint256 result; - hasher.Finalize(result.begin()); - - return result; -} - -uint256 SproutNote::nullifier(const SproutSpendingKey& a_sk) const { - return PRF_nf(a_sk, rho); -} - // Construct and populate Sapling note for a given payment address and value. SaplingNote::SaplingNote(const SaplingPaymentAddress& address, const uint64_t value) : BaseNote(value) { d = address.d; @@ -88,57 +61,6 @@ boost::optional SaplingNote::nullifier(const SaplingFullViewingKey& vk, return result; } -SproutNotePlaintext::SproutNotePlaintext( - const SproutNote& note, - std::array memo) : BaseNotePlaintext(note, memo) -{ - rho = note.rho; - r = note.r; -} - -SproutNote SproutNotePlaintext::note(const SproutPaymentAddress& addr) const -{ - return SproutNote(addr.a_pk, value_, rho, r); -} - -SproutNotePlaintext SproutNotePlaintext::decrypt(const ZCNoteDecryption& decryptor, - const ZCNoteDecryption::Ciphertext& ciphertext, - const uint256& ephemeralKey, - const uint256& h_sig, - unsigned char nonce - ) -{ - auto plaintext = decryptor.decrypt(ciphertext, ephemeralKey, h_sig, nonce); - - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << plaintext; - - SproutNotePlaintext ret; - ss >> ret; - - assert(ss.size() == 0); - - return ret; -} - -ZCNoteEncryption::Ciphertext SproutNotePlaintext::encrypt(ZCNoteEncryption& encryptor, - const uint256& pk_enc - ) const -{ - CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << (*this); - - ZCNoteEncryption::Plaintext pt; - - assert(pt.size() == ss.size()); - - memcpy(&pt[0], &ss[0], pt.size()); - - return encryptor.encrypt(pk_enc, pt); -} - - - // Construct and populate SaplingNotePlaintext for a given note and memo. SaplingNotePlaintext::SaplingNotePlaintext( const SaplingNote& note, diff --git a/src/zcash/Note.hpp b/src/zcash/Note.hpp index 7d3377306..5b16d95c5 100644 --- a/src/zcash/Note.hpp +++ b/src/zcash/Note.hpp @@ -1,3 +1,5 @@ +// Copyright (c) 2019-2020 The Hush developers + #ifndef ZC_NOTE_H_ #define ZC_NOTE_H_ @@ -22,25 +24,6 @@ public: inline uint64_t value() const { return value_; }; }; -class SproutNote : public BaseNote { -public: - uint256 a_pk; - uint256 rho; - uint256 r; - - SproutNote(uint256 a_pk, uint64_t value, uint256 rho, uint256 r) - : BaseNote(value), a_pk(a_pk), rho(rho), r(r) {} - - SproutNote(); - - virtual ~SproutNote() {}; - - uint256 cm() const; - - uint256 nullifier(const SproutSpendingKey& a_sk) const; -}; - - class SaplingNote : public BaseNote { public: diversifier_t d; @@ -74,48 +57,6 @@ public: inline const std::array & memo() const { return memo_; } }; -class SproutNotePlaintext : public BaseNotePlaintext { -public: - uint256 rho; - uint256 r; - - SproutNotePlaintext() {} - - SproutNotePlaintext(const SproutNote& note, std::array memo); - - SproutNote note(const SproutPaymentAddress& addr) const; - - virtual ~SproutNotePlaintext() {} - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action) { - unsigned char leadingByte = 0x00; - READWRITE(leadingByte); - - if (leadingByte != 0x00) { - throw std::ios_base::failure("lead byte of SproutNotePlaintext is not recognized"); - } - - READWRITE(value_); - READWRITE(rho); - READWRITE(r); - READWRITE(memo_); - } - - static SproutNotePlaintext decrypt(const ZCNoteDecryption& decryptor, - const ZCNoteDecryption::Ciphertext& ciphertext, - const uint256& ephemeralKey, - const uint256& h_sig, - unsigned char nonce - ); - - ZCNoteEncryption::Ciphertext encrypt(ZCNoteEncryption& encryptor, - const uint256& pk_enc - ) const; -}; - typedef std::pair SaplingNotePlaintextEncryptionResult; class SaplingNotePlaintext : public BaseNotePlaintext { diff --git a/src/zcash/NoteEncryption.cpp b/src/zcash/NoteEncryption.cpp index 63e073265..9f2d64563 100644 --- a/src/zcash/NoteEncryption.cpp +++ b/src/zcash/NoteEncryption.cpp @@ -1,3 +1,5 @@ +// Copyright (c) 2019-2020 The Hush developers + #include "NoteEncryption.hpp" #include #include "sodium.h" @@ -374,52 +376,6 @@ typename NoteDecryption::Plaintext NoteDecryption::decrypt return plaintext; } -// -// Payment disclosure - decrypt with esk -// -template -typename PaymentDisclosureNoteDecryption::Plaintext PaymentDisclosureNoteDecryption::decryptWithEsk - (const PaymentDisclosureNoteDecryption::Ciphertext &ciphertext, - const uint256 &pk_enc, - const uint256 &esk, - const uint256 &hSig, - unsigned char nonce - ) const -{ - uint256 dhsecret; - - if (crypto_scalarmult(dhsecret.begin(), esk.begin(), pk_enc.begin()) != 0) { - throw std::logic_error("Could not create DH secret"); - } - - // Regenerate keypair - uint256 epk = NoteEncryption::generate_pubkey(esk); - - unsigned char K[NOTEENCRYPTION_CIPHER_KEYSIZE]; - KDF(K, dhsecret, epk, pk_enc, hSig, nonce); - - // The nonce is zero because we never reuse keys - unsigned char cipher_nonce[crypto_aead_chacha20poly1305_IETF_NPUBBYTES] = {}; - - PaymentDisclosureNoteDecryption::Plaintext plaintext; - - // Message length is always NOTEENCRYPTION_AUTH_BYTES less than - // the ciphertext length. - if (crypto_aead_chacha20poly1305_ietf_decrypt(plaintext.begin(), NULL, - NULL, - ciphertext.begin(), PaymentDisclosureNoteDecryption::CLEN, - NULL, - 0, - cipher_nonce, K) != 0) { - throw note_decryption_failed(); - } - - return plaintext; -} - - - - template uint256 NoteEncryption::generate_privkey(const uint252 &a_sk) { @@ -461,6 +417,4 @@ uint252 random_uint252() template class NoteEncryption; template class NoteDecryption; -template class PaymentDisclosureNoteDecryption; - } diff --git a/src/zcash/NoteEncryption.hpp b/src/zcash/NoteEncryption.hpp index f6e692028..9c726d5cf 100644 --- a/src/zcash/NoteEncryption.hpp +++ b/src/zcash/NoteEncryption.hpp @@ -1,7 +1,4 @@ -/* -See the Zcash protocol specification for more information. -https://github.com/zcash/zips/blob/master/protocol/protocol.pdf -*/ +// Copyright (c) 2019-2020 The Hush developers #ifndef ZC_NOTE_ENCRYPTION_H_ #define ZC_NOTE_ENCRYPTION_H_ @@ -169,33 +166,9 @@ public: }; - -// Subclass PaymentDisclosureNoteDecryption provides a method to decrypt a note with esk. -template -class PaymentDisclosureNoteDecryption : public NoteDecryption { -protected: -public: - enum { CLEN=MLEN+NOTEENCRYPTION_AUTH_BYTES }; - typedef std::array Ciphertext; - typedef std::array Plaintext; - - PaymentDisclosureNoteDecryption() : NoteDecryption() {} - PaymentDisclosureNoteDecryption(uint256 sk_enc) : NoteDecryption(sk_enc) {} - - Plaintext decryptWithEsk( - const Ciphertext &ciphertext, - const uint256 &pk_enc, - const uint256 &esk, - const uint256 &hSig, - unsigned char nonce - ) const; -}; - } typedef libzcash::NoteEncryption ZCNoteEncryption; typedef libzcash::NoteDecryption ZCNoteDecryption; -typedef libzcash::PaymentDisclosureNoteDecryption ZCPaymentDisclosureNoteDecryption; - #endif /* ZC_NOTE_ENCRYPTION_H_ */ diff --git a/src/zcash/Proof.cpp b/src/zcash/Proof.cpp index af87d1b81..1a0ebfe75 100644 --- a/src/zcash/Proof.cpp +++ b/src/zcash/Proof.cpp @@ -1,251 +1,20 @@ +// Copyright (c) 2019-2020 The Hush developers + #include "Proof.hpp" #include "crypto/common.h" #include -#include -#include #include -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 -void write_bigint(base_blob<8 * LIMBS * sizeof(mp_limb_t)> &blob, const bigint &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 -bigint read_bigint(const base_blob<8 * LIMBS * sizeof(mp_limb_t)> &blob) -{ - bigint 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(); - - // 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(); - - // 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 &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 PHGRProof::to_libsnark_proof() const -{ - r1cs_ppzksnark_proof proof; - - proof.g_A.g = g_A.to_libsnark_g1(); - proof.g_A.h = g_A_prime.to_libsnark_g1(); - proof.g_B.g = g_B.to_libsnark_g2(); - proof.g_B.h = g_B_prime.to_libsnark_g1(); - proof.g_C.g = g_C.to_libsnark_g1(); - proof.g_C.h = g_C_prime.to_libsnark_g1(); - proof.g_K = g_K.to_libsnark_g1(); - proof.g_H = g_H.to_libsnark_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& vk, - const r1cs_ppzksnark_processed_verification_key& pvk, - const r1cs_primary_input& primary_input, - const r1cs_ppzksnark_proof& proof -) -{ - if (perform_verification) { - return r1cs_ppzksnark_online_verifier_strong_IC(pvk, primary_input, proof); - } else { - return true; - } -} - } diff --git a/src/zcash/Proof.hpp b/src/zcash/Proof.hpp index e06095d57..0a3d0bb14 100644 --- a/src/zcash/Proof.hpp +++ b/src/zcash/Proof.hpp @@ -1,3 +1,5 @@ +// Copyright (c) 2019-2020 The Hush developers + #ifndef ZC_PROOF_H_ #define ZC_PROOF_H_ @@ -16,12 +18,6 @@ private: public: Fq() : data() { } - template - Fq(libsnark_Fq element); - - template - libsnark_Fq to_libsnark_fq() const; - ADD_SERIALIZE_METHODS; template @@ -49,12 +45,6 @@ private: public: Fq2() : data() { } - template - Fq2(libsnark_Fq2 element); - - template - libsnark_Fq2 to_libsnark_fq2() const; - ADD_SERIALIZE_METHODS; template @@ -84,12 +74,6 @@ private: public: CompressedG1() : y_lsb(false), x() { } - template - CompressedG1(libsnark_G1 point); - - template - libsnark_G1 to_libsnark_g1() const; - ADD_SERIALIZE_METHODS; template @@ -134,12 +118,6 @@ private: public: CompressedG2() : y_gt(false), x() { } - template - CompressedG2(libsnark_G2 point); - - template - libsnark_G2 to_libsnark_g2() const; - ADD_SERIALIZE_METHODS; template @@ -190,17 +168,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 - PHGRProof(const libsnark_proof& proof); - - // Produces a libsnark zkSNARK proof out of this proof, - // or throws an exception if it is invalid. - template - libsnark_proof to_libsnark_proof() const; - - static PHGRProof random_invalid(); - ADD_SERIALIZE_METHODS; template diff --git a/src/zcash/Zcash.h b/src/zcash/Zcash.h index 84dfe9525..e45aa1d02 100644 --- a/src/zcash/Zcash.h +++ b/src/zcash/Zcash.h @@ -1,3 +1,4 @@ +// Copyright (c) 2019-2020 The Hush developers #ifndef ZC_ZCASH_H_ #define ZC_ZCASH_H_ diff --git a/src/zcash/circuit/commitment.tcc b/src/zcash/circuit/commitment.tcc deleted file mode 100644 index d1b0b10fa..000000000 --- a/src/zcash/circuit/commitment.tcc +++ /dev/null @@ -1,100 +0,0 @@ -template -class note_commitment_gadget : gadget { -private: - std::shared_ptr> block1; - std::shared_ptr> block2; - std::shared_ptr> hasher1; - std::shared_ptr> intermediate_hash; - std::shared_ptr> hasher2; - -public: - note_commitment_gadget( - protoboard &pb, - pb_variable& ZERO, - pb_variable_array& a_pk, - pb_variable_array& v, - pb_variable_array& rho, - pb_variable_array& r, - std::shared_ptr> result - ) : gadget(pb) { - pb_variable_array leading_byte = - from_bits({1, 0, 1, 1, 0, 0, 0, 0}, ZERO); - - pb_variable_array first_of_rho(rho.begin(), rho.begin()+184); - pb_variable_array last_of_rho(rho.begin()+184, rho.end()); - - intermediate_hash.reset(new digest_variable(pb, 256, "")); - - // final padding - pb_variable_array 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(pb, { - leading_byte, - a_pk, - v, - first_of_rho - }, "")); - - block2.reset(new block_variable(pb, { - last_of_rho, - r, - length_padding - }, "")); - - pb_linear_combination_array IV = SHA256_default_IV(pb); - - hasher1.reset(new sha256_compression_function_gadget( - pb, - IV, - block1->bits, - *intermediate_hash, - "")); - - pb_linear_combination_array IV2(intermediate_hash->bits); - - hasher2.reset(new sha256_compression_function_gadget( - 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(); - } -}; diff --git a/src/zcash/circuit/gadget.tcc b/src/zcash/circuit/gadget.tcc deleted file mode 100644 index 0a2ec7719..000000000 --- a/src/zcash/circuit/gadget.tcc +++ /dev/null @@ -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 -class joinsplit_gadget : gadget { -private: - // Verifier inputs - pb_variable_array zk_packed_inputs; - pb_variable_array zk_unpacked_inputs; - std::shared_ptr> unpacker; - - std::shared_ptr> zk_merkle_root; - std::shared_ptr> zk_h_sig; - std::array>, NumInputs> zk_input_nullifiers; - std::array>, NumInputs> zk_input_macs; - std::array>, NumOutputs> zk_output_commitments; - pb_variable_array zk_vpub_old; - pb_variable_array zk_vpub_new; - - // Aux inputs - pb_variable ZERO; - std::shared_ptr> zk_phi; - pb_variable_array zk_total_uint64; - - // Input note gadgets - std::array>, NumInputs> zk_input_notes; - std::array>, NumInputs> zk_mac_authentication; - - // Output note gadgets - std::array>, 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 &pb) : gadget(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( - 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(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( - 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( - 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( - 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(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 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 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( - 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( - this->pb, - zk_total_uint64[i], - "" - ); - } - - this->pb.add_r1cs_constraint(r1cs_constraint( - 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& inputs, - const std::array& 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 witness_map( - const uint256& rt, - const uint256& h_sig, - const std::array& macs, - const std::array& nullifiers, - const std::array& commitments, - uint64_t vpub_old, - uint64_t vpub_new - ) { - std::vector 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(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& packed_into, - std::shared_ptr>& var - ) { - var.reset(new digest_variable(this->pb, 256, "")); - packed_into.insert(packed_into.end(), var->bits.begin(), var->bits.end()); - } - - void alloc_uint64( - pb_variable_array& packed_into, - pb_variable_array& integer - ) { - integer.allocate(this->pb, 64, ""); - packed_into.insert(packed_into.end(), integer.begin(), integer.end()); - } -}; diff --git a/src/zcash/circuit/merkle.tcc b/src/zcash/circuit/merkle.tcc deleted file mode 100644 index 09f02ae9f..000000000 --- a/src/zcash/circuit/merkle.tcc +++ /dev/null @@ -1,60 +0,0 @@ -template -class merkle_tree_gadget : gadget { -private: - typedef sha256_two_to_one_hash_gadget sha256_gadget; - - pb_variable_array positions; - std::shared_ptr> authvars; - std::shared_ptr> auth; - -public: - merkle_tree_gadget( - protoboard& pb, - digest_variable leaf, - digest_variable root, - pb_variable& enforce - ) : gadget(pb) { - positions.allocate(pb, INCREMENTAL_MERKLE_TREE_DEPTH); - authvars.reset(new merkle_authentication_path_variable( - pb, INCREMENTAL_MERKLE_TREE_DEPTH, "auth" - )); - auth.reset(new merkle_tree_check_read_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( - 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(); - } -}; diff --git a/src/zcash/circuit/note.tcc b/src/zcash/circuit/note.tcc deleted file mode 100644 index c598c62ee..000000000 --- a/src/zcash/circuit/note.tcc +++ /dev/null @@ -1,244 +0,0 @@ -template -class note_gadget : public gadget { -public: - pb_variable_array value; - std::shared_ptr> r; - - note_gadget(protoboard &pb) : gadget(pb) { - value.allocate(pb, 64); - r.reset(new digest_variable(pb, 256, "")); - } - - void generate_r1cs_constraints() { - for (size_t i = 0; i < 64; i++) { - generate_boolean_r1cs_constraint( - 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 -class input_note_gadget : public note_gadget { -private: - std::shared_ptr> a_pk; - std::shared_ptr> rho; - - std::shared_ptr> commitment; - std::shared_ptr> commit_to_inputs; - - pb_variable value_enforce; - std::shared_ptr> witness_input; - - std::shared_ptr> spend_authority; - std::shared_ptr> expose_nullifiers; -public: - std::shared_ptr> a_sk; - - input_note_gadget( - protoboard& pb, - pb_variable& ZERO, - std::shared_ptr> nullifier, - digest_variable rt - ) : note_gadget(pb) { - a_sk.reset(new digest_variable(pb, 252, "")); - a_pk.reset(new digest_variable(pb, 256, "")); - rho.reset(new digest_variable(pb, 256, "")); - commitment.reset(new digest_variable(pb, 256, "")); - - spend_authority.reset(new PRF_addr_a_pk_gadget( - pb, - ZERO, - a_sk->bits, - a_pk - )); - - expose_nullifiers.reset(new PRF_nf_gadget( - pb, - ZERO, - a_sk->bits, - rho->bits, - nullifier - )); - - commit_to_inputs.reset(new note_commitment_gadget( - pb, - ZERO, - a_pk->bits, - this->value, - rho->bits, - this->r->bits, - commitment - )); - - value_enforce.allocate(pb); - - witness_input.reset(new merkle_tree_gadget( - pb, - *commitment, - rt, - value_enforce - )); - } - - void generate_r1cs_constraints() { - note_gadget::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(this->pb, value_enforce,""); - - this->pb.add_r1cs_constraint(r1cs_constraint( - 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::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 -class output_note_gadget : public note_gadget { -private: - std::shared_ptr> rho; - std::shared_ptr> a_pk; - - std::shared_ptr> prevent_faerie_gold; - std::shared_ptr> commit_to_outputs; - -public: - output_note_gadget( - protoboard& pb, - pb_variable& ZERO, - pb_variable_array& phi, - pb_variable_array& h_sig, - bool nonce, - std::shared_ptr> commitment - ) : note_gadget(pb) { - rho.reset(new digest_variable(pb, 256, "")); - a_pk.reset(new digest_variable(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( - pb, - ZERO, - phi, - h_sig, - nonce, - rho - )); - - // Commit to the output notes publicly without - // disclosing them. - commit_to_outputs.reset(new note_commitment_gadget( - pb, - ZERO, - a_pk->bits, - this->value, - rho->bits, - this->r->bits, - commitment - )); - } - - void generate_r1cs_constraints() { - note_gadget::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::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(); - } -}; diff --git a/src/zcash/circuit/prfs.tcc b/src/zcash/circuit/prfs.tcc deleted file mode 100644 index 3f50ac9e5..000000000 --- a/src/zcash/circuit/prfs.tcc +++ /dev/null @@ -1,109 +0,0 @@ -template -class PRF_gadget : gadget { -private: - std::shared_ptr> block; - std::shared_ptr> hasher; - std::shared_ptr> result; - -public: - PRF_gadget( - protoboard& pb, - pb_variable& ZERO, - bool a, - bool b, - bool c, - bool d, - pb_variable_array x, - pb_variable_array y, - std::shared_ptr> result - ) : gadget(pb), result(result) { - - pb_linear_combination_array IV = SHA256_default_IV(pb); - - pb_variable_array 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(pb, { - discriminants, - x, - y - }, "PRF_block")); - - hasher.reset(new sha256_compression_function_gadget( - pb, - IV, - block->bits, - *result, - "PRF_hasher")); - } - - void generate_r1cs_constraints() { - hasher->generate_r1cs_constraints(); - } - - void generate_r1cs_witness() { - hasher->generate_r1cs_witness(); - } -}; - -template -pb_variable_array gen256zeroes(pb_variable& ZERO) { - pb_variable_array ret; - while (ret.size() < 256) { - ret.emplace_back(ZERO); - } - - return ret; -} - -template -class PRF_addr_a_pk_gadget : public PRF_gadget { -public: - PRF_addr_a_pk_gadget( - protoboard& pb, - pb_variable& ZERO, - pb_variable_array& a_sk, - std::shared_ptr> result - ) : PRF_gadget(pb, ZERO, 1, 1, 0, 0, a_sk, gen256zeroes(ZERO), result) {} -}; - -template -class PRF_nf_gadget : public PRF_gadget { -public: - PRF_nf_gadget( - protoboard& pb, - pb_variable& ZERO, - pb_variable_array& a_sk, - pb_variable_array& rho, - std::shared_ptr> result - ) : PRF_gadget(pb, ZERO, 1, 1, 1, 0, a_sk, rho, result) {} -}; - -template -class PRF_pk_gadget : public PRF_gadget { -public: - PRF_pk_gadget( - protoboard& pb, - pb_variable& ZERO, - pb_variable_array& a_sk, - pb_variable_array& h_sig, - bool nonce, - std::shared_ptr> result - ) : PRF_gadget(pb, ZERO, 0, nonce, 0, 0, a_sk, h_sig, result) {} -}; - -template -class PRF_rho_gadget : public PRF_gadget { -public: - PRF_rho_gadget( - protoboard& pb, - pb_variable& ZERO, - pb_variable_array& phi, - pb_variable_array& h_sig, - bool nonce, - std::shared_ptr> result - ) : PRF_gadget(pb, ZERO, 0, nonce, 1, 0, phi, h_sig, result) {} -}; diff --git a/src/zcash/circuit/utils.tcc b/src/zcash/circuit/utils.tcc deleted file mode 100644 index fa7ae324a..000000000 --- a/src/zcash/circuit/utils.tcc +++ /dev/null @@ -1,75 +0,0 @@ -#include "uint252.h" - -template -pb_variable_array from_bits(std::vector bits, pb_variable& ZERO) { - pb_variable_array acc; - - BOOST_FOREACH(bool bit, bits) { - acc.emplace_back(bit ? ONE : ZERO); - } - - return acc; -} - -std::vector trailing252(std::vector input) { - if (input.size() != 256) { - throw std::length_error("trailing252 input invalid length"); - } - - return std::vector(input.begin() + 4, input.end()); -} - -template -std::vector to_bool_vector(T input) { - std::vector input_v(input.begin(), input.end()); - - return convertBytesVectorToVector(input_v); -} - -std::vector uint256_to_bool_vector(uint256 input) { - return to_bool_vector(input); -} - -std::vector uint252_to_bool_vector(uint252 input) { - return trailing252(to_bool_vector(input)); -} - -std::vector uint64_to_bool_vector(uint64_t input) { - auto num_bv = convertIntToVectorLE(input); - - return convertBytesVectorToVector(num_bv); -} - -void insert_uint256(std::vector& into, uint256 from) { - std::vector blob = uint256_to_bool_vector(from); - into.insert(into.end(), blob.begin(), blob.end()); -} - -void insert_uint64(std::vector& into, uint64_t from) { - std::vector num = uint64_to_bool_vector(from); - into.insert(into.end(), num.begin(), num.end()); -} - -template -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 -linear_combination packed_addition(pb_variable_array input) { - auto input_swapped = swap_endianness_u64(input); - - return pb_packing_sum(pb_variable_array( - input_swapped.rbegin(), input_swapped.rend() - )); -} diff --git a/src/zcash/prf.cpp b/src/zcash/prf.cpp index 2491de83e..9ab3d0f10 100644 --- a/src/zcash/prf.cpp +++ b/src/zcash/prf.cpp @@ -1,3 +1,5 @@ +// Copyright (c) 2019-2020 The Hush developers + #include "prf.h" #include "crypto/sha256.h" #include "hash.h" diff --git a/src/zcash/util.cpp b/src/zcash/util.cpp index 6f32bf79a..064e1cca9 100644 --- a/src/zcash/util.cpp +++ b/src/zcash/util.cpp @@ -1,3 +1,5 @@ +// Copyright (c) 2019-2020 The Hush developers + #include "zcash/util.h" #include #include diff --git a/src/zcash/util.h b/src/zcash/util.h index 10886e3ca..0c04a5aac 100644 --- a/src/zcash/util.h +++ b/src/zcash/util.h @@ -1,3 +1,4 @@ +// Copyright (c) 2019-2020 The Hush developers #ifndef ZC_UTIL_H_ #define ZC_UTIL_H_ diff --git a/src/zcash/zip32.cpp b/src/zcash/zip32.cpp index 15478843e..615c5896d 100644 --- a/src/zcash/zip32.cpp +++ b/src/zcash/zip32.cpp @@ -1,4 +1,5 @@ // Copyright (c) 2018 The Zcash 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. diff --git a/src/zcash/zip32.h b/src/zcash/zip32.h index 44bc58598..1521dddd1 100644 --- a/src/zcash/zip32.h +++ b/src/zcash/zip32.h @@ -1,4 +1,5 @@ // Copyright (c) 2018 The Zcash 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. @@ -134,7 +135,7 @@ struct SaplingExtendedSpendingKey { } }; -typedef boost::variant SpendingKey; +typedef boost::variant SpendingKey; } diff --git a/src/zcbenchmarks.cpp b/src/zcbenchmarks.cpp index 209b820b8..152ad7295 100644 --- a/src/zcbenchmarks.cpp +++ b/src/zcbenchmarks.cpp @@ -1,3 +1,5 @@ +// Copyright (c) 2019-2020 The Hush developers + #include #include #include @@ -23,7 +25,6 @@ #include "sodium.h" #include "streams.h" #include "txdb.h" -#include "utiltest.h" #include "wallet/wallet.h" #include "zcbenchmarks.h" @@ -39,7 +40,7 @@ void pre_wallet_load() { LogPrintf("%s: In progress...\n", __func__); if (ShutdownRequested()) - throw new std::runtime_error("The node is shutting down"); + throw new std::runtime_error("The Hush node is shutting down"); if (pwalletMain) pwalletMain->Flush(false); @@ -91,79 +92,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; - - /* Get the anchor of an empty commitment tree. */ - uint256 anchor = SproutMerkleTree().root(); - - struct timeval tv_start; - timer_start(tv_start); - JSDescription jsdesc(true, - *pzcashParams, - joinSplitPubKey, - anchor, - {JSInput(), JSInput()}, - {JSOutput(), JSOutput()}, - 0, - 0); - double ret = timer_stop(tv_start); - - auto verifier = libzcash::ProofVerifier::Strict(); - assert(jsdesc.Verify(*pzcashParams, verifier, joinSplitPubKey)); - return ret; -} - -std::vector benchmark_create_joinsplit_threaded(int nThreads) -{ - std::vector ret; - std::vector> tasks; - std::vector threads; - for (int i = 0; i < nThreads; i++) { - std::packaged_task task(&benchmark_create_joinsplit); - tasks.emplace_back(task.get_future()); - threads.emplace_back(std::move(task)); - } - std::future_status status; - for (auto it = tasks.begin(); it != tasks.end(); it++) { - it->wait(); - ret.push_back(it->get()); - } - for (auto it = threads.begin(); it != threads.end(); it++) { - it->join(); - } - return ret; -} - -double benchmark_verify_joinsplit(const JSDescription &joinsplit) -{ - struct timeval tv_start; - timer_start(tv_start); - uint256 joinSplitPubKey; - auto verifier = libzcash::ProofVerifier::Strict(); - joinsplit.Verify(*pzcashParams, verifier, joinSplitPubKey); - return timer_stop(tv_start); -} - #ifdef ENABLE_MINING double benchmark_solve_equihash() { @@ -280,160 +208,6 @@ double benchmark_large_tx(size_t nInputs) return timer_stop(tv_start); } -double benchmark_try_decrypt_notes(size_t nAddrs) -{ - CWallet wallet; - for (int i = 0; i < nAddrs; i++) { - auto sk = libzcash::SproutSpendingKey::random(); - wallet.AddSproutSpendingKey(sk); - } - - auto sk = libzcash::SproutSpendingKey::random(); - auto tx = GetValidReceive(*pzcashParams, sk, 10, true); - - struct timeval tv_start; - timer_start(tv_start); - auto nd = wallet.FindMySproutNotes(tx); - return timer_stop(tv_start); -} - -double benchmark_increment_note_witnesses(size_t nTxs) -{ - CWallet wallet; - SproutMerkleTree sproutTree; - SaplingMerkleTree saplingTree; - - auto sk = libzcash::SproutSpendingKey::random(); - wallet.AddSproutSpendingKey(sk); - - // First block - CBlock block1; - for (int i = 0; i < nTxs; i++) { - auto wtx = GetValidReceive(*pzcashParams, sk, 10, true); - auto note = GetNote(*pzcashParams, sk, wtx, 0, 1); - auto nullifier = note.nullifier(sk); - - mapSproutNoteData_t noteData; - JSOutPoint jsoutpt {wtx.GetHash(), 0, 1}; - SproutNoteData nd {sk.address(), nullifier}; - noteData[jsoutpt] = nd; - - wtx.SetSproutNoteData(noteData); - wallet.AddToWallet(wtx, true, NULL); - block1.vtx.push_back(wtx); - } - CBlockIndex index1(block1); - index1.SetHeight(1); - - // Increment to get transactions witnessed - wallet.ChainTip(&index1, &block1, sproutTree, saplingTree, true); - - // Second block - CBlock block2; - block2.hashPrevBlock = block1.GetHash(); - { - auto wtx = GetValidReceive(*pzcashParams, sk, 10, true); - auto note = GetNote(*pzcashParams, sk, wtx, 0, 1); - auto nullifier = note.nullifier(sk); - - mapSproutNoteData_t noteData; - JSOutPoint jsoutpt {wtx.GetHash(), 0, 1}; - SproutNoteData nd {sk.address(), nullifier}; - noteData[jsoutpt] = nd; - - wtx.SetSproutNoteData(noteData); - wallet.AddToWallet(wtx, true, NULL); - block2.vtx.push_back(wtx); - } - CBlockIndex index2(block2); - index2.SetHeight(2); - - struct timeval tv_start; - timer_start(tv_start); - wallet.ChainTip(&index2, &block2, sproutTree, saplingTree, true); - return timer_stop(tv_start); -} - -// Fake the input of a given block -class FakeCoinsViewDB : public CCoinsViewDB { - uint256 hash; - SproutMerkleTree t; - -public: - FakeCoinsViewDB(std::string dbName, uint256& hash) : CCoinsViewDB(dbName, 100, false, false), hash(hash) {} - - bool GetAnchorAt(const uint256 &rt, SproutMerkleTree &tree) const { - if (rt == t.root()) { - tree = t; - return true; - } - return false; - } - - bool GetNullifier(const uint256 &nf, ShieldedType type) const { - return false; - } - - uint256 GetBestBlock() const { - return hash; - } - - uint256 GetBestAnchor() const { - return t.root(); - } - - bool BatchWrite(CCoinsMap &mapCoins, - const uint256 &hashBlock, - const uint256 &hashAnchor, - CAnchorsSproutMap &mapSproutAnchors, - CNullifiersMap &mapSproutNullifiers, - CNullifiersMap& mapSaplingNullifiers) { - return false; - } - - bool GetStats(CCoinsStats &stats) const { - return false; - } -}; - -double benchmark_connectblock_slow() -{ - // Test for issue 2017-05-01.a - SelectParams(CBaseChainParams::MAIN); - CBlock block; - FILE* fp = fopen((GetDataDir() / "benchmark/block-107134.dat").string().c_str(), "rb"); - if (!fp) throw new std::runtime_error("Failed to open block data file"); - CAutoFile blkFile(fp, SER_DISK, CLIENT_VERSION); - blkFile >> block; - blkFile.fclose(); - - // Fake its inputs - auto hashPrev = uint256S("00000000159a41f468e22135942a567781c3f3dc7ad62257993eb3c69c3f95ef"); - FakeCoinsViewDB fakeDB("benchmark/block-107134-inputs", hashPrev); - CCoinsViewCache view(&fakeDB); - - // Fake the chain - CBlockIndex index(block); - index.SetHeight(107134); - CBlockIndex indexPrev; - indexPrev.phashBlock = &hashPrev; - indexPrev.SetHeight(index.GetHeight() - 1); - index.pprev = &indexPrev; - mapBlockIndex.insert(std::make_pair(hashPrev, &indexPrev)); - - CValidationState state; - struct timeval tv_start; - timer_start(tv_start); - assert(ConnectBlock(block, state, &index, view, true)); - auto duration = timer_stop(tv_start); - - // Undo alterations to global state - mapBlockIndex.erase(hashPrev); - SelectParamsFromCommandLine(); - - return duration; -} - extern UniValue getnewaddress(const UniValue& params, bool fHelp, const CPubKey& mypk); // in rpcwallet.cpp extern UniValue sendtoaddress(const UniValue& params, bool fHelp, const CPubKey& mypk); diff --git a/src/zcbenchmarks.h b/src/zcbenchmarks.h index 363823838..49cf4b749 100644 --- a/src/zcbenchmarks.h +++ b/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 extern double benchmark_sleep(); -extern double benchmark_parameter_loading(); extern double benchmark_create_joinsplit(); extern std::vector benchmark_create_joinsplit_threaded(int nThreads); extern double benchmark_solve_equihash(); diff --git a/zcutil/build-arm.sh b/zcutil/build-arm.sh new file mode 100644 index 000000000..838607c7e --- /dev/null +++ b/zcutil/build-arm.sh @@ -0,0 +1,64 @@ +#!/bin/bash +# Copyright (c) 2019-2020 radix42 +# Copyright (c) 2019-2020 The Hush developers +# Original aarch64 port by radix42. Thank you! + +set -eu -o pipefail + +cat <<'EOF' + ________________ +< Building Hush! > + ---------------- + \ ^__^ + \ (oo)\_______ + (__)\ )\/\ + ||----w | + || || +EOF + +if [ "x$*" = 'x--help' ] +then + cat ./zcutil/dragon.txt + cat <