From 76d26f64585b975710ea3847db03cdbb79646d86 Mon Sep 17 00:00:00 2001 From: ca333 Date: Tue, 9 May 2017 04:31:02 +0200 Subject: [PATCH 001/339] add libcurl build recipe for static linking --- depends/packages/libcurl.mk | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 depends/packages/libcurl.mk diff --git a/depends/packages/libcurl.mk b/depends/packages/libcurl.mk new file mode 100644 index 000000000..9e8577bb5 --- /dev/null +++ b/depends/packages/libcurl.mk @@ -0,0 +1,23 @@ +package=libcurl +$(package)_version=7.54.0 +$(package)_download_path=https://curl.haxx.se/download +$(package)_file_name=curl-$($(package)_version).tar.gz +$(package)_sha256_hash=a84b635941c74e26cce69dd817489bec687eb1f230e7d1897fc5b5f108b59adf +$(package)_config_opts=--disable-shared --enable-static --prefix=$(host_prefix) +$(package)_cflags= +$(package)_conf_tool=./configure + +define $(package)_set_vars +endef + +define $(package)_config_cmds + $($(package)_conf_tool) $($(package)_config_opts) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef From f4b532076cee930c05fb3de2a018af9f924cc784 Mon Sep 17 00:00:00 2001 From: ca333 Date: Tue, 9 May 2017 04:35:33 +0200 Subject: [PATCH 002/339] statify libcurl --- src/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile.am b/src/Makefile.am index b6f4f2e83..ce0bd6cd3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -23,7 +23,7 @@ BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPP BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include BITCOIN_INCLUDES += -I$(srcdir)/univalue/include -LIBBITCOIN_SERVER=libbitcoin_server.a +LIBBITCOIN_SERVER=libbitcoin_server.a -lcurl LIBBITCOIN_WALLET=libbitcoin_wallet.a LIBBITCOIN_COMMON=libbitcoin_common.a LIBBITCOIN_CLI=libbitcoin_cli.a From 9069e4addf009e0069cea756d5c2f3d365e31e49 Mon Sep 17 00:00:00 2001 From: Max Lapan Date: Sun, 23 Jul 2017 16:34:31 +0200 Subject: [PATCH 003/339] Debian package for komodo 1. tweaks in control file (name, url, git, etc) 2. package script 3. changelog --- contrib/debian/changelog | 2 +- contrib/debian/control | 14 +++++++------- zcutil/build-debian-package.sh | 34 +++++++++++++++++----------------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/contrib/debian/changelog b/contrib/debian/changelog index c400dca73..b9503400b 100644 --- a/contrib/debian/changelog +++ b/contrib/debian/changelog @@ -1,4 +1,4 @@ -zcash (1.0.8) jessie; urgency=medium +komodo (1.0.8) jessie; urgency=medium * 1.0.8 release. diff --git a/contrib/debian/control b/contrib/debian/control index b0c220cf0..84ffaac0d 100644 --- a/contrib/debian/control +++ b/contrib/debian/control @@ -1,21 +1,21 @@ -Source: zcash +Source: komodo Section: utils Priority: optional Maintainer: Zcash Company -Homepage: https://z.cash +Homepage: https://komodoplatform.com/ Build-Depends: autoconf, automake, bsdmainutils, build-essential, git, g++-multilib, libc6-dev, libtool, m4, ncurses-dev, pkg-config, python, unzip, wget, zlib1g-dev -Vcs-Git: https://github.com/zcash/zcash.git -Vcs-Browser: https://github.com/zcash/zcash +Vcs-Git: https://github.com/jl777/komodo +Vcs-Browser: https://github.com/jl777/komodo -Package: zcash +Package: komodo Architecture: amd64 Depends: ${shlibs:Depends} Description: HTTPS for money. Based on Bitcoin's code, it intends to offer a far higher standard of privacy and anonymity through a sophisticiated zero-knowledge proving scheme which preserves confidentiality of transaction metadata. - This package provides the daemon, zcashd, and the CLI tool, - zcash-cli, to interact with the daemon. + This package provides the daemon, komodod, and the CLI tool, + komodo-cli, to interact with the daemon. diff --git a/zcutil/build-debian-package.sh b/zcutil/build-debian-package.sh index 8c2d05c3f..11b68badc 100755 --- a/zcutil/build-debian-package.sh +++ b/zcutil/build-debian-package.sh @@ -5,8 +5,8 @@ set -e set -x -BUILD_PATH="/tmp/zcbuild" -PACKAGE_NAME="zcash" +BUILD_PATH="/tmp/kmdbuild" +PACKAGE_NAME="komodo" SRC_PATH=`pwd` SRC_DEB=$SRC_PATH/contrib/debian SRC_DOC=$SRC_PATH/doc @@ -17,7 +17,7 @@ if [ ! -d $BUILD_PATH ]; then mkdir $BUILD_PATH fi -PACKAGE_VERSION=$($SRC_PATH/src/zcashd --version | grep version | cut -d' ' -f4 | tr -d v) +PACKAGE_VERSION=$($SRC_PATH/src/komodod --version | grep version | cut -d' ' -f4 | tr -d v) BUILD_DIR="$BUILD_PATH/$PACKAGE_NAME-$PACKAGE_VERSION-amd64" if [ -d $BUILD_DIR ]; then @@ -28,7 +28,7 @@ DEB_BIN=$BUILD_DIR/usr/bin DEB_CMP=$BUILD_DIR/usr/share/bash-completion/completions DEB_DOC=$BUILD_DIR/usr/share/doc/$PACKAGE_NAME DEB_MAN=$BUILD_DIR/usr/share/man/man1 -mkdir -p $BUILD_DIR/DEBIAN $DEB_CMP $DEB_BIN $DEB_DOC $DEB_MAN +mkdir -p $BUILD_DIR/DEBIAN $DEB_BIN $DEB_DOC chmod 0755 -R $BUILD_DIR/* # Package maintainer scripts (currently empty) @@ -37,32 +37,32 @@ chmod 0755 -R $BUILD_DIR/* #cp $SRC_DEB/preinst $BUILD_DIR/DEBIAN #cp $SRC_DEB/prerm $BUILD_DIR/DEBIAN # Copy binaries -cp $SRC_PATH/src/zcashd $DEB_BIN -cp $SRC_PATH/src/zcash-cli $DEB_BIN -cp $SRC_PATH/zcutil/fetch-params.sh $DEB_BIN/zcash-fetch-params +cp $SRC_PATH/src/komodod $DEB_BIN +cp $SRC_PATH/src/komodo-cli $DEB_BIN +cp $SRC_PATH/zcutil/fetch-params.sh $DEB_BIN/komodo-fetch-params # Copy docs cp $SRC_PATH/doc/release-notes/release-notes-1.0.0.md $DEB_DOC/changelog cp $SRC_DEB/changelog $DEB_DOC/changelog.Debian cp $SRC_DEB/copyright $DEB_DOC cp -r $SRC_DEB/examples $DEB_DOC # Copy manpages -cp $SRC_DOC/man/zcashd.1 $DEB_MAN -cp $SRC_DOC/man/zcash-cli.1 $DEB_MAN -cp $SRC_DOC/man/zcash-fetch-params.1 $DEB_MAN -# Copy bash completion files -cp $SRC_PATH/contrib/bitcoind.bash-completion $DEB_CMP/zcashd -cp $SRC_PATH/contrib/bitcoin-cli.bash-completion $DEB_CMP/zcash-cli +#cp $SRC_DOC/man/zcashd.1 $DEB_MAN +#cp $SRC_DOC/man/zcash-cli.1 $DEB_MAN +#cp $SRC_DOC/man/zcash-fetch-params.1 $DEB_MAN +# Copy bash completion files TODO: fix them for komodo +#cp $SRC_PATH/contrib/bitcoind.bash-completion $DEB_CMP/komodod +#cp $SRC_PATH/contrib/bitcoin-cli.bash-completion $DEB_CMP/komodod-cli # Gzip files gzip --best -n $DEB_DOC/changelog gzip --best -n $DEB_DOC/changelog.Debian -gzip --best -n $DEB_MAN/zcashd.1 -gzip --best -n $DEB_MAN/zcash-cli.1 -gzip --best -n $DEB_MAN/zcash-fetch-params.1 +#gzip --best -n $DEB_MAN/zcashd.1 +#gzip --best -n $DEB_MAN/zcash-cli.1 +#gzip --best -n $DEB_MAN/zcash-fetch-params.1 cd $SRC_PATH/contrib # Create the control file -dpkg-shlibdeps $DEB_BIN/zcashd $DEB_BIN/zcash-cli +dpkg-shlibdeps $DEB_BIN/komodod $DEB_BIN/komodo-cli dpkg-gencontrol -P$BUILD_DIR # Create the Debian package From a30e0a4a6c0c2af8d1bb1d0f7967382364d05d82 Mon Sep 17 00:00:00 2001 From: Paul Romero Date: Thu, 24 Aug 2017 21:12:45 +0100 Subject: [PATCH 004/339] README.md updates spelling, grammar etc. --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ef3d637a6..54406f618 100644 --- a/README.md +++ b/README.md @@ -188,7 +188,7 @@ Jumblr works like described previously where all the nodes with jumblr active sy JUMBLR implements t -> z, z -> z and z -> t transactions to maximize privacy of the destination t (transparent) address. So while it is transparent, its first activity is funds coming from an untracable z address. -Which of the three stages is done is randomly selected at each turn. Also when there are more than one possible transaction at the selected stage, a random one is selected. This randomization prevents analyzing incoming z ->t transactions by its size to correlate it to the originating address. +Which of the three stages is done is randomly selected at each turn. Also when there is more than one possible transaction at the selected stage, a random one is selected. This randomization prevents analyzing incoming z ->t transactions by its size to correlate it to the originating address. jumblr_deposit designates the deposit address as the jumblr deposit address for that session. You can select an address that already has funds in it and it will immediately start jumblr process. If there are no funds, it will wait until you send funds to it. @@ -197,7 +197,7 @@ There are three sizes of a jumblr transaction: 10 KMD, 100 KMD and 1000 KMD. The jumblr_secret notifies JUMBLR where to send the final z -> t transactions. In order to allow larger accounts to obtain privacy, up to 777 secret addresses are supported. Whenever a z -> t stage is activated, a random secret address from the list of the then active secret addresses is selected. Practical Advice: -Obtaining privacy used to be very difficult. JUMBLR makes it as simple as issuing two command line calls. Higher level layers can be added to help manage the addresses, ie. linking them at the passphrase level. Such things are left to each implementation. +Obtaining privacy used to be very difficult. JUMBLR makes it as simple as issuing two command line calls. Higher level layers can be added to help manage the addresses, ie. linking them at the passphrase level. Such matters are left to each implementation. Once obtained, it is very easy to lose all the privacy. With a single errant transaction that combines some previously used address and the secretaddress, well, the secretaddress is no longer so private. @@ -205,9 +205,9 @@ The advice is to setup a totally separate node! This might seem a bit drastic, but if you want to maintain privacy, it is best to make it look like all the transactions are coming from a different node. The easiest way for most people to do this is to actually have a different node. -It can be a dedicated laptop (recommended) or a VPS (for not so big amounts) with a totally fresh komodod wallet. Generate an address on this wallet and use that as the jumblr_secret address on your main node. As the JUMBLR operates funds will teleport into your secret node's address. If you are careful and never use the same IP address for both your nodes, you will be able to maintain very good privacy. +It can be a dedicated laptop (recommended) or a VPS (for smaller amounts) with a totally fresh komodod wallet. Generate an address on this wallet and use that as the jumblr_secret address on your main node. As the JUMBLR operates funds will teleport into your secret node's address. If you are careful and never use the same IP address for both your nodes, you will be able to maintain very good privacy. -Of course, dont be sending emails that link the two accounts together! Dont use secret address funds for home delivery purchases!! Etc. There are many ways to lose the privacy, just think about what linkages can be dont at the IP and blockchain level and that should be a useful preparation. +Of course, don't send emails that link the two accounts together! Dont use secret address funds for home delivery purchases! Etc. There are many ways to lose the privacy, just think about what linkages can be dont at the IP and blockchain level and that should be a useful preparation. What if you have 100,000 KMD and you dont want others to know you are such a whale? From 7c49b46d5a5b6a1d0f38fddc56138de6f53807b1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 13 Oct 2017 16:43:52 +0300 Subject: [PATCH 005/339] Revert "Merge branch 'master' into dPoW" This reverts commit a487e5a1d32e369f663512297330ce3a2a38bc1f, reversing changes made to 6be96b7e1c7255bc9af455bc9f092b59f77d229c. --- README.md | 4 ---- contrib/debian/changelog | 2 +- contrib/debian/control | 14 +++++++------- depends/packages/libcurl.mk | 2 -- src/Makefile.am | 1 - zcutil/build-debian-package.sh | 34 +++++++++++++++++----------------- 6 files changed, 25 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index d59f452cb..2bbd8a743 100644 --- a/README.md +++ b/README.md @@ -145,19 +145,15 @@ mv ~/.komodo ~/.komodo.old && mkdir ~/.komodo && cp ~/.komodo.old/komodo.conf ~/ komodod now has jumblr_deposit and jumblr_secret RPC calls. Jumblr works like described previously where all the nodes with jumblr active synchronize their tx activity during the same block to maximize the mixing effect. However, unlike all other mixers/tumblers, you never give up control of your coins to anybody else. JUMBLR uses a one to many allocation of funds, ie. one deposit address and many secret addresses. You can always run multiple komodod daemons to get multiple active deposit addresses. JUMBLR implements t -> z, z -> z and z -> t transactions to maximize privacy of the destination t (transparent) address. So while it is transparent, its first activity is funds coming from an untracable z address. - Which of the three stages is done is randomly selected at each turn. Also when there is more than one possible transaction at the selected stage, a random one is selected. This randomization prevents analyzing incoming z ->t transactions by its size to correlate it to the originating address. - jumblr_deposit designates the deposit address as the jumblr deposit address for that session. You can select an address that already has funds in it and it will immediately start jumblr process. If there are no funds, it will wait until you send funds to it. There are three sizes of a jumblr transaction: 10 KMD, 100 KMD and 1000 KMD. There is also a fixed interval of blocks where all jumblr nodes are active. Currently it is set to be 10, but this is subject to change. Only during every 10*10 blocks are the largest 1000 KMD transactions processed, so this concentrates all the large transactions every N*N blocks. jumblr_secret notifies JUMBLR where to send the final z -> t transactions. In order to allow larger accounts to obtain privacy, up to 777 secret addresses are supported. Whenever a z -> t stage is activated, a random secret address from the list of the then active secret addresses is selected. Practical Advice: Obtaining privacy used to be very difficult. JUMBLR makes it as simple as issuing two command line calls. Higher level layers can be added to help manage the addresses, ie. linking them at the passphrase level. Such matters are left to each implementation. - Once obtained, it is very easy to lose all the privacy. With a single errant transaction that combines some previously used address and the secretaddress, well, the secretaddress is no longer so private. The advice is to setup a totally separate node! This might seem a bit drastic, but if you want to maintain privacy, it is best to make it look like all the transactions are coming from a different node. The easiest way for most people to do this is to actually have a different node. - It can be a dedicated laptop (recommended) or a VPS (for smaller amounts) with a totally fresh komodod wallet. Generate an address on this wallet and use that as the jumblr_secret address on your main node. As the JUMBLR operates funds will teleport into your secret node's address. If you are careful and never use the same IP address for both your nodes, you will be able to maintain very good privacy. Of course, don't send emails that link the two accounts together! Dont use secret address funds for home delivery purchases! Etc. There are many ways to lose the privacy, just think about what linkages can be dont at the IP and blockchain level and that should be a useful preparation. What if you have 100,000 KMD and you dont want others to know you are such a whale? diff --git a/contrib/debian/changelog b/contrib/debian/changelog index b9503400b..c400dca73 100644 --- a/contrib/debian/changelog +++ b/contrib/debian/changelog @@ -1,4 +1,4 @@ -komodo (1.0.8) jessie; urgency=medium +zcash (1.0.8) jessie; urgency=medium * 1.0.8 release. diff --git a/contrib/debian/control b/contrib/debian/control index 84ffaac0d..b0c220cf0 100644 --- a/contrib/debian/control +++ b/contrib/debian/control @@ -1,21 +1,21 @@ -Source: komodo +Source: zcash Section: utils Priority: optional Maintainer: Zcash Company -Homepage: https://komodoplatform.com/ +Homepage: https://z.cash Build-Depends: autoconf, automake, bsdmainutils, build-essential, git, g++-multilib, libc6-dev, libtool, m4, ncurses-dev, pkg-config, python, unzip, wget, zlib1g-dev -Vcs-Git: https://github.com/jl777/komodo -Vcs-Browser: https://github.com/jl777/komodo +Vcs-Git: https://github.com/zcash/zcash.git +Vcs-Browser: https://github.com/zcash/zcash -Package: komodo +Package: zcash Architecture: amd64 Depends: ${shlibs:Depends} Description: HTTPS for money. Based on Bitcoin's code, it intends to offer a far higher standard of privacy and anonymity through a sophisticiated zero-knowledge proving scheme which preserves confidentiality of transaction metadata. - This package provides the daemon, komodod, and the CLI tool, - komodo-cli, to interact with the daemon. + This package provides the daemon, zcashd, and the CLI tool, + zcash-cli, to interact with the daemon. diff --git a/depends/packages/libcurl.mk b/depends/packages/libcurl.mk index 19c5eab16..349469f11 100644 --- a/depends/packages/libcurl.mk +++ b/depends/packages/libcurl.mk @@ -3,7 +3,6 @@ $(package)_version=7.54.0 $(package)_download_path=https://curl.haxx.se/download $(package)_file_name=curl-$($(package)_version).tar.gz $(package)_sha256_hash=a84b635941c74e26cce69dd817489bec687eb1f230e7d1897fc5b5f108b59adf - $(package)_config_opts_linux=--disable-shared --enable-static --prefix=$(host_prefix) $(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) @@ -30,7 +29,6 @@ define $(package)_build_cmds endef endif - define $(package)_stage_cmds $(MAKE) DESTDIR=$($(package)_staging_dir) install endef diff --git a/src/Makefile.am b/src/Makefile.am index 5b2e0c226..72805281a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -32,7 +32,6 @@ else LIBBITCOIN_SERVER=libbitcoin_server.a endif - LIBBITCOIN_WALLET=libbitcoin_wallet.a LIBBITCOIN_COMMON=libbitcoin_common.a LIBBITCOIN_CLI=libbitcoin_cli.a diff --git a/zcutil/build-debian-package.sh b/zcutil/build-debian-package.sh index 11b68badc..8c2d05c3f 100755 --- a/zcutil/build-debian-package.sh +++ b/zcutil/build-debian-package.sh @@ -5,8 +5,8 @@ set -e set -x -BUILD_PATH="/tmp/kmdbuild" -PACKAGE_NAME="komodo" +BUILD_PATH="/tmp/zcbuild" +PACKAGE_NAME="zcash" SRC_PATH=`pwd` SRC_DEB=$SRC_PATH/contrib/debian SRC_DOC=$SRC_PATH/doc @@ -17,7 +17,7 @@ if [ ! -d $BUILD_PATH ]; then mkdir $BUILD_PATH fi -PACKAGE_VERSION=$($SRC_PATH/src/komodod --version | grep version | cut -d' ' -f4 | tr -d v) +PACKAGE_VERSION=$($SRC_PATH/src/zcashd --version | grep version | cut -d' ' -f4 | tr -d v) BUILD_DIR="$BUILD_PATH/$PACKAGE_NAME-$PACKAGE_VERSION-amd64" if [ -d $BUILD_DIR ]; then @@ -28,7 +28,7 @@ DEB_BIN=$BUILD_DIR/usr/bin DEB_CMP=$BUILD_DIR/usr/share/bash-completion/completions DEB_DOC=$BUILD_DIR/usr/share/doc/$PACKAGE_NAME DEB_MAN=$BUILD_DIR/usr/share/man/man1 -mkdir -p $BUILD_DIR/DEBIAN $DEB_BIN $DEB_DOC +mkdir -p $BUILD_DIR/DEBIAN $DEB_CMP $DEB_BIN $DEB_DOC $DEB_MAN chmod 0755 -R $BUILD_DIR/* # Package maintainer scripts (currently empty) @@ -37,32 +37,32 @@ chmod 0755 -R $BUILD_DIR/* #cp $SRC_DEB/preinst $BUILD_DIR/DEBIAN #cp $SRC_DEB/prerm $BUILD_DIR/DEBIAN # Copy binaries -cp $SRC_PATH/src/komodod $DEB_BIN -cp $SRC_PATH/src/komodo-cli $DEB_BIN -cp $SRC_PATH/zcutil/fetch-params.sh $DEB_BIN/komodo-fetch-params +cp $SRC_PATH/src/zcashd $DEB_BIN +cp $SRC_PATH/src/zcash-cli $DEB_BIN +cp $SRC_PATH/zcutil/fetch-params.sh $DEB_BIN/zcash-fetch-params # Copy docs cp $SRC_PATH/doc/release-notes/release-notes-1.0.0.md $DEB_DOC/changelog cp $SRC_DEB/changelog $DEB_DOC/changelog.Debian cp $SRC_DEB/copyright $DEB_DOC cp -r $SRC_DEB/examples $DEB_DOC # Copy manpages -#cp $SRC_DOC/man/zcashd.1 $DEB_MAN -#cp $SRC_DOC/man/zcash-cli.1 $DEB_MAN -#cp $SRC_DOC/man/zcash-fetch-params.1 $DEB_MAN -# Copy bash completion files TODO: fix them for komodo -#cp $SRC_PATH/contrib/bitcoind.bash-completion $DEB_CMP/komodod -#cp $SRC_PATH/contrib/bitcoin-cli.bash-completion $DEB_CMP/komodod-cli +cp $SRC_DOC/man/zcashd.1 $DEB_MAN +cp $SRC_DOC/man/zcash-cli.1 $DEB_MAN +cp $SRC_DOC/man/zcash-fetch-params.1 $DEB_MAN +# Copy bash completion files +cp $SRC_PATH/contrib/bitcoind.bash-completion $DEB_CMP/zcashd +cp $SRC_PATH/contrib/bitcoin-cli.bash-completion $DEB_CMP/zcash-cli # Gzip files gzip --best -n $DEB_DOC/changelog gzip --best -n $DEB_DOC/changelog.Debian -#gzip --best -n $DEB_MAN/zcashd.1 -#gzip --best -n $DEB_MAN/zcash-cli.1 -#gzip --best -n $DEB_MAN/zcash-fetch-params.1 +gzip --best -n $DEB_MAN/zcashd.1 +gzip --best -n $DEB_MAN/zcash-cli.1 +gzip --best -n $DEB_MAN/zcash-fetch-params.1 cd $SRC_PATH/contrib # Create the control file -dpkg-shlibdeps $DEB_BIN/komodod $DEB_BIN/komodo-cli +dpkg-shlibdeps $DEB_BIN/zcashd $DEB_BIN/zcash-cli dpkg-gencontrol -P$BUILD_DIR # Create the Debian package From 07f83521f7f4dc21e895d3a2a60a1a40aa0ce2bb Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Thu, 19 Oct 2017 14:08:32 -0700 Subject: [PATCH 006/339] basic integration of cryptoconditions --- .gitmodules | 4 +++ configure.ac | 2 +- src/Makefile.am | 16 +++++++++--- src/cJSON.h | 1 + src/cryptoconditions | 1 + src/komodo_structs.h | 5 ++++ src/script/interpreter.cpp | 52 ++++++++++++++++++++++++++++++++++++++ src/script/interpreter.h | 7 +++++ src/script/script.cpp | 3 +++ src/script/script.h | 3 ++- src/script/script_error.h | 5 +++- 11 files changed, 92 insertions(+), 7 deletions(-) create mode 100644 .gitmodules create mode 160000 src/cryptoconditions diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..44ceb9030 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "cryptoconditions"] + path = src/cryptoconditions + url = https://github.com/libscott/libcryptoconditions + branch = komodo-integration diff --git a/configure.ac b/configure.ac index c471bab89..9f8f1900f 100644 --- a/configure.ac +++ b/configure.ac @@ -996,7 +996,7 @@ unset PKG_CONFIG_LIBDIR PKG_CONFIG_LIBDIR="$PKGCONFIG_LIBDIR_TEMP" ac_configure_args="${ac_configure_args} --disable-shared --with-pic --with-bignum=no" -AC_CONFIG_SUBDIRS([src/secp256k1 src/univalue]) +AC_CONFIG_SUBDIRS([src/secp256k1 src/univalue src/cryptoconditions]) AC_OUTPUT diff --git a/src/Makefile.am b/src/Makefile.am index 72805281a..8907fa54a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -DIST_SUBDIRS = secp256k1 univalue +DIST_SUBDIRS = secp256k1 univalue cryptoconditions AM_LDFLAGS = $(PTHREAD_CFLAGS) $(LIBTOOL_LDFLAGS) @@ -21,6 +21,7 @@ BITCOIN_CONFIG_INCLUDES=-I$(builddir)/config BITCOIN_INCLUDES=-I$(builddir) -I$(builddir)/obj $(BOOST_CPPFLAGS) $(LEVELDB_CPPFLAGS) $(CRYPTO_CFLAGS) $(SSL_CFLAGS) BITCOIN_INCLUDES += -I$(srcdir)/secp256k1/include +BITCOIN_INCLUDES += -I$(srcdir)/cryptoconditions/include -I$(srcdir)/cryptoconditions/src/asn BITCOIN_INCLUDES += -I$(srcdir)/univalue/include if TARGET_WINDOWS @@ -38,6 +39,7 @@ LIBBITCOIN_CLI=libbitcoin_cli.a LIBBITCOIN_UTIL=libbitcoin_util.a LIBBITCOIN_CRYPTO=crypto/libbitcoin_crypto.a LIBSECP256K1=secp256k1/libsecp256k1.la +LIBCRYPTOCONDITIONS=cryptoconditions/libcryptoconditions.la LIBUNIVALUE=univalue/libunivalue.la LIBZCASH=libzcash.a -lcurl @@ -47,6 +49,9 @@ $(LIBSECP256K1): $(wildcard secp256k1/src/*) $(wildcard secp256k1/include/*) $(LIBUNIVALUE): $(wildcard univalue/lib/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C univalue/ +$(LIBCRYPTOCONDITIONS): $(wildcard cryptoconditions/src/*) $(wildcard cryptoconditions/include/*) + $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) + # Make is not made aware of per-object dependencies to avoid limiting building parallelization # But to build the less dependent modules first, we manually select their order here: EXTRA_LIBRARIES = \ @@ -389,7 +394,8 @@ komodod_LDADD = \ $(LIBZCASH) \ $(LIBLEVELDB) \ $(LIBMEMENV) \ - $(LIBSECP256K1) + $(LIBSECP256K1) \ + $(LIBCRYPTOCONDITIONS) if ENABLE_ZMQ komodod_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS) @@ -450,7 +456,8 @@ komodo_tx_LDADD = \ $(LIBSECP256K1) \ $(LIBZCASH) \ $(LIBBITCOIN_CRYPTO) \ - $(LIBZCASH_LIBS) + $(LIBZCASH_LIBS) \ + $(LIBCRYPTOCONDITIONS) komodo_tx_LDADD += $(BOOST_LIBS) $(CRYPTO_LIBS) # @@ -507,7 +514,8 @@ endif libzcashconsensus_la_LDFLAGS = -no-undefined $(RELDFLAGS) libzcashconsensus_la_LIBADD = $(CRYPTO_LIBS) -libzcashconsensus_la_CPPFLAGS = $(CRYPTO_CFLAGS) -I$(builddir)/obj -DBUILD_BITCOIN_INTERNAL +libzcashconsensus_la_CPPFLAGS = $(CRYPTO_CFLAGS) -I$(builddir)/obj -DBUILD_BITCOIN_INTERNAL \ + -I$(builddir)/cryptoconditions/src/asn endif # diff --git a/src/cJSON.h b/src/cJSON.h index d3076aa53..2ee786358 100755 --- a/src/cJSON.h +++ b/src/cJSON.h @@ -30,6 +30,7 @@ #include #include #include +#include "komodo_structs.h" //#include "../crypto777/OS_portable.h" diff --git a/src/cryptoconditions b/src/cryptoconditions new file mode 160000 index 000000000..7bd65d43a --- /dev/null +++ b/src/cryptoconditions @@ -0,0 +1 @@ +Subproject commit 7bd65d43af4e95ea6d8edf6c3dc5f340e39770cd diff --git a/src/komodo_structs.h b/src/komodo_structs.h index a35e7e008..fa8b3c2f1 100644 --- a/src/komodo_structs.h +++ b/src/komodo_structs.h @@ -22,6 +22,9 @@ #define PACKED __attribute__((packed)) #endif*/ +#ifndef KOMODO_STRUCTS_H +#define KOMODO_STRUCTS_H + #define GENESIS_NBITS 0x1f00ffff #define KOMODO_MINRATIFY ((height < 90000) ? 7 : 11) #define KOMODO_MAXBLOCKS 5000000 @@ -88,3 +91,5 @@ struct komodo_state struct komodo_event **Komodo_events; int32_t Komodo_numevents; uint32_t RTbufs[64][3]; uint64_t RTmask; }; + +#endif /* KOMODO_STRUCTS_H */ diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 6c17eab70..f65581068 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -13,6 +13,8 @@ #include "pubkey.h" #include "script/script.h" #include "uint256.h" +#include "cryptoconditions/include/cryptoconditions.h" + using namespace std; @@ -934,6 +936,51 @@ bool EvalScript(vector >& stack, const CScript& script, un } break; + case OP_CHECKCRYPTOCONDITION: + case OP_CHECKCRYPTOCONDITIONVERIFY: + { + // (fulfillment condition -- bool) + + if (stack.size() < 2) + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); + + valtype& vchFulfillment = stacktop(-2); + valtype& vchCondition = stacktop(-1); + + // Hard limit fulfillment size + if (vchFulfillment.size() > 1024 * 10) { + return set_error(serror, SCRIPT_ERR_CRYPTOCONDITION_INVALID_FULFILLMENT); + } + + CC *cond = (CC*) calloc(1, sizeof(CC)); + char *fulfillmentBin = (char*) vchFulfillment.data(); + int rc = cc_readFulfillmentBinary(cond, fulfillmentBin, vchFulfillment.size()); + if (rc != 0) { + return set_error(serror, SCRIPT_ERR_CRYPTOCONDITION_INVALID_FULFILLMENT); + } + + char *condBin = (char*) &vchCondition[0]; + // TODO: Should nHashType be hardcoded? + // Other types use the last byte of the signature + char *msg = (char*) checker.GetMessage(script, SIGHASH_ALL).begin(); +; + bool fSuccess = cc_verify(cond, msg, 32, condBin, vchCondition.size()); + + popstack(stack); + popstack(stack); + + stack.push_back(fSuccess ? vchTrue : vchFalse); + + if (opcode == OP_CHECKCRYPTOCONDITIONVERIFY) + { + if (fSuccess) + popstack(stack); + else + return set_error(serror, SCRIPT_ERR_CRYPTOCONDITION_VERIFY); + } + } + break; + default: return set_error(serror, SCRIPT_ERR_BAD_OPCODE); } @@ -1147,6 +1194,11 @@ bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) con return true; } +uint256 TransactionSignatureChecker::GetMessage(const CScript& scriptCode, int nHashType) const +{ + return SignatureHash(scriptCode, *txTo, nIn, nHashType); +} + bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror) { diff --git a/src/script/interpreter.h b/src/script/interpreter.h index b94916fac..fad2d9a91 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -102,6 +102,12 @@ public: return false; } + virtual uint256 GetMessage(const CScript& scriptCode, int nHashType) const + { + uint256 blob; + return blob; + } + virtual ~BaseSignatureChecker() {} }; @@ -118,6 +124,7 @@ public: TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn) : txTo(txToIn), nIn(nInIn) {} bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode) const; bool CheckLockTime(const CScriptNum& nLockTime) const; + uint256 GetMessage(const CScript& scriptCode, int nHashType) const; }; class MutableTransactionSignatureChecker : public TransactionSignatureChecker diff --git a/src/script/script.cpp b/src/script/script.cpp index fd3392473..3cb3f855d 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -138,6 +138,9 @@ const char* GetOpName(opcodetype opcode) case OP_CHECKSIGVERIFY : return "OP_CHECKSIGVERIFY"; case OP_CHECKMULTISIG : return "OP_CHECKMULTISIG"; case OP_CHECKMULTISIGVERIFY : return "OP_CHECKMULTISIGVERIFY"; + case OP_CHECKCRYPTOCONDITION : return "OP_CHECKCRYPTOCONDITION"; + case OP_CHECKCRYPTOCONDITIONVERIFY + : return "OP_CHECKCRYPTOCONDITIONVERIFY"; // expanson case OP_NOP1 : return "OP_NOP1"; diff --git a/src/script/script.h b/src/script/script.h index e0e89185f..584fefac1 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -154,6 +154,8 @@ enum opcodetype OP_CHECKSIGVERIFY = 0xad, OP_CHECKMULTISIG = 0xae, OP_CHECKMULTISIGVERIFY = 0xaf, + OP_CHECKCRYPTOCONDITION = 0xcc, + OP_CHECKCRYPTOCONDITIONVERIFY = 0xcd, // expansion OP_NOP1 = 0xb0, @@ -168,7 +170,6 @@ enum opcodetype OP_NOP9 = 0xb8, OP_NOP10 = 0xb9, - // template matching params OP_SMALLDATA = 0xf9, OP_SMALLINTEGER = 0xfa, diff --git a/src/script/script_error.h b/src/script/script_error.h index bb10b8a29..e84268977 100644 --- a/src/script/script_error.h +++ b/src/script/script_error.h @@ -52,7 +52,10 @@ typedef enum ScriptError_t /* softfork safeness */ SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS, - SCRIPT_ERR_ERROR_COUNT + SCRIPT_ERR_ERROR_COUNT, + + SCRIPT_ERR_CRYPTOCONDITION_VERIFY, + SCRIPT_ERR_CRYPTOCONDITION_INVALID_FULFILLMENT } ScriptError; #define SCRIPT_ERR_LAST SCRIPT_ERR_ERROR_COUNT From 2b67565e51f0df0c6d6473292de76af169f1c217 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Fri, 20 Oct 2017 23:44:45 -0700 Subject: [PATCH 007/339] update cryptoconditions module ref --- .gitmodules | 2 +- src/cryptoconditions | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 44ceb9030..0c640d62c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "cryptoconditions"] path = src/cryptoconditions - url = https://github.com/libscott/libcryptoconditions + url = git@github.com:libscott/libcryptoconditions.git branch = komodo-integration diff --git a/src/cryptoconditions b/src/cryptoconditions index 7bd65d43a..a59c22dcf 160000 --- a/src/cryptoconditions +++ b/src/cryptoconditions @@ -1 +1 @@ -Subproject commit 7bd65d43af4e95ea6d8edf6c3dc5f340e39770cd +Subproject commit a59c22dcf9a67be5f11f88ff89bbd9cb40fd22c0 From a032ddea1f0ab6ed403499b7ea1febfcd1e6d2e9 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Sat, 21 Oct 2017 17:54:17 -0700 Subject: [PATCH 008/339] configure.ac must not include cryptoconditions in AC_CONFIG_SUBDIRS because that disables shared linking. cryptoconditions must not include config.h because that includes conflicting variables. --- configure.ac | 2 +- src/Makefile.am | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 9f8f1900f..c471bab89 100644 --- a/configure.ac +++ b/configure.ac @@ -996,7 +996,7 @@ unset PKG_CONFIG_LIBDIR PKG_CONFIG_LIBDIR="$PKGCONFIG_LIBDIR_TEMP" ac_configure_args="${ac_configure_args} --disable-shared --with-pic --with-bignum=no" -AC_CONFIG_SUBDIRS([src/secp256k1 src/univalue src/cryptoconditions]) +AC_CONFIG_SUBDIRS([src/secp256k1 src/univalue]) AC_OUTPUT diff --git a/src/Makefile.am b/src/Makefile.am index 8907fa54a..815d75d4c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -515,7 +515,8 @@ endif libzcashconsensus_la_LDFLAGS = -no-undefined $(RELDFLAGS) libzcashconsensus_la_LIBADD = $(CRYPTO_LIBS) libzcashconsensus_la_CPPFLAGS = $(CRYPTO_CFLAGS) -I$(builddir)/obj -DBUILD_BITCOIN_INTERNAL \ - -I$(builddir)/cryptoconditions/src/asn + -I$(builddir)/cryptoconditions/src/asn \ + -I$(builddir)/cryptoconditions/src endif # From 342611f9325e6074ddbe00f53adc0b6e3d40d4e7 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Sat, 21 Oct 2017 23:23:57 -0700 Subject: [PATCH 009/339] add rpccryptoconditions --- src/Makefile.am | 1 + src/rpcclient.cpp | 6 +- src/rpccryptoconditions.cpp | 925 ++++++++++++++++++++++++++++++++++++ src/rpcserver.cpp | 2 + src/rpcserver.h | 3 + 5 files changed, 936 insertions(+), 1 deletion(-) create mode 100644 src/rpccryptoconditions.cpp diff --git a/src/Makefile.am b/src/Makefile.am index 815d75d4c..919c6fc89 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -238,6 +238,7 @@ libbitcoin_server_a_SOURCES = \ rpcmisc.cpp \ rpcnet.cpp \ rpcrawtransaction.cpp \ + rpccryptoconditions.cpp \ rpcserver.cpp \ script/sigcache.cpp \ timedata.cpp \ diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index da8fdc4b6..2378e3ca0 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -75,8 +75,12 @@ static const CRPCConvertParam vRPCConvertParams[] = { "getrawtransaction", 1 }, { "createrawtransaction", 0 }, { "createrawtransaction", 1 }, + { "createrawtransactioncc", 0 }, + { "createrawtransactioncc", 1 }, { "signrawtransaction", 1 }, { "signrawtransaction", 2 }, + { "signrawtransactioncc", 1 }, + { "signrawtransactioncc", 2 }, { "sendrawtransaction", 1 }, { "fundrawtransaction", 1 }, { "gettxout", 1 }, @@ -156,7 +160,7 @@ UniValue ParseNonRFCJSONValue(const std::string& strVal) UniValue jVal; if (!jVal.read(std::string("[")+strVal+std::string("]")) || !jVal.isArray() || jVal.size()!=1) - throw runtime_error(string("Error parsing JSON:")+strVal); + throw runtime_error(string("Error JSON:")+strVal); return jVal[0]; } diff --git a/src/rpccryptoconditions.cpp b/src/rpccryptoconditions.cpp new file mode 100644 index 000000000..946667aae --- /dev/null +++ b/src/rpccryptoconditions.cpp @@ -0,0 +1,925 @@ +// Copyright (c) 2010 Satoshi Nakamoto +// Copyright (c) 2009-2015 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 "base58.h" +#include "consensus/validation.h" +#include "core_io.h" +#include "init.h" +#include "keystore.h" +#include "main.h" +#include "merkleblock.h" +#include "net.h" +#include "primitives/transaction.h" +#include "rpcserver.h" +#include "script/script.h" +#include "script/script_error.h" +#include "script/sign.h" +#include "script/standard.h" +#include "uint256.h" +#include "cryptoconditions/include/cryptoconditions.h" +#ifdef ENABLE_WALLET +#include "wallet/wallet.h" +#endif + +#include + +#include + +#include + +using namespace std; + +void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); + + +UniValue TxJoinSplitToJSONcc(const CTransaction& tx) { + UniValue vjoinsplit(UniValue::VARR); + for (unsigned int i = 0; i < tx.vjoinsplit.size(); i++) { + const JSDescription& jsdescription = tx.vjoinsplit[i]; + UniValue joinsplit(UniValue::VOBJ); + + joinsplit.push_back(Pair("vpub_old", ValueFromAmount(jsdescription.vpub_old))); + joinsplit.push_back(Pair("vpub_new", ValueFromAmount(jsdescription.vpub_new))); + + joinsplit.push_back(Pair("anchor", jsdescription.anchor.GetHex())); + + { + UniValue nullifiers(UniValue::VARR); + BOOST_FOREACH(const uint256 nf, jsdescription.nullifiers) { + nullifiers.push_back(nf.GetHex()); + } + joinsplit.push_back(Pair("nullifiers", nullifiers)); + } + + { + UniValue commitments(UniValue::VARR); + BOOST_FOREACH(const uint256 commitment, jsdescription.commitments) { + commitments.push_back(commitment.GetHex()); + } + joinsplit.push_back(Pair("commitments", commitments)); + } + + joinsplit.push_back(Pair("onetimePubKey", jsdescription.ephemeralKey.GetHex())); + joinsplit.push_back(Pair("randomSeed", jsdescription.randomSeed.GetHex())); + + { + UniValue macs(UniValue::VARR); + BOOST_FOREACH(const uint256 mac, jsdescription.macs) { + macs.push_back(mac.GetHex()); + } + joinsplit.push_back(Pair("macs", macs)); + } + + CDataStream ssProof(SER_NETWORK, PROTOCOL_VERSION); + ssProof << jsdescription.proof; + joinsplit.push_back(Pair("proof", HexStr(ssProof.begin(), ssProof.end()))); + + { + UniValue ciphertexts(UniValue::VARR); + for (const ZCNoteEncryption::Ciphertext ct : jsdescription.ciphertexts) { + ciphertexts.push_back(HexStr(ct.begin(), ct.end())); + } + joinsplit.push_back(Pair("ciphertexts", ciphertexts)); + } + + vjoinsplit.push_back(joinsplit); + } + return vjoinsplit; +} + +uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime); + +void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry); + + +UniValue getrawtransactioncc(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "getrawtransaction \"txid\" ( verbose )\n" + "\nNOTE: By default this function only works sometimes. This is when the tx is in the mempool\n" + "or there is an unspent output in the utxo for this transaction. To make it always work,\n" + "you need to maintain a transaction index, using the -txindex command line option.\n" + "\nReturn the raw transaction data.\n" + "\nIf verbose=0, returns a string that is serialized, hex-encoded data for 'txid'.\n" + "If verbose is non-zero, returns an Object with information about 'txid'.\n" + + "\nArguments:\n" + "1. \"txid\" (string, required) The transaction id\n" + "2. verbose (numeric, optional, default=0) If 0, return a string, other return a json object\n" + + "\nResult (if verbose is not set or set to 0):\n" + "\"data\" (string) The serialized, hex-encoded data for 'txid'\n" + + "\nResult (if verbose > 0):\n" + "{\n" + " \"hex\" : \"data\", (string) The serialized, hex-encoded data for 'txid'\n" + " \"txid\" : \"id\", (string) The transaction id (same as provided)\n" + " \"version\" : n, (numeric) The version\n" + " \"locktime\" : ttt, (numeric) The lock time\n" + " \"vin\" : [ (array of json objects)\n" + " {\n" + " \"txid\": \"id\", (string) The transaction id\n" + " \"vout\": n, (numeric) \n" + " \"scriptSig\": { (json object) The script\n" + " \"asm\": \"asm\", (string) asm\n" + " \"hex\": \"hex\" (string) hex\n" + " },\n" + " \"sequence\": n (numeric) The script sequence number\n" + " }\n" + " ,...\n" + " ],\n" + " \"vout\" : [ (array of json objects)\n" + " {\n" + " \"value\" : x.xxx, (numeric) The value in btc\n" + " \"n\" : n, (numeric) index\n" + " \"scriptPubKey\" : { (json object)\n" + " \"asm\" : \"asm\", (string) the asm\n" + " \"hex\" : \"hex\", (string) the hex\n" + " \"reqSigs\" : n, (numeric) The required sigs\n" + " \"type\" : \"pubkeyhash\", (string) The type, eg 'pubkeyhash'\n" + " \"addresses\" : [ (json array of string)\n" + " \"bitcoinaddress\" (string) bitcoin address\n" + " ,...\n" + " ]\n" + " }\n" + " }\n" + " ,...\n" + " ],\n" + " \"vjoinsplit\" : [ (array of json objects, only for version >= 2)\n" + " {\n" + " \"vpub_old\" : x.xxx, (numeric) public input value in ZEC\n" + " \"vpub_new\" : x.xxx, (numeric) public output value in ZEC\n" + " \"anchor\" : \"hex\", (string) the anchor\n" + " \"nullifiers\" : [ (json array of string)\n" + " \"hex\" (string) input note nullifier\n" + " ,...\n" + " ],\n" + " \"commitments\" : [ (json array of string)\n" + " \"hex\" (string) output note commitment\n" + " ,...\n" + " ],\n" + " \"onetimePubKey\" : \"hex\", (string) the onetime public key used to encrypt the ciphertexts\n" + " \"randomSeed\" : \"hex\", (string) the random seed\n" + " \"macs\" : [ (json array of string)\n" + " \"hex\" (string) input note MAC\n" + " ,...\n" + " ],\n" + " \"proof\" : \"hex\", (string) the zero-knowledge proof\n" + " \"ciphertexts\" : [ (json array of string)\n" + " \"hex\" (string) output note ciphertext\n" + " ,...\n" + " ]\n" + " }\n" + " ,...\n" + " ],\n" + " \"blockhash\" : \"hash\", (string) the block hash\n" + " \"confirmations\" : n, (numeric) The confirmations\n" + " \"time\" : ttt, (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT)\n" + " \"blocktime\" : ttt (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n" + "}\n" + + "\nExamples:\n" + + HelpExampleCli("getrawtransaction", "\"mytxid\"") + + HelpExampleCli("getrawtransaction", "\"mytxid\" 1") + + HelpExampleRpc("getrawtransaction", "\"mytxid\", 1") + ); + + LOCK(cs_main); + + uint256 hash = ParseHashV(params[0], "parameter 1"); + + bool fVerbose = false; + if (params.size() > 1) + fVerbose = (params[1].get_int() != 0); + + CTransaction tx; + uint256 hashBlock; + if (!GetTransaction(hash, tx, hashBlock, true)) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); + + string strHex = EncodeHexTx(tx); + + if (!fVerbose) + return strHex; + + UniValue result(UniValue::VOBJ); + result.push_back(Pair("hex", strHex)); + TxToJSON(tx, hashBlock, result); + return result; +} + +int32_t gettxout_scriptPubKeycc(uint8_t *scriptPubKey,int32_t maxsize,uint256 txid,int32_t n) +{ + int32_t i,m; uint8_t *ptr; + LOCK(cs_main); + /*CCoins coins; + for (iter=0; iter<2; iter++) + { + if ( iter == 0 ) + { + LOCK(mempool.cs); + CCoinsViewMemPool view(pcoinsTip,mempool); + if ( view.GetCoins(txid,coins) == 0 ) + { + //fprintf(stderr,"cant get view\n"); + continue; + } + mempool.pruneSpent(txid, coins); // TODO: this should be done by the CCoinsViewMemPool + } + else if ( pcoinsTip->GetCoins(txid,coins) == 0 ) + { + //fprintf(stderr,"cant get pcoinsTip->GetCoins\n"); + continue; + } + if ( n < 0 || (unsigned int)n >= coins.vout.size() || coins.vout[n].IsNull() ) + { + fprintf(stderr,"iter.%d n.%d vs voutsize.%d\n",iter,n,(int32_t)coins.vout.size()); + continue; + } + ptr = (uint8_t *)coins.vout[n].scriptPubKey.data(); + m = coins.vout[n].scriptPubKey.size(); + for (i=0; i setTxids; + uint256 oneTxid; + UniValue txids = params[0].get_array(); + for (size_t idx = 0; idx < txids.size(); idx++) { + const UniValue& txid = txids[idx]; + if (txid.get_str().length() != 64 || !IsHex(txid.get_str())) + throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid txid ")+txid.get_str()); + uint256 hash(uint256S(txid.get_str())); + if (setTxids.count(hash)) + throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated txid: ")+txid.get_str()); + setTxids.insert(hash); + oneTxid = hash; + } + + LOCK(cs_main); + + CBlockIndex* pblockindex = NULL; + + uint256 hashBlock; + if (params.size() > 1) + { + hashBlock = uint256S(params[1].get_str()); + if (!mapBlockIndex.count(hashBlock)) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); + pblockindex = mapBlockIndex[hashBlock]; + } else { + CCoins coins; + if (pcoinsTip->GetCoins(oneTxid, coins) && coins.nHeight > 0 && coins.nHeight <= chainActive.Height()) + pblockindex = chainActive[coins.nHeight]; + } + + if (pblockindex == NULL) + { + CTransaction tx; + if (!GetTransaction(oneTxid, tx, hashBlock, false) || hashBlock.IsNull()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block"); + if (!mapBlockIndex.count(hashBlock)) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction index corrupt"); + pblockindex = mapBlockIndex[hashBlock]; + } + + CBlock block; + if(!ReadBlockFromDisk(block, pblockindex)) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); + + unsigned int ntxFound = 0; + BOOST_FOREACH(const CTransaction&tx, block.vtx) + if (setTxids.count(tx.GetHash())) + ntxFound++; + if (ntxFound != setTxids.size()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "(Not all) transactions not found in specified block"); + + CDataStream ssMB(SER_NETWORK, PROTOCOL_VERSION); + CMerkleBlock mb(block, setTxids); + ssMB << mb; + std::string strHex = HexStr(ssMB.begin(), ssMB.end()); + return strHex; +} + +UniValue verifytxoutproofcc(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "verifytxoutproof \"proof\"\n" + "\nVerifies that a proof points to a transaction in a block, returning the transaction it commits to\n" + "and throwing an RPC error if the block is not in our best chain\n" + "\nArguments:\n" + "1. \"proof\" (string, required) The hex-encoded proof generated by gettxoutproof\n" + "\nResult:\n" + "[\"txid\"] (array, strings) The txid(s) which the proof commits to, or empty array if the proof is invalid\n" + ); + + CDataStream ssMB(ParseHexV(params[0], "proof"), SER_NETWORK, PROTOCOL_VERSION); + CMerkleBlock merkleBlock; + ssMB >> merkleBlock; + + UniValue res(UniValue::VARR); + + vector vMatch; + if (merkleBlock.txn.ExtractMatches(vMatch) != merkleBlock.header.hashMerkleRoot) + return res; + + LOCK(cs_main); + + if (!mapBlockIndex.count(merkleBlock.header.GetHash()) || !chainActive.Contains(mapBlockIndex[merkleBlock.header.GetHash()])) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain"); + + BOOST_FOREACH(const uint256& hash, vMatch) + res.push_back(hash.GetHex()); + return res; +} + +UniValue createrawtransactioncc(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 2) + throw runtime_error( + "createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,...}\n" + "\nCreate a transaction spending the given inputs and sending to the given addresses.\n" + "Returns hex-encoded raw transaction.\n" + "Note that the transaction's inputs are not signed, and\n" + "it is not stored in the wallet or transmitted to the network.\n" + + "\nArguments:\n" + "1. \"transactions\" (string, required) A json array of json objects\n" + " [\n" + " {\n" + " \"txid\":\"id\", (string, required) The transaction id\n" + " \"vout\":n (numeric, required) The output number\n" + " }\n" + " ,...\n" + " ]\n" + "2. \"addresses\" (string, required) a json object with addresses as keys and amounts as values\n" + " {\n" + " \"address\": x.xxx (numeric, required) The key is the bitcoin address, the value is the btc amount\n" + " ,...\n" + " }\n" + + "\nResult:\n" + "\"transaction\" (string) hex string of the transaction\n" + + "\nExamples\n" + + HelpExampleCli("createrawtransactioncc", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"{\\\"address\\\":0.01}\"") + + HelpExampleRpc("createrawtransactioncc", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"address\\\":0.01}\"") + ); + + LOCK(cs_main); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VARR)(UniValue::VARR)); + + UniValue inputs = params[0].get_array(); + UniValue outputs = params[1].get_array(); + + CMutableTransaction rawTx; + + for (size_t idx = 0; idx < inputs.size(); idx++) { + const UniValue& input = inputs[idx]; + const UniValue& o = input.get_obj(); + + uint256 txid = ParseHashO(o, "txid"); + + const UniValue& vout_v = find_value(o, "vout"); + if (!vout_v.isNum()) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key"); + int nOutput = vout_v.get_int(); + if (nOutput < 0) + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive"); + + CTxIn in(COutPoint(txid, nOutput)); + rawTx.vin.push_back(in); + } + + for (size_t idx = 0; idx < outputs.size(); idx++) { + const UniValue& output = outputs[idx].get_obj(); + + const UniValue& condition = find_value(output, "condition"); + std::string encoded = condition.write(); + fprintf(stderr, "%s\n", encoded.c_str()); + char *err = new char[1000]; + CC *cond = cc_conditionFromJSONString(encoded.c_str(), err); + if (NULL == cond) + throw JSONRPCError(RPC_INVALID_PARAMETER, err); + char *condBin = new char[1000]; + size_t binLength = cc_conditionBinary(cond, condBin); + std::vector condVec(condBin, condBin + binLength); + + CScript redeemScript; + redeemScript << ToByteVector(condVec) << OP_CHECKCRYPTOCONDITIONVERIFY; + CAmount nAmount = AmountFromValue(find_value(output, "amount")); + + CTxOut out(nAmount, redeemScript); + rawTx.vout.push_back(out); + } + + /* + set setAddress; + vector addrList = sendTo.getKeys(); + BOOST_FOREACH(const string& name_, addrList) { + CBitcoinAddress address(name_); + if (!address.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+name_); + + if (setAddress.count(address)) + throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_); + setAddress.insert(address); + + CScript scriptPubKey = GetScriptForDestination(address.Get()); + CAmount nAmount = AmountFromValue(sendTo[name_]); + + CTxOut out(nAmount, scriptPubKey); + rawTx.vout.push_back(out); + } + */ + + return EncodeHexTx(rawTx); +} + +UniValue decoderawtransactioncc(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "decoderawtransaction \"hexstring\"\n" + "\nReturn a JSON object representing the serialized, hex-encoded transaction.\n" + + "\nArguments:\n" + "1. \"hex\" (string, required) The transaction hex string\n" + + "\nResult:\n" + "{\n" + " \"txid\" : \"id\", (string) The transaction id\n" + " \"version\" : n, (numeric) The version\n" + " \"locktime\" : ttt, (numeric) The lock time\n" + " \"vin\" : [ (array of json objects)\n" + " {\n" + " \"txid\": \"id\", (string) The transaction id\n" + " \"vout\": n, (numeric) The output number\n" + " \"scriptSig\": { (json object) The script\n" + " \"asm\": \"asm\", (string) asm\n" + " \"hex\": \"hex\" (string) hex\n" + " },\n" + " \"sequence\": n (numeric) The script sequence number\n" + " }\n" + " ,...\n" + " ],\n" + " \"vout\" : [ (array of json objects)\n" + " {\n" + " \"value\" : x.xxx, (numeric) The value in btc\n" + " \"n\" : n, (numeric) index\n" + " \"scriptPubKey\" : { (json object)\n" + " \"asm\" : \"asm\", (string) the asm\n" + " \"hex\" : \"hex\", (string) the hex\n" + " \"reqSigs\" : n, (numeric) The required sigs\n" + " \"type\" : \"pubkeyhash\", (string) The type, eg 'pubkeyhash'\n" + " \"addresses\" : [ (json array of string)\n" + " \"12tvKAXCxZjSmdNbao16dKXC8tRWfcF5oc\" (string) bitcoin address\n" + " ,...\n" + " ]\n" + " }\n" + " }\n" + " ,...\n" + " ],\n" + " \"vjoinsplit\" : [ (array of json objects, only for version >= 2)\n" + " {\n" + " \"vpub_old\" : x.xxx, (numeric) public input value in ZEC\n" + " \"vpub_new\" : x.xxx, (numeric) public output value in ZEC\n" + " \"anchor\" : \"hex\", (string) the anchor\n" + " \"nullifiers\" : [ (json array of string)\n" + " \"hex\" (string) input note nullifier\n" + " ,...\n" + " ],\n" + " \"commitments\" : [ (json array of string)\n" + " \"hex\" (string) output note commitment\n" + " ,...\n" + " ],\n" + " \"onetimePubKey\" : \"hex\", (string) the onetime public key used to encrypt the ciphertexts\n" + " \"randomSeed\" : \"hex\", (string) the random seed\n" + " \"macs\" : [ (json array of string)\n" + " \"hex\" (string) input note MAC\n" + " ,...\n" + " ],\n" + " \"proof\" : \"hex\", (string) the zero-knowledge proof\n" + " \"ciphertexts\" : [ (json array of string)\n" + " \"hex\" (string) output note ciphertext\n" + " ,...\n" + " ]\n" + " }\n" + " ,...\n" + " ],\n" + "}\n" + + "\nExamples:\n" + + HelpExampleCli("decoderawtransaction", "\"hexstring\"") + + HelpExampleRpc("decoderawtransaction", "\"hexstring\"") + ); + + LOCK(cs_main); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)); + + CTransaction tx; + + if (!DecodeHexTx(tx, params[0].get_str())) + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); + + UniValue result(UniValue::VOBJ); + TxToJSON(tx, uint256(), result); + + return result; +} + +UniValue decodescriptcc(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() != 1) + throw runtime_error( + "decodescript \"hex\"\n" + "\nDecode a hex-encoded script.\n" + "\nArguments:\n" + "1. \"hex\" (string) the hex encoded script\n" + "\nResult:\n" + "{\n" + " \"asm\":\"asm\", (string) Script public key\n" + " \"hex\":\"hex\", (string) hex encoded public key\n" + " \"type\":\"type\", (string) The output type\n" + " \"reqSigs\": n, (numeric) The required signatures\n" + " \"addresses\": [ (json array of string)\n" + " \"address\" (string) bitcoin address\n" + " ,...\n" + " ],\n" + " \"p2sh\",\"address\" (string) script address\n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("decodescript", "\"hexstring\"") + + HelpExampleRpc("decodescript", "\"hexstring\"") + ); + + LOCK(cs_main); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)); + + UniValue r(UniValue::VOBJ); + CScript script; + if (params[0].get_str().size() > 0){ + vector scriptData(ParseHexV(params[0], "argument")); + script = CScript(scriptData.begin(), scriptData.end()); + } else { + // Empty scripts are valid + } + ScriptPubKeyToJSON(script, r, false); + + r.push_back(Pair("p2sh", CBitcoinAddress(CScriptID(script)).ToString())); + return r; +} + +/** Pushes a JSON object for script verification or signing errors to vErrorsRet. */ +static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std::string& strMessage) {} + + +UniValue signrawtransactioncc(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 4) + throw runtime_error( + "signrawtransactioncc \"hexstring\" ( [{\"txid\":\"id\",\"vout\":n,\"scriptPubKey\":\"hex\",\"redeemScript\":\"hex\"},...] [\"privatekey1\",...] sighashtype )\n" + "\nSign cryptocondition inputs for raw transaction (serialized, hex-encoded).\n" + "The second optional argument (may be null) is an array of previous transaction outputs that\n" + "this transaction depends on but may not yet be in the block chain.\n" + "The third optional argument (may be null) is an array of base58-encoded private\n" + "keys that, if given, will be the only keys used to sign the transaction.\n" +#ifdef ENABLE_WALLET + + HelpRequiringPassphrase() + "\n" +#endif + + "\nArguments:\n" + "1. \"hexstring\" (string, required) The transaction hex string\n" + /* "2. \"prevtxs\" (string, optional) An json array of previous dependent transaction outputs\n" + " [ (json array of json objects, or 'null' if none provided)\n" + " {\n" + " \"txid\":\"id\", (string, required) The transaction id\n" + " \"vout\":n, (numeric, required) The output number\n" + " \"scriptPubKey\": \"hex\", (string, required) script key\n" + " \"redeemScript\": \"hex\" (string, required for P2SH) redeem script\n" + " }\n" + " ,...\n" + " ]\n" */ + "3. \"privatekeys\" (string, optional) A json array of base58-encoded private keys for signing\n" + " [ (json array of strings, or 'null' if none provided)\n" + " \"privatekey\" (string) private key in base58-encoding\n" + " ,...\n" + " ]\n" + /* "4. \"sighashtype\" (string, optional, default=ALL) The signature hash type. Must be one of\n" + " \"ALL\"\n" + " \"NONE\"\n" + " \"SINGLE\"\n" + " \"ALL|ANYONECANPAY\"\n" + " \"NONE|ANYONECANPAY\"\n" + " \"SINGLE|ANYONECANPAY\"\n" */ + + "\nResult:\n" + "{\n" + " \"hex\" : \"value\", (string) The hex-encoded raw transaction with signature(s)\n" + " \"complete\" : true|false, (boolean) If the transaction has a complete set of signatures\n" + " \"errors\" : [ (json array of objects) Script verification errors (if there are any)\n" + " {\n" + " \"txid\" : \"hash\", (string) The hash of the referenced, previous transaction\n" + " \"vout\" : n, (numeric) The index of the output to spent and used as input\n" + " \"scriptSig\" : \"hex\", (string) The hex-encoded signature script\n" + " \"sequence\" : n, (numeric) Script sequence number\n" + " \"error\" : \"text\" (string) Verification or signing error related to the input\n" + " }\n" + " ,...\n" + " ]\n" + "}\n" + + "\nExamples:\n" + + HelpExampleCli("signrawtransactioncc", "\"myhex\"") + + HelpExampleRpc("signrawtransactioncc", "\"myhex\"") + ); + +#ifdef ENABLE_WALLET + LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL); +#else + LOCK(cs_main); +#endif + RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VARR)(UniValue::VARR)(UniValue::VSTR), true); + + vector txData(ParseHexV(params[0], "argument 1")); + CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION); + vector txVariants; + while (!ssData.empty()) { + //try { + CMutableTransaction tx; + ssData >> tx; + txVariants.push_back(tx); + //} + //catch (const std::exception&) { + //throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); + //} + } + + if (txVariants.empty()) + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transaction"); + + // mergedTx will end up with all the signatures; it + // starts as a clone of the rawtx: + CMutableTransaction mergedTx(txVariants[0]); + + // Fetch previous transactions (inputs): + CCoinsView viewDummy; + CCoinsViewCache view(&viewDummy); + { + LOCK(mempool.cs); + CCoinsViewCache &viewChain = *pcoinsTip; + CCoinsViewMemPool viewMempool(&viewChain, mempool); + view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view + + BOOST_FOREACH(const CTxIn& txin, mergedTx.vin) { + const uint256& prevHash = txin.prevout.hash; + CCoins coins; + view.AccessCoins(prevHash); // this is certainly allowed to fail + } + + view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long + } + + bool fGivenKeys = false; + CBasicKeyStore tempKeystore; + if (params.size() > 2 && !params[2].isNull()) { + fGivenKeys = true; + UniValue keys = params[2].get_array(); + for (size_t idx = 0; idx < keys.size(); idx++) { + UniValue k = keys[idx]; + CBitcoinSecret vchSecret; + bool fGood = vchSecret.SetString(k.get_str()); + if (!fGood) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key"); + CKey key = vchSecret.GetKey(); + if (!key.IsValid()) + throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Private key outside allowed range"); + tempKeystore.AddKey(key); + } + } +#ifdef ENABLE_WALLET + else if (pwalletMain) + EnsureWalletIsUnlocked(); +#endif + + // Add previous txouts given in the RPC call: + /* + if (params.size() > 1 && !params[1].isNull()) { + UniValue prevTxs = params[1].get_array(); + for (size_t idx = 0; idx < prevTxs.size(); idx++) { + const UniValue& p = prevTxs[idx]; + if (!p.isObject()) + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}"); + + UniValue prevOut = p.get_obj(); + + RPCTypeCheckObj(prevOut, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM)("scriptPubKey", UniValue::VSTR)); + + uint256 txid = ParseHashO(prevOut, "txid"); + + int nOut = find_value(prevOut, "vout").get_int(); + if (nOut < 0) + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive"); + + vector pkData(ParseHexO(prevOut, "scriptPubKey")); + CScript scriptPubKey(pkData.begin(), pkData.end()); + + { + CCoinsModifier coins = view.ModifyCoins(txid); + if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) { + string err("Previous output scriptPubKey mismatch:\n"); + err = err + coins->vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+ + scriptPubKey.ToString(); + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err); + } + if ((unsigned int)nOut >= coins->vout.size()) + coins->vout.resize(nOut+1); + coins->vout[nOut].scriptPubKey = scriptPubKey; + coins->vout[nOut].nValue = 0; // we don't know the actual output value + } + + // if redeemScript given and not using the local wallet (private keys + // given), add redeemScript to the tempKeystore so it can be signed: + if (fGivenKeys && scriptPubKey.IsPayToScriptHash()) { + RPCTypeCheckObj(prevOut, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM)("scriptPubKey", UniValue::VSTR)("redeemScript",UniValue::VSTR)); + UniValue v = find_value(prevOut, "redeemScript"); + if (!v.isNull()) { + vector rsData(ParseHexV(v, "redeemScript")); + CScript redeemScript(rsData.begin(), rsData.end()); + tempKeystore.AddCScript(redeemScript); + } + } + } + } + */ + +#ifdef ENABLE_WALLET + const CKeyStore& keystore = ((fGivenKeys || !pwalletMain) ? tempKeystore : *pwalletMain); +#else + const CKeyStore& keystore = tempKeystore; +#endif + + int nHashType = SIGHASH_ALL; + /* + if (params.size() > 3 && !params[3].isNull()) { + static map mapSigHashValues = + boost::assign::map_list_of + (string("ALL"), int(SIGHASH_ALL)) + (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY)) + (string("NONE"), int(SIGHASH_NONE)) + (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY)) + (string("SINGLE"), int(SIGHASH_SINGLE)) + (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY)) + ; + string strHashType = params[3].get_str(); + if (mapSigHashValues.count(strHashType)) + nHashType = mapSigHashValues[strHashType]; + else + throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param"); + } + */ + + bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE); + + // Script verification errors + UniValue vErrors(UniValue::VARR); + + // Sign what we can: + for (unsigned int i = 0; i < mergedTx.vin.size(); i++) { + CTxIn& txin = mergedTx.vin[i]; + const CCoins* coins = view.AccessCoins(txin.prevout.hash); + if (coins == NULL || !coins->IsAvailable(txin.prevout.n)) { + TxInErrorToJSON(txin, vErrors, "Input not found or already spent"); + continue; + } + const CScript& prevPubKey = coins->vout[txin.prevout.n].scriptPubKey; + + txin.scriptSig.clear(); + // Only sign SIGHASH_SINGLE if there's a corresponding output: + if (!fHashSingle || (i < mergedTx.vout.size())) + SignSignature(keystore, prevPubKey, mergedTx, i, nHashType); + + // ... and merge in other signatures: + BOOST_FOREACH(const CMutableTransaction& txv, txVariants) { + txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig); + } + ScriptError serror = SCRIPT_ERR_OK; + if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i), &serror)) { + TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror)); + } + } + bool fComplete = vErrors.empty(); + + UniValue result(UniValue::VOBJ); + result.push_back(Pair("hex", EncodeHexTx(mergedTx))); + result.push_back(Pair("complete", fComplete)); + if (!vErrors.empty()) { + result.push_back(Pair("errors", vErrors)); + } + + return result; +} + +UniValue sendrawtransactioncc(const UniValue& params, bool fHelp) +{ + if (fHelp || params.size() < 1 || params.size() > 2) + throw runtime_error( + "sendrawtransaction \"hexstring\" ( allowhighfees )\n" + "\nSubmits raw transaction (serialized, hex-encoded) to local node and network.\n" + "\nAlso see createrawtransaction and signrawtransaction calls.\n" + "\nArguments:\n" + "1. \"hexstring\" (string, required) The hex string of the raw transaction)\n" + "2. allowhighfees (boolean, optional, default=false) Allow high fees\n" + "\nResult:\n" + "\"hex\" (string) The transaction hash in hex\n" + "\nExamples:\n" + "\nCreate a transaction\n" + + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") + + "Sign the transaction, and get back the hex\n" + + HelpExampleCli("signrawtransaction", "\"myhex\"") + + "\nSend the transaction (signed hex)\n" + + HelpExampleCli("sendrawtransaction", "\"signedhex\"") + + "\nAs a json rpc call\n" + + HelpExampleRpc("sendrawtransaction", "\"signedhex\"") + ); + + LOCK(cs_main); + RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VBOOL)); + + // parse hex string from parameter + CTransaction tx; + if (!DecodeHexTx(tx, params[0].get_str())) + throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); + uint256 hashTx = tx.GetHash(); + + bool fOverrideFees = false; + if (params.size() > 1) + fOverrideFees = params[1].get_bool(); + + CCoinsViewCache &view = *pcoinsTip; + const CCoins* existingCoins = view.AccessCoins(hashTx); + bool fHaveMempool = mempool.exists(hashTx); + bool fHaveChain = existingCoins && existingCoins->nHeight < 1000000000; + if (!fHaveMempool && !fHaveChain) { + // push to local node and sync with wallets + CValidationState state; + bool fMissingInputs; + if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, !fOverrideFees)) { + if (state.IsInvalid()) { + throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason())); + } else { + if (fMissingInputs) { + throw JSONRPCError(RPC_TRANSACTION_ERROR, "Missing inputs"); + } + throw JSONRPCError(RPC_TRANSACTION_ERROR, state.GetRejectReason()); + } + } + } else if (fHaveChain) { + throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain"); + } + RelayTransaction(tx); + + return hashTx.GetHex(); +} diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 518ba4693..06c08a3be 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -325,6 +325,8 @@ static const CRPCCommand vRPCCommands[] = { "rawtransactions", "getrawtransaction", &getrawtransaction, true }, { "rawtransactions", "sendrawtransaction", &sendrawtransaction, false }, { "rawtransactions", "signrawtransaction", &signrawtransaction, false }, /* uses wallet if enabled */ + { "rawtransactions", "createrawtransactioncc", &createrawtransactioncc, true }, + { "rawtransactions", "signrawtransactioncc", &signrawtransactioncc, false }, /* uses wallet if enabled */ #ifdef ENABLE_WALLET { "rawtransactions", "fundrawtransaction", &fundrawtransaction, false }, #endif diff --git a/src/rpcserver.h b/src/rpcserver.h index ecf7b0573..611abd05f 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -262,6 +262,9 @@ extern UniValue sendrawtransaction(const UniValue& params, bool fHelp); extern UniValue gettxoutproof(const UniValue& params, bool fHelp); extern UniValue verifytxoutproof(const UniValue& params, bool fHelp); +extern UniValue createrawtransactioncc(const UniValue& params, bool fHelp); // in rpccryptocondition.cpp +extern UniValue signrawtransactioncc(const UniValue& params, bool fHelp); + extern UniValue getblockcount(const UniValue& params, bool fHelp); // in rpcblockchain.cpp extern UniValue getbestblockhash(const UniValue& params, bool fHelp); extern UniValue getdifficulty(const UniValue& params, bool fHelp); From 8fa1b4be0e9c60ef3f6f877e44a32ae20b7b91e4 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Sun, 22 Oct 2017 21:57:07 -0700 Subject: [PATCH 010/339] upgrade cJSON and move cJSON extensions to different module --- src/bitcoin-cli.cpp | 2 +- src/cJSON.c | 3577 +++++++++++++++++++++++++++++++------------ src/cJSON.h | 458 +++--- src/komodo.h | 2 +- src/komodo_cJSON.c | 559 +++++++ src/komodo_cJSON.h | 128 ++ src/komodo_jumblr.h | 18 +- src/komodo_notary.h | 2 + 8 files changed, 3516 insertions(+), 1230 deletions(-) mode change 100755 => 100644 src/cJSON.c mode change 100755 => 100644 src/cJSON.h create mode 100755 src/komodo_cJSON.c create mode 100755 src/komodo_cJSON.h diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index bb9aeb580..cac650a00 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -72,7 +72,7 @@ public: #include "komodo_globals.h" #include "komodo_utils.h" -#include "cJSON.c" +#include "komodo_cJSON.c" #include "komodo_notary.h" void komodo_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numnotaries,uint8_t notaryid,uint256 txhash,uint64_t voutmask,uint8_t numvouts,uint32_t *pvals,uint8_t numpvals,int32_t KMDheight,uint32_t KMDtimestamp,uint64_t opretvalue,uint8_t *opretbuf,uint16_t opretlen,uint16_t vout) diff --git a/src/cJSON.c b/src/cJSON.c old mode 100755 new mode 100644 index 82b78a403..5b58f2ffc --- a/src/cJSON.c +++ b/src/cJSON.c @@ -1,1136 +1,2699 @@ - /* - Copyright (c) 2009 Dave Gamble - - 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. - */ + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + 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. +*/ /* cJSON */ /* JSON parser in C. */ + +#ifdef __GNUC__ +#pragma GCC visibility push(default) +#endif + +#include +#include #include +#include +#include +#include +#include +#include + +#ifdef __GNUC__ +#pragma GCC visibility pop +#endif #include "cJSON.h" -#ifndef DBL_EPSILON -#define DBL_EPSILON 2.2204460492503131E-16 +/* define our own boolean type */ +#define true ((cJSON_bool)1) +#define false ((cJSON_bool)0) + +typedef struct { + const unsigned char *json; + size_t position; +} cJSON_error; +static cJSON_error global_error = { NULL, 0 }; + +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) +{ + return (const char*) (global_error.json + global_error.position); +} + +/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 5) || (CJSON_VERSION_PATCH != 9) + #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. #endif -static const char *ep; - -long stripquotes(char *str) +CJSON_PUBLIC(const char*) cJSON_Version(void) { - long len,offset; - if ( str == 0 ) - return(0); - len = strlen(str); - if ( str[0] == '"' && str[len-1] == '"' ) - str[len-1] = 0, offset = 1; - else offset = 0; - return(offset); + static char version[15]; + sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); + + return version; } -const char *cJSON_GetErrorPtr(void) {return ep;} - -static int32_t cJSON_strcasecmp(const char *s1,const char *s2) +/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ +static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) { - if (!s1) return (s1==s2)?0:1;if (!s2) return 1; - for(; tolower((int32_t)(*s1)) == tolower((int32_t)(*s2)); ++s1, ++s2) if(*s1 == 0) return 0; - return tolower((int32_t)(*(const unsigned char *)s1)) - tolower((int32_t)(*(const unsigned char *)s2)); + if ((string1 == NULL) || (string2 == NULL)) + { + return 1; + } + + if (string1 == string2) + { + return 0; + } + + for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) + { + if (*string1 == '\0') + { + return 0; + } + } + + return tolower(*string1) - tolower(*string2); } -static void *(*cJSON_malloc)(size_t sz) = malloc; -static void (*cJSON_free)(void *ptr) = free; - -static char* cJSON_strdup(const char* str) +typedef struct internal_hooks { - size_t len; - char* copy; - - len = strlen(str) + 1; - if (!(copy = (char*)cJSON_malloc(len+1))) return 0; - memcpy(copy,str,len); + void *(*allocate)(size_t size); + void (*deallocate)(void *pointer); + void *(*reallocate)(void *pointer, size_t size); +} internal_hooks; + +static internal_hooks global_hooks = { malloc, free, realloc }; + +static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks) +{ + size_t length = 0; + unsigned char *copy = NULL; + + if (string == NULL) + { + return NULL; + } + + length = strlen((const char*)string) + sizeof(""); + if (!(copy = (unsigned char*)hooks->allocate(length))) + { + return NULL; + } + memcpy(copy, string, length); + return copy; } -void cJSON_InitHooks(cJSON_Hooks* hooks) +CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) { - if (!hooks) { /* Reset hooks */ - cJSON_malloc = malloc; - cJSON_free = free; + if (hooks == NULL) + { + /* Reset hooks */ + global_hooks.allocate = malloc; + global_hooks.deallocate = free; + global_hooks.reallocate = realloc; return; } - - cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc; - cJSON_free = (hooks->free_fn)?hooks->free_fn:free; + + global_hooks.allocate = malloc; + if (hooks->malloc_fn != NULL) + { + global_hooks.allocate = hooks->malloc_fn; + } + + global_hooks.deallocate = free; + if (hooks->free_fn != NULL) + { + global_hooks.deallocate = hooks->free_fn; + } + + /* use realloc only if both free and malloc are used */ + global_hooks.reallocate = NULL; + if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free)) + { + global_hooks.reallocate = realloc; + } } /* Internal constructor. */ -static cJSON *cJSON_New_Item(void) +static cJSON *cJSON_New_Item(const internal_hooks * const hooks) { - cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); - if (node) memset(node,0,sizeof(cJSON)); - return node; + cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON)); + if (node) + { + memset(node, '\0', sizeof(cJSON)); + } + + return node; } /* Delete a cJSON structure. */ -void cJSON_Delete(cJSON *c) +CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) { - cJSON *next; - while (c) - { - next=c->next; - if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child); - if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring); - if (c->string) cJSON_free(c->string); - cJSON_free(c); - c=next; - } + cJSON *next = NULL; + while (item != NULL) + { + next = item->next; + if (!(item->type & cJSON_IsReference) && (item->child != NULL)) + { + cJSON_Delete(item->child); + } + if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) + { + global_hooks.deallocate(item->valuestring); + } + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) + { + global_hooks.deallocate(item->string); + } + global_hooks.deallocate(item); + item = next; + } } -/* Parse the input text to generate a number, and populate the result into item. */ -static const char *parse_number(cJSON *item,const char *num) +/* get the decimal point character of the current locale */ +static unsigned char get_decimal_point(void) { - double n=0,sign=1,scale=0;int32_t subscale=0,signsubscale=1; - - if (*num=='-') sign=-1,num++; /* Has sign? */ - if (*num=='0') num++; /* is zero */ - if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */ - if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */ - if (*num=='e' || *num=='E') /* Exponent? */ - { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */ - while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */ - } - - n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */ - - item->valuedouble=n; - item->valueint=(int64_t)n; - item->type=cJSON_Number; - return num; + struct lconv *lconv = localeconv(); + return (unsigned char) lconv->decimal_point[0]; +} + +typedef struct +{ + const unsigned char *content; + size_t length; + size_t offset; + size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ + internal_hooks hooks; +} parse_buffer; + +/* check if the given size is left to read in a given parse buffer (starting with 1) */ +#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length)) +#define cannot_read(buffer, size) (!can_read(buffer, size)) +/* check if the buffer can be accessed at the given index (starting with 0) */ +#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) +#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) +/* get a pointer to the buffer at the position */ +#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) + +/* Parse the input text to generate a number, and populate the result into item. */ +static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer) +{ + double number = 0; + unsigned char *after_end = NULL; + unsigned char number_c_string[64]; + unsigned char decimal_point = get_decimal_point(); + size_t i = 0; + + if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { + return false; + } + + /* copy the number into a temporary buffer and replace '.' with the decimal point + * of the current locale (for strtod) + * This also takes care of '\0' not necessarily being available for marking the end of the input */ + for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) + { + switch (buffer_at_offset(input_buffer)[i]) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '+': + case '-': + case 'e': + case 'E': + number_c_string[i] = buffer_at_offset(input_buffer)[i]; + break; + + case '.': + number_c_string[i] = decimal_point; + break; + + default: + goto loop_end; + } + } +loop_end: + number_c_string[i] = '\0'; + + number = strtod((const char*)number_c_string, (char**)&after_end); + if (number_c_string == after_end) + { + return false; /* parse_error */ + } + + item->valuedouble = number; + + /* use saturation in case of overflow */ + if (number >= INT_MAX) + { + item->valueint = INT_MAX; + } + else if (number <= INT_MIN) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = (int)number; + } + + item->type = cJSON_Number; + + input_buffer->offset += (size_t)(after_end - number_c_string); + return true; +} + +/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) +{ + if (number >= INT_MAX) + { + object->valueint = INT_MAX; + } + else if (number <= INT_MIN) + { + object->valueint = INT_MIN; + } + else + { + object->valueint = (int)number; + } + + return object->valuedouble = number; +} + +typedef struct +{ + unsigned char *buffer; + size_t length; + size_t offset; + size_t depth; /* current nesting depth (for formatted printing) */ + cJSON_bool noalloc; + cJSON_bool format; /* is this print a formatted print */ + internal_hooks hooks; +} printbuffer; + +/* realloc printbuffer if necessary to have at least "needed" bytes more */ +static unsigned char* ensure(printbuffer * const p, size_t needed) +{ + unsigned char *newbuffer = NULL; + size_t newsize = 0; + + if ((p == NULL) || (p->buffer == NULL)) + { + return NULL; + } + + if ((p->length > 0) && (p->offset >= p->length)) + { + /* make sure that offset is valid */ + return NULL; + } + + if (needed > INT_MAX) + { + /* sizes bigger than INT_MAX are currently not supported */ + return NULL; + } + + needed += p->offset + 1; + if (needed <= p->length) + { + return p->buffer + p->offset; + } + + if (p->noalloc) { + return NULL; + } + + /* calculate new buffer size */ + if (needed > (INT_MAX / 2)) + { + /* overflow of int, use INT_MAX if possible */ + if (needed <= INT_MAX) + { + newsize = INT_MAX; + } + else + { + return NULL; + } + } + else + { + newsize = needed * 2; + } + + if (p->hooks.reallocate != NULL) + { + /* reallocate with realloc if available */ + newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize); + if (newbuffer == NULL) + { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + } + else + { + /* otherwise reallocate manually */ + newbuffer = (unsigned char*)p->hooks.allocate(newsize); + if (!newbuffer) + { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + if (newbuffer) + { + memcpy(newbuffer, p->buffer, p->offset + 1); + } + p->hooks.deallocate(p->buffer); + } + p->length = newsize; + p->buffer = newbuffer; + + return newbuffer + p->offset; +} + +/* calculate the new length of the string in a printbuffer and update the offset */ +static void update_offset(printbuffer * const buffer) +{ + const unsigned char *buffer_pointer = NULL; + if ((buffer == NULL) || (buffer->buffer == NULL)) + { + return; + } + buffer_pointer = buffer->buffer + buffer->offset; + + buffer->offset += strlen((const char*)buffer_pointer); } /* Render the number nicely from the given item into a string. */ -static char *print_number(cJSON *item) +static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) { - char *str; - double d = item->valuedouble; - if ( fabs(((double)item->valueint) - d) <= DBL_EPSILON && d >= (1. - DBL_EPSILON) && d < (1LL << 62) )//d <= INT_MAX && d >= INT_MIN ) - { - str = (char *)cJSON_malloc(24); /* 2^64+1 can be represented in 21 chars + sign. */ - if ( str != 0 ) - sprintf(str,"%lld",(long long)item->valueint); - } - else - { - str = (char *)cJSON_malloc(66); /* This is a nice tradeoff. */ - if ( str != 0 ) - { - if ( fabs(floor(d) - d) <= DBL_EPSILON && fabs(d) < 1.0e60 ) - sprintf(str,"%.0f",d); - //else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d); - else - sprintf(str,"%.8f",d); - } - } - return str; -} + unsigned char *output_pointer = NULL; + double d = item->valuedouble; + int length = 0; + size_t i = 0; + unsigned char number_buffer[26]; /* temporary buffer to print the number into */ + unsigned char decimal_point = get_decimal_point(); + double test; -static unsigned parse_hex4(const char *str) -{ - unsigned h=0; - if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; - h=h<<4;str++; - if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; - h=h<<4;str++; - if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; - h=h<<4;str++; - if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; - return h; -} + if (output_buffer == NULL) + { + return false; + } -/* Parse the input text into an unescaped cstring, and populate item. */ -static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; -static const char *parse_string(cJSON *item,const char *str) -{ - const char *ptr=str+1;char *ptr2;char *out;int32_t len=0;unsigned uc,uc2; - if (*str!='\"') {ep=str;return 0;} /* not a string! */ - - while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; // Skip escaped quotes - - out=(char*)cJSON_malloc(len+2); /* This is how long we need for the string, roughly. */ - if (!out) return 0; - - ptr=str+1;ptr2=out; - while (*ptr!='\"' && *ptr) - { - if (*ptr!='\\') + /* This checks for NaN and Infinity */ + if ((d * 0) != 0) + { + length = sprintf((char*)number_buffer, "null"); + } + else + { + /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ + length = sprintf((char*)number_buffer, "%1.15g", d); + + /* Check whether the original double can be recovered */ + if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || ((double)test != d)) { - if ( *ptr == '%' && is_hexstr((char *)&ptr[1],2) && isprint(_decode_hex((char *)&ptr[1])) != 0 ) - *ptr2++ = _decode_hex((char *)&ptr[1]), ptr += 3; - else *ptr2++ = *ptr++; + /* If not, print with 17 decimal places of precision */ + length = sprintf((char*)number_buffer, "%1.17g", d); } - else - { - ptr++; - switch (*ptr) - { - case 'b': *ptr2++='\b'; break; - case 'f': *ptr2++='\f'; break; - case 'n': *ptr2++='\n'; break; - case 'r': *ptr2++='\r'; break; - case 't': *ptr2++='\t'; break; - case 'u': // transcode utf16 to utf8 - uc=parse_hex4(ptr+1);ptr+=4; // get the unicode char - - if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; // check for invalid - - if (uc>=0xD800 && uc<=0xDBFF) // UTF16 surrogate pairs - { - if (ptr[1]!='\\' || ptr[2]!='u') break; // missing second-half of surrogate. - uc2=parse_hex4(ptr+3);ptr+=6; - if (uc2<0xDC00 || uc2>0xDFFF) break; // invalid second-half of surrogate - uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF)); - } - - len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len; - - switch (len) { - case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; - case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; - case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; - case 1: *--ptr2 =(uc | firstByteMark[len]); - } - ptr2+=len; - break; - default: *ptr2++=*ptr; break; - } - ptr++; - } - } - *ptr2=0; - if (*ptr=='\"') ptr++; - item->valuestring=out; - item->type=cJSON_String; - return ptr; + } + + /* sprintf failed or buffer overrun occured */ + if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) + { + return false; + } + + /* reserve appropriate space in the output */ + output_pointer = ensure(output_buffer, (size_t)length); + if (output_pointer == NULL) + { + return false; + } + + /* copy the printed number to the output and replace locale + * dependent decimal point with '.' */ + for (i = 0; i < ((size_t)length); i++) + { + if (number_buffer[i] == decimal_point) + { + output_pointer[i] = '.'; + continue; + } + + output_pointer[i] = number_buffer[i]; + } + output_pointer[i] = '\0'; + + output_buffer->offset += (size_t)length; + + return true; +} + +/* parse 4 digit hexadecimal number */ +static unsigned parse_hex4(const unsigned char * const input) +{ + unsigned int h = 0; + size_t i = 0; + + for (i = 0; i < 4; i++) + { + /* parse digit */ + if ((input[i] >= '0') && (input[i] <= '9')) + { + h += (unsigned int) input[i] - '0'; + } + else if ((input[i] >= 'A') && (input[i] <= 'F')) + { + h += (unsigned int) 10 + input[i] - 'A'; + } + else if ((input[i] >= 'a') && (input[i] <= 'f')) + { + h += (unsigned int) 10 + input[i] - 'a'; + } + else /* invalid */ + { + return 0; + } + + if (i < 3) + { + /* shift left to make place for the next nibble */ + h = h << 4; + } + } + + return h; +} + +/* converts a UTF-16 literal to UTF-8 + * A literal can be one or two sequences of the form \uXXXX */ +static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer) +{ + long unsigned int codepoint = 0; + unsigned int first_code = 0; + const unsigned char *first_sequence = input_pointer; + unsigned char utf8_length = 0; + unsigned char utf8_position = 0; + unsigned char sequence_length = 0; + unsigned char first_byte_mark = 0; + + if ((input_end - first_sequence) < 6) + { + /* input ends unexpectedly */ + goto fail; + } + + /* get the first utf16 sequence */ + first_code = parse_hex4(first_sequence + 2); + + /* check that the code is valid */ + if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) + { + goto fail; + } + + /* UTF16 surrogate pair */ + if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) + { + const unsigned char *second_sequence = first_sequence + 6; + unsigned int second_code = 0; + sequence_length = 12; /* \uXXXX\uXXXX */ + + if ((input_end - second_sequence) < 6) + { + /* input ends unexpectedly */ + goto fail; + } + + if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) + { + /* missing second half of the surrogate pair */ + goto fail; + } + + /* get the second utf16 sequence */ + second_code = parse_hex4(second_sequence + 2); + /* check that the code is valid */ + if ((second_code < 0xDC00) || (second_code > 0xDFFF)) + { + /* invalid second half of the surrogate pair */ + goto fail; + } + + + /* calculate the unicode codepoint from the surrogate pair */ + codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); + } + else + { + sequence_length = 6; /* \uXXXX */ + codepoint = first_code; + } + + /* encode as UTF-8 + * takes at maximum 4 bytes to encode: + * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + if (codepoint < 0x80) + { + /* normal ascii, encoding 0xxxxxxx */ + utf8_length = 1; + } + else if (codepoint < 0x800) + { + /* two bytes, encoding 110xxxxx 10xxxxxx */ + utf8_length = 2; + first_byte_mark = 0xC0; /* 11000000 */ + } + else if (codepoint < 0x10000) + { + /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ + utf8_length = 3; + first_byte_mark = 0xE0; /* 11100000 */ + } + else if (codepoint <= 0x10FFFF) + { + /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + utf8_length = 4; + first_byte_mark = 0xF0; /* 11110000 */ + } + else + { + /* invalid unicode codepoint */ + goto fail; + } + + /* encode as utf8 */ + for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) + { + /* 10xxxxxx */ + (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); + codepoint >>= 6; + } + /* encode first byte */ + if (utf8_length > 1) + { + (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); + } + else + { + (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); + } + + *output_pointer += utf8_length; + + return sequence_length; + +fail: + return 0; +} + +/* Parse the input text into an unescaped cinput, and populate item. */ +static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer) +{ + const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; + const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; + unsigned char *output_pointer = NULL; + unsigned char *output = NULL; + + /* not a string */ + if (buffer_at_offset(input_buffer)[0] != '\"') + { + goto fail; + } + + { + /* calculate approximate size of the output (overestimate) */ + size_t allocation_length = 0; + size_t skipped_bytes = 0; + while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) + { + /* is escape sequence */ + if (input_end[0] == '\\') + { + if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) + { + /* prevent buffer overflow when last input character is a backslash */ + goto fail; + } + skipped_bytes++; + input_end++; + } + input_end++; + } + if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) + { + goto fail; /* string ended unexpectedly */ + } + + /* This is at most how much we need for the output */ + allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; + output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof("")); + if (output == NULL) + { + goto fail; /* allocation failure */ + } + } + + output_pointer = output; + /* loop through the string literal */ + while (input_pointer < input_end) + { + if (*input_pointer != '\\') + { + *output_pointer++ = *input_pointer++; + } + /* escape sequence */ + else + { + unsigned char sequence_length = 2; + if ((input_end - input_pointer) < 1) + { + goto fail; + } + + switch (input_pointer[1]) + { + case 'b': + *output_pointer++ = '\b'; + break; + case 'f': + *output_pointer++ = '\f'; + break; + case 'n': + *output_pointer++ = '\n'; + break; + case 'r': + *output_pointer++ = '\r'; + break; + case 't': + *output_pointer++ = '\t'; + break; + case '\"': + case '\\': + case '/': + *output_pointer++ = input_pointer[1]; + break; + + /* UTF-16 literal */ + case 'u': + sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); + if (sequence_length == 0) + { + /* failed to convert UTF16-literal to UTF-8 */ + goto fail; + } + break; + + default: + goto fail; + } + input_pointer += sequence_length; + } + } + + /* zero terminate the output */ + *output_pointer = '\0'; + + item->type = cJSON_String; + item->valuestring = (char*)output; + + input_buffer->offset = (size_t) (input_end - input_buffer->content); + input_buffer->offset++; + + return true; + +fail: + if (output != NULL) + { + input_buffer->hooks.deallocate(output); + } + + if (input_pointer != NULL) + { + input_buffer->offset = (size_t)(input_pointer - input_buffer->content); + } + + return false; } /* Render the cstring provided to an escaped version that can be printed. */ -static char *print_string_ptr(const char *str) +static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) { - const char *ptr;char *ptr2,*out;int32_t len=0;unsigned char token; - - if (!str) return cJSON_strdup(""); - ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;} - - out=(char*)cJSON_malloc(len+3+1); - if (!out) return 0; - - ptr2=out;ptr=str; - *ptr2++='\"'; - while (*ptr) - { - if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++; - else - { - *ptr2++='\\'; - switch (token=*ptr++) - { - case '\\': *ptr2++='\\'; break; - case '\"': *ptr2++='\"'; break; - case '\b': *ptr2++='b'; break; - case '\f': *ptr2++='f'; break; - case '\n': *ptr2++='n'; break; - case '\r': *ptr2++='r'; break; - case '\t': *ptr2++='t'; break; - default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */ - } - } - } - *ptr2++='\"';*ptr2++=0; - return out; + const unsigned char *input_pointer = NULL; + unsigned char *output = NULL; + unsigned char *output_pointer = NULL; + size_t output_length = 0; + /* numbers of additional characters needed for escaping */ + size_t escape_characters = 0; + + if (output_buffer == NULL) + { + return false; + } + + /* empty string */ + if (input == NULL) + { + output = ensure(output_buffer, sizeof("\"\"")); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "\"\""); + + return true; + } + + /* set "flag" to 1 if something needs to be escaped */ + for (input_pointer = input; *input_pointer; input_pointer++) + { + switch (*input_pointer) + { + case '\"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + /* one character escape sequence */ + escape_characters++; + break; + default: + if (*input_pointer < 32) + { + /* UTF-16 escape sequence uXXXX */ + escape_characters += 5; + } + break; + } + } + output_length = (size_t)(input_pointer - input) + escape_characters; + + output = ensure(output_buffer, output_length + sizeof("\"\"")); + if (output == NULL) + { + return false; + } + + /* no characters have to be escaped */ + if (escape_characters == 0) + { + output[0] = '\"'; + memcpy(output + 1, input, output_length); + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; + } + + output[0] = '\"'; + output_pointer = output + 1; + /* copy the string */ + for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) + { + if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) + { + /* normal character, copy */ + *output_pointer = *input_pointer; + } + else + { + /* character needs to be escaped */ + *output_pointer++ = '\\'; + switch (*input_pointer) + { + case '\\': + *output_pointer = '\\'; + break; + case '\"': + *output_pointer = '\"'; + break; + case '\b': + *output_pointer = 'b'; + break; + case '\f': + *output_pointer = 'f'; + break; + case '\n': + *output_pointer = 'n'; + break; + case '\r': + *output_pointer = 'r'; + break; + case '\t': + *output_pointer = 't'; + break; + default: + /* escape and print as unicode codepoint */ + sprintf((char*)output_pointer, "u%04x", *input_pointer); + output_pointer += 4; + break; + } + } + } + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; +} + +/* Invoke print_string_ptr (which is useful) on an item. */ +static cJSON_bool print_string(const cJSON * const item, printbuffer * const p) +{ + return print_string_ptr((unsigned char*)item->valuestring, p); } -/* Invote print_string_ptr (which is useful) on an item. */ -static char *print_string(cJSON *item) {return print_string_ptr(item->valuestring);} /* Predeclare these prototypes. */ -static const char *parse_value(cJSON *item,const char *value); -static char *print_value(cJSON *item,int32_t depth,int32_t fmt); -static const char *parse_array(cJSON *item,const char *value); -static char *print_array(cJSON *item,int32_t depth,int32_t fmt); -static const char *parse_object(cJSON *item,const char *value); -static char *print_object(cJSON *item,int32_t depth,int32_t fmt); +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer); +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer); +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer); /* Utility to jump whitespace and cr/lf */ -static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;} +static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL)) + { + return NULL; + } + + while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) + { + buffer->offset++; + } + + if (buffer->offset == buffer->length) + { + buffer->offset--; + } + + return buffer; +} /* Parse an object - create a new root, and populate. */ -cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int32_t require_null_terminated) +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) { - const char *end=0; - cJSON *c=cJSON_New_Item(); - ep=0; - if (!c) return 0; /* memory fail */ - - end=parse_value(c,skip(value)); - if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */ - - /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ - if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}} - if (return_parse_end) *return_parse_end=end; - return c; + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + cJSON *item = NULL; + + /* reset error position */ + global_error.json = NULL; + global_error.position = 0; + + if (value == NULL) + { + goto fail; + } + + buffer.content = (const unsigned char*)value; + buffer.length = strlen((const char*)value) + sizeof(""); + buffer.offset = 0; + buffer.hooks = global_hooks; + + item = cJSON_New_Item(&global_hooks); + if (item == NULL) /* memory fail */ + { + goto fail; + } + + if (!parse_value(item, buffer_skip_whitespace(&buffer))) + { + /* parse failure. ep is set. */ + goto fail; + } + + /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ + if (require_null_terminated) + { + buffer_skip_whitespace(&buffer); + if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') + { + goto fail; + } + } + if (return_parse_end) + { + *return_parse_end = (const char*)buffer_at_offset(&buffer); + } + + return item; + +fail: + if (item != NULL) + { + cJSON_Delete(item); + } + + if (value != NULL) + { + cJSON_error local_error; + local_error.json = (const unsigned char*)value; + local_error.position = 0; + + if (buffer.offset < buffer.length) + { + local_error.position = buffer.offset; + } + else if (buffer.length > 0) + { + local_error.position = buffer.length - 1; + } + + if (return_parse_end != NULL) + { + *return_parse_end = (const char*)local_error.json + local_error.position; + } + + global_error = local_error; + } + + return NULL; } + /* Default options for cJSON_Parse */ -cJSON *cJSON_Parse(const char *value) +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) { - return(cJSON_ParseWithOpts(value,0,0)); + return cJSON_ParseWithOpts(value, 0, 0); +} + +#define cjson_min(a, b) ((a < b) ? a : b) + +static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks) +{ + printbuffer buffer[1]; + unsigned char *printed = NULL; + + memset(buffer, 0, sizeof(buffer)); + + /* create buffer */ + buffer->buffer = (unsigned char*) hooks->allocate(256); + buffer->format = format; + buffer->hooks = *hooks; + if (buffer->buffer == NULL) + { + goto fail; + } + + /* print the value */ + if (!print_value(item, buffer)) + { + goto fail; + } + update_offset(buffer); + + /* check if reallocate is available */ + if (hooks->reallocate != NULL) + { + printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->length); + buffer->buffer = NULL; + if (printed == NULL) { + goto fail; + } + } + else /* otherwise copy the JSON over to a new buffer */ + { + printed = (unsigned char*) hooks->allocate(buffer->offset + 1); + if (printed == NULL) + { + goto fail; + } + memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1)); + printed[buffer->offset] = '\0'; /* just to be sure */ + + /* free the buffer */ + hooks->deallocate(buffer->buffer); + } + + return printed; + +fail: + if (buffer->buffer != NULL) + { + hooks->deallocate(buffer->buffer); + } + + if (printed != NULL) + { + hooks->deallocate(printed); + } + + return NULL; } /* Render a cJSON item/entity/structure to text. */ -char *cJSON_Print(cJSON *item) +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) { - return(print_value(item,0,1)); + return (char*)print(item, true, &global_hooks); +} + +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) +{ + return (char*)print(item, false, &global_hooks); +} + +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if (prebuffer < 0) + { + return NULL; + } + + p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer); + if (!p.buffer) + { + return NULL; + } + + p.length = (size_t)prebuffer; + p.offset = 0; + p.noalloc = false; + p.format = fmt; + p.hooks = global_hooks; + + if (!print_value(item, &p)) + { + global_hooks.deallocate(p.buffer); + return NULL; + } + + return (char*)p.buffer; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cJSON_bool fmt) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if ((len < 0) || (buf == NULL)) + { + return false; + } + + p.buffer = (unsigned char*)buf; + p.length = (size_t)len; + p.offset = 0; + p.noalloc = true; + p.format = fmt; + p.hooks = global_hooks; + + return print_value(item, &p); } -char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0);} /* Parser core - when encountering text, process appropriately. */ -static const char *parse_value(cJSON *item,const char *value) +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer) { - if (!value) return 0; /* Fail on null. */ - if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; } - if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; } - if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; } - if (*value=='\"') { return parse_string(item,value); } - if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); } - if (*value=='[') { return parse_array(item,value); } - if (*value=='{') { return parse_object(item,value); } - - ep=value;return 0; /* failure. */ + if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { + return false; /* no input */ + } + + /* parse the different types of values */ + /* null */ + if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0)) + { + item->type = cJSON_NULL; + input_buffer->offset += 4; + return true; + } + /* false */ + if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0)) + { + item->type = cJSON_False; + input_buffer->offset += 5; + return true; + } + /* true */ + if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0)) + { + item->type = cJSON_True; + item->valueint = 1; + input_buffer->offset += 4; + return true; + } + /* string */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) + { + return parse_string(item, input_buffer); + } + /* number */ + if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) + { + return parse_number(item, input_buffer); + } + /* array */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) + { + return parse_array(item, input_buffer); + } + /* object */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) + { + return parse_object(item, input_buffer); + } + + + return false; } /* Render a value to text. */ -static char *print_value(cJSON *item,int32_t depth,int32_t fmt) +static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer) { - char *out=0; - if (!item) return 0; - switch ((item->type)&255) - { - case cJSON_NULL: out=cJSON_strdup("null"); break; - case cJSON_False: out=cJSON_strdup("false");break; - case cJSON_True: out=cJSON_strdup("true"); break; - case cJSON_Number: out=print_number(item);break; - case cJSON_String: out=print_string(item);break; - case cJSON_Array: out=print_array(item,depth,fmt);break; - case cJSON_Object: out=print_object(item,depth,fmt);break; - } - return out; + unsigned char *output = NULL; + + if ((item == NULL) || (output_buffer == NULL)) + { + return false; + } + + switch ((item->type) & 0xFF) + { + case cJSON_NULL: + output = ensure(output_buffer, 5); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "null"); + return true; + + case cJSON_False: + output = ensure(output_buffer, 6); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "false"); + return true; + + case cJSON_True: + output = ensure(output_buffer, 5); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "true"); + return true; + + case cJSON_Number: + return print_number(item, output_buffer); + + case cJSON_Raw: + { + size_t raw_length = 0; + if (item->valuestring == NULL) + { + if (!output_buffer->noalloc) + { + output_buffer->hooks.deallocate(output_buffer->buffer); + } + return false; + } + + raw_length = strlen(item->valuestring) + sizeof(""); + output = ensure(output_buffer, raw_length); + if (output == NULL) + { + return false; + } + memcpy(output, item->valuestring, raw_length); + return true; + } + + case cJSON_String: + return print_string(item, output_buffer); + + case cJSON_Array: + return print_array(item, output_buffer); + + case cJSON_Object: + return print_object(item, output_buffer); + + default: + return false; + } } /* Build an array from input text. */ -static const char *parse_array(cJSON *item,const char *value) +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer) { - cJSON *child; - if (*value!='[') {ep=value;return 0;} /* not an array! */ - - item->type=cJSON_Array; - value=skip(value+1); - if (*value==']') return value+1; /* empty array. */ - - item->child=child=cJSON_New_Item(); - if (!item->child) return 0; /* memory fail */ - value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */ - if (!value) return 0; - - while (*value==',') - { - cJSON *new_item; - if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ - child->next=new_item;new_item->prev=child;child=new_item; - value=skip(parse_value(child,skip(value+1))); - if (!value) return 0; /* memory fail */ - } - - if (*value==']') return value+1; /* end of array */ - ep=value;return 0; /* malformed. */ + cJSON *head = NULL; /* head of the linked list */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= CJSON_NESTING_LIMIT) + { + return false; /* to deeply nested */ + } + input_buffer->depth++; + + if (buffer_at_offset(input_buffer)[0] != '[') + { + /* not an array */ + goto fail; + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) + { + /* empty array */ + goto success; + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) + { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do + { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) + { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) + { + /* start the linked list */ + current_item = head = new_item; + } + else + { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse next value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) + { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } + while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') + { + goto fail; /* expected end of array */ + } + +success: + input_buffer->depth--; + + item->type = cJSON_Array; + item->child = head; + + input_buffer->offset++; + + return true; + +fail: + if (head != NULL) + { + cJSON_Delete(head); + } + + return false; } /* Render an array to text */ -static char *print_array(cJSON *item,int32_t depth,int32_t fmt) +static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer) { - char **entries; - char *out=0,*ptr,*ret;int32_t len=5; - cJSON *child=item->child; - int32_t numentries=0,i=0,fail=0; - - /* How many entries in the array? */ - while (child) numentries++,child=child->next; - /* Explicitly handle numentries==0 */ - if (!numentries) - { - out=(char*)cJSON_malloc(3+1); - if (out) strcpy(out,"[]"); - return out; - } - /* Allocate an array to hold the values for each */ - entries=(char**)cJSON_malloc((1+numentries)*sizeof(char*)); - if (!entries) return 0; - memset(entries,0,numentries*sizeof(char*)); - /* Retrieve all the results: */ - child=item->child; - while (child && !fail) - { - ret=print_value(child,depth+1,fmt); - entries[i++]=ret; - if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1; - child=child->next; - } - - /* If we didn't fail, try to malloc the output string */ - if (!fail) out=(char*)cJSON_malloc(len+1); - /* If that fails, we fail. */ - if (!out) fail=1; - - /* Handle failure. */ - if (fail) - { - for (i=0;ichild; + + if (output_buffer == NULL) + { + return false; + } + + /* Compose the output array. */ + /* opening square bracket */ + output_pointer = ensure(output_buffer, 1); + if (output_pointer == NULL) + { + return false; + } + + *output_pointer = '['; + output_buffer->offset++; + output_buffer->depth++; + + while (current_element != NULL) + { + if (!print_value(current_element, output_buffer)) + { + return false; + } + update_offset(output_buffer); + if (current_element->next) + { + length = (size_t) (output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ','; + if(output_buffer->format) + { + *output_pointer++ = ' '; + } + *output_pointer = '\0'; + output_buffer->offset += length; + } + current_element = current_element->next; + } + + output_pointer = ensure(output_buffer, 2); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ']'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; } /* Build an object from the text. */ -static const char *parse_object(cJSON *item,const char *value) +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer) { - cJSON *child; - if (*value!='{') {ep=value;return 0;} /* not an object! */ - - item->type=cJSON_Object; - value=skip(value+1); - if (*value=='}') return value+1; /* empty array. */ - - item->child=child=cJSON_New_Item(); - if (!item->child) return 0; - value=skip(parse_string(child,skip(value))); - if (!value) return 0; - child->string=child->valuestring;child->valuestring=0; - if (*value!=':') {ep=value;return 0;} /* fail! */ - value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ - if (!value) return 0; - - while (*value==',') - { - cJSON *new_item; - if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ - child->next=new_item;new_item->prev=child;child=new_item; - value=skip(parse_string(child,skip(value+1))); - if (!value) return 0; - child->string=child->valuestring;child->valuestring=0; - if (*value!=':') {ep=value;return 0;} /* fail! */ - value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ - if (!value) return 0; - } - - if (*value=='}') return value+1; /* end of array */ - ep=value;return 0; /* malformed. */ + cJSON *head = NULL; /* linked list head */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= CJSON_NESTING_LIMIT) + { + return false; /* to deeply nested */ + } + input_buffer->depth++; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) + { + goto fail; /* not an object */ + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) + { + goto success; /* empty object */ + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) + { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do + { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) + { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) + { + /* start the linked list */ + current_item = head = new_item; + } + else + { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse the name of the child */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_string(current_item, input_buffer)) + { + goto fail; /* faile to parse name */ + } + buffer_skip_whitespace(input_buffer); + + /* swap valuestring and string, because we parsed the name */ + current_item->string = current_item->valuestring; + current_item->valuestring = NULL; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) + { + goto fail; /* invalid object */ + } + + /* parse the value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) + { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } + while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) + { + goto fail; /* expected end of object */ + } + +success: + input_buffer->depth--; + + item->type = cJSON_Object; + item->child = head; + + input_buffer->offset++; + return true; + +fail: + if (head != NULL) + { + cJSON_Delete(head); + } + + return false; } /* Render an object to text. */ -static char *print_object(cJSON *item,int32_t depth,int32_t fmt) +static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer) { - char **entries=0,**names=0; - char *out=0,*ptr,*ret,*str;int32_t len=7,i=0,j; - cJSON *child=item->child,*firstchild; - int32_t numentries=0,fail=0; - // Count the number of entries - firstchild = child; - while ( child ) + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_item = item->child; + + if (output_buffer == NULL) { - numentries++; - child = child->next; - if ( child == firstchild ) + return false; + } + + /* Compose the output: */ + length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */ + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + + *output_pointer++ = '{'; + output_buffer->depth++; + if (output_buffer->format) + { + *output_pointer++ = '\n'; + } + output_buffer->offset += length; + + while (current_item) + { + if (output_buffer->format) { - printf("cJSON infinite loop detected\n"); - break; + size_t i; + output_pointer = ensure(output_buffer, output_buffer->depth); + if (output_pointer == NULL) + { + return false; + } + for (i = 0; i < output_buffer->depth; i++) + { + *output_pointer++ = '\t'; + } + output_buffer->offset += output_buffer->depth; + } + + /* print key */ + if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) + { + return false; + } + update_offset(output_buffer); + + length = (size_t) (output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ':'; + if (output_buffer->format) + { + *output_pointer++ = '\t'; + } + output_buffer->offset += length; + + /* print value */ + if (!print_value(current_item, output_buffer)) + { + return false; + } + update_offset(output_buffer); + + /* print comma if not last */ + length = (size_t) ((output_buffer->format ? 1 : 0) + (current_item->next ? 1 : 0)); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + if (current_item->next) + { + *output_pointer++ = ','; + } + + if (output_buffer->format) + { + *output_pointer++ = '\n'; + } + *output_pointer = '\0'; + output_buffer->offset += length; + + current_item = current_item->next; + } + + output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); + if (output_pointer == NULL) + { + return false; + } + if (output_buffer->format) + { + size_t i; + for (i = 0; i < (output_buffer->depth - 1); i++) + { + *output_pointer++ = '\t'; } } - /* Explicitly handle empty object case */ - if (!numentries) - { - out=(char*)cJSON_malloc(fmt?depth+4+1:3+1); - if (!out) return 0; - ptr=out;*ptr++='{'; - if (fmt) {*ptr++='\n';for (i=0;ichild;depth++;if (fmt) len+=depth; - while ( child ) - { - names[i]=str=print_string_ptr(child->string); - entries[i++]=ret=print_value(child,depth,fmt); - if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1; - child=child->next; - if ( child == firstchild ) - break; - } - - /* Try to allocate the output string */ - if (!fail) out=(char*)cJSON_malloc(len+1); - if (!out) fail=1; - - /* Handle failure */ - if (fail) - { - for (i=0;idepth--; + + return true; } /* Get Array size/item / object item. */ -int32_t cJSON_GetArraySize(cJSON *array) {cJSON *c; if ( array == 0 ) return(0); c=array->child;int32_t i=0;while(c)i++,c=c->next;return i;} -cJSON *cJSON_GetArrayItem(cJSON *array,int32_t item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;} -cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;} +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) +{ + cJSON *child = NULL; + size_t size = 0; + + if (array == NULL) + { + return 0; + } + + child = array->child; + + while(child != NULL) + { + size++; + child = child->next; + } + + /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ + + return (int)size; +} + +static cJSON* get_array_item(const cJSON *array, size_t index) +{ + cJSON *current_child = NULL; + + if (array == NULL) + { + return NULL; + } + + current_child = array->child; + while ((current_child != NULL) && (index > 0)) + { + index--; + current_child = current_child->next; + } + + return current_child; +} + +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) +{ + if (index < 0) + { + return NULL; + } + + return get_array_item(array, (size_t)index); +} + +static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive) +{ + cJSON *current_element = NULL; + + if ((object == NULL) || (name == NULL)) + { + return NULL; + } + + current_element = object->child; + if (case_sensitive) + { + while ((current_element != NULL) && (strcmp(name, current_element->string) != 0)) + { + current_element = current_element->next; + } + } + else + { + while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) + { + current_element = current_element->next; + } + } + + return current_element; +} + +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) +{ + return get_object_item(object, string, false); +} + +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) +{ + return get_object_item(object, string, true); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) +{ + return cJSON_GetObjectItem(object, string) ? 1 : 0; +} /* Utility for array list handling. */ -static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} +static void suffix_object(cJSON *prev, cJSON *item) +{ + prev->next = item; + item->prev = prev; +} + /* Utility for handling references. */ -static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;} +static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks) +{ + cJSON *reference = NULL; + if (item == NULL) + { + return NULL; + } + + reference = cJSON_New_Item(hooks); + if (reference == NULL) + { + return NULL; + } + + memcpy(reference, item, sizeof(cJSON)); + reference->string = NULL; + reference->type |= cJSON_IsReference; + reference->next = reference->prev = NULL; + return reference; +} /* Add item to array/object. */ -void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}} -void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);} -void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));} -void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));} +CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item) +{ + cJSON *child = NULL; -cJSON *cJSON_DetachItemFromArray(cJSON *array,int32_t which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0; - if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;} -void cJSON_DeleteItemFromArray(cJSON *array,int32_t which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));} -cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int32_t i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;} -void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} + if ((item == NULL) || (array == NULL)) + { + return; + } + + child = array->child; + + if (child == NULL) + { + /* list is empty, start new one */ + array->child = item; + } + else + { + /* append to the end */ + while (child->next) + { + child = child->next; + } + suffix_object(child, item); + } +} + +CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) +{ + if (item == NULL) + { + return; + } + + /* call cJSON_AddItemToObjectCS for code reuse */ + cJSON_AddItemToObjectCS(object, (char*)cJSON_strdup((const unsigned char*)string, &global_hooks), item); + /* remove cJSON_StringIsConst flag */ + item->type &= ~cJSON_StringIsConst; +} + +#if defined (__clang__) || ((__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic push +#endif +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif + +/* Add an item to an object with constant string as key */ +CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) +{ + if ((item == NULL) || (string == NULL)) + { + return; + } + if (!(item->type & cJSON_StringIsConst) && item->string) + { + global_hooks.deallocate(item->string); + } + item->string = (char*)string; + item->type |= cJSON_StringIsConst; + cJSON_AddItemToArray(object, item); +} +#if defined (__clang__) || ((__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic pop +#endif + +CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) +{ + if (array == NULL) + { + return; + } + + cJSON_AddItemToArray(array, create_reference(item, &global_hooks)); +} + +CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) +{ + if ((object == NULL) || (string == NULL)) + { + return; + } + + cJSON_AddItemToObject(object, string, create_reference(item, &global_hooks)); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) +{ + if ((parent == NULL) || (item == NULL)) + { + return NULL; + } + + if (item->prev != NULL) + { + /* not the first element */ + item->prev->next = item->next; + } + if (item->next != NULL) + { + /* not the last element */ + item->next->prev = item->prev; + } + + if (item == parent->child) + { + /* first element */ + parent->child = item->next; + } + /* make sure the detached item doesn't point anywhere anymore */ + item->prev = NULL; + item->next = NULL; + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) +{ + if (which < 0) + { + return NULL; + } + + return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which)); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) +{ + cJSON_Delete(cJSON_DetachItemFromArray(array, which)); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItem(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObject(object, string)); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string)); +} /* Replace array/object items with new ones. */ -void cJSON_ReplaceItemInArray(cJSON *array,int32_t which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; - newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem; - if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);} -void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int32_t i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}} +CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) +{ + cJSON *after_inserted = NULL; + + if (which < 0) + { + return; + } + + after_inserted = get_array_item(array, (size_t)which); + if (after_inserted == NULL) + { + cJSON_AddItemToArray(array, newitem); + return; + } + + newitem->next = after_inserted; + newitem->prev = after_inserted->prev; + after_inserted->prev = newitem; + if (after_inserted == array->child) + { + array->child = newitem; + } + else + { + newitem->prev->next = newitem; + } +} + +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) +{ + if ((parent == NULL) || (replacement == NULL) || (item == NULL)) + { + return false; + } + + if (replacement == item) + { + return true; + } + + replacement->next = item->next; + replacement->prev = item->prev; + + if (replacement->next != NULL) + { + replacement->next->prev = replacement; + } + if (replacement->prev != NULL) + { + replacement->prev->next = replacement; + } + if (parent->child == item) + { + parent->child = replacement; + } + + item->next = NULL; + item->prev = NULL; + cJSON_Delete(item); + + return true; +} + +CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) +{ + if (which < 0) + { + return; + } + + cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); +} + +static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive) +{ + if ((replacement == NULL) || (string == NULL)) + { + return false; + } + + /* replace the name in the replacement */ + if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL)) + { + cJSON_free(replacement->string); + } + replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + replacement->type &= ~cJSON_StringIsConst; + + cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); + + return true; +} + +CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) +{ + replace_item_in_object(object, string, newitem, false); +} + +CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) +{ + replace_item_in_object(object, string, newitem, true); +} /* Create basic types: */ -cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;} -cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;} -cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;} -cJSON *cJSON_CreateBool(int32_t b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;} -cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int64_t)num;}return item;} -cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;} -cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;} -cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_NULL; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_True; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_False; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool b) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = b ? cJSON_True : cJSON_False; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_Number; + item->valuedouble = num; + + /* use saturation in case of overflow */ + if (num >= INT_MAX) + { + item->valueint = INT_MAX; + } + else if (num <= INT_MIN) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = (int)num; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_String; + item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + if(!item->valuestring) + { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_Raw; + item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); + if(!item->valuestring) + { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type=cJSON_Array; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) + { + item->type = cJSON_Object; + } + + return item; +} /* Create Arrays: */ -cJSON *cJSON_CreateIntArray(int64_t *numbers,int32_t count) {int32_t i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} -cJSON *cJSON_CreateFloatArray(float *numbers,int32_t count) {int32_t i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} -cJSON *cJSON_CreateDoubleArray(double *numbers,int32_t count) {int32_t i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} -cJSON *cJSON_CreateStringArray(char **strings,int32_t count) {int32_t i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber(numbers[i]); + if (!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber((double)numbers[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0;a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber(numbers[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (strings == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for (i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateString(strings[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p,n); + } + p = n; + } + + return a; +} /* Duplication */ -cJSON *cJSON_Duplicate(cJSON *item,int32_t recurse) +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) { - cJSON *newitem,*cptr,*nptr=0,*newchild; - /* Bail on bad ptr */ - if (!item) return 0; - /* Create new item */ - newitem=cJSON_New_Item(); - if (!newitem) return 0; - /* Copy over all vars */ - newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble; - if (item->valuestring) {newitem->valuestring=cJSON_strdup(item->valuestring); if (!newitem->valuestring) {cJSON_Delete(newitem);return 0;}} - if (item->string) {newitem->string=cJSON_strdup(item->string); if (!newitem->string) {cJSON_Delete(newitem);return 0;}} - /* If non-recursive, then we're done! */ - if (!recurse) return newitem; - /* Walk the ->next chain for the child. */ - cptr=item->child; - while (cptr) - { - newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */ - if (!newchild) {cJSON_Delete(newitem);return 0;} - if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */ - else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */ - cptr=cptr->next; - } - return newitem; -} + cJSON *newitem = NULL; + cJSON *child = NULL; + cJSON *next = NULL; + cJSON *newchild = NULL; -void cJSON_Minify(char *json) -{ - char *into=json; - while (*json) - { - if (*json==' ') json++; - else if (*json=='\t') json++; // Whitespace characters. - else if (*json=='\r') json++; - else if (*json=='\n') json++; - else if (*json=='/' && json[1]=='/') while (*json && *json!='\n') json++; // double-slash comments, to end of line. - else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;} // multiline comments. - else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} // string literals, which are \" sensitive. - else *into++=*json++; // All other characters. - } - *into=0; // and null-terminate. -} - -// the following written by jl777 -/****************************************************************************** - * Copyright © 2014-2017 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. * - * * - ******************************************************************************/ - -void copy_cJSON(struct destbuf *dest,cJSON *obj) -{ - char *str; - int i; - long offset; - dest->buf[0] = 0; - if ( obj != 0 ) + /* Bail on bad ptr */ + if (!item) { - str = cJSON_Print(obj); - if ( str != 0 ) + goto fail; + } + /* Create new item */ + newitem = cJSON_New_Item(&global_hooks); + if (!newitem) + { + goto fail; + } + /* Copy over all vars */ + newitem->type = item->type & (~cJSON_IsReference); + newitem->valueint = item->valueint; + newitem->valuedouble = item->valuedouble; + if (item->valuestring) + { + newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); + if (!newitem->valuestring) { - offset = stripquotes(str); - //strcpy(dest,str+offset); - for (i=0; ibuf[i]= str[offset+i]) == 0 ) - break; - dest->buf[i] = 0; - free(str); + goto fail; } } -} - -void copy_cJSON2(char *dest,int32_t maxlen,cJSON *obj) -{ - struct destbuf tmp; - maxlen--; - dest[0] = 0; - if ( maxlen > sizeof(tmp.buf) ) - maxlen = sizeof(tmp.buf); - copy_cJSON(&tmp,obj); - if ( strlen(tmp.buf) < maxlen ) - strcpy(dest,tmp.buf); - else dest[0] = 0; -} - -int64_t _get_cJSON_int(cJSON *json) -{ - struct destbuf tmp; - if ( json != 0 ) + if (item->string) { - copy_cJSON(&tmp,json); - if ( tmp.buf[0] != 0 ) - return(calc_nxt64bits(tmp.buf)); - } - return(0); -} - -int64_t get_cJSON_int(cJSON *json,char *field) -{ - cJSON *numjson; - if ( json != 0 ) - { - numjson = cJSON_GetObjectItem(json,field); - if ( numjson != 0 ) - return(_get_cJSON_int(numjson)); - } - return(0); -} - -int64_t conv_floatstr(char *numstr) -{ - double val,corr; - val = atof(numstr); - corr = (val < 0.) ? -0.50000000001 : 0.50000000001; - return((int64_t)(val * SATOSHIDEN + corr)); -} - -int64_t _conv_cJSON_float(cJSON *json) -{ - int64_t conv_floatstr(char *); - struct destbuf tmp; - if ( json != 0 ) - { - copy_cJSON(&tmp,json); - return(conv_floatstr(tmp.buf)); - } - return(0); -} - -int64_t conv_cJSON_float(cJSON *json,char *field) -{ - if ( json != 0 ) - return(_conv_cJSON_float(cJSON_GetObjectItem(json,field))); - return(0); -} - -int32_t extract_cJSON_str(char *dest,int32_t max,cJSON *json,char *field) -{ - int32_t safecopy(char *dest,char *src,long len); - char *str; - cJSON *obj; - int32_t len; - long offset; - dest[0] = 0; - obj = cJSON_GetObjectItem(json,field); - if ( obj != 0 ) - { - str = cJSON_Print(obj); - offset = stripquotes(str); - len = safecopy(dest,str+offset,max); - free(str); - return(len); - } - return(0); -} - -cJSON *gen_list_json(char **list) -{ - cJSON *array,*item; - array = cJSON_CreateArray(); - while ( list != 0 && *list != 0 && *list[0] != 0 ) - { - item = cJSON_CreateString(*list++); - cJSON_AddItemToArray(array,item); - } - return(array); -} - -uint64_t get_API_nxt64bits(cJSON *obj) -{ - uint64_t nxt64bits = 0; - struct destbuf tmp; - if ( obj != 0 ) - { - if ( is_cJSON_Number(obj) != 0 ) - return((uint64_t)obj->valuedouble); - copy_cJSON(&tmp,obj); - nxt64bits = calc_nxt64bits(tmp.buf); - } - return(nxt64bits); -} -uint64_t j64bits(cJSON *json,char *field) { if ( field == 0 ) return(get_API_nxt64bits(json)); return(get_API_nxt64bits(cJSON_GetObjectItem(json,field))); } -uint64_t j64bitsi(cJSON *json,int32_t i) { return(get_API_nxt64bits(cJSON_GetArrayItem(json,i))); } - -uint64_t get_satoshi_obj(cJSON *json,char *field) -{ - int32_t i,n; - uint64_t prev,satoshis,mult = 1; - struct destbuf numstr,checkstr; - cJSON *numjson; - numjson = cJSON_GetObjectItem(json,field); - copy_cJSON(&numstr,numjson); - satoshis = prev = 0; mult = 1; n = (int32_t)strlen(numstr.buf); - for (i=n-1; i>=0; i--,mult*=10) - { - satoshis += (mult * (numstr.buf[i] - '0')); - if ( satoshis < prev ) - printf("get_satoshi_obj numstr.(%s) i.%d prev.%llu vs satoshis.%llu\n",numstr.buf,i,(unsigned long long)prev,(unsigned long long)satoshis); - prev = satoshis; - } - sprintf(checkstr.buf,"%llu",(long long)satoshis); - if ( strcmp(checkstr.buf,numstr.buf) != 0 ) - { - printf("SATOSHI GREMLIN?? numstr.(%s) -> %.8f -> (%s)\n",numstr.buf,dstr(satoshis),checkstr.buf); - } - return(satoshis); -} - -void add_satoshis_json(cJSON *json,char *field,uint64_t satoshis) -{ - cJSON *obj; - char numstr[64]; - sprintf(numstr,"%lld",(long long)satoshis); - obj = cJSON_CreateString(numstr); - cJSON_AddItemToObject(json,field,obj); - if ( satoshis != get_satoshi_obj(json,field) ) - printf("error adding satoshi obj %ld -> %ld\n",(unsigned long)satoshis,(unsigned long)get_satoshi_obj(json,field)); -} - -char *cJSON_str(cJSON *json) -{ - if ( json != 0 && is_cJSON_String(json) != 0 ) - return(json->valuestring); - return(0); -} - -void jadd(cJSON *json,char *field,cJSON *item) { if ( json != 0 )cJSON_AddItemToObject(json,field,item); } -void jaddstr(cJSON *json,char *field,char *str) { if ( json != 0 && str != 0 ) cJSON_AddItemToObject(json,field,cJSON_CreateString(str)); } -void jaddnum(cJSON *json,char *field,double num) { if ( json != 0 )cJSON_AddItemToObject(json,field,cJSON_CreateNumber(num)); } -void jadd64bits(cJSON *json,char *field,uint64_t nxt64bits) { char numstr[64]; sprintf(numstr,"%llu",(long long)nxt64bits), jaddstr(json,field,numstr); } -void jaddi(cJSON *json,cJSON *item) { if ( json != 0 ) cJSON_AddItemToArray(json,item); } -void jaddistr(cJSON *json,char *str) { if ( json != 0 ) cJSON_AddItemToArray(json,cJSON_CreateString(str)); } -void jaddinum(cJSON *json,double num) { if ( json != 0 ) cJSON_AddItemToArray(json,cJSON_CreateNumber(num)); } -void jaddi64bits(cJSON *json,uint64_t nxt64bits) { char numstr[64]; sprintf(numstr,"%llu",(long long)nxt64bits), jaddistr(json,numstr); } -char *jstr(cJSON *json,char *field) { if ( json == 0 ) return(0); if ( field == 0 ) return(cJSON_str(json)); return(cJSON_str(cJSON_GetObjectItem(json,field))); } - -char *jstri(cJSON *json,int32_t i) { return(cJSON_str(cJSON_GetArrayItem(json,i))); } -char *jprint(cJSON *json,int32_t freeflag) -{ - char *str; - /*static portable_mutex_t mutex; static int32_t initflag; - if ( initflag == 0 ) - { - portable_mutex_init(&mutex); - initflag = 1; - }*/ - if ( json == 0 ) - return(clonestr((char *)"{}")); - //portable_mutex_lock(&mutex); - //usleep(5000); - str = cJSON_Print(json), _stripwhite(str,' '); - if ( freeflag != 0 ) - free_json(json); - //portable_mutex_unlock(&mutex); - return(str); -} - -bits256 get_API_bits256(cJSON *obj) -{ - bits256 hash; char *str; - memset(hash.bytes,0,sizeof(hash)); - if ( obj != 0 ) - { - if ( is_cJSON_String(obj) != 0 && (str= obj->valuestring) != 0 && strlen(str) == 64 ) - decode_hex(hash.bytes,sizeof(hash),str); - } - return(hash); -} -bits256 jbits256(cJSON *json,char *field) { if ( field == 0 ) return(get_API_bits256(json)); return(get_API_bits256(cJSON_GetObjectItem(json,field))); } -bits256 jbits256i(cJSON *json,int32_t i) { return(get_API_bits256(cJSON_GetArrayItem(json,i))); } -void jaddbits256(cJSON *json,char *field,bits256 hash) { char str[65]; bits256_str(str,hash), jaddstr(json,field,str); } -void jaddibits256(cJSON *json,bits256 hash) { char str[65]; bits256_str(str,hash), jaddistr(json,str); } - -char *get_cJSON_fieldname(cJSON *obj) -{ - if ( obj != 0 ) - { - if ( obj->child != 0 && obj->child->string != 0 ) - return(obj->child->string); - else if ( obj->string != 0 ) - return(obj->string); - } - return((char *)""); -} - -int32_t jnum(cJSON *obj,char *field) -{ - char *str; int32_t polarity = 1; - if ( field != 0 ) - obj = jobj(obj,field); - if ( obj != 0 ) - { - if ( is_cJSON_Number(obj) != 0 ) - return(obj->valuedouble); - else if ( is_cJSON_String(obj) != 0 && (str= jstr(obj,0)) != 0 ) + newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); + if (!newitem->string) { - if ( str[0] == '-' ) - polarity = -1, str++; - return(polarity * (int32_t)calc_nxt64bits(str)); + goto fail; } } - return(0); -} - -void ensure_jsonitem(cJSON *json,char *field,char *value) -{ - cJSON *obj = cJSON_GetObjectItem(json,field); - if ( obj == 0 ) - cJSON_AddItemToObject(json,field,cJSON_CreateString(value)); - else cJSON_ReplaceItemInObject(json,field,cJSON_CreateString(value)); -} - -int32_t in_jsonarray(cJSON *array,char *value) -{ - int32_t i,n; - struct destbuf remote; - if ( array != 0 && is_cJSON_Array(array) != 0 ) + /* If non-recursive, then we're done! */ + if (!recurse) { - n = cJSON_GetArraySize(array); - for (i=0; inext chain for the child. */ + child = item->child; + while (child != NULL) + { + newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ + if (!newchild) { - if ( array == 0 || n == 0 ) - break; - copy_cJSON(&remote,cJSON_GetArrayItem(array,i)); - if ( strcmp(remote.buf,value) == 0 ) - return(1); + goto fail; } - } - return(0); -} - -int32_t myatoi(char *str,int32_t range) -{ - long x; char *ptr; - x = strtol(str,&ptr,10); - if ( range != 0 && x >= range ) - x = (range - 1); - return((int32_t)x); -} - -int32_t get_API_int(cJSON *obj,int32_t val) -{ - struct destbuf buf; - if ( obj != 0 ) - { - if ( is_cJSON_Number(obj) != 0 ) - return((int32_t)obj->valuedouble); - copy_cJSON(&buf,obj); - val = myatoi(buf.buf,0); - if ( val < 0 ) - val = 0; - } - return(val); -} -int32_t jint(cJSON *json,char *field) { if ( json == 0 ) return(0); if ( field == 0 ) return(get_API_int(json,0)); return(get_API_int(cJSON_GetObjectItem(json,field),0)); } -int32_t jinti(cJSON *json,int32_t i) { if ( json == 0 ) return(0); return(get_API_int(cJSON_GetArrayItem(json,i),0)); } - -uint32_t get_API_uint(cJSON *obj,uint32_t val) -{ - struct destbuf buf; - if ( obj != 0 ) - { - if ( is_cJSON_Number(obj) != 0 ) - return((uint32_t)obj->valuedouble); - copy_cJSON(&buf,obj); - val = myatoi(buf.buf,0); - } - return(val); -} -uint32_t juint(cJSON *json,char *field) { if ( json == 0 ) return(0); if ( field == 0 ) return(get_API_uint(json,0)); return(get_API_uint(cJSON_GetObjectItem(json,field),0)); } -uint32_t juinti(cJSON *json,int32_t i) { if ( json == 0 ) return(0); return(get_API_uint(cJSON_GetArrayItem(json,i),0)); } - -double get_API_float(cJSON *obj) -{ - double val = 0.; - struct destbuf buf; - if ( obj != 0 ) - { - if ( is_cJSON_Number(obj) != 0 ) - return(obj->valuedouble); - copy_cJSON(&buf,obj); - val = atof(buf.buf); - } - return(val); -} - -double jdouble(cJSON *json,char *field) -{ - if ( json != 0 ) - { - if ( field == 0 ) - return(get_API_float(json)); - else return(get_API_float(cJSON_GetObjectItem(json,field))); - } else return(0.); -} - -double jdoublei(cJSON *json,int32_t i) -{ - if ( json != 0 ) - return(get_API_float(cJSON_GetArrayItem(json,i))); - else return(0.); -} - -cJSON *jobj(cJSON *json,char *field) { if ( json != 0 ) return(cJSON_GetObjectItem(json,field)); return(0); } - -void jdelete(cJSON *json,char *field) -{ - if ( jobj(json,field) != 0 ) - cJSON_DeleteItemFromObject(json,field); -} - -cJSON *jduplicate(cJSON *json) { return(cJSON_Duplicate(json,1)); } - -cJSON *jitem(cJSON *array,int32_t i) { if ( array != 0 && is_cJSON_Array(array) != 0 && cJSON_GetArraySize(array) > i ) return(cJSON_GetArrayItem(array,i)); return(0); } -cJSON *jarray(int32_t *nump,cJSON *json,char *field) -{ - cJSON *array; - if ( json != 0 ) - { - if ( field == 0 ) - array = json; - else array = cJSON_GetObjectItem(json,field); - if ( array != 0 && is_cJSON_Array(array) != 0 && (*nump= cJSON_GetArraySize(array)) > 0 ) - return(array); - } - *nump = 0; - return(0); -} - -int32_t expand_nxt64bits(char *NXTaddr,uint64_t nxt64bits) -{ - int32_t i,n; - uint64_t modval; - char rev[64]; - for (i=0; nxt64bits!=0; i++) - { - modval = nxt64bits % 10; - rev[i] = (char)(modval + '0'); - nxt64bits /= 10; - } - n = i; - for (i=0; i= 22 ) - { - printf("calc_nxt64bits: illegal NXTaddr.(%s) too long\n",NXTaddr); - return(0); - } - else if ( strcmp(NXTaddr,"0") == 0 || strcmp(NXTaddr,"false") == 0 ) - { - // printf("zero address?\n"); getchar(); - return(0); - } - if ( NXTaddr[0] == '-' ) - polarity = -1, NXTaddr++, n--; - mult = 1; - lastval = 0; - for (i=n-1; i>=0; i--,mult*=10) - { - c = NXTaddr[i]; - if ( c < '0' || c > '9' ) + if (next != NULL) { - printf("calc_nxt64bits: illegal char.(%c %d) in (%s).%d\n",c,c,NXTaddr,(int32_t)i); -#ifdef __APPLE__ - //while ( 1 ) + /* If newitem->child already set, then crosswire ->prev and ->next and move on */ + next->next = newchild; + newchild->prev = next; + next = newchild; + } + else + { + /* Set newitem->child and move to it */ + newitem->child = newchild; + next = newchild; + } + child = child->next; + } + + return newitem; + +fail: + if (newitem != NULL) + { + cJSON_Delete(newitem); + } + + return NULL; +} + +CJSON_PUBLIC(void) cJSON_Minify(char *json) +{ + unsigned char *into = (unsigned char*)json; + + if (json == NULL) + { + return; + } + + while (*json) + { + if (*json == ' ') + { + json++; + } + else if (*json == '\t') + { + /* Whitespace characters. */ + json++; + } + else if (*json == '\r') + { + json++; + } + else if (*json=='\n') + { + json++; + } + else if ((*json == '/') && (json[1] == '/')) + { + /* double-slash comments, to end of line. */ + while (*json && (*json != '\n')) { - //sleep(60); - printf("calc_nxt64bits: illegal char.(%c %d) in (%s).%d\n",c,c,NXTaddr,(int32_t)i); + json++; } -#endif - return(0); } - nxt64bits += mult * (c - '0'); - if ( nxt64bits < lastval ) - printf("calc_nxt64bits: warning: 64bit overflow %llx < %llx\n",(long long)nxt64bits,(long long)lastval); - lastval = nxt64bits; + else if ((*json == '/') && (json[1] == '*')) + { + /* multiline comments. */ + while (*json && !((*json == '*') && (json[1] == '/'))) + { + json++; + } + json += 2; + } + else if (*json == '\"') + { + /* string literals, which are \" sensitive. */ + *into++ = (unsigned char)*json++; + while (*json && (*json != '\"')) + { + if (*json == '\\') + { + *into++ = (unsigned char)*json++; + } + *into++ = (unsigned char)*json++; + } + *into++ = (unsigned char)*json++; + } + else + { + /* All other characters. */ + *into++ = (unsigned char)*json++; + } } - while ( *NXTaddr == '0' && *NXTaddr != 0 ) - NXTaddr++; - if ( cmp_nxt64bits(NXTaddr,nxt64bits) != 0 ) - printf("error calculating nxt64bits: %s -> %llx -> %s\n",NXTaddr,(long long)nxt64bits,nxt64str(nxt64bits)); - if ( polarity < 0 ) - return(-(int64_t)nxt64bits); - return(nxt64bits); + + /* and null-terminate. */ + *into = '\0'; } -cJSON *addrs_jsonarray(uint64_t *addrs,int32_t num) +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item) { - int32_t j; cJSON *array; - array = cJSON_CreateArray(); - for (j=0; jtype & 0xFF) == cJSON_Invalid; } -void free_json(cJSON *json) { if ( json != 0 ) cJSON_Delete(json); } +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_False; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xff) == cJSON_True; +} + + +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & (cJSON_True | cJSON_False)) != 0; +} +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_NULL; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Number; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_String; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Array; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Object; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Raw; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) +{ + if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) + { + return false; + } + + /* check if type is valid */ + switch (a->type & 0xFF) + { + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + case cJSON_Number: + case cJSON_String: + case cJSON_Raw: + case cJSON_Array: + case cJSON_Object: + break; + + default: + return false; + } + + /* identical objects are equal */ + if (a == b) + { + return true; + } + + switch (a->type & 0xFF) + { + /* in these cases and equal type is enough */ + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + return true; + + case cJSON_Number: + if (a->valuedouble == b->valuedouble) + { + return true; + } + return false; + + case cJSON_String: + case cJSON_Raw: + if ((a->valuestring == NULL) || (b->valuestring == NULL)) + { + return false; + } + if (strcmp(a->valuestring, b->valuestring) == 0) + { + return true; + } + + return false; + + case cJSON_Array: + { + cJSON *a_element = a->child; + cJSON *b_element = b->child; + + for (; (a_element != NULL) && (b_element != NULL);) + { + if (!cJSON_Compare(a_element, b_element, case_sensitive)) + { + return false; + } + + a_element = a_element->next; + b_element = b_element->next; + } + + /* one of the arrays is longer than the other */ + if (a_element != b_element) { + return false; + } + + return true; + } + + case cJSON_Object: + { + cJSON *a_element = NULL; + cJSON *b_element = NULL; + cJSON_ArrayForEach(a_element, a) + { + /* TODO This has O(n^2) runtime, which is horrible! */ + b_element = get_object_item(b, a_element->string, case_sensitive); + if (b_element == NULL) + { + return false; + } + + if (!cJSON_Compare(a_element, b_element, case_sensitive)) + { + return false; + } + } + + /* doing this twice, once on a and b to prevent true comparison if a subset of b + * TODO: Do this the proper way, this is just a fix for now */ + cJSON_ArrayForEach(b_element, b) + { + a_element = get_object_item(a, b_element->string, case_sensitive); + if (a_element == NULL) + { + return false; + } + + if (!cJSON_Compare(b_element, a_element, case_sensitive)) + { + return false; + } + } + + return true; + } + + default: + return false; + } +} + +CJSON_PUBLIC(void *) cJSON_malloc(size_t size) +{ + return global_hooks.allocate(size); +} + +CJSON_PUBLIC(void) cJSON_free(void *object) +{ + global_hooks.deallocate(object); +} diff --git a/src/cJSON.h b/src/cJSON.h old mode 100755 new mode 100644 index 2ee786358..1e388137e --- a/src/cJSON.h +++ b/src/cJSON.h @@ -1,230 +1,260 @@ /* - Copyright (c) 2009 Dave Gamble - - 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. - */ + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + 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. +*/ #ifndef cJSON__h #define cJSON__h -#include -#include -#include -#include -#include -#include -#include -#include "komodo_structs.h" - -//#include "../crypto777/OS_portable.h" - -#define MAX_JSON_FIELD 4096 // on the big side - #ifdef __cplusplus extern "C" { #endif - - /* cJSON Types: */ -#define cJSON_False 0 -#define cJSON_True 1 -#define cJSON_NULL 2 -#define cJSON_Number 3 -#define cJSON_String 4 -#define cJSON_Array 5 -#define cJSON_Object 6 - -#define is_cJSON_Null(json) ((json) != 0 && ((json)->type & 0xff) == cJSON_NULL) -#define is_cJSON_Array(json) ((json) != 0 && ((json)->type & 0xff) == cJSON_Array) -#define is_cJSON_String(json) ((json) != 0 && ((json)->type & 0xff) == cJSON_String) -#define is_cJSON_Number(json) ((json) != 0 && ((json)->type & 0xff) == cJSON_Number) -#define is_cJSON_Object(json) ((json) != 0 && ((json)->type & 0xff) == cJSON_Object) -#define is_cJSON_True(json) ((json) != 0 && ((json)->type & 0xff) == cJSON_True) -#define is_cJSON_False(json) ((json) != 0 && ((json)->type & 0xff) == cJSON_False) - + +/* project version */ +#define CJSON_VERSION_MAJOR 1 +#define CJSON_VERSION_MINOR 5 +#define CJSON_VERSION_PATCH 9 + +#include + +/* cJSON Types: */ +#define cJSON_Invalid (0) +#define cJSON_False (1 << 0) +#define cJSON_True (1 << 1) +#define cJSON_NULL (1 << 2) +#define cJSON_Number (1 << 3) +#define cJSON_String (1 << 4) +#define cJSON_Array (1 << 5) +#define cJSON_Object (1 << 6) +#define cJSON_Raw (1 << 7) /* raw json */ + #define cJSON_IsReference 256 - - /* The cJSON structure: */ - typedef struct cJSON { - struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ - struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ - - int32_t type; /* The type of the item, as above. */ - - char *valuestring; /* The item's string, if type==cJSON_String */ - int64_t valueint; /* The item's number, if type==cJSON_Number */ - double valuedouble; /* The item's number, if type==cJSON_Number */ - - char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ - } cJSON; - - typedef struct cJSON_Hooks { - void *(*malloc_fn)(size_t sz); - void (*free_fn)(void *ptr); - } cJSON_Hooks; - - /* Supply malloc, realloc and free functions to cJSON */ - extern void cJSON_InitHooks(cJSON_Hooks* hooks); - - - /* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */ - extern cJSON *cJSON_Parse(const char *value); - /* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */ - extern char *cJSON_Print(cJSON *item); - /* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */ - extern char *cJSON_PrintUnformatted(cJSON *item); - /* Delete a cJSON entity and all subentities. */ - extern void cJSON_Delete(cJSON *c); - - /* Returns the number of items in an array (or object). */ - extern int cJSON_GetArraySize(cJSON *array); - /* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ - extern cJSON *cJSON_GetArrayItem(cJSON *array,int32_t item); - /* Get item "string" from object. Case insensitive. */ - extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string); - - /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ - extern const char *cJSON_GetErrorPtr(void); - - /* These calls create a cJSON item of the appropriate type. */ - extern cJSON *cJSON_CreateNull(void); - extern cJSON *cJSON_CreateTrue(void); - extern cJSON *cJSON_CreateFalse(void); - extern cJSON *cJSON_CreateBool(int32_t b); - extern cJSON *cJSON_CreateNumber(double num); - extern cJSON *cJSON_CreateString(const char *string); - extern cJSON *cJSON_CreateArray(void); - extern cJSON *cJSON_CreateObject(void); - - /* These utilities create an Array of count items. */ - extern cJSON *cJSON_CreateIntArray(int64_t *numbers,int32_t count); - extern cJSON *cJSON_CreateFloatArray(float *numbers,int32_t count); - extern cJSON *cJSON_CreateDoubleArray(double *numbers,int32_t count); - extern cJSON *cJSON_CreateStringArray(char **strings,int32_t count); - - /* Append item to the specified array/object. */ - extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); - extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); - /* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ - extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); - extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item); - - /* Remove/Detatch items from Arrays/Objects. */ - extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int32_t which); - extern void cJSON_DeleteItemFromArray(cJSON *array,int32_t which); - extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string); - extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string); - - /* Update array items. */ - extern void cJSON_ReplaceItemInArray(cJSON *array,int32_t which,cJSON *newitem); - extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); - - /* Duplicate a cJSON item */ - extern cJSON *cJSON_Duplicate(cJSON *item,int32_t recurse); - /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will - need to be released. With recurse!=0, it will duplicate any children connected to the item. - The item->next and ->prev pointers are always zero on return from Duplicate. */ - - /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ - extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int32_t require_null_terminated); - - extern void cJSON_Minify(char *json); - - /* Macros for creating things quickly. */ -#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) -#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) -#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) -#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) -#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) -#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) - - struct destbuf { char buf[MAX_JSON_FIELD]; }; - - /* When assigning an integer value, it needs to be propagated to valuedouble too. */ -#define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val)) -#define jfieldstr get_cJSON_fieldname - - char *cJSON_str(cJSON *json); - char *jstr(cJSON *json,char *field); - char *jprint(cJSON *json,int32_t freeflag); - int32_t jint(cJSON *json,char *field); - uint32_t juint(cJSON *json,char *field); - char *jstri(cJSON *json,int32_t i); - int32_t jinti(cJSON *json,int32_t i); - uint32_t juinti(cJSON *json,int32_t i); - uint64_t j64bitsi(cJSON *json,int32_t i); - double jdoublei(cJSON *json,int32_t i); - double jdouble(cJSON *json,char *field); - cJSON *jobj(cJSON *json,char *field); - cJSON *jarray(int32_t *nump,cJSON *json,char *field); - cJSON *jitem(cJSON *array,int32_t i); - uint64_t j64bits(cJSON *json,char *field); - void jadd(cJSON *json,char *field,cJSON *item); - void jaddstr(cJSON *json,char *field,char *str); - void jaddnum(cJSON *json,char *field,double num); - void jadd64bits(cJSON *json,char *field,uint64_t nxt64bits); - void jaddi(cJSON *json,cJSON *item); - void jaddistr(cJSON *json,char *str); - void jaddinum(cJSON *json,double num); - void jaddi64bits(cJSON *json,uint64_t nxt64bits); - void jdelete(cJSON *object,char *string); - cJSON *jduplicate(cJSON *json); - int32_t jnum(cJSON *obj,char *field); - - bits256 jbits256(cJSON *json,char *field); - bits256 jbits256i(cJSON *json,int32_t i); - void jaddbits256(cJSON *json,char *field,bits256 hash); - void jaddibits256(cJSON *json,bits256 hash); - void copy_cJSON(struct destbuf *dest,cJSON *obj); - void copy_cJSON2(char *dest,int32_t maxlen,cJSON *obj); - cJSON *gen_list_json(char **list); - int32_t extract_cJSON_str(char *dest,int32_t max,cJSON *json,char *field); +#define cJSON_StringIsConst 512 - void free_json(cJSON *json); - int64_t _conv_cJSON_float(cJSON *json); - int64_t conv_cJSON_float(cJSON *json,char *field); - int64_t get_cJSON_int(cJSON *json,char *field); - void add_satoshis_json(cJSON *json,char *field,uint64_t satoshis); - uint64_t get_satoshi_obj(cJSON *json,char *field); - - int32_t get_API_int(cJSON *obj,int32_t val); - uint32_t get_API_uint(cJSON *obj,uint32_t val); - uint64_t get_API_nxt64bits(cJSON *obj); - double get_API_float(cJSON *obj); - char *get_cJSON_fieldname(cJSON *obj); - void ensure_jsonitem(cJSON *json,char *field,char *value); - int32_t in_jsonarray(cJSON *array,char *value); - char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char *command,char *params); - uint64_t calc_nxt64bits(const char *str); - int32_t expand_nxt64bits(char *str,uint64_t nxt64bits); - char *nxt64str(uint64_t nxt64bits); - char *nxt64str2(uint64_t nxt64bits); - cJSON *addrs_jsonarray(uint64_t *addrs,int32_t num); - int32_t myatoi(char *str,int32_t range); +/* The cJSON structure: */ +typedef struct cJSON +{ + /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON *next; + struct cJSON *prev; + /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ + struct cJSON *child; - char *stringifyM(char *str); -#define replace_backslashquotes unstringify - char *unstringify(char *str); -#define jtrue cJSON_CreateTrue -#define jfalse cJSON_CreateFalse + /* The type of the item, as above. */ + int type; -#define jfieldname get_cJSON_fieldname + /* The item's string, if type==cJSON_String and type == cJSON_Raw */ + char *valuestring; + /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ + int valueint; + /* The item's number, if type==cJSON_Number */ + double valuedouble; + + /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ + char *string; +} cJSON; + +typedef struct cJSON_Hooks +{ + void *(*malloc_fn)(size_t sz); + void (*free_fn)(void *ptr); +} cJSON_Hooks; + +typedef int cJSON_bool; + +#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) +#define __WINDOWS__ +#endif +#ifdef __WINDOWS__ + +/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 2 define options: + +CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols +CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) +CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol + +For *nix builds that support visibility attribute, you can define similar behavior by + +setting default visibility to hidden by adding +-fvisibility=hidden (for gcc) +or +-xldscope=hidden (for sun cc) +to CFLAGS + +then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does + +*/ + +/* export symbols by default, this is necessary for copy pasting the C and header file */ +#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_EXPORT_SYMBOLS +#endif + +#if defined(CJSON_HIDE_SYMBOLS) +#define CJSON_PUBLIC(type) type __stdcall +#elif defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllexport) type __stdcall +#elif defined(CJSON_IMPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllimport) type __stdcall +#endif +#else /* !WIN32 */ +#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) +#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type +#else +#define CJSON_PUBLIC(type) type +#endif +#endif + +/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. + * This is to prevent stack overflows. */ +#ifndef CJSON_NESTING_LIMIT +#define CJSON_NESTING_LIMIT 1000 +#endif + +/* returns the version of cJSON as a string */ +CJSON_PUBLIC(const char*) cJSON_Version(void); + +/* Supply malloc, realloc and free functions to cJSON */ +CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); + +/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ +/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); +/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ +/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); + +/* Render a cJSON entity to text for transfer/storage. */ +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); +/* Render a cJSON entity to text for transfer/storage without any formatting. */ +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); +/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); +/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ +/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); +/* Delete a cJSON entity and all subentities. */ +CJSON_PUBLIC(void) cJSON_Delete(cJSON *c); + +/* Returns the number of items in an array (or object). */ +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); +/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); +/* Get item "string" from object. Case insensitive. */ +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); +/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); + +/* These functions check the type of an item */ +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); + +/* These calls create a cJSON item of the appropriate type. */ +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); +/* raw json */ +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); + +/* These utilities create an Array of count items. */ +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count); + +/* Append item to the specified array/object. */ +CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); +/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. + * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before + * writing to `item->string` */ +CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); +/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ +CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); + +/* Remove/Detatch items from Arrays/Objects. */ +CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); +CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); + +/* Update array items. */ +CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); +CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); +CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); +CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); + +/* Duplicate a cJSON item */ +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); +/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will +need to be released. With recurse!=0, it will duplicate any children connected to the item. +The item->next and ->prev pointers are always zero on return from Duplicate. */ +/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. + * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); + + +CJSON_PUBLIC(void) cJSON_Minify(char *json); + +/* Macros for creating things quickly. */ +#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) +#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) +#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) +#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) +#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) +#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) +#define cJSON_AddRawToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateRaw(s)) + +/* When assigning an integer value, it needs to be propagated to valuedouble too. */ +#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) +/* helper for the cJSON_SetNumberValue macro */ +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); +#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) + +/* Macro for iterating over an array or object */ +#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) + +/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ +CJSON_PUBLIC(void *) cJSON_malloc(size_t size); +CJSON_PUBLIC(void) cJSON_free(void *object); #ifdef __cplusplus } diff --git a/src/komodo.h b/src/komodo.h index e1e40448d..010f1b3b6 100644 --- a/src/komodo.h +++ b/src/komodo.h @@ -42,7 +42,7 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block); #include "komodo_utils.h" #include "komodo_curve25519.h" -#include "cJSON.c" +#include "komodo_cJSON.c" #include "komodo_bitcoind.h" #include "komodo_interest.h" #include "komodo_pax.h" diff --git a/src/komodo_cJSON.c b/src/komodo_cJSON.c new file mode 100755 index 000000000..ca2c6517c --- /dev/null +++ b/src/komodo_cJSON.c @@ -0,0 +1,559 @@ + +/* + Copyright (c) 2009 Dave Gamble + + 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. + */ + +/* cJSON */ +/* JSON parser in C. */ +#include + +#include "cJSON.h" +#include "komodo_cJSON.h" +#include "cJSON.c" + +#ifndef DBL_EPSILON +#define DBL_EPSILON 2.2204460492503131E-16 +#endif + +static const char *ep; + +long stripquotes(char *str) +{ + long len,offset; + if ( str == 0 ) + return(0); + len = strlen(str); + if ( str[0] == '"' && str[len-1] == '"' ) + str[len-1] = 0, offset = 1; + else offset = 0; + return(offset); +} + +static int32_t cJSON_strcasecmp(const char *s1,const char *s2) +{ + if (!s1) return (s1==s2)?0:1;if (!s2) return 1; + for(; tolower((int32_t)(*s1)) == tolower((int32_t)(*s2)); ++s1, ++s2) if(*s1 == 0) return 0; + return tolower((int32_t)(*(const unsigned char *)s1)) - tolower((int32_t)(*(const unsigned char *)s2)); +} + +// the following written by jl777 +/****************************************************************************** + * Copyright © 2014-2017 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. * + * * + ******************************************************************************/ + +void copy_cJSON(struct destbuf *dest,cJSON *obj) +{ + char *str; + int i; + long offset; + dest->buf[0] = 0; + if ( obj != 0 ) + { + str = cJSON_Print(obj); + if ( str != 0 ) + { + offset = stripquotes(str); + //strcpy(dest,str+offset); + for (i=0; ibuf[i]= str[offset+i]) == 0 ) + break; + dest->buf[i] = 0; + free(str); + } + } +} + +void copy_cJSON2(char *dest,int32_t maxlen,cJSON *obj) +{ + struct destbuf tmp; + maxlen--; + dest[0] = 0; + if ( maxlen > sizeof(tmp.buf) ) + maxlen = sizeof(tmp.buf); + copy_cJSON(&tmp,obj); + if ( strlen(tmp.buf) < maxlen ) + strcpy(dest,tmp.buf); + else dest[0] = 0; +} + +int64_t _get_cJSON_int(cJSON *json) +{ + struct destbuf tmp; + if ( json != 0 ) + { + copy_cJSON(&tmp,json); + if ( tmp.buf[0] != 0 ) + return(calc_nxt64bits(tmp.buf)); + } + return(0); +} + +int64_t get_cJSON_int(cJSON *json,char *field) +{ + cJSON *numjson; + if ( json != 0 ) + { + numjson = cJSON_GetObjectItem(json,field); + if ( numjson != 0 ) + return(_get_cJSON_int(numjson)); + } + return(0); +} + +int64_t conv_floatstr(char *numstr) +{ + double val,corr; + val = atof(numstr); + corr = (val < 0.) ? -0.50000000001 : 0.50000000001; + return((int64_t)(val * SATOSHIDEN + corr)); +} + +int64_t _conv_cJSON_float(cJSON *json) +{ + int64_t conv_floatstr(char *); + struct destbuf tmp; + if ( json != 0 ) + { + copy_cJSON(&tmp,json); + return(conv_floatstr(tmp.buf)); + } + return(0); +} + +int64_t conv_cJSON_float(cJSON *json,char *field) +{ + if ( json != 0 ) + return(_conv_cJSON_float(cJSON_GetObjectItem(json,field))); + return(0); +} + +int32_t extract_cJSON_str(char *dest,int32_t max,cJSON *json,char *field) +{ + int32_t safecopy(char *dest,char *src,long len); + char *str; + cJSON *obj; + int32_t len; + long offset; + dest[0] = 0; + obj = cJSON_GetObjectItem(json,field); + if ( obj != 0 ) + { + str = cJSON_Print(obj); + offset = stripquotes(str); + len = safecopy(dest,str+offset,max); + free(str); + return(len); + } + return(0); +} + +cJSON *gen_list_json(char **list) +{ + cJSON *array,*item; + array = cJSON_CreateArray(); + while ( list != 0 && *list != 0 && *list[0] != 0 ) + { + item = cJSON_CreateString(*list++); + cJSON_AddItemToArray(array,item); + } + return(array); +} + +uint64_t get_API_nxt64bits(cJSON *obj) +{ + uint64_t nxt64bits = 0; + struct destbuf tmp; + if ( obj != 0 ) + { + if ( cJSON_IsNumber(obj) != 0 ) + return((uint64_t)obj->valuedouble); + copy_cJSON(&tmp,obj); + nxt64bits = calc_nxt64bits(tmp.buf); + } + return(nxt64bits); +} +uint64_t j64bits(cJSON *json,char *field) { if ( field == 0 ) return(get_API_nxt64bits(json)); return(get_API_nxt64bits(cJSON_GetObjectItem(json,field))); } +uint64_t j64bitsi(cJSON *json,int32_t i) { return(get_API_nxt64bits(cJSON_GetArrayItem(json,i))); } + +uint64_t get_satoshi_obj(cJSON *json,char *field) +{ + int32_t i,n; + uint64_t prev,satoshis,mult = 1; + struct destbuf numstr,checkstr; + cJSON *numjson; + numjson = cJSON_GetObjectItem(json,field); + copy_cJSON(&numstr,numjson); + satoshis = prev = 0; mult = 1; n = (int32_t)strlen(numstr.buf); + for (i=n-1; i>=0; i--,mult*=10) + { + satoshis += (mult * (numstr.buf[i] - '0')); + if ( satoshis < prev ) + printf("get_satoshi_obj numstr.(%s) i.%d prev.%llu vs satoshis.%llu\n",numstr.buf,i,(unsigned long long)prev,(unsigned long long)satoshis); + prev = satoshis; + } + sprintf(checkstr.buf,"%llu",(long long)satoshis); + if ( strcmp(checkstr.buf,numstr.buf) != 0 ) + { + printf("SATOSHI GREMLIN?? numstr.(%s) -> %.8f -> (%s)\n",numstr.buf,dstr(satoshis),checkstr.buf); + } + return(satoshis); +} + +void add_satoshis_json(cJSON *json,char *field,uint64_t satoshis) +{ + cJSON *obj; + char numstr[64]; + sprintf(numstr,"%lld",(long long)satoshis); + obj = cJSON_CreateString(numstr); + cJSON_AddItemToObject(json,field,obj); + if ( satoshis != get_satoshi_obj(json,field) ) + printf("error adding satoshi obj %ld -> %ld\n",(unsigned long)satoshis,(unsigned long)get_satoshi_obj(json,field)); +} + +char *cJSON_str(cJSON *json) +{ + if ( json != 0 && cJSON_IsString(json) != 0 ) + return(json->valuestring); + return(0); +} + +void jadd(cJSON *json,char *field,cJSON *item) { if ( json != 0 )cJSON_AddItemToObject(json,field,item); } +void jaddstr(cJSON *json,char *field,char *str) { if ( json != 0 && str != 0 ) cJSON_AddItemToObject(json,field,cJSON_CreateString(str)); } +void jaddnum(cJSON *json,char *field,double num) { if ( json != 0 )cJSON_AddItemToObject(json,field,cJSON_CreateNumber(num)); } +void jadd64bits(cJSON *json,char *field,uint64_t nxt64bits) { char numstr[64]; sprintf(numstr,"%llu",(long long)nxt64bits), jaddstr(json,field,numstr); } +void jaddi(cJSON *json,cJSON *item) { if ( json != 0 ) cJSON_AddItemToArray(json,item); } +void jaddistr(cJSON *json,char *str) { if ( json != 0 ) cJSON_AddItemToArray(json,cJSON_CreateString(str)); } +void jaddinum(cJSON *json,double num) { if ( json != 0 ) cJSON_AddItemToArray(json,cJSON_CreateNumber(num)); } +void jaddi64bits(cJSON *json,uint64_t nxt64bits) { char numstr[64]; sprintf(numstr,"%llu",(long long)nxt64bits), jaddistr(json,numstr); } +char *jstr(cJSON *json,char *field) { if ( json == 0 ) return(0); if ( field == 0 ) return(cJSON_str(json)); return(cJSON_str(cJSON_GetObjectItem(json,field))); } + +char *jstri(cJSON *json,int32_t i) { return(cJSON_str(cJSON_GetArrayItem(json,i))); } +char *jprint(cJSON *json,int32_t freeflag) +{ + char *str; + /*static portable_mutex_t mutex; static int32_t initflag; + if ( initflag == 0 ) + { + portable_mutex_init(&mutex); + initflag = 1; + }*/ + if ( json == 0 ) + return(clonestr((char *)"{}")); + //portable_mutex_lock(&mutex); + //usleep(5000); + str = cJSON_Print(json), _stripwhite(str,' '); + if ( freeflag != 0 ) + free_json(json); + //portable_mutex_unlock(&mutex); + return(str); +} + +bits256 get_API_bits256(cJSON *obj) +{ + bits256 hash; char *str; + memset(hash.bytes,0,sizeof(hash)); + if ( obj != 0 ) + { + if ( cJSON_IsString(obj) != 0 && (str= obj->valuestring) != 0 && strlen(str) == 64 ) + decode_hex(hash.bytes,sizeof(hash),str); + } + return(hash); +} +bits256 jbits256(cJSON *json,char *field) { if ( field == 0 ) return(get_API_bits256(json)); return(get_API_bits256(cJSON_GetObjectItem(json,field))); } +bits256 jbits256i(cJSON *json,int32_t i) { return(get_API_bits256(cJSON_GetArrayItem(json,i))); } +void jaddbits256(cJSON *json,char *field,bits256 hash) { char str[65]; bits256_str(str,hash), jaddstr(json,field,str); } +void jaddibits256(cJSON *json,bits256 hash) { char str[65]; bits256_str(str,hash), jaddistr(json,str); } + +char *get_cJSON_fieldname(cJSON *obj) +{ + if ( obj != 0 ) + { + if ( obj->child != 0 && obj->child->string != 0 ) + return(obj->child->string); + else if ( obj->string != 0 ) + return(obj->string); + } + return((char *)""); +} + +int32_t jnum(cJSON *obj,char *field) +{ + char *str; int32_t polarity = 1; + if ( field != 0 ) + obj = jobj(obj,field); + if ( obj != 0 ) + { + if ( cJSON_IsNumber(obj) != 0 ) + return(obj->valuedouble); + else if ( cJSON_IsString(obj) != 0 && (str= jstr(obj,0)) != 0 ) + { + if ( str[0] == '-' ) + polarity = -1, str++; + return(polarity * (int32_t)calc_nxt64bits(str)); + } + } + return(0); +} + +void ensure_jsonitem(cJSON *json,char *field,char *value) +{ + cJSON *obj = cJSON_GetObjectItem(json,field); + if ( obj == 0 ) + cJSON_AddItemToObject(json,field,cJSON_CreateString(value)); + else cJSON_ReplaceItemInObject(json,field,cJSON_CreateString(value)); +} + +int32_t in_jsonarray(cJSON *array,char *value) +{ + int32_t i,n; + struct destbuf remote; + if ( array != 0 && cJSON_IsArray(array) != 0 ) + { + n = cJSON_GetArraySize(array); + for (i=0; i= range ) + x = (range - 1); + return((int32_t)x); +} + +int32_t get_API_int(cJSON *obj,int32_t val) +{ + struct destbuf buf; + if ( obj != 0 ) + { + if ( cJSON_IsNumber(obj) != 0 ) + return((int32_t)obj->valuedouble); + copy_cJSON(&buf,obj); + val = myatoi(buf.buf,0); + if ( val < 0 ) + val = 0; + } + return(val); +} + +int32_t jint(cJSON *json,char *field) { if ( json == 0 ) return(0); if ( field == 0 ) return(get_API_int(json,0)); return(get_API_int(cJSON_GetObjectItem(json,field),0)); } +int32_t jinti(cJSON *json,int32_t i) { if ( json == 0 ) return(0); return(get_API_int(cJSON_GetArrayItem(json,i),0)); } + +uint32_t get_API_uint(cJSON *obj,uint32_t val) +{ + struct destbuf buf; + if ( obj != 0 ) + { + if ( cJSON_IsNumber(obj) != 0 ) + return((uint32_t)obj->valuedouble); + copy_cJSON(&buf,obj); + val = myatoi(buf.buf,0); + } + return(val); +} +uint32_t juint(cJSON *json,char *field) { if ( json == 0 ) return(0); if ( field == 0 ) return(get_API_uint(json,0)); return(get_API_uint(cJSON_GetObjectItem(json,field),0)); } +uint32_t juinti(cJSON *json,int32_t i) { if ( json == 0 ) return(0); return(get_API_uint(cJSON_GetArrayItem(json,i),0)); } + +double get_API_float(cJSON *obj) +{ + double val = 0.; + struct destbuf buf; + if ( obj != 0 ) + { + if ( cJSON_IsNumber(obj) != 0 ) + return(obj->valuedouble); + copy_cJSON(&buf,obj); + val = atof(buf.buf); + } + return(val); +} + +double jdouble(cJSON *json,char *field) +{ + if ( json != 0 ) + { + if ( field == 0 ) + return(get_API_float(json)); + else return(get_API_float(cJSON_GetObjectItem(json,field))); + } else return(0.); +} + +double jdoublei(cJSON *json,int32_t i) +{ + if ( json != 0 ) + return(get_API_float(cJSON_GetArrayItem(json,i))); + else return(0.); +} + +cJSON *jobj(cJSON *json,char *field) { if ( json != 0 ) return(cJSON_GetObjectItem(json,field)); return(0); } + +void jdelete(cJSON *json,char *field) +{ + if ( jobj(json,field) != 0 ) + cJSON_DeleteItemFromObject(json,field); +} + +cJSON *jduplicate(cJSON *json) { return(cJSON_Duplicate(json,1)); } + +cJSON *jitem(cJSON *array,int32_t i) { if ( array != 0 && cJSON_IsArray(array) != 0 && cJSON_GetArraySize(array) > i ) return(cJSON_GetArrayItem(array,i)); return(0); } +cJSON *jarray(int32_t *nump,cJSON *json,char *field) +{ + cJSON *array; + if ( json != 0 ) + { + if ( field == 0 ) + array = json; + else array = cJSON_GetObjectItem(json,field); + if ( array != 0 && cJSON_IsArray(array) != 0 && (*nump= cJSON_GetArraySize(array)) > 0 ) + return(array); + } + *nump = 0; + return(0); +} + +int32_t expand_nxt64bits(char *NXTaddr,uint64_t nxt64bits) +{ + int32_t i,n; + uint64_t modval; + char rev[64]; + for (i=0; nxt64bits!=0; i++) + { + modval = nxt64bits % 10; + rev[i] = (char)(modval + '0'); + nxt64bits /= 10; + } + n = i; + for (i=0; i= 22 ) + { + printf("calc_nxt64bits: illegal NXTaddr.(%s) too long\n",NXTaddr); + return(0); + } + else if ( strcmp(NXTaddr,"0") == 0 || strcmp(NXTaddr,"false") == 0 ) + { + // printf("zero address?\n"); getchar(); + return(0); + } + if ( NXTaddr[0] == '-' ) + polarity = -1, NXTaddr++, n--; + mult = 1; + lastval = 0; + for (i=n-1; i>=0; i--,mult*=10) + { + c = NXTaddr[i]; + if ( c < '0' || c > '9' ) + { + printf("calc_nxt64bits: illegal char.(%c %d) in (%s).%d\n",c,c,NXTaddr,(int32_t)i); +#ifdef __APPLE__ + //while ( 1 ) + { + //sleep(60); + printf("calc_nxt64bits: illegal char.(%c %d) in (%s).%d\n",c,c,NXTaddr,(int32_t)i); + } +#endif + return(0); + } + nxt64bits += mult * (c - '0'); + if ( nxt64bits < lastval ) + printf("calc_nxt64bits: warning: 64bit overflow %llx < %llx\n",(long long)nxt64bits,(long long)lastval); + lastval = nxt64bits; + } + while ( *NXTaddr == '0' && *NXTaddr != 0 ) + NXTaddr++; + if ( cmp_nxt64bits(NXTaddr,nxt64bits) != 0 ) + printf("error calculating nxt64bits: %s -> %llx -> %s\n",NXTaddr,(long long)nxt64bits,nxt64str(nxt64bits)); + if ( polarity < 0 ) + return(-(int64_t)nxt64bits); + return(nxt64bits); +} + +cJSON *addrs_jsonarray(uint64_t *addrs,int32_t num) +{ + int32_t j; cJSON *array; + array = cJSON_CreateArray(); + for (j=0; j +#include +#include +#include +#include +#include +#include +#include "komodo_structs.h" + +#include "cJSON.h" + +//#include "../crypto777/OS_portable.h" + +#define MAX_JSON_FIELD 4096 // on the big side + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* Macros for creating things quickly. */ +#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) +#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) +#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) +#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) +#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) +#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) + + struct destbuf { char buf[MAX_JSON_FIELD]; }; + +#define jfieldstr get_cJSON_fieldname + + char *cJSON_str(cJSON *json); + char *jstr(cJSON *json,char *field); + char *jprint(cJSON *json,int32_t freeflag); + int32_t jint(cJSON *json,char *field); + uint32_t juint(cJSON *json,char *field); + char *jstri(cJSON *json,int32_t i); + int32_t jinti(cJSON *json,int32_t i); + uint32_t juinti(cJSON *json,int32_t i); + uint64_t j64bitsi(cJSON *json,int32_t i); + double jdoublei(cJSON *json,int32_t i); + double jdouble(cJSON *json,char *field); + cJSON *jobj(cJSON *json,char *field); + cJSON *jarray(int32_t *nump,cJSON *json,char *field); + cJSON *jitem(cJSON *array,int32_t i); + uint64_t j64bits(cJSON *json,char *field); + void jadd(cJSON *json,char *field,cJSON *item); + void jaddstr(cJSON *json,char *field,char *str); + void jaddnum(cJSON *json,char *field,double num); + void jadd64bits(cJSON *json,char *field,uint64_t nxt64bits); + void jaddi(cJSON *json,cJSON *item); + void jaddistr(cJSON *json,char *str); + void jaddinum(cJSON *json,double num); + void jaddi64bits(cJSON *json,uint64_t nxt64bits); + void jdelete(cJSON *object,char *string); + cJSON *jduplicate(cJSON *json); + int32_t jnum(cJSON *obj,char *field); + + bits256 jbits256(cJSON *json,char *field); + bits256 jbits256i(cJSON *json,int32_t i); + void jaddbits256(cJSON *json,char *field,bits256 hash); + void jaddibits256(cJSON *json,bits256 hash); + void copy_cJSON(struct destbuf *dest,cJSON *obj); + void copy_cJSON2(char *dest,int32_t maxlen,cJSON *obj); + cJSON *gen_list_json(char **list); + int32_t extract_cJSON_str(char *dest,int32_t max,cJSON *json,char *field); + + void free_json(cJSON *json); + int64_t _conv_cJSON_float(cJSON *json); + int64_t conv_cJSON_float(cJSON *json,char *field); + int64_t get_cJSON_int(cJSON *json,char *field); + void add_satoshis_json(cJSON *json,char *field,uint64_t satoshis); + uint64_t get_satoshi_obj(cJSON *json,char *field); + + int32_t get_API_int(cJSON *obj,int32_t val); + uint32_t get_API_uint(cJSON *obj,uint32_t val); + uint64_t get_API_nxt64bits(cJSON *obj); + double get_API_float(cJSON *obj); + char *get_cJSON_fieldname(cJSON *obj); + void ensure_jsonitem(cJSON *json,char *field,char *value); + int32_t in_jsonarray(cJSON *array,char *value); + char *bitcoind_RPC(char **retstrp,char *debugstr,char *url,char *userpass,char *command,char *params); + uint64_t calc_nxt64bits(const char *str); + int32_t expand_nxt64bits(char *str,uint64_t nxt64bits); + char *nxt64str(uint64_t nxt64bits); + char *nxt64str2(uint64_t nxt64bits); + cJSON *addrs_jsonarray(uint64_t *addrs,int32_t num); + int32_t myatoi(char *str,int32_t range); + + char *stringifyM(char *str); +#define replace_backslashquotes unstringify + char *unstringify(char *str); +#define jtrue cJSON_CreateTrue +#define jfalse cJSON_CreateFalse + +#define jfieldname get_cJSON_fieldname + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/komodo_jumblr.h b/src/komodo_jumblr.h index f0bfecc9c..baafc6dbe 100755 --- a/src/komodo_jumblr.h +++ b/src/komodo_jumblr.h @@ -141,7 +141,7 @@ int32_t Jumblr_depositaddradd(char *depositaddr) // external { if ( (retjson= cJSON_Parse(retstr)) != 0 ) { - if ( (ismine= jobj(retjson,(char *)"ismine")) != 0 && is_cJSON_True(ismine) != 0 ) + if ( (ismine= jobj(retjson,(char *)"ismine")) != 0 && cJSON_IsTrue(ismine) != 0 ) { retval = 0; safecopy(Jumblr_deposit,depositaddr,sizeof(Jumblr_deposit)); @@ -149,7 +149,7 @@ int32_t Jumblr_depositaddradd(char *depositaddr) // external else { retval = JUMBLR_ERROR_NOTINWALLET; - printf("%s not in wallet: ismine.%p %d %s\n",depositaddr,ismine,is_cJSON_True(ismine),jprint(retjson,0)); + printf("%s not in wallet: ismine.%p %d %s\n",depositaddr,ismine,cJSON_IsTrue(ismine),jprint(retjson,0)); } free_json(retjson); } @@ -366,7 +366,7 @@ int64_t jumblr_balance(char *addr) //printf("jumblr.[%s].(%s)\n","KMD",retstr); if ( (retjson= cJSON_Parse(retstr)) != 0 ) { - if ( (n= cJSON_GetArraySize(retjson)) > 0 && is_cJSON_Array(retjson) != 0 ) + if ( (n= cJSON_GetArraySize(retjson)) > 0 && cJSON_IsArray(retjson) != 0 ) for (i=0; i 0 && is_cJSON_Array(array) != 0 ) + if ( (n= cJSON_GetArraySize(array)) > 0 && cJSON_IsArray(array) != 0 ) { //printf("%s -> n%d\n",retstr,n); for (i=0; i 0 && is_cJSON_Array(array) != 0 ) + if ( (n= cJSON_GetArraySize(array)) > 0 && cJSON_IsArray(array) != 0 ) { for (i=0; i Date: Sun, 22 Oct 2017 23:27:44 -0700 Subject: [PATCH 011/339] function to create a cryptocondition from a Univalue --- configure.ac | 2 +- src/rpccryptoconditions.cpp | 21 +++++++++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/configure.ac b/configure.ac index c471bab89..9f8f1900f 100644 --- a/configure.ac +++ b/configure.ac @@ -996,7 +996,7 @@ unset PKG_CONFIG_LIBDIR PKG_CONFIG_LIBDIR="$PKGCONFIG_LIBDIR_TEMP" ac_configure_args="${ac_configure_args} --disable-shared --with-pic --with-bignum=no" -AC_CONFIG_SUBDIRS([src/secp256k1 src/univalue]) +AC_CONFIG_SUBDIRS([src/secp256k1 src/univalue src/cryptoconditions]) AC_OUTPUT diff --git a/src/rpccryptoconditions.cpp b/src/rpccryptoconditions.cpp index 946667aae..e297ed4e4 100644 --- a/src/rpccryptoconditions.cpp +++ b/src/rpccryptoconditions.cpp @@ -375,6 +375,14 @@ UniValue verifytxoutproofcc(const UniValue& params, bool fHelp) return res; } +CC *ConditionFromValue(const UniValue& condition) { + std::string encoded = condition.write(); + char *err = new char[1000]; + CC *cond = cc_conditionFromJSONString(encoded.c_str(), err); + if (NULL == cond) + throw JSONRPCError(RPC_INVALID_PARAMETER, err); +} + UniValue createrawtransactioncc(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 2) @@ -409,7 +417,7 @@ UniValue createrawtransactioncc(const UniValue& params, bool fHelp) ); LOCK(cs_main); - RPCTypeCheck(params, boost::assign::list_of(UniValue::VARR)(UniValue::VARR)); + //RPCTypeCheck(params, boost::assign::list_of(UniValue::VARR)(UniValue::VARR)); UniValue inputs = params[0].get_array(); UniValue outputs = params[1].get_array(); @@ -429,6 +437,9 @@ UniValue createrawtransactioncc(const UniValue& params, bool fHelp) if (nOutput < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive"); + CC *cond = ConditionFromValue(find_value(output, "condition")); + char *ffillBin = new char[1024*1024]; + CTxIn in(COutPoint(txid, nOutput)); rawTx.vin.push_back(in); } @@ -436,13 +447,7 @@ UniValue createrawtransactioncc(const UniValue& params, bool fHelp) for (size_t idx = 0; idx < outputs.size(); idx++) { const UniValue& output = outputs[idx].get_obj(); - const UniValue& condition = find_value(output, "condition"); - std::string encoded = condition.write(); - fprintf(stderr, "%s\n", encoded.c_str()); - char *err = new char[1000]; - CC *cond = cc_conditionFromJSONString(encoded.c_str(), err); - if (NULL == cond) - throw JSONRPCError(RPC_INVALID_PARAMETER, err); + CC *cond = ConditionFromValue(find_value(output, "condition")); char *condBin = new char[1000]; size_t binLength = cc_conditionBinary(cond, condBin); std::vector condVec(condBin, condBin + binLength); From 6585a02268125511b5589fe330a39c376f78d165 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Tue, 23 Jan 2018 14:05:43 -0300 Subject: [PATCH 012/339] cli method to create CC transaction --- qa/test_rpc_cryptoconditions.py | 47 ++++++ src/rpccryptoconditions.cpp | 246 +++++++++++--------------------- 2 files changed, 129 insertions(+), 164 deletions(-) create mode 100644 qa/test_rpc_cryptoconditions.py diff --git a/qa/test_rpc_cryptoconditions.py b/qa/test_rpc_cryptoconditions.py new file mode 100644 index 000000000..a93eab86a --- /dev/null +++ b/qa/test_rpc_cryptoconditions.py @@ -0,0 +1,47 @@ +import os +import subprocess +import json +import base64 + + +inputs = [ + { + 'txid': '9b907ef1e3c26fc71fe4a4b3580bc75264112f95050014157059c736f0202e71', + 'vout': 0, + 'fulfillment': { + 'type': 'preimage-sha-256', + 'preimage': '', + }, + } +] + +outputs = [ + { + "condition": { + 'type': 'preimage-sha-256', + 'preimage': '' + }, + "amount": 1, + } +] + +addresses = ['RQygCQA7ovCrVCHM3sSkDQjjQUg5X4SCJw'] +privkeys = ["UszeEw39HcoeRegZb74xuvngbcQ5jkwQZZVpAvBp1bvBhXD36ghX"] + + +proc = subprocess.Popen(['src/komodo-cli', 'createrawtransactioncc', json.dumps(inputs), json.dumps(outputs)], + stdout=subprocess.PIPE) + +assert not proc.wait() + +tx_hex = proc.stdout.read().strip() +tx = base64.b16decode(tx_hex, casefold=True) + +print repr(tx) + +proc = subprocess.Popen(['src/komodo-cli', 'signrawtransactioncc', tx_hex, json.dumps(privkeys)], + stdout=subprocess.PIPE) + +proc.wait() + +result = json.loads(proc.stdout.read()) diff --git a/src/rpccryptoconditions.cpp b/src/rpccryptoconditions.cpp index e297ed4e4..18d6774f0 100644 --- a/src/rpccryptoconditions.cpp +++ b/src/rpccryptoconditions.cpp @@ -375,45 +375,73 @@ UniValue verifytxoutproofcc(const UniValue& params, bool fHelp) return res; } -CC *ConditionFromValue(const UniValue& condition) { - std::string encoded = condition.write(); + +CC *ConditionFromString(std::string encoded) { char *err = new char[1000]; CC *cond = cc_conditionFromJSONString(encoded.c_str(), err); if (NULL == cond) throw JSONRPCError(RPC_INVALID_PARAMETER, err); } + +CC *ConditionFromCharVector(vector& vch) { + return ConditionFromString(std::string(vch.begin(), vch.end())); +} + + +CC *ConditionFromUnsignedInputScript(const CScript& script) +{ + opcodetype op; + CScript::const_iterator it = script.begin(); + + vector vch; + if (script.GetOp2(it, op, &vch)) { + if (vch.at(0) == '{') { + return ConditionFromCharVector(vch); + } + } + return NULL; +} + + +CC *ConditionFromValue(UniValue value) { + std::string conditionEncoded = value.write(); + // TODO: Is null? + return ConditionFromString(conditionEncoded); +} + UniValue createrawtransactioncc(const UniValue& params, bool fHelp) { if (fHelp || params.size() != 2) throw runtime_error( - "createrawtransaction [{\"txid\":\"id\",\"vout\":n},...] {\"address\":amount,...}\n" + "createrawtransactioncc [{\"txid\":\"id\",\"vout\":n,\"fulfillment\":{...}},...] {\"address\":amount,...}\n" "\nCreate a transaction spending the given inputs and sending to the given addresses.\n" "Returns hex-encoded raw transaction.\n" "Note that the transaction's inputs are not signed, and\n" "it is not stored in the wallet or transmitted to the network.\n" "\nArguments:\n" - "1. \"transactions\" (string, required) A json array of json objects\n" + "1. \"inputs\" (string, required) A json array of json objects\n" " [\n" " {\n" - " \"txid\":\"id\", (string, required) The transaction id\n" - " \"vout\":n (numeric, required) The output number\n" + " \"txid\":\"id\", (string, required) The transaction id\n" + " \"vout\":n, (numeric, required) The output number\n" + " \"fulfillment\":{...} (object, required) The JSON encoded cryptocondition fulfillment for the previous transaction's output\n" " }\n" " ,...\n" " ]\n" - "2. \"addresses\" (string, required) a json object with addresses as keys and amounts as values\n" + "2. \"outputs\" (string, required) a json array with addresses as keys and amounts as values\n" " {\n" - " \"address\": x.xxx (numeric, required) The key is the bitcoin address, the value is the btc amount\n" - " ,...\n" + " \"condition\":\"{...}\" (object, required) The JSON encoded condition\n" + " \"amount\":n, (numeric, required) The coin amount in satoshis\n" " }\n" "\nResult:\n" - "\"transaction\" (string) hex string of the transaction\n" + "\"transaction\" (string) hex string of the transaction\n" - "\nExamples\n" - + HelpExampleCli("createrawtransactioncc", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"{\\\"address\\\":0.01}\"") - + HelpExampleRpc("createrawtransactioncc", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"address\\\":0.01}\"") + // "\nExamples\n" + // + HelpExampleCli("createrawtransactioncc", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"{\\\"address\\\":0.01}\"") + // + HelpExampleRpc("createrawtransactioncc", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"address\\\":0.01}\"") ); LOCK(cs_main); @@ -437,49 +465,46 @@ UniValue createrawtransactioncc(const UniValue& params, bool fHelp) if (nOutput < 0) throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive"); - CC *cond = ConditionFromValue(find_value(output, "condition")); - char *ffillBin = new char[1024*1024]; + const UniValue& ffill_v = find_value(input, "fulfillment"); + if (!ffill_v.isObject()) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "\"fulfillment\" missing or not an object"); + } + const std::string ffillEncoded = ffill_v.write(); - CTxIn in(COutPoint(txid, nOutput)); + // Validate the fulfillment + CC *cond = ConditionFromString(ffillEncoded); + if (cond == NULL) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "\"fulfillment\" not a valid JSON encoded crypto condition"); + } + cc_free(cond); + + CScript inputScript; + const std::vector ffill(ffillEncoded.c_str(), ffillEncoded.c_str() + ffillEncoded.size()); + inputScript << ffill; + + CTxIn in(COutPoint(txid, nOutput), inputScript); rawTx.vin.push_back(in); } for (size_t idx = 0; idx < outputs.size(); idx++) { const UniValue& output = outputs[idx].get_obj(); + // This does not need to be fulfilled, we just want the condition binary CC *cond = ConditionFromValue(find_value(output, "condition")); + char *condBin = new char[1000]; size_t binLength = cc_conditionBinary(cond, condBin); - std::vector condVec(condBin, condBin + binLength); + const std::vector condVec(condBin, condBin + binLength); CScript redeemScript; - redeemScript << ToByteVector(condVec) << OP_CHECKCRYPTOCONDITIONVERIFY; + redeemScript << condVec << OP_CHECKCRYPTOCONDITIONVERIFY; + CAmount nAmount = AmountFromValue(find_value(output, "amount")); CTxOut out(nAmount, redeemScript); rawTx.vout.push_back(out); } - /* - set setAddress; - vector addrList = sendTo.getKeys(); - BOOST_FOREACH(const string& name_, addrList) { - CBitcoinAddress address(name_); - if (!address.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, string("Invalid Bitcoin address: ")+name_); - - if (setAddress.count(address)) - throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated address: ")+name_); - setAddress.insert(address); - - CScript scriptPubKey = GetScriptForDestination(address.Get()); - CAmount nAmount = AmountFromValue(sendTo[name_]); - - CTxOut out(nAmount, scriptPubKey); - rawTx.vout.push_back(out); - } - */ - return EncodeHexTx(rawTx); } @@ -575,57 +600,15 @@ UniValue decoderawtransactioncc(const UniValue& params, bool fHelp) return result; } -UniValue decodescriptcc(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "decodescript \"hex\"\n" - "\nDecode a hex-encoded script.\n" - "\nArguments:\n" - "1. \"hex\" (string) the hex encoded script\n" - "\nResult:\n" - "{\n" - " \"asm\":\"asm\", (string) Script public key\n" - " \"hex\":\"hex\", (string) hex encoded public key\n" - " \"type\":\"type\", (string) The output type\n" - " \"reqSigs\": n, (numeric) The required signatures\n" - " \"addresses\": [ (json array of string)\n" - " \"address\" (string) bitcoin address\n" - " ,...\n" - " ],\n" - " \"p2sh\",\"address\" (string) script address\n" - "}\n" - "\nExamples:\n" - + HelpExampleCli("decodescript", "\"hexstring\"") - + HelpExampleRpc("decodescript", "\"hexstring\"") - ); - - LOCK(cs_main); - RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)); - - UniValue r(UniValue::VOBJ); - CScript script; - if (params[0].get_str().size() > 0){ - vector scriptData(ParseHexV(params[0], "argument")); - script = CScript(scriptData.begin(), scriptData.end()); - } else { - // Empty scripts are valid - } - ScriptPubKeyToJSON(script, r, false); - - r.push_back(Pair("p2sh", CBitcoinAddress(CScriptID(script)).ToString())); - return r; -} - /** Pushes a JSON object for script verification or signing errors to vErrorsRet. */ static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std::string& strMessage) {} UniValue signrawtransactioncc(const UniValue& params, bool fHelp) { - if (fHelp || params.size() < 1 || params.size() > 4) + if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( - "signrawtransactioncc \"hexstring\" ( [{\"txid\":\"id\",\"vout\":n,\"scriptPubKey\":\"hex\",\"redeemScript\":\"hex\"},...] [\"privatekey1\",...] sighashtype )\n" + "signrawtransactioncc \"hexstring\" ( [\"privatekey1\",...] sighashtype )\n" "\nSign cryptocondition inputs for raw transaction (serialized, hex-encoded).\n" "The second optional argument (may be null) is an array of previous transaction outputs that\n" "this transaction depends on but may not yet be in the block chain.\n" @@ -637,17 +620,7 @@ UniValue signrawtransactioncc(const UniValue& params, bool fHelp) "\nArguments:\n" "1. \"hexstring\" (string, required) The transaction hex string\n" - /* "2. \"prevtxs\" (string, optional) An json array of previous dependent transaction outputs\n" - " [ (json array of json objects, or 'null' if none provided)\n" - " {\n" - " \"txid\":\"id\", (string, required) The transaction id\n" - " \"vout\":n, (numeric, required) The output number\n" - " \"scriptPubKey\": \"hex\", (string, required) script key\n" - " \"redeemScript\": \"hex\" (string, required for P2SH) redeem script\n" - " }\n" - " ,...\n" - " ]\n" */ - "3. \"privatekeys\" (string, optional) A json array of base58-encoded private keys for signing\n" + "2. \"privatekeys\" (string, optional) A json array of base58-encoded private keys for signing\n" " [ (json array of strings, or 'null' if none provided)\n" " \"privatekey\" (string) private key in base58-encoding\n" " ,...\n" @@ -709,24 +682,6 @@ UniValue signrawtransactioncc(const UniValue& params, bool fHelp) // starts as a clone of the rawtx: CMutableTransaction mergedTx(txVariants[0]); - // Fetch previous transactions (inputs): - CCoinsView viewDummy; - CCoinsViewCache view(&viewDummy); - { - LOCK(mempool.cs); - CCoinsViewCache &viewChain = *pcoinsTip; - CCoinsViewMemPool viewMempool(&viewChain, mempool); - view.SetBackend(viewMempool); // temporarily switch cache backend to db+mempool view - - BOOST_FOREACH(const CTxIn& txin, mergedTx.vin) { - const uint256& prevHash = txin.prevout.hash; - CCoins coins; - view.AccessCoins(prevHash); // this is certainly allowed to fail - } - - view.SetBackend(viewDummy); // switch back to avoid locking mempool for too long - } - bool fGivenKeys = false; CBasicKeyStore tempKeystore; if (params.size() > 2 && !params[2].isNull()) { @@ -749,57 +704,6 @@ UniValue signrawtransactioncc(const UniValue& params, bool fHelp) EnsureWalletIsUnlocked(); #endif - // Add previous txouts given in the RPC call: - /* - if (params.size() > 1 && !params[1].isNull()) { - UniValue prevTxs = params[1].get_array(); - for (size_t idx = 0; idx < prevTxs.size(); idx++) { - const UniValue& p = prevTxs[idx]; - if (!p.isObject()) - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "expected object with {\"txid'\",\"vout\",\"scriptPubKey\"}"); - - UniValue prevOut = p.get_obj(); - - RPCTypeCheckObj(prevOut, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM)("scriptPubKey", UniValue::VSTR)); - - uint256 txid = ParseHashO(prevOut, "txid"); - - int nOut = find_value(prevOut, "vout").get_int(); - if (nOut < 0) - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "vout must be positive"); - - vector pkData(ParseHexO(prevOut, "scriptPubKey")); - CScript scriptPubKey(pkData.begin(), pkData.end()); - - { - CCoinsModifier coins = view.ModifyCoins(txid); - if (coins->IsAvailable(nOut) && coins->vout[nOut].scriptPubKey != scriptPubKey) { - string err("Previous output scriptPubKey mismatch:\n"); - err = err + coins->vout[nOut].scriptPubKey.ToString() + "\nvs:\n"+ - scriptPubKey.ToString(); - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, err); - } - if ((unsigned int)nOut >= coins->vout.size()) - coins->vout.resize(nOut+1); - coins->vout[nOut].scriptPubKey = scriptPubKey; - coins->vout[nOut].nValue = 0; // we don't know the actual output value - } - - // if redeemScript given and not using the local wallet (private keys - // given), add redeemScript to the tempKeystore so it can be signed: - if (fGivenKeys && scriptPubKey.IsPayToScriptHash()) { - RPCTypeCheckObj(prevOut, boost::assign::map_list_of("txid", UniValue::VSTR)("vout", UniValue::VNUM)("scriptPubKey", UniValue::VSTR)("redeemScript",UniValue::VSTR)); - UniValue v = find_value(prevOut, "redeemScript"); - if (!v.isNull()) { - vector rsData(ParseHexV(v, "redeemScript")); - CScript redeemScript(rsData.begin(), rsData.end()); - tempKeystore.AddCScript(redeemScript); - } - } - } - } - */ - #ifdef ENABLE_WALLET const CKeyStore& keystore = ((fGivenKeys || !pwalletMain) ? tempKeystore : *pwalletMain); #else @@ -834,6 +738,18 @@ UniValue signrawtransactioncc(const UniValue& params, bool fHelp) // Sign what we can: for (unsigned int i = 0; i < mergedTx.vin.size(); i++) { CTxIn& txin = mergedTx.vin[i]; + + CC *cond; + + printf("Go\n"); + if (cond = ConditionFromUnsignedInputScript(txin.scriptSig)) { + printf("Found unsigned\n"); + continue; + } + printf("No luck\n"); + + /* + * Replace all this with detection of cryptoconditions spec and signing with each privkey const CCoins* coins = view.AccessCoins(txin.prevout.hash); if (coins == NULL || !coins->IsAvailable(txin.prevout.n)) { TxInErrorToJSON(txin, vErrors, "Input not found or already spent"); @@ -854,6 +770,7 @@ UniValue signrawtransactioncc(const UniValue& params, bool fHelp) if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i), &serror)) { TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror)); } + */ } bool fComplete = vErrors.empty(); @@ -867,13 +784,14 @@ UniValue signrawtransactioncc(const UniValue& params, bool fHelp) return result; } + UniValue sendrawtransactioncc(const UniValue& params, bool fHelp) { if (fHelp || params.size() < 1 || params.size() > 2) throw runtime_error( "sendrawtransaction \"hexstring\" ( allowhighfees )\n" "\nSubmits raw transaction (serialized, hex-encoded) to local node and network.\n" - "\nAlso see createrawtransaction and signrawtransaction calls.\n" + "\nAlso see createrawtransactioncc and signrawtransactioncc calls.\n" "\nArguments:\n" "1. \"hexstring\" (string, required) The hex string of the raw transaction)\n" "2. allowhighfees (boolean, optional, default=false) Allow high fees\n" @@ -881,7 +799,7 @@ UniValue sendrawtransactioncc(const UniValue& params, bool fHelp) "\"hex\" (string) The transaction hash in hex\n" "\nExamples:\n" "\nCreate a transaction\n" - + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") + + + HelpExampleCli("createrawtransactioncc", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") + "Sign the transaction, and get back the hex\n" + HelpExampleCli("signrawtransaction", "\"myhex\"") + "\nSend the transaction (signed hex)\n" From 63d3e4aab1b310b1658dafa648d50a96da6745bd Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Tue, 23 Jan 2018 14:12:43 -0300 Subject: [PATCH 013/339] add isFulfulled to cryptoconditions --- src/cryptoconditions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cryptoconditions b/src/cryptoconditions index a59c22dcf..6e34f2e32 160000 --- a/src/cryptoconditions +++ b/src/cryptoconditions @@ -1 +1 @@ -Subproject commit a59c22dcf9a67be5f11f88ff89bbd9cb40fd22c0 +Subproject commit 6e34f2e325516a08ea11e847f661bf6a8e524d38 From 6e821110fdfa03f3deb051b5146142bd46d8c60e Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Tue, 6 Feb 2018 18:37:08 -0300 Subject: [PATCH 014/339] auxiliary cryptoconditions --- src/cryptoconditions | 2 +- src/komodo_cryptoconditions.h | 8 ++++++++ src/script/interpreter.cpp | 5 +++-- 3 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 src/komodo_cryptoconditions.h diff --git a/src/cryptoconditions b/src/cryptoconditions index 6e34f2e32..89325dc29 160000 --- a/src/cryptoconditions +++ b/src/cryptoconditions @@ -1 +1 @@ -Subproject commit 6e34f2e325516a08ea11e847f661bf6a8e524d38 +Subproject commit 89325dc29391f473da75503105a4946f2f96fb76 diff --git a/src/komodo_cryptoconditions.h b/src/komodo_cryptoconditions.h new file mode 100644 index 000000000..d5e643c91 --- /dev/null +++ b/src/komodo_cryptoconditions.h @@ -0,0 +1,8 @@ + + +/* + * Method stub for aux conditions. Unimplemented, thus fails if an aux condition is encountered. + */ +int komodoCCAux(CC *cond, void *context) { + return 0; +} diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index f65581068..94727cbca 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -14,6 +14,7 @@ #include "script/script.h" #include "uint256.h" #include "cryptoconditions/include/cryptoconditions.h" +#include "komodo_cryptoconditions.h" using namespace std; @@ -963,8 +964,8 @@ bool EvalScript(vector >& stack, const CScript& script, un // TODO: Should nHashType be hardcoded? // Other types use the last byte of the signature char *msg = (char*) checker.GetMessage(script, SIGHASH_ALL).begin(); -; - bool fSuccess = cc_verify(cond, msg, 32, condBin, vchCondition.size()); + + bool fSuccess = cc_verify(cond, msg, 32, condBin, vchCondition.size(), komodoCCAux, NULL); popstack(stack); popstack(stack); From a01d0f56724dcfe0345637c4209cbfedb9ba2b34 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Fri, 16 Feb 2018 14:24:38 -0300 Subject: [PATCH 015/339] remove rpc crypto conditions --- src/Makefile.am | 1 - src/rpcclient.cpp | 4 - src/rpccryptoconditions.cpp | 848 ------------------------------------ src/rpcserver.cpp | 2 - src/rpcserver.h | 3 - 5 files changed, 858 deletions(-) delete mode 100644 src/rpccryptoconditions.cpp diff --git a/src/Makefile.am b/src/Makefile.am index 919c6fc89..815d75d4c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -238,7 +238,6 @@ libbitcoin_server_a_SOURCES = \ rpcmisc.cpp \ rpcnet.cpp \ rpcrawtransaction.cpp \ - rpccryptoconditions.cpp \ rpcserver.cpp \ script/sigcache.cpp \ timedata.cpp \ diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index 2378e3ca0..545d75b6f 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -75,12 +75,8 @@ static const CRPCConvertParam vRPCConvertParams[] = { "getrawtransaction", 1 }, { "createrawtransaction", 0 }, { "createrawtransaction", 1 }, - { "createrawtransactioncc", 0 }, - { "createrawtransactioncc", 1 }, { "signrawtransaction", 1 }, { "signrawtransaction", 2 }, - { "signrawtransactioncc", 1 }, - { "signrawtransactioncc", 2 }, { "sendrawtransaction", 1 }, { "fundrawtransaction", 1 }, { "gettxout", 1 }, diff --git a/src/rpccryptoconditions.cpp b/src/rpccryptoconditions.cpp deleted file mode 100644 index 18d6774f0..000000000 --- a/src/rpccryptoconditions.cpp +++ /dev/null @@ -1,848 +0,0 @@ -// Copyright (c) 2010 Satoshi Nakamoto -// Copyright (c) 2009-2015 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 "base58.h" -#include "consensus/validation.h" -#include "core_io.h" -#include "init.h" -#include "keystore.h" -#include "main.h" -#include "merkleblock.h" -#include "net.h" -#include "primitives/transaction.h" -#include "rpcserver.h" -#include "script/script.h" -#include "script/script_error.h" -#include "script/sign.h" -#include "script/standard.h" -#include "uint256.h" -#include "cryptoconditions/include/cryptoconditions.h" -#ifdef ENABLE_WALLET -#include "wallet/wallet.h" -#endif - -#include - -#include - -#include - -using namespace std; - -void ScriptPubKeyToJSON(const CScript& scriptPubKey, UniValue& out, bool fIncludeHex); - - -UniValue TxJoinSplitToJSONcc(const CTransaction& tx) { - UniValue vjoinsplit(UniValue::VARR); - for (unsigned int i = 0; i < tx.vjoinsplit.size(); i++) { - const JSDescription& jsdescription = tx.vjoinsplit[i]; - UniValue joinsplit(UniValue::VOBJ); - - joinsplit.push_back(Pair("vpub_old", ValueFromAmount(jsdescription.vpub_old))); - joinsplit.push_back(Pair("vpub_new", ValueFromAmount(jsdescription.vpub_new))); - - joinsplit.push_back(Pair("anchor", jsdescription.anchor.GetHex())); - - { - UniValue nullifiers(UniValue::VARR); - BOOST_FOREACH(const uint256 nf, jsdescription.nullifiers) { - nullifiers.push_back(nf.GetHex()); - } - joinsplit.push_back(Pair("nullifiers", nullifiers)); - } - - { - UniValue commitments(UniValue::VARR); - BOOST_FOREACH(const uint256 commitment, jsdescription.commitments) { - commitments.push_back(commitment.GetHex()); - } - joinsplit.push_back(Pair("commitments", commitments)); - } - - joinsplit.push_back(Pair("onetimePubKey", jsdescription.ephemeralKey.GetHex())); - joinsplit.push_back(Pair("randomSeed", jsdescription.randomSeed.GetHex())); - - { - UniValue macs(UniValue::VARR); - BOOST_FOREACH(const uint256 mac, jsdescription.macs) { - macs.push_back(mac.GetHex()); - } - joinsplit.push_back(Pair("macs", macs)); - } - - CDataStream ssProof(SER_NETWORK, PROTOCOL_VERSION); - ssProof << jsdescription.proof; - joinsplit.push_back(Pair("proof", HexStr(ssProof.begin(), ssProof.end()))); - - { - UniValue ciphertexts(UniValue::VARR); - for (const ZCNoteEncryption::Ciphertext ct : jsdescription.ciphertexts) { - ciphertexts.push_back(HexStr(ct.begin(), ct.end())); - } - joinsplit.push_back(Pair("ciphertexts", ciphertexts)); - } - - vjoinsplit.push_back(joinsplit); - } - return vjoinsplit; -} - -uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime); - -void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue& entry); - - -UniValue getrawtransactioncc(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( - "getrawtransaction \"txid\" ( verbose )\n" - "\nNOTE: By default this function only works sometimes. This is when the tx is in the mempool\n" - "or there is an unspent output in the utxo for this transaction. To make it always work,\n" - "you need to maintain a transaction index, using the -txindex command line option.\n" - "\nReturn the raw transaction data.\n" - "\nIf verbose=0, returns a string that is serialized, hex-encoded data for 'txid'.\n" - "If verbose is non-zero, returns an Object with information about 'txid'.\n" - - "\nArguments:\n" - "1. \"txid\" (string, required) The transaction id\n" - "2. verbose (numeric, optional, default=0) If 0, return a string, other return a json object\n" - - "\nResult (if verbose is not set or set to 0):\n" - "\"data\" (string) The serialized, hex-encoded data for 'txid'\n" - - "\nResult (if verbose > 0):\n" - "{\n" - " \"hex\" : \"data\", (string) The serialized, hex-encoded data for 'txid'\n" - " \"txid\" : \"id\", (string) The transaction id (same as provided)\n" - " \"version\" : n, (numeric) The version\n" - " \"locktime\" : ttt, (numeric) The lock time\n" - " \"vin\" : [ (array of json objects)\n" - " {\n" - " \"txid\": \"id\", (string) The transaction id\n" - " \"vout\": n, (numeric) \n" - " \"scriptSig\": { (json object) The script\n" - " \"asm\": \"asm\", (string) asm\n" - " \"hex\": \"hex\" (string) hex\n" - " },\n" - " \"sequence\": n (numeric) The script sequence number\n" - " }\n" - " ,...\n" - " ],\n" - " \"vout\" : [ (array of json objects)\n" - " {\n" - " \"value\" : x.xxx, (numeric) The value in btc\n" - " \"n\" : n, (numeric) index\n" - " \"scriptPubKey\" : { (json object)\n" - " \"asm\" : \"asm\", (string) the asm\n" - " \"hex\" : \"hex\", (string) the hex\n" - " \"reqSigs\" : n, (numeric) The required sigs\n" - " \"type\" : \"pubkeyhash\", (string) The type, eg 'pubkeyhash'\n" - " \"addresses\" : [ (json array of string)\n" - " \"bitcoinaddress\" (string) bitcoin address\n" - " ,...\n" - " ]\n" - " }\n" - " }\n" - " ,...\n" - " ],\n" - " \"vjoinsplit\" : [ (array of json objects, only for version >= 2)\n" - " {\n" - " \"vpub_old\" : x.xxx, (numeric) public input value in ZEC\n" - " \"vpub_new\" : x.xxx, (numeric) public output value in ZEC\n" - " \"anchor\" : \"hex\", (string) the anchor\n" - " \"nullifiers\" : [ (json array of string)\n" - " \"hex\" (string) input note nullifier\n" - " ,...\n" - " ],\n" - " \"commitments\" : [ (json array of string)\n" - " \"hex\" (string) output note commitment\n" - " ,...\n" - " ],\n" - " \"onetimePubKey\" : \"hex\", (string) the onetime public key used to encrypt the ciphertexts\n" - " \"randomSeed\" : \"hex\", (string) the random seed\n" - " \"macs\" : [ (json array of string)\n" - " \"hex\" (string) input note MAC\n" - " ,...\n" - " ],\n" - " \"proof\" : \"hex\", (string) the zero-knowledge proof\n" - " \"ciphertexts\" : [ (json array of string)\n" - " \"hex\" (string) output note ciphertext\n" - " ,...\n" - " ]\n" - " }\n" - " ,...\n" - " ],\n" - " \"blockhash\" : \"hash\", (string) the block hash\n" - " \"confirmations\" : n, (numeric) The confirmations\n" - " \"time\" : ttt, (numeric) The transaction time in seconds since epoch (Jan 1 1970 GMT)\n" - " \"blocktime\" : ttt (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n" - "}\n" - - "\nExamples:\n" - + HelpExampleCli("getrawtransaction", "\"mytxid\"") - + HelpExampleCli("getrawtransaction", "\"mytxid\" 1") - + HelpExampleRpc("getrawtransaction", "\"mytxid\", 1") - ); - - LOCK(cs_main); - - uint256 hash = ParseHashV(params[0], "parameter 1"); - - bool fVerbose = false; - if (params.size() > 1) - fVerbose = (params[1].get_int() != 0); - - CTransaction tx; - uint256 hashBlock; - if (!GetTransaction(hash, tx, hashBlock, true)) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No information available about transaction"); - - string strHex = EncodeHexTx(tx); - - if (!fVerbose) - return strHex; - - UniValue result(UniValue::VOBJ); - result.push_back(Pair("hex", strHex)); - TxToJSON(tx, hashBlock, result); - return result; -} - -int32_t gettxout_scriptPubKeycc(uint8_t *scriptPubKey,int32_t maxsize,uint256 txid,int32_t n) -{ - int32_t i,m; uint8_t *ptr; - LOCK(cs_main); - /*CCoins coins; - for (iter=0; iter<2; iter++) - { - if ( iter == 0 ) - { - LOCK(mempool.cs); - CCoinsViewMemPool view(pcoinsTip,mempool); - if ( view.GetCoins(txid,coins) == 0 ) - { - //fprintf(stderr,"cant get view\n"); - continue; - } - mempool.pruneSpent(txid, coins); // TODO: this should be done by the CCoinsViewMemPool - } - else if ( pcoinsTip->GetCoins(txid,coins) == 0 ) - { - //fprintf(stderr,"cant get pcoinsTip->GetCoins\n"); - continue; - } - if ( n < 0 || (unsigned int)n >= coins.vout.size() || coins.vout[n].IsNull() ) - { - fprintf(stderr,"iter.%d n.%d vs voutsize.%d\n",iter,n,(int32_t)coins.vout.size()); - continue; - } - ptr = (uint8_t *)coins.vout[n].scriptPubKey.data(); - m = coins.vout[n].scriptPubKey.size(); - for (i=0; i setTxids; - uint256 oneTxid; - UniValue txids = params[0].get_array(); - for (size_t idx = 0; idx < txids.size(); idx++) { - const UniValue& txid = txids[idx]; - if (txid.get_str().length() != 64 || !IsHex(txid.get_str())) - throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid txid ")+txid.get_str()); - uint256 hash(uint256S(txid.get_str())); - if (setTxids.count(hash)) - throw JSONRPCError(RPC_INVALID_PARAMETER, string("Invalid parameter, duplicated txid: ")+txid.get_str()); - setTxids.insert(hash); - oneTxid = hash; - } - - LOCK(cs_main); - - CBlockIndex* pblockindex = NULL; - - uint256 hashBlock; - if (params.size() > 1) - { - hashBlock = uint256S(params[1].get_str()); - if (!mapBlockIndex.count(hashBlock)) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found"); - pblockindex = mapBlockIndex[hashBlock]; - } else { - CCoins coins; - if (pcoinsTip->GetCoins(oneTxid, coins) && coins.nHeight > 0 && coins.nHeight <= chainActive.Height()) - pblockindex = chainActive[coins.nHeight]; - } - - if (pblockindex == NULL) - { - CTransaction tx; - if (!GetTransaction(oneTxid, tx, hashBlock, false) || hashBlock.IsNull()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block"); - if (!mapBlockIndex.count(hashBlock)) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction index corrupt"); - pblockindex = mapBlockIndex[hashBlock]; - } - - CBlock block; - if(!ReadBlockFromDisk(block, pblockindex)) - throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); - - unsigned int ntxFound = 0; - BOOST_FOREACH(const CTransaction&tx, block.vtx) - if (setTxids.count(tx.GetHash())) - ntxFound++; - if (ntxFound != setTxids.size()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "(Not all) transactions not found in specified block"); - - CDataStream ssMB(SER_NETWORK, PROTOCOL_VERSION); - CMerkleBlock mb(block, setTxids); - ssMB << mb; - std::string strHex = HexStr(ssMB.begin(), ssMB.end()); - return strHex; -} - -UniValue verifytxoutproofcc(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "verifytxoutproof \"proof\"\n" - "\nVerifies that a proof points to a transaction in a block, returning the transaction it commits to\n" - "and throwing an RPC error if the block is not in our best chain\n" - "\nArguments:\n" - "1. \"proof\" (string, required) The hex-encoded proof generated by gettxoutproof\n" - "\nResult:\n" - "[\"txid\"] (array, strings) The txid(s) which the proof commits to, or empty array if the proof is invalid\n" - ); - - CDataStream ssMB(ParseHexV(params[0], "proof"), SER_NETWORK, PROTOCOL_VERSION); - CMerkleBlock merkleBlock; - ssMB >> merkleBlock; - - UniValue res(UniValue::VARR); - - vector vMatch; - if (merkleBlock.txn.ExtractMatches(vMatch) != merkleBlock.header.hashMerkleRoot) - return res; - - LOCK(cs_main); - - if (!mapBlockIndex.count(merkleBlock.header.GetHash()) || !chainActive.Contains(mapBlockIndex[merkleBlock.header.GetHash()])) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain"); - - BOOST_FOREACH(const uint256& hash, vMatch) - res.push_back(hash.GetHex()); - return res; -} - - -CC *ConditionFromString(std::string encoded) { - char *err = new char[1000]; - CC *cond = cc_conditionFromJSONString(encoded.c_str(), err); - if (NULL == cond) - throw JSONRPCError(RPC_INVALID_PARAMETER, err); -} - - -CC *ConditionFromCharVector(vector& vch) { - return ConditionFromString(std::string(vch.begin(), vch.end())); -} - - -CC *ConditionFromUnsignedInputScript(const CScript& script) -{ - opcodetype op; - CScript::const_iterator it = script.begin(); - - vector vch; - if (script.GetOp2(it, op, &vch)) { - if (vch.at(0) == '{') { - return ConditionFromCharVector(vch); - } - } - return NULL; -} - - -CC *ConditionFromValue(UniValue value) { - std::string conditionEncoded = value.write(); - // TODO: Is null? - return ConditionFromString(conditionEncoded); -} - -UniValue createrawtransactioncc(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 2) - throw runtime_error( - "createrawtransactioncc [{\"txid\":\"id\",\"vout\":n,\"fulfillment\":{...}},...] {\"address\":amount,...}\n" - "\nCreate a transaction spending the given inputs and sending to the given addresses.\n" - "Returns hex-encoded raw transaction.\n" - "Note that the transaction's inputs are not signed, and\n" - "it is not stored in the wallet or transmitted to the network.\n" - - "\nArguments:\n" - "1. \"inputs\" (string, required) A json array of json objects\n" - " [\n" - " {\n" - " \"txid\":\"id\", (string, required) The transaction id\n" - " \"vout\":n, (numeric, required) The output number\n" - " \"fulfillment\":{...} (object, required) The JSON encoded cryptocondition fulfillment for the previous transaction's output\n" - " }\n" - " ,...\n" - " ]\n" - "2. \"outputs\" (string, required) a json array with addresses as keys and amounts as values\n" - " {\n" - " \"condition\":\"{...}\" (object, required) The JSON encoded condition\n" - " \"amount\":n, (numeric, required) The coin amount in satoshis\n" - " }\n" - - "\nResult:\n" - "\"transaction\" (string) hex string of the transaction\n" - - // "\nExamples\n" - // + HelpExampleCli("createrawtransactioncc", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"{\\\"address\\\":0.01}\"") - // + HelpExampleRpc("createrawtransactioncc", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"address\\\":0.01}\"") - ); - - LOCK(cs_main); - //RPCTypeCheck(params, boost::assign::list_of(UniValue::VARR)(UniValue::VARR)); - - UniValue inputs = params[0].get_array(); - UniValue outputs = params[1].get_array(); - - CMutableTransaction rawTx; - - for (size_t idx = 0; idx < inputs.size(); idx++) { - const UniValue& input = inputs[idx]; - const UniValue& o = input.get_obj(); - - uint256 txid = ParseHashO(o, "txid"); - - const UniValue& vout_v = find_value(o, "vout"); - if (!vout_v.isNum()) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key"); - int nOutput = vout_v.get_int(); - if (nOutput < 0) - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive"); - - const UniValue& ffill_v = find_value(input, "fulfillment"); - if (!ffill_v.isObject()) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "\"fulfillment\" missing or not an object"); - } - const std::string ffillEncoded = ffill_v.write(); - - // Validate the fulfillment - CC *cond = ConditionFromString(ffillEncoded); - if (cond == NULL) { - throw JSONRPCError(RPC_INVALID_PARAMETER, "\"fulfillment\" not a valid JSON encoded crypto condition"); - } - cc_free(cond); - - CScript inputScript; - const std::vector ffill(ffillEncoded.c_str(), ffillEncoded.c_str() + ffillEncoded.size()); - inputScript << ffill; - - CTxIn in(COutPoint(txid, nOutput), inputScript); - rawTx.vin.push_back(in); - } - - for (size_t idx = 0; idx < outputs.size(); idx++) { - const UniValue& output = outputs[idx].get_obj(); - - // This does not need to be fulfilled, we just want the condition binary - CC *cond = ConditionFromValue(find_value(output, "condition")); - - char *condBin = new char[1000]; - size_t binLength = cc_conditionBinary(cond, condBin); - const std::vector condVec(condBin, condBin + binLength); - - CScript redeemScript; - redeemScript << condVec << OP_CHECKCRYPTOCONDITIONVERIFY; - - CAmount nAmount = AmountFromValue(find_value(output, "amount")); - - CTxOut out(nAmount, redeemScript); - rawTx.vout.push_back(out); - } - - return EncodeHexTx(rawTx); -} - -UniValue decoderawtransactioncc(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() != 1) - throw runtime_error( - "decoderawtransaction \"hexstring\"\n" - "\nReturn a JSON object representing the serialized, hex-encoded transaction.\n" - - "\nArguments:\n" - "1. \"hex\" (string, required) The transaction hex string\n" - - "\nResult:\n" - "{\n" - " \"txid\" : \"id\", (string) The transaction id\n" - " \"version\" : n, (numeric) The version\n" - " \"locktime\" : ttt, (numeric) The lock time\n" - " \"vin\" : [ (array of json objects)\n" - " {\n" - " \"txid\": \"id\", (string) The transaction id\n" - " \"vout\": n, (numeric) The output number\n" - " \"scriptSig\": { (json object) The script\n" - " \"asm\": \"asm\", (string) asm\n" - " \"hex\": \"hex\" (string) hex\n" - " },\n" - " \"sequence\": n (numeric) The script sequence number\n" - " }\n" - " ,...\n" - " ],\n" - " \"vout\" : [ (array of json objects)\n" - " {\n" - " \"value\" : x.xxx, (numeric) The value in btc\n" - " \"n\" : n, (numeric) index\n" - " \"scriptPubKey\" : { (json object)\n" - " \"asm\" : \"asm\", (string) the asm\n" - " \"hex\" : \"hex\", (string) the hex\n" - " \"reqSigs\" : n, (numeric) The required sigs\n" - " \"type\" : \"pubkeyhash\", (string) The type, eg 'pubkeyhash'\n" - " \"addresses\" : [ (json array of string)\n" - " \"12tvKAXCxZjSmdNbao16dKXC8tRWfcF5oc\" (string) bitcoin address\n" - " ,...\n" - " ]\n" - " }\n" - " }\n" - " ,...\n" - " ],\n" - " \"vjoinsplit\" : [ (array of json objects, only for version >= 2)\n" - " {\n" - " \"vpub_old\" : x.xxx, (numeric) public input value in ZEC\n" - " \"vpub_new\" : x.xxx, (numeric) public output value in ZEC\n" - " \"anchor\" : \"hex\", (string) the anchor\n" - " \"nullifiers\" : [ (json array of string)\n" - " \"hex\" (string) input note nullifier\n" - " ,...\n" - " ],\n" - " \"commitments\" : [ (json array of string)\n" - " \"hex\" (string) output note commitment\n" - " ,...\n" - " ],\n" - " \"onetimePubKey\" : \"hex\", (string) the onetime public key used to encrypt the ciphertexts\n" - " \"randomSeed\" : \"hex\", (string) the random seed\n" - " \"macs\" : [ (json array of string)\n" - " \"hex\" (string) input note MAC\n" - " ,...\n" - " ],\n" - " \"proof\" : \"hex\", (string) the zero-knowledge proof\n" - " \"ciphertexts\" : [ (json array of string)\n" - " \"hex\" (string) output note ciphertext\n" - " ,...\n" - " ]\n" - " }\n" - " ,...\n" - " ],\n" - "}\n" - - "\nExamples:\n" - + HelpExampleCli("decoderawtransaction", "\"hexstring\"") - + HelpExampleRpc("decoderawtransaction", "\"hexstring\"") - ); - - LOCK(cs_main); - RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)); - - CTransaction tx; - - if (!DecodeHexTx(tx, params[0].get_str())) - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); - - UniValue result(UniValue::VOBJ); - TxToJSON(tx, uint256(), result); - - return result; -} - -/** Pushes a JSON object for script verification or signing errors to vErrorsRet. */ -static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std::string& strMessage) {} - - -UniValue signrawtransactioncc(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( - "signrawtransactioncc \"hexstring\" ( [\"privatekey1\",...] sighashtype )\n" - "\nSign cryptocondition inputs for raw transaction (serialized, hex-encoded).\n" - "The second optional argument (may be null) is an array of previous transaction outputs that\n" - "this transaction depends on but may not yet be in the block chain.\n" - "The third optional argument (may be null) is an array of base58-encoded private\n" - "keys that, if given, will be the only keys used to sign the transaction.\n" -#ifdef ENABLE_WALLET - + HelpRequiringPassphrase() + "\n" -#endif - - "\nArguments:\n" - "1. \"hexstring\" (string, required) The transaction hex string\n" - "2. \"privatekeys\" (string, optional) A json array of base58-encoded private keys for signing\n" - " [ (json array of strings, or 'null' if none provided)\n" - " \"privatekey\" (string) private key in base58-encoding\n" - " ,...\n" - " ]\n" - /* "4. \"sighashtype\" (string, optional, default=ALL) The signature hash type. Must be one of\n" - " \"ALL\"\n" - " \"NONE\"\n" - " \"SINGLE\"\n" - " \"ALL|ANYONECANPAY\"\n" - " \"NONE|ANYONECANPAY\"\n" - " \"SINGLE|ANYONECANPAY\"\n" */ - - "\nResult:\n" - "{\n" - " \"hex\" : \"value\", (string) The hex-encoded raw transaction with signature(s)\n" - " \"complete\" : true|false, (boolean) If the transaction has a complete set of signatures\n" - " \"errors\" : [ (json array of objects) Script verification errors (if there are any)\n" - " {\n" - " \"txid\" : \"hash\", (string) The hash of the referenced, previous transaction\n" - " \"vout\" : n, (numeric) The index of the output to spent and used as input\n" - " \"scriptSig\" : \"hex\", (string) The hex-encoded signature script\n" - " \"sequence\" : n, (numeric) Script sequence number\n" - " \"error\" : \"text\" (string) Verification or signing error related to the input\n" - " }\n" - " ,...\n" - " ]\n" - "}\n" - - "\nExamples:\n" - + HelpExampleCli("signrawtransactioncc", "\"myhex\"") - + HelpExampleRpc("signrawtransactioncc", "\"myhex\"") - ); - -#ifdef ENABLE_WALLET - LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL); -#else - LOCK(cs_main); -#endif - RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VARR)(UniValue::VARR)(UniValue::VSTR), true); - - vector txData(ParseHexV(params[0], "argument 1")); - CDataStream ssData(txData, SER_NETWORK, PROTOCOL_VERSION); - vector txVariants; - while (!ssData.empty()) { - //try { - CMutableTransaction tx; - ssData >> tx; - txVariants.push_back(tx); - //} - //catch (const std::exception&) { - //throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); - //} - } - - if (txVariants.empty()) - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Missing transaction"); - - // mergedTx will end up with all the signatures; it - // starts as a clone of the rawtx: - CMutableTransaction mergedTx(txVariants[0]); - - bool fGivenKeys = false; - CBasicKeyStore tempKeystore; - if (params.size() > 2 && !params[2].isNull()) { - fGivenKeys = true; - UniValue keys = params[2].get_array(); - for (size_t idx = 0; idx < keys.size(); idx++) { - UniValue k = keys[idx]; - CBitcoinSecret vchSecret; - bool fGood = vchSecret.SetString(k.get_str()); - if (!fGood) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key"); - CKey key = vchSecret.GetKey(); - if (!key.IsValid()) - throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Private key outside allowed range"); - tempKeystore.AddKey(key); - } - } -#ifdef ENABLE_WALLET - else if (pwalletMain) - EnsureWalletIsUnlocked(); -#endif - -#ifdef ENABLE_WALLET - const CKeyStore& keystore = ((fGivenKeys || !pwalletMain) ? tempKeystore : *pwalletMain); -#else - const CKeyStore& keystore = tempKeystore; -#endif - - int nHashType = SIGHASH_ALL; - /* - if (params.size() > 3 && !params[3].isNull()) { - static map mapSigHashValues = - boost::assign::map_list_of - (string("ALL"), int(SIGHASH_ALL)) - (string("ALL|ANYONECANPAY"), int(SIGHASH_ALL|SIGHASH_ANYONECANPAY)) - (string("NONE"), int(SIGHASH_NONE)) - (string("NONE|ANYONECANPAY"), int(SIGHASH_NONE|SIGHASH_ANYONECANPAY)) - (string("SINGLE"), int(SIGHASH_SINGLE)) - (string("SINGLE|ANYONECANPAY"), int(SIGHASH_SINGLE|SIGHASH_ANYONECANPAY)) - ; - string strHashType = params[3].get_str(); - if (mapSigHashValues.count(strHashType)) - nHashType = mapSigHashValues[strHashType]; - else - throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid sighash param"); - } - */ - - bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE); - - // Script verification errors - UniValue vErrors(UniValue::VARR); - - // Sign what we can: - for (unsigned int i = 0; i < mergedTx.vin.size(); i++) { - CTxIn& txin = mergedTx.vin[i]; - - CC *cond; - - printf("Go\n"); - if (cond = ConditionFromUnsignedInputScript(txin.scriptSig)) { - printf("Found unsigned\n"); - continue; - } - printf("No luck\n"); - - /* - * Replace all this with detection of cryptoconditions spec and signing with each privkey - const CCoins* coins = view.AccessCoins(txin.prevout.hash); - if (coins == NULL || !coins->IsAvailable(txin.prevout.n)) { - TxInErrorToJSON(txin, vErrors, "Input not found or already spent"); - continue; - } - const CScript& prevPubKey = coins->vout[txin.prevout.n].scriptPubKey; - - txin.scriptSig.clear(); - // Only sign SIGHASH_SINGLE if there's a corresponding output: - if (!fHashSingle || (i < mergedTx.vout.size())) - SignSignature(keystore, prevPubKey, mergedTx, i, nHashType); - - // ... and merge in other signatures: - BOOST_FOREACH(const CMutableTransaction& txv, txVariants) { - txin.scriptSig = CombineSignatures(prevPubKey, mergedTx, i, txin.scriptSig, txv.vin[i].scriptSig); - } - ScriptError serror = SCRIPT_ERR_OK; - if (!VerifyScript(txin.scriptSig, prevPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&mergedTx, i), &serror)) { - TxInErrorToJSON(txin, vErrors, ScriptErrorString(serror)); - } - */ - } - bool fComplete = vErrors.empty(); - - UniValue result(UniValue::VOBJ); - result.push_back(Pair("hex", EncodeHexTx(mergedTx))); - result.push_back(Pair("complete", fComplete)); - if (!vErrors.empty()) { - result.push_back(Pair("errors", vErrors)); - } - - return result; -} - - -UniValue sendrawtransactioncc(const UniValue& params, bool fHelp) -{ - if (fHelp || params.size() < 1 || params.size() > 2) - throw runtime_error( - "sendrawtransaction \"hexstring\" ( allowhighfees )\n" - "\nSubmits raw transaction (serialized, hex-encoded) to local node and network.\n" - "\nAlso see createrawtransactioncc and signrawtransactioncc calls.\n" - "\nArguments:\n" - "1. \"hexstring\" (string, required) The hex string of the raw transaction)\n" - "2. allowhighfees (boolean, optional, default=false) Allow high fees\n" - "\nResult:\n" - "\"hex\" (string) The transaction hash in hex\n" - "\nExamples:\n" - "\nCreate a transaction\n" - + HelpExampleCli("createrawtransactioncc", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") + - "Sign the transaction, and get back the hex\n" - + HelpExampleCli("signrawtransaction", "\"myhex\"") + - "\nSend the transaction (signed hex)\n" - + HelpExampleCli("sendrawtransaction", "\"signedhex\"") + - "\nAs a json rpc call\n" - + HelpExampleRpc("sendrawtransaction", "\"signedhex\"") - ); - - LOCK(cs_main); - RPCTypeCheck(params, boost::assign::list_of(UniValue::VSTR)(UniValue::VBOOL)); - - // parse hex string from parameter - CTransaction tx; - if (!DecodeHexTx(tx, params[0].get_str())) - throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); - uint256 hashTx = tx.GetHash(); - - bool fOverrideFees = false; - if (params.size() > 1) - fOverrideFees = params[1].get_bool(); - - CCoinsViewCache &view = *pcoinsTip; - const CCoins* existingCoins = view.AccessCoins(hashTx); - bool fHaveMempool = mempool.exists(hashTx); - bool fHaveChain = existingCoins && existingCoins->nHeight < 1000000000; - if (!fHaveMempool && !fHaveChain) { - // push to local node and sync with wallets - CValidationState state; - bool fMissingInputs; - if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, !fOverrideFees)) { - if (state.IsInvalid()) { - throw JSONRPCError(RPC_TRANSACTION_REJECTED, strprintf("%i: %s", state.GetRejectCode(), state.GetRejectReason())); - } else { - if (fMissingInputs) { - throw JSONRPCError(RPC_TRANSACTION_ERROR, "Missing inputs"); - } - throw JSONRPCError(RPC_TRANSACTION_ERROR, state.GetRejectReason()); - } - } - } else if (fHaveChain) { - throw JSONRPCError(RPC_TRANSACTION_ALREADY_IN_CHAIN, "transaction already in block chain"); - } - RelayTransaction(tx); - - return hashTx.GetHex(); -} diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 06c08a3be..518ba4693 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -325,8 +325,6 @@ static const CRPCCommand vRPCCommands[] = { "rawtransactions", "getrawtransaction", &getrawtransaction, true }, { "rawtransactions", "sendrawtransaction", &sendrawtransaction, false }, { "rawtransactions", "signrawtransaction", &signrawtransaction, false }, /* uses wallet if enabled */ - { "rawtransactions", "createrawtransactioncc", &createrawtransactioncc, true }, - { "rawtransactions", "signrawtransactioncc", &signrawtransactioncc, false }, /* uses wallet if enabled */ #ifdef ENABLE_WALLET { "rawtransactions", "fundrawtransaction", &fundrawtransaction, false }, #endif diff --git a/src/rpcserver.h b/src/rpcserver.h index 611abd05f..ecf7b0573 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -262,9 +262,6 @@ extern UniValue sendrawtransaction(const UniValue& params, bool fHelp); extern UniValue gettxoutproof(const UniValue& params, bool fHelp); extern UniValue verifytxoutproof(const UniValue& params, bool fHelp); -extern UniValue createrawtransactioncc(const UniValue& params, bool fHelp); // in rpccryptocondition.cpp -extern UniValue signrawtransactioncc(const UniValue& params, bool fHelp); - extern UniValue getblockcount(const UniValue& params, bool fHelp); // in rpcblockchain.cpp extern UniValue getbestblockhash(const UniValue& params, bool fHelp); extern UniValue getdifficulty(const UniValue& params, bool fHelp); From a99ca25a5adfc520fff84bcf5156917cebda7d54 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Sat, 17 Feb 2018 02:03:34 -0300 Subject: [PATCH 016/339] cryptocondition transaction is standard too --- src/script/script.cpp | 23 +++++++++++++++++++++++ src/script/script.h | 2 ++ src/script/standard.cpp | 7 +++++++ src/script/standard.h | 1 + 4 files changed, 33 insertions(+) diff --git a/src/script/script.cpp b/src/script/script.cpp index 3cb3f855d..a78bd7e29 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -223,6 +223,29 @@ bool CScript::IsPayToScriptHash() const this->at(22) == OP_EQUAL); } +bool CScript::IsPayToCryptoCondition() const +{ + const_iterator pc = this->begin(); + vector data; + int i; + while (pc < this->end()) + { + opcodetype opcode; + if (!this->GetOp(pc, opcode, data)) + return 0; + if (0 == i) + if (opcode != OP_PUSHDATA1) + return 0; + if (1 == i) + if (opcode != OP_CHECKCRYPTOCONDITION) + return 0; + if (i > 1) + return 0; + i++; + } + return 1; +} + bool CScript::IsPushOnly() const { const_iterator pc = begin(); diff --git a/src/script/script.h b/src/script/script.h index 584fefac1..800289a15 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -176,6 +176,7 @@ enum opcodetype OP_PUBKEYS = 0xfb, OP_PUBKEYHASH = 0xfd, OP_PUBKEY = 0xfe, + OP_CRYPTOCONDITION = 0xfc, OP_INVALIDOPCODE = 0xff, }; @@ -563,6 +564,7 @@ public: unsigned int GetSigOpCount(const CScript& scriptSig) const; bool IsPayToScriptHash() const; + bool IsPayToCryptoCondition() const; /** Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). */ bool IsPushOnly() const; diff --git a/src/script/standard.cpp b/src/script/standard.cpp index 71838853d..c304840f4 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -68,6 +68,13 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector Date: Sun, 18 Feb 2018 18:49:04 -0300 Subject: [PATCH 017/339] enable cryptoconditions spending --- src/script/script.cpp | 23 ++++++++++++++--------- src/script/standard.cpp | 4 +++- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/script/script.cpp b/src/script/script.cpp index a78bd7e29..c5eab8ca8 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -227,21 +227,26 @@ bool CScript::IsPayToCryptoCondition() const { const_iterator pc = this->begin(); vector data; - int i; + int i = 0; while (pc < this->end()) { opcodetype opcode; if (!this->GetOp(pc, opcode, data)) return 0; - if (0 == i) - if (opcode != OP_PUSHDATA1) + switch (i++) { + case 0: + // Binary condition should be less than 76 bytes + if (!(opcode > OP_0 && opcode < OP_PUSHDATA1)) + return 0; + break; + case 1: + if (opcode != OP_CHECKCRYPTOCONDITION) + return 0; + break; + default: return 0; - if (1 == i) - if (opcode != OP_CHECKCRYPTOCONDITION) - return 0; - if (i > 1) - return 0; - i++; + break; + } } return 1; } diff --git a/src/script/standard.cpp b/src/script/standard.cpp index c304840f4..4dadaff56 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -71,7 +71,7 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector Date: Sun, 18 Feb 2018 19:35:48 -0300 Subject: [PATCH 018/339] make IsPayToCryptoCondition neat --- src/script/script.cpp | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/src/script/script.cpp b/src/script/script.cpp index c5eab8ca8..5069d9152 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -227,28 +227,15 @@ bool CScript::IsPayToCryptoCondition() const { const_iterator pc = this->begin(); vector data; - int i = 0; - while (pc < this->end()) - { - opcodetype opcode; - if (!this->GetOp(pc, opcode, data)) - return 0; - switch (i++) { - case 0: - // Binary condition should be less than 76 bytes - if (!(opcode > OP_0 && opcode < OP_PUSHDATA1)) - return 0; - break; - case 1: - if (opcode != OP_CHECKCRYPTOCONDITION) - return 0; - break; - default: - return 0; - break; - } - } - return 1; + opcodetype opcode; + if (this->GetOp(pc, opcode, data)) + // Sha256 conditions are <76 bytes + if (opcode > OP_0 && opcode < OP_PUSHDATA1) + if (this->GetOp(pc, opcode, data)) + if (opcode == OP_CHECKCRYPTOCONDITION) + if (pc == this->end()) + return 1; + return 0; } bool CScript::IsPushOnly() const From 6263d4023951ec1ae40b416e551446bcd273e1f9 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Sun, 18 Feb 2018 20:38:29 -0300 Subject: [PATCH 019/339] guard cryptoconditions --- src/script/interpreter.cpp | 5 ++++- src/script/standard.cpp | 13 ++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 94727cbca..f203ccf85 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -940,7 +940,9 @@ bool EvalScript(vector >& stack, const CScript& script, un case OP_CHECKCRYPTOCONDITION: case OP_CHECKCRYPTOCONDITIONVERIFY: { - // (fulfillment condition -- bool) + if (!IsCryptoConditionsEnabled()) { + goto INTERPRETER_DEFAULT; + } if (stack.size() < 2) return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); @@ -982,6 +984,7 @@ bool EvalScript(vector >& stack, const CScript& script, un } break; +INTERPRETER_DEFAULT: default: return set_error(serror, SCRIPT_ERR_BAD_OPCODE); } diff --git a/src/script/standard.cpp b/src/script/standard.cpp index 4dadaff56..308f4e085 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -9,6 +9,7 @@ #include "script/script.h" #include "util.h" #include "utilstrencodings.h" +#include "komodo_cryptoconditions.h" #include @@ -68,11 +69,13 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector Date: Sun, 18 Feb 2018 20:40:24 -0300 Subject: [PATCH 020/339] guard cryptoconditions --- src/komodo_cryptoconditions.h | 13 ++++++++++++- src/script/interpreter.cpp | 6 ++++-- src/script/standard.cpp | 13 ++++++++----- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/komodo_cryptoconditions.h b/src/komodo_cryptoconditions.h index d5e643c91..3cfc15e12 100644 --- a/src/komodo_cryptoconditions.h +++ b/src/komodo_cryptoconditions.h @@ -1,8 +1,19 @@ +#ifndef KOMODO_CRYPTOCONDITIONS_H +#define KOMODO_CRYPTOCONDITIONS_H +#include "cryptoconditions/include/cryptoconditions.h" + +extern int32_t ASSETCHAINS_CC; + +static bool IsCryptoConditionsEnabled() { + return 0 != ASSETCHAINS_CC; +} /* * Method stub for aux conditions. Unimplemented, thus fails if an aux condition is encountered. */ -int komodoCCAux(CC *cond, void *context) { +static int komodoCCAux(CC *cond, void *context) { return 0; } + +#endif /* KOMODO_CRYPTOCONDITIONS_H */ diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 94727cbca..4e03527a4 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -13,7 +13,6 @@ #include "pubkey.h" #include "script/script.h" #include "uint256.h" -#include "cryptoconditions/include/cryptoconditions.h" #include "komodo_cryptoconditions.h" @@ -940,7 +939,9 @@ bool EvalScript(vector >& stack, const CScript& script, un case OP_CHECKCRYPTOCONDITION: case OP_CHECKCRYPTOCONDITIONVERIFY: { - // (fulfillment condition -- bool) + if (!IsCryptoConditionsEnabled()) { + goto INTERPRETER_DEFAULT; + } if (stack.size() < 2) return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); @@ -982,6 +983,7 @@ bool EvalScript(vector >& stack, const CScript& script, un } break; +INTERPRETER_DEFAULT: default: return set_error(serror, SCRIPT_ERR_BAD_OPCODE); } diff --git a/src/script/standard.cpp b/src/script/standard.cpp index 4dadaff56..60f059ac3 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -9,6 +9,7 @@ #include "script/script.h" #include "util.h" #include "utilstrencodings.h" +#include "komodo_cryptoconditions.h" #include @@ -68,11 +69,13 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector Date: Sun, 18 Feb 2018 21:48:58 -0300 Subject: [PATCH 021/339] remove test file that shoudnt be there --- qa/test_rpc_cryptoconditions.py | 47 --------------------------------- 1 file changed, 47 deletions(-) delete mode 100644 qa/test_rpc_cryptoconditions.py diff --git a/qa/test_rpc_cryptoconditions.py b/qa/test_rpc_cryptoconditions.py deleted file mode 100644 index a93eab86a..000000000 --- a/qa/test_rpc_cryptoconditions.py +++ /dev/null @@ -1,47 +0,0 @@ -import os -import subprocess -import json -import base64 - - -inputs = [ - { - 'txid': '9b907ef1e3c26fc71fe4a4b3580bc75264112f95050014157059c736f0202e71', - 'vout': 0, - 'fulfillment': { - 'type': 'preimage-sha-256', - 'preimage': '', - }, - } -] - -outputs = [ - { - "condition": { - 'type': 'preimage-sha-256', - 'preimage': '' - }, - "amount": 1, - } -] - -addresses = ['RQygCQA7ovCrVCHM3sSkDQjjQUg5X4SCJw'] -privkeys = ["UszeEw39HcoeRegZb74xuvngbcQ5jkwQZZVpAvBp1bvBhXD36ghX"] - - -proc = subprocess.Popen(['src/komodo-cli', 'createrawtransactioncc', json.dumps(inputs), json.dumps(outputs)], - stdout=subprocess.PIPE) - -assert not proc.wait() - -tx_hex = proc.stdout.read().strip() -tx = base64.b16decode(tx_hex, casefold=True) - -print repr(tx) - -proc = subprocess.Popen(['src/komodo-cli', 'signrawtransactioncc', tx_hex, json.dumps(privkeys)], - stdout=subprocess.PIPE) - -proc.wait() - -result = json.loads(proc.stdout.read()) From 4f0da23b911db5b9426dd9ef1076681552de459f Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Mon, 19 Feb 2018 01:22:27 -0300 Subject: [PATCH 022/339] integration test for hoek and komodod with -ac_cc --- qa/cryptoconditions/README.md | 1 + qa/cryptoconditions/test_integration.py | 78 +++++++++++++++++++++++++ qa/cryptoconditions/testsupport.py | 47 +++++++++++++++ 3 files changed, 126 insertions(+) create mode 100644 qa/cryptoconditions/README.md create mode 100644 qa/cryptoconditions/test_integration.py create mode 100644 qa/cryptoconditions/testsupport.py diff --git a/qa/cryptoconditions/README.md b/qa/cryptoconditions/README.md new file mode 100644 index 000000000..6c8e01d60 --- /dev/null +++ b/qa/cryptoconditions/README.md @@ -0,0 +1 @@ +Integration tests for Crypto-Conditions diff --git a/qa/cryptoconditions/test_integration.py b/qa/cryptoconditions/test_integration.py new file mode 100644 index 000000000..a47b458e1 --- /dev/null +++ b/qa/cryptoconditions/test_integration.py @@ -0,0 +1,78 @@ +import sys +import time +import json +from testsupport import * + + +def wait_for_block(height): + for i in range(100): + try: + return rpc.getblock(str(height)) + except RPCError as e: + time.sleep(3) + raise Exception('Time out waiting for block at height %s' % height) + + +def sign_and_submit(tx): + signed = hoek.signTxBitcoin({'tx': tx, 'privateKeys': [notary_sk]}) + signed = hoek.signTxEd25519({'tx': signed['tx'], 'privateKeys': [alice_sk]}) + encoded = hoek.encodeTx(signed) + try: + rpc.getrawtransaction(encoded['txid']) + return encoded['txid'] + except RPCError: + pass + print >> sys.stderr, "submit transaction: %s:%s" % (encoded['txid'], json.dumps(signed)) + return rpc.sendrawtransaction(encoded['hex']) + + +def test_basic_spend(): + block = wait_for_block(3) + reward_txid = block['tx'][0] + reward_tx_raw = rpc.getrawtransaction(reward_txid) + reward_tx = hoek.decodeTx({'hex': reward_tx_raw}) + balance = reward_tx['tx']['outputs'][0]['amount'] + + spend0 = { + 'inputs': [ + {'txid': reward_txid, 'idx': 0, 'script': {'pubkey': notary_pk}} + ], + "outputs": [ + {"amount": 1000, "script": {"condition": cond_alice}}, + {"amount": balance - 1000, "script": {"address": notary_addr}} + ] + } + + spend0_txid = sign_and_submit(spend0) + + spend1 = { + 'inputs': [ + {'txid': spend0_txid, 'idx': 0, 'script': {"fulfillment": cond_alice}}, + {'txid': spend0_txid, 'idx': 1, 'script': {'address': notary_addr}} + ], + 'outputs': [ + {"amount": balance, "script": {"address": notary_addr}} + ] + } + + spend1_txid = sign_and_submit(spend1) + + assert rpc.getrawtransaction(spend1_txid) + + print("all done!") + + +notary_addr = 'RXSwmXKtDURwXP7sdqNfsJ6Ga8RaxTchxE' +notary_pk = '0205a8ad0c1dbc515f149af377981aab58b836af008d4d7ab21bd76faf80550b47' +notary_sk = 'UxFWWxsf1d7w7K5TvAWSkeX4H95XQKwdwGv49DXwWUTzPTTjHBbU' +alice_pk = '8ryTLBMnozUK4xUz7y49fjzZhxDDMK7c4mucLdbVY6jW' +alice_sk = 'E4ER7uYvaSTdpQFzTXNNSTkR6jNRJyqhZPJMGuU899nY' +cond_alice = {"type": "ed25519-sha-256", "publicKey": alice_pk} + + + +if __name__ == '__main__': + hoek = Hoek() + rpc = Komodod('/home/scott/.komodo/CCWAT/CCWAT.conf') + test_basic_spend() + diff --git a/qa/cryptoconditions/testsupport.py b/qa/cryptoconditions/testsupport.py new file mode 100644 index 000000000..166d98d14 --- /dev/null +++ b/qa/cryptoconditions/testsupport.py @@ -0,0 +1,47 @@ +import sys +import json +import subprocess + + +class RPCError(IOError): + pass + + +class JsonClient(object): + def __getattr__(self, method): + def inner(*args): + return self._exec(method, args) + return inner + + def load_response(self, data): + data = json.loads(data) + if data.get('error'): + raise RPCError(data['error']) + if 'result' in data: + return data['result'] + return data + + +def run_cmd(cmd): + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE) + #print >>sys.stderr, "> %s" % repr(cmd)[1:-1] + assert proc.wait() == 0 + return proc.stdout.read() + + +class Hoek(JsonClient): + def _exec(self, method, args): + return self.load_response(run_cmd(['hoek', method, json.dumps(args[0])])) + + +class Komodod(JsonClient): + def __init__(self, conf_path): + urltpl = 'http://$rpcuser:$rpcpassword@${rpchost:-127.0.0.1}:$rpcport' + cmd = ['bash', '-c', '. "%s"; echo -n %s' % (conf_path, urltpl)] + self.url = run_cmd(cmd) + + def _exec(self, method, args): + req = {'method': method, 'params': args, 'id': 1} + cmd = ['curl', '-s', '-H', 'Content-Type: application/json', '-d', json.dumps(req), self.url] + return self.load_response(run_cmd(cmd)) + From a236c673fe6fee1464b967a672afa43904155940 Mon Sep 17 00:00:00 2001 From: libscott Date: Mon, 19 Feb 2018 01:37:54 -0300 Subject: [PATCH 023/339] Update cryptoconditions test suite README --- qa/cryptoconditions/README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/qa/cryptoconditions/README.md b/qa/cryptoconditions/README.md index 6c8e01d60..d14ab5b7d 100644 --- a/qa/cryptoconditions/README.md +++ b/qa/cryptoconditions/README.md @@ -1 +1,7 @@ -Integration tests for Crypto-Conditions +# Integration tests for Crypto-Conditions + +These tests are for the [Crypto-Conditions](https://github.com/rfcs/crypto-conditions) functionality in Komodod, using [Hoek](https://github.com/libscott/hoek) as a tool to create and sign transactions. + +The tests use Python as a scripting language and each one should "just work" given Linux and a 2.7+ Python interpreter. Each file prefixed with "test_" is a test case. + +The tests require `hoek` to be on the $PATH. Included is a script to perform a complete installation of `hoek`. From d17b8ec6a2cb6e86c45b443eabaff8c4d2aa3572 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Mon, 19 Feb 2018 03:22:26 -0300 Subject: [PATCH 024/339] use a fanout tx to create inputs --- qa/cryptoconditions/test_integration.py | 48 ++----------- qa/cryptoconditions/testsupport.py | 93 ++++++++++++++++++++++--- 2 files changed, 90 insertions(+), 51 deletions(-) diff --git a/qa/cryptoconditions/test_integration.py b/qa/cryptoconditions/test_integration.py index a47b458e1..0bb004aeb 100644 --- a/qa/cryptoconditions/test_integration.py +++ b/qa/cryptoconditions/test_integration.py @@ -4,42 +4,14 @@ import json from testsupport import * -def wait_for_block(height): - for i in range(100): - try: - return rpc.getblock(str(height)) - except RPCError as e: - time.sleep(3) - raise Exception('Time out waiting for block at height %s' % height) - - -def sign_and_submit(tx): - signed = hoek.signTxBitcoin({'tx': tx, 'privateKeys': [notary_sk]}) - signed = hoek.signTxEd25519({'tx': signed['tx'], 'privateKeys': [alice_sk]}) - encoded = hoek.encodeTx(signed) - try: - rpc.getrawtransaction(encoded['txid']) - return encoded['txid'] - except RPCError: - pass - print >> sys.stderr, "submit transaction: %s:%s" % (encoded['txid'], json.dumps(signed)) - return rpc.sendrawtransaction(encoded['hex']) - - def test_basic_spend(): - block = wait_for_block(3) - reward_txid = block['tx'][0] - reward_tx_raw = rpc.getrawtransaction(reward_txid) - reward_tx = hoek.decodeTx({'hex': reward_tx_raw}) - balance = reward_tx['tx']['outputs'][0]['amount'] - spend0 = { 'inputs': [ - {'txid': reward_txid, 'idx': 0, 'script': {'pubkey': notary_pk}} + {'txid': fanout, 'idx': 0, 'script': {'address': notary_addr}} ], "outputs": [ - {"amount": 1000, "script": {"condition": cond_alice}}, - {"amount": balance - 1000, "script": {"address": notary_addr}} + {"amount": 500, "script": {"condition": cond_alice}}, + {"amount": 500, "script": {"address": notary_addr}} ] } @@ -51,7 +23,7 @@ def test_basic_spend(): {'txid': spend0_txid, 'idx': 1, 'script': {'address': notary_addr}} ], 'outputs': [ - {"amount": balance, "script": {"address": notary_addr}} + {"amount": 1000, "script": {"address": notary_addr}} ] } @@ -62,17 +34,7 @@ def test_basic_spend(): print("all done!") -notary_addr = 'RXSwmXKtDURwXP7sdqNfsJ6Ga8RaxTchxE' -notary_pk = '0205a8ad0c1dbc515f149af377981aab58b836af008d4d7ab21bd76faf80550b47' -notary_sk = 'UxFWWxsf1d7w7K5TvAWSkeX4H95XQKwdwGv49DXwWUTzPTTjHBbU' -alice_pk = '8ryTLBMnozUK4xUz7y49fjzZhxDDMK7c4mucLdbVY6jW' -alice_sk = 'E4ER7uYvaSTdpQFzTXNNSTkR6jNRJyqhZPJMGuU899nY' -cond_alice = {"type": "ed25519-sha-256", "publicKey": alice_pk} - - if __name__ == '__main__': - hoek = Hoek() - rpc = Komodod('/home/scott/.komodo/CCWAT/CCWAT.conf') + fanout = setup() test_basic_spend() - diff --git a/qa/cryptoconditions/testsupport.py b/qa/cryptoconditions/testsupport.py index 166d98d14..c33a611d2 100644 --- a/qa/cryptoconditions/testsupport.py +++ b/qa/cryptoconditions/testsupport.py @@ -1,5 +1,7 @@ import sys import json +import time +import argparse import subprocess @@ -31,17 +33,92 @@ def run_cmd(cmd): class Hoek(JsonClient): def _exec(self, method, args): - return self.load_response(run_cmd(['hoek', method, json.dumps(args[0])])) + cmd = ['hoek', method, json.dumps(args[0])] + return self.load_response(run_cmd(cmd)) class Komodod(JsonClient): - def __init__(self, conf_path): - urltpl = 'http://$rpcuser:$rpcpassword@${rpchost:-127.0.0.1}:$rpcport' - cmd = ['bash', '-c', '. "%s"; echo -n %s' % (conf_path, urltpl)] - self.url = run_cmd(cmd) - def _exec(self, method, args): req = {'method': method, 'params': args, 'id': 1} - cmd = ['curl', '-s', '-H', 'Content-Type: application/json', '-d', json.dumps(req), self.url] + cmd = ['curl', '-s', '-H', 'Content-Type: application/json', + '-d', json.dumps(req), CONFIG['komodod_url']] return self.load_response(run_cmd(cmd)) - + + +rpc = Komodod() +hoek = Hoek() + + +def wait_for_block(height): + print >>sys.stderr, "Waiting for block height %s" % height + for i in range(100): + try: + return rpc.getblock(str(height)) + except RPCError as e: + time.sleep(3) + raise Exception('Time out waiting for block at height %s' % height) + + +def sign_and_submit(tx): + signed = hoek.signTxBitcoin({'tx': tx, 'privateKeys': [notary_sk]}) + signed = hoek.signTxEd25519({'tx': signed['tx'], 'privateKeys': [alice_sk]}) + encoded = hoek.encodeTx(signed) + try: + rpc.getrawtransaction(encoded['txid']) + print >> sys.stderr, "Transaction already in chain: %s" % encoded['txid'] + return encoded['txid'] + except RPCError: + pass + print >> sys.stderr, "submit transaction: %s:%s" % (encoded['txid'], json.dumps(signed)) + print encoded + return rpc.sendrawtransaction(encoded['hex']) + + + +CONFIG = None +FANOUT_TXID = None + + +def setup(): + global CONFIG, FANOUT_TXID + if not CONFIG: + parser = argparse.ArgumentParser(description='Crypto-Condition integration suite.') + parser.add_argument('komodod_conf', help='Location of Komodod config file') + args = parser.parse_args() + + urltpl = 'http://$rpcuser:$rpcpassword@${rpchost:-127.0.0.1}:$rpcport' + cmd = ['bash', '-c', '. %s && echo -n %s' % (args.komodod_conf, urltpl)] + url = run_cmd(cmd) + + CONFIG = {'komodod_url': url} + + if not FANOUT_TXID: + block = wait_for_block(1) + reward_txid = block['tx'][0] + reward_tx_raw = rpc.getrawtransaction(reward_txid) + reward_tx = hoek.decodeTx({'hex': reward_tx_raw}) + balance = reward_tx['tx']['outputs'][0]['amount'] + + n_outs = 100 + remainder = balance - n_outs * 1000 + + fanout = { + 'inputs': [ + {'txid': reward_txid, 'idx': 0, 'script': {'pubkey': notary_pk}} + ], + "outputs": (100 * [ + {"amount": 1000, "script": {"address": notary_addr}} + ] + [{"amount": remainder, 'script': {'address': notary_addr}}]) + } + + FANOUT_TXID = sign_and_submit(fanout) + + return FANOUT_TXID + + +notary_addr = 'RXSwmXKtDURwXP7sdqNfsJ6Ga8RaxTchxE' +notary_pk = '0205a8ad0c1dbc515f149af377981aab58b836af008d4d7ab21bd76faf80550b47' +notary_sk = 'UxFWWxsf1d7w7K5TvAWSkeX4H95XQKwdwGv49DXwWUTzPTTjHBbU' +alice_pk = '8ryTLBMnozUK4xUz7y49fjzZhxDDMK7c4mucLdbVY6jW' +alice_sk = 'E4ER7uYvaSTdpQFzTXNNSTkR6jNRJyqhZPJMGuU899nY' +cond_alice = {"type": "ed25519-sha-256", "publicKey": alice_pk} From 82e6c354304e25b50063071ae2c864b7104cbfd6 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Mon, 19 Feb 2018 15:16:14 -0300 Subject: [PATCH 025/339] test with invalid crypto-condition fulfillment --- qa/cryptoconditions/test_integration.py | 92 ++++++++++++++++++---- qa/cryptoconditions/testsupport.py | 100 ++++++++++++------------ 2 files changed, 128 insertions(+), 64 deletions(-) diff --git a/qa/cryptoconditions/test_integration.py b/qa/cryptoconditions/test_integration.py index 0bb004aeb..87ee59825 100644 --- a/qa/cryptoconditions/test_integration.py +++ b/qa/cryptoconditions/test_integration.py @@ -1,40 +1,100 @@ import sys import time import json +import logging +import binascii from testsupport import * -def test_basic_spend(): +@fanout_input(0) +def test_basic_spend(inp): spend0 = { - 'inputs': [ - {'txid': fanout, 'idx': 0, 'script': {'address': notary_addr}} - ], + 'inputs': [inp], "outputs": [ {"amount": 500, "script": {"condition": cond_alice}}, {"amount": 500, "script": {"address": notary_addr}} ] } - - spend0_txid = sign_and_submit(spend0) - + spend0_txid = submit(sign(spend0)) spend1 = { 'inputs': [ {'txid': spend0_txid, 'idx': 0, 'script': {"fulfillment": cond_alice}}, {'txid': spend0_txid, 'idx': 1, 'script': {'address': notary_addr}} ], - 'outputs': [ - {"amount": 1000, "script": {"address": notary_addr}} - ] + 'outputs': [{"amount": 1000, "script": {"address": notary_addr}}] } - - spend1_txid = sign_and_submit(spend1) - + spend1_txid = submit(sign(spend1)) assert rpc.getrawtransaction(spend1_txid) - print("all done!") +@fanout_input(1) +def test_fulfillment_wrong_signature(inp): + spend0 = { + 'inputs': [inp], + "outputs": [{"amount": 1000, "script": {"condition": cond_bob}}] + } + spend0_txid = submit(sign(spend0)) + spend1 = { + 'inputs': [{'txid': spend0_txid, 'idx': 0, 'script': {"fulfillment": cond_alice}}], + 'outputs': [{"amount": 1000, "script": {"address": notary_addr}}] + } + + signed = sign(spend1) + # Set the correct pubkey, signature is wrong + signed['tx']['inputs'][0]['script']['fulfillment']['publicKey'] = bob_pk + + try: + assert not submit(sign(spend1)), 'should raise an error' + except RPCError as e: + assert '16: mandatory-script-verify-flag-failed' in str(e), str(e) + + +@fanout_input(2) +def test_fulfillment_wrong_pubkey(inp): + spend0 = { + 'inputs': [inp], + "outputs": [{"amount": 1000, "script": {"condition": cond_alice}}] + } + spend0_txid = submit(sign(spend0)) + spend1 = { + 'inputs': [{'txid': spend0_txid, 'idx': 0, 'script': {"fulfillment": cond_alice}}], + 'outputs': [{"amount": 1000, "script": {"address": notary_addr}}] + } + + signed = sign(spend1) + # Set the wrong pubkey, signature is correct + signed['tx']['inputs'][0]['script']['fulfillment']['publicKey'] = bob_pk + + try: + assert not submit(signed), 'should raise an error' + except RPCError as e: + assert '16: mandatory-script-verify-flag-failed' in str(e), str(e) + + +@fanout_input(3) +def test_fulfillment_invalid_fulfillment(inp): + spend0 = { + 'inputs': [inp], + "outputs": [{"amount": 1000, "script": {"condition": cond_alice}}] + } + spend0_txid = submit(sign(spend0)) + + # Create a valid script with an invalid fulfillment payload + script = binascii.hexlify(b"\007invalid").decode('utf-8') + + spend1 = { + 'inputs': [{'txid': spend0_txid, 'idx': 0, 'script': script}], + 'outputs': [{"amount": 1000, "script": {"address": notary_addr}}] + } + + try: + assert not submit({'tx': spend1}), 'should raise an error' + except RPCError as e: + assert 'Crypto-Condition payload is invalid' in str(e), str(e) if __name__ == '__main__': - fanout = setup() - test_basic_spend() + for name, f in globals().items(): + if name.startswith('test_'): + logging.info("Running test: %s" % name) + f() diff --git a/qa/cryptoconditions/testsupport.py b/qa/cryptoconditions/testsupport.py index c33a611d2..aad64e320 100644 --- a/qa/cryptoconditions/testsupport.py +++ b/qa/cryptoconditions/testsupport.py @@ -1,8 +1,10 @@ +from __future__ import print_function import sys import json import time -import argparse +import logging import subprocess +import functools class RPCError(IOError): @@ -11,12 +13,14 @@ class RPCError(IOError): class JsonClient(object): def __getattr__(self, method): + if method[0] == '_': + return getattr(super(JsonClient, self), method) def inner(*args): return self._exec(method, args) return inner def load_response(self, data): - data = json.loads(data) + data = json.loads(data.decode("utf-8")) if data.get('error'): raise RPCError(data['error']) if 'result' in data: @@ -26,7 +30,6 @@ class JsonClient(object): def run_cmd(cmd): proc = subprocess.Popen(cmd, stdout=subprocess.PIPE) - #print >>sys.stderr, "> %s" % repr(cmd)[1:-1] assert proc.wait() == 0 return proc.stdout.read() @@ -39,9 +42,13 @@ class Hoek(JsonClient): class Komodod(JsonClient): def _exec(self, method, args): + if not hasattr(self, '_url'): + urltpl = 'http://$rpcuser:$rpcpassword@${rpchost:-127.0.0.1}:$rpcport' + cmd = ['bash', '-c', '. $KOMODO_CONF_PATH && echo -n %s' % urltpl] + self._url = run_cmd(cmd) + req = {'method': method, 'params': args, 'id': 1} - cmd = ['curl', '-s', '-H', 'Content-Type: application/json', - '-d', json.dumps(req), CONFIG['komodod_url']] + cmd = ['curl', '-s', '-H', 'Content-Type: application/json', '-d', json.dumps(req), self._url] return self.load_response(run_cmd(cmd)) @@ -50,7 +57,7 @@ hoek = Hoek() def wait_for_block(height): - print >>sys.stderr, "Waiting for block height %s" % height + logging.info("Waiting for block height %s" % height) for i in range(100): try: return rpc.getblock(str(height)) @@ -59,61 +66,55 @@ def wait_for_block(height): raise Exception('Time out waiting for block at height %s' % height) -def sign_and_submit(tx): +def sign(tx): signed = hoek.signTxBitcoin({'tx': tx, 'privateKeys': [notary_sk]}) - signed = hoek.signTxEd25519({'tx': signed['tx'], 'privateKeys': [alice_sk]}) - encoded = hoek.encodeTx(signed) + return hoek.signTxEd25519({'tx': signed['tx'], 'privateKeys': [alice_sk]}) + + +def submit(tx): + encoded = hoek.encodeTx(tx) try: rpc.getrawtransaction(encoded['txid']) - print >> sys.stderr, "Transaction already in chain: %s" % encoded['txid'] + logging.info("Transaction already in chain: %s" % encoded['txid']) return encoded['txid'] except RPCError: pass - print >> sys.stderr, "submit transaction: %s:%s" % (encoded['txid'], json.dumps(signed)) - print encoded + logging.info("submit transaction: %s:%s" % (encoded['txid'], json.dumps(tx))) return rpc.sendrawtransaction(encoded['hex']) +def get_fanout_txid(): + block = wait_for_block(1) + reward_txid = block['tx'][0] + reward_tx_raw = rpc.getrawtransaction(reward_txid) + reward_tx = hoek.decodeTx({'hex': reward_tx_raw}) + balance = reward_tx['tx']['outputs'][0]['amount'] -CONFIG = None -FANOUT_TXID = None + n_outs = 100 + remainder = balance - n_outs * 1000 + + fanout = { + 'inputs': [ + {'txid': reward_txid, 'idx': 0, 'script': {'pubkey': notary_pk}} + ], + "outputs": (100 * [ + {"amount": 1000, "script": {"address": notary_addr}} + ] + [{"amount": remainder, 'script': {'address': notary_addr}}]) + } + + return submit(sign(fanout)) -def setup(): - global CONFIG, FANOUT_TXID - if not CONFIG: - parser = argparse.ArgumentParser(description='Crypto-Condition integration suite.') - parser.add_argument('komodod_conf', help='Location of Komodod config file') - args = parser.parse_args() +def fanout_input(n): + def decorate(f): + def wrapper(): + if not hasattr(fanout_input, 'txid'): + fanout_input.txid = get_fanout_txid() + inp = {'txid': fanout_input.txid, 'idx': n, 'script': {'address': notary_addr}} + f(inp) + return functools.wraps(f)(wrapper) + return decorate - urltpl = 'http://$rpcuser:$rpcpassword@${rpchost:-127.0.0.1}:$rpcport' - cmd = ['bash', '-c', '. %s && echo -n %s' % (args.komodod_conf, urltpl)] - url = run_cmd(cmd) - - CONFIG = {'komodod_url': url} - - if not FANOUT_TXID: - block = wait_for_block(1) - reward_txid = block['tx'][0] - reward_tx_raw = rpc.getrawtransaction(reward_txid) - reward_tx = hoek.decodeTx({'hex': reward_tx_raw}) - balance = reward_tx['tx']['outputs'][0]['amount'] - - n_outs = 100 - remainder = balance - n_outs * 1000 - - fanout = { - 'inputs': [ - {'txid': reward_txid, 'idx': 0, 'script': {'pubkey': notary_pk}} - ], - "outputs": (100 * [ - {"amount": 1000, "script": {"address": notary_addr}} - ] + [{"amount": remainder, 'script': {'address': notary_addr}}]) - } - - FANOUT_TXID = sign_and_submit(fanout) - - return FANOUT_TXID notary_addr = 'RXSwmXKtDURwXP7sdqNfsJ6Ga8RaxTchxE' @@ -122,3 +123,6 @@ notary_sk = 'UxFWWxsf1d7w7K5TvAWSkeX4H95XQKwdwGv49DXwWUTzPTTjHBbU' alice_pk = '8ryTLBMnozUK4xUz7y49fjzZhxDDMK7c4mucLdbVY6jW' alice_sk = 'E4ER7uYvaSTdpQFzTXNNSTkR6jNRJyqhZPJMGuU899nY' cond_alice = {"type": "ed25519-sha-256", "publicKey": alice_pk} +bob_pk = 'C8MfEjKiFxDguacHvcM7MV83cRQ55RAHacC73xqg8qeu' +bob_sk = 'GrP1fZdUxUc1NYmu7kiNkJV4p7PKpshp1yBY7hogPUWT' +cond_bob = {"type": "ed25519-sha-256", "publicKey": bob_pk} From 456c9e72fd848cb542e02a2c37fcd4d9138735c0 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Mon, 19 Feb 2018 15:39:05 -0300 Subject: [PATCH 026/339] simplify CC tests --- qa/cryptoconditions/test_integration.py | 70 ++++++------------------- qa/cryptoconditions/testsupport.py | 7 +-- 2 files changed, 20 insertions(+), 57 deletions(-) diff --git a/qa/cryptoconditions/test_integration.py b/qa/cryptoconditions/test_integration.py index 87ee59825..ee266dfdf 100644 --- a/qa/cryptoconditions/test_integration.py +++ b/qa/cryptoconditions/test_integration.py @@ -8,87 +8,49 @@ from testsupport import * @fanout_input(0) def test_basic_spend(inp): - spend0 = { - 'inputs': [inp], - "outputs": [ - {"amount": 500, "script": {"condition": cond_alice}}, - {"amount": 500, "script": {"address": notary_addr}} - ] - } - spend0_txid = submit(sign(spend0)) - spend1 = { - 'inputs': [ - {'txid': spend0_txid, 'idx': 0, 'script': {"fulfillment": cond_alice}}, - {'txid': spend0_txid, 'idx': 1, 'script': {'address': notary_addr}} - ], - 'outputs': [{"amount": 1000, "script": {"address": notary_addr}}] - } - spend1_txid = submit(sign(spend1)) - assert rpc.getrawtransaction(spend1_txid) + spend = {'inputs': [inp], "outputs": [nospend]} + spend_txid = submit(sign(spend)) + assert rpc.getrawtransaction(spend_txid) @fanout_input(1) def test_fulfillment_wrong_signature(inp): - spend0 = { - 'inputs': [inp], - "outputs": [{"amount": 1000, "script": {"condition": cond_bob}}] - } - spend0_txid = submit(sign(spend0)) - spend1 = { - 'inputs': [{'txid': spend0_txid, 'idx': 0, 'script': {"fulfillment": cond_alice}}], - 'outputs': [{"amount": 1000, "script": {"address": notary_addr}}] - } + # Set other pubkey and sign + inp['script']['fulfillment']['publicKey'] = bob_pk + spend = {'inputs': [inp], 'outputs': [nospend]} + signed = sign(spend) - signed = sign(spend1) # Set the correct pubkey, signature is wrong - signed['tx']['inputs'][0]['script']['fulfillment']['publicKey'] = bob_pk + signed['tx']['inputs'][0]['script']['fulfillment']['publicKey'] = alice_pk try: - assert not submit(sign(spend1)), 'should raise an error' + assert not submit(signed), 'should raise an error' except RPCError as e: - assert '16: mandatory-script-verify-flag-failed' in str(e), str(e) + assert 'Script evaluated without error but finished with a false/empty top stack element' in str(e), str(e) @fanout_input(2) def test_fulfillment_wrong_pubkey(inp): - spend0 = { - 'inputs': [inp], - "outputs": [{"amount": 1000, "script": {"condition": cond_alice}}] - } - spend0_txid = submit(sign(spend0)) - spend1 = { - 'inputs': [{'txid': spend0_txid, 'idx': 0, 'script': {"fulfillment": cond_alice}}], - 'outputs': [{"amount": 1000, "script": {"address": notary_addr}}] - } + spend = {'inputs': [inp], 'outputs': [nospend]} - signed = sign(spend1) + signed = sign(spend) # Set the wrong pubkey, signature is correct signed['tx']['inputs'][0]['script']['fulfillment']['publicKey'] = bob_pk try: assert not submit(signed), 'should raise an error' except RPCError as e: - assert '16: mandatory-script-verify-flag-failed' in str(e), str(e) + assert 'Script evaluated without error but finished with a false/empty top stack element' in str(e), str(e) @fanout_input(3) def test_fulfillment_invalid_fulfillment(inp): - spend0 = { - 'inputs': [inp], - "outputs": [{"amount": 1000, "script": {"condition": cond_alice}}] - } - spend0_txid = submit(sign(spend0)) - # Create a valid script with an invalid fulfillment payload - script = binascii.hexlify(b"\007invalid").decode('utf-8') - - spend1 = { - 'inputs': [{'txid': spend0_txid, 'idx': 0, 'script': script}], - 'outputs': [{"amount": 1000, "script": {"address": notary_addr}}] - } + inp['script'] = binascii.hexlify(b"\007invalid").decode('utf-8') + spend = {'inputs': [inp], 'outputs': [nospend]} try: - assert not submit({'tx': spend1}), 'should raise an error' + assert not submit({'tx': spend}), 'should raise an error' except RPCError as e: assert 'Crypto-Condition payload is invalid' in str(e), str(e) diff --git a/qa/cryptoconditions/testsupport.py b/qa/cryptoconditions/testsupport.py index aad64e320..5b00f8218 100644 --- a/qa/cryptoconditions/testsupport.py +++ b/qa/cryptoconditions/testsupport.py @@ -68,7 +68,7 @@ def wait_for_block(height): def sign(tx): signed = hoek.signTxBitcoin({'tx': tx, 'privateKeys': [notary_sk]}) - return hoek.signTxEd25519({'tx': signed['tx'], 'privateKeys': [alice_sk]}) + return hoek.signTxEd25519({'tx': signed['tx'], 'privateKeys': [alice_sk, bob_sk]}) def submit(tx): @@ -98,7 +98,7 @@ def get_fanout_txid(): {'txid': reward_txid, 'idx': 0, 'script': {'pubkey': notary_pk}} ], "outputs": (100 * [ - {"amount": 1000, "script": {"address": notary_addr}} + {"amount": 1000, "script": {"condition": cond_alice}} ] + [{"amount": remainder, 'script': {'address': notary_addr}}]) } @@ -110,7 +110,7 @@ def fanout_input(n): def wrapper(): if not hasattr(fanout_input, 'txid'): fanout_input.txid = get_fanout_txid() - inp = {'txid': fanout_input.txid, 'idx': n, 'script': {'address': notary_addr}} + inp = {'txid': fanout_input.txid, 'idx': n, 'script': {'fulfillment': cond_alice}} f(inp) return functools.wraps(f)(wrapper) return decorate @@ -126,3 +126,4 @@ cond_alice = {"type": "ed25519-sha-256", "publicKey": alice_pk} bob_pk = 'C8MfEjKiFxDguacHvcM7MV83cRQ55RAHacC73xqg8qeu' bob_sk = 'GrP1fZdUxUc1NYmu7kiNkJV4p7PKpshp1yBY7hogPUWT' cond_bob = {"type": "ed25519-sha-256", "publicKey": bob_pk} +nospend = {"amount": 1000, "script": {"address": notary_addr}} From f5cf215f71a2477070314b2eb14d9ba4fce63e81 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Mon, 19 Feb 2018 18:24:12 -0300 Subject: [PATCH 027/339] extra tests for failure modes and remove CRYPTOCONDITION_OVERSIZE error state --- qa/cryptoconditions/README.md | 7 +++-- qa/cryptoconditions/test_integration.py | 40 +++++++++++++++++++++++-- qa/cryptoconditions/testsupport.py | 10 +++++-- src/cryptoconditions | 2 +- src/script/interpreter.cpp | 5 ---- src/script/script_error.cpp | 2 ++ src/script/script_error.h | 1 + 7 files changed, 54 insertions(+), 13 deletions(-) diff --git a/qa/cryptoconditions/README.md b/qa/cryptoconditions/README.md index d14ab5b7d..d93e8e266 100644 --- a/qa/cryptoconditions/README.md +++ b/qa/cryptoconditions/README.md @@ -2,6 +2,9 @@ These tests are for the [Crypto-Conditions](https://github.com/rfcs/crypto-conditions) functionality in Komodod, using [Hoek](https://github.com/libscott/hoek) as a tool to create and sign transactions. -The tests use Python as a scripting language and each one should "just work" given Linux and a 2.7+ Python interpreter. Each file prefixed with "test_" is a test case. +## How to run the tests -The tests require `hoek` to be on the $PATH. Included is a script to perform a complete installation of `hoek`. +1. Install hoek: https://github.com/libscott/hoek +2. Start komodod: `src/komodod -ac_name=CCTEST -ac_supply=21000000 -gen -pubkey=0205a8ad0c1dbc515f149af377981aab58b836af008d4d7ab21bd76faf80550b47 -ac_cc=1` +3. Set environment variable pointing to Komodo conf: `export KOMODO_CONF_PATH=~/.komodo/CCTEST/CCTEST.conf` +4. Run tests: `python test_integration.py` (you can also use a test runner such as `nose`). diff --git a/qa/cryptoconditions/test_integration.py b/qa/cryptoconditions/test_integration.py index ee266dfdf..24792cc60 100644 --- a/qa/cryptoconditions/test_integration.py +++ b/qa/cryptoconditions/test_integration.py @@ -3,6 +3,7 @@ import time import json import logging import binascii +import struct from testsupport import * @@ -20,7 +21,7 @@ def test_fulfillment_wrong_signature(inp): spend = {'inputs': [inp], 'outputs': [nospend]} signed = sign(spend) - # Set the correct pubkey, signature is wrong + # Set the correct pubkey, signature is bob's signed['tx']['inputs'][0]['script']['fulfillment']['publicKey'] = alice_pk try: @@ -32,8 +33,8 @@ def test_fulfillment_wrong_signature(inp): @fanout_input(2) def test_fulfillment_wrong_pubkey(inp): spend = {'inputs': [inp], 'outputs': [nospend]} - signed = sign(spend) + # Set the wrong pubkey, signature is correct signed['tx']['inputs'][0]['script']['fulfillment']['publicKey'] = bob_pk @@ -44,7 +45,7 @@ def test_fulfillment_wrong_pubkey(inp): @fanout_input(3) -def test_fulfillment_invalid_fulfillment(inp): +def test_invalid_fulfillment_binary(inp): # Create a valid script with an invalid fulfillment payload inp['script'] = binascii.hexlify(b"\007invalid").decode('utf-8') spend = {'inputs': [inp], 'outputs': [nospend]} @@ -55,8 +56,41 @@ def test_fulfillment_invalid_fulfillment(inp): assert 'Crypto-Condition payload is invalid' in str(e), str(e) +@fanout_input(4) +def test_invalid_condition(inp): + # Create a valid output script with an invalid cryptocondition binary + outputscript = to_hex(b"\007invalid\xcc") + spend = {'inputs': [inp], 'outputs': [{'amount': 1000, 'script': outputscript}]} + spend_txid = submit(sign(spend)) + + spend1 = { + 'inputs': [{'txid': spend_txid, 'idx': 0, 'script': {'fulfillment': cond_alice}}], + 'outputs': [nospend], + } + + try: + assert not submit(sign(spend1)), 'should raise an error' + except RPCError as e: + assert 'Script evaluated without error but finished with a false/empty top stack element' in str(e), str(e) + + +@fanout_input(19) +def test_oversize_fulfillment(inp): + # Create oversize fulfillment script where the total length is <2000 + binscript = b'\x4d%s%s' % (struct.pack('h', 2000), b'a' * 2000) + inp['script'] = to_hex(binscript) + spend = {'inputs': [inp], 'outputs': [nospend]} + + try: + assert not submit({'tx': spend}), 'should raise an error' + except RPCError as e: + assert 'scriptsig-size' in str(e), str(e) + + if __name__ == '__main__': + logging.basicConfig(level=logging.INFO) for name, f in globals().items(): if name.startswith('test_'): logging.info("Running test: %s" % name) f() + logging.info("Test OK: %s" % name) diff --git a/qa/cryptoconditions/testsupport.py b/qa/cryptoconditions/testsupport.py index 5b00f8218..e6025c0bc 100644 --- a/qa/cryptoconditions/testsupport.py +++ b/qa/cryptoconditions/testsupport.py @@ -2,9 +2,11 @@ from __future__ import print_function import sys import json import time +import copy +import base64 import logging -import subprocess import functools +import subprocess class RPCError(IOError): @@ -34,6 +36,10 @@ def run_cmd(cmd): return proc.stdout.read() +def to_hex(s): + return base64.b16encode(s).decode('utf-8') + + class Hoek(JsonClient): def _exec(self, method, args): cmd = ['hoek', method, json.dumps(args[0])] @@ -111,7 +117,7 @@ def fanout_input(n): if not hasattr(fanout_input, 'txid'): fanout_input.txid = get_fanout_txid() inp = {'txid': fanout_input.txid, 'idx': n, 'script': {'fulfillment': cond_alice}} - f(inp) + f(copy.deepcopy(inp)) return functools.wraps(f)(wrapper) return decorate diff --git a/src/cryptoconditions b/src/cryptoconditions index 89325dc29..7ab93ba86 160000 --- a/src/cryptoconditions +++ b/src/cryptoconditions @@ -1 +1 @@ -Subproject commit 89325dc29391f473da75503105a4946f2f96fb76 +Subproject commit 7ab93ba86174efa32da3dac8b625ff9e1ef05fdd diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 4e03527a4..e0c2c1d01 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -949,11 +949,6 @@ bool EvalScript(vector >& stack, const CScript& script, un valtype& vchFulfillment = stacktop(-2); valtype& vchCondition = stacktop(-1); - // Hard limit fulfillment size - if (vchFulfillment.size() > 1024 * 10) { - return set_error(serror, SCRIPT_ERR_CRYPTOCONDITION_INVALID_FULFILLMENT); - } - CC *cond = (CC*) calloc(1, sizeof(CC)); char *fulfillmentBin = (char*) vchFulfillment.data(); int rc = cc_readFulfillmentBinary(cond, fulfillmentBin, vchFulfillment.size()); diff --git a/src/script/script_error.cpp b/src/script/script_error.cpp index f1aa1fb40..41c8a24e0 100644 --- a/src/script/script_error.cpp +++ b/src/script/script_error.cpp @@ -67,6 +67,8 @@ const char* ScriptErrorString(const ScriptError serror) return "NOPx reserved for soft-fork upgrades"; case SCRIPT_ERR_PUBKEYTYPE: return "Public key is neither compressed or uncompressed"; + case SCRIPT_ERR_CRYPTOCONDITION_INVALID_FULFILLMENT: + return "Crypto-Condition payload is invalid"; case SCRIPT_ERR_UNKNOWN_ERROR: case SCRIPT_ERR_ERROR_COUNT: default: break; diff --git a/src/script/script_error.h b/src/script/script_error.h index e84268977..35c8fbfd8 100644 --- a/src/script/script_error.h +++ b/src/script/script_error.h @@ -54,6 +54,7 @@ typedef enum ScriptError_t SCRIPT_ERR_ERROR_COUNT, + /* crypto-condition script errors */ SCRIPT_ERR_CRYPTOCONDITION_VERIFY, SCRIPT_ERR_CRYPTOCONDITION_INVALID_FULFILLMENT } ScriptError; From ccb128503efa55d3348d8ad5b913dbb8d7b942a6 Mon Sep 17 00:00:00 2001 From: libscott Date: Mon, 19 Feb 2018 18:31:39 -0300 Subject: [PATCH 028/339] Update README.md --- qa/cryptoconditions/README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/qa/cryptoconditions/README.md b/qa/cryptoconditions/README.md index d93e8e266..2bf479ecd 100644 --- a/qa/cryptoconditions/README.md +++ b/qa/cryptoconditions/README.md @@ -5,6 +5,7 @@ These tests are for the [Crypto-Conditions](https://github.com/rfcs/crypto-condi ## How to run the tests 1. Install hoek: https://github.com/libscott/hoek -2. Start komodod: `src/komodod -ac_name=CCTEST -ac_supply=21000000 -gen -pubkey=0205a8ad0c1dbc515f149af377981aab58b836af008d4d7ab21bd76faf80550b47 -ac_cc=1` -3. Set environment variable pointing to Komodo conf: `export KOMODO_CONF_PATH=~/.komodo/CCTEST/CCTEST.conf` -4. Run tests: `python test_integration.py` (you can also use a test runner such as `nose`). +1. Allow peer-less block creation: set "fMiningRequiresPeers = false" in src/chainparams.cpp, then build komodod. +1. Start komodod: `src/komodod -ac_name=CCTEST -ac_supply=21000000 -gen -pubkey=0205a8ad0c1dbc515f149af377981aab58b836af008d4d7ab21bd76faf80550b47 -ac_cc=1` +1. Set environment variable pointing to Komodo conf: `export KOMODO_CONF_PATH=~/.komodo/CCTEST/CCTEST.conf` +1. Run tests: `python test_integration.py` (you can also use a test runner such as `nose`). From fbc955c49338668eaffb1e161825c2ec5e1ed010 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Mon, 19 Feb 2018 20:45:11 -0300 Subject: [PATCH 029/339] use public github submodule url --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index 0c640d62c..83942a053 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "cryptoconditions"] path = src/cryptoconditions - url = git@github.com:libscott/libcryptoconditions.git + url = https://github.com/libscott/libcryptoconditions.git branch = komodo-integration From 85b55ada89d71b7d51cd23e556677bbbfe1104ab Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Mon, 19 Feb 2018 21:13:05 -0300 Subject: [PATCH 030/339] use public github url --- src/cryptoconditions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cryptoconditions b/src/cryptoconditions index 7ab93ba86..e48284938 160000 --- a/src/cryptoconditions +++ b/src/cryptoconditions @@ -1 +1 @@ -Subproject commit 7ab93ba86174efa32da3dac8b625ff9e1ef05fdd +Subproject commit e482849382f36702fe083c5604dd160f4ebaedd1 From 73b9e32b9d7ede630af0df9bae8853cd9fa1b88a Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Wed, 21 Feb 2018 14:10:42 -0300 Subject: [PATCH 031/339] update to latest libcryptoconditions --- src/cryptoconditions | 2 +- src/script/interpreter.cpp | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/cryptoconditions b/src/cryptoconditions index e48284938..6b859e63a 160000 --- a/src/cryptoconditions +++ b/src/cryptoconditions @@ -1 +1 @@ -Subproject commit e482849382f36702fe083c5604dd160f4ebaedd1 +Subproject commit 6b859e63a2bce5107f9b888823f2709a13dd3c26 diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index e0c2c1d01..1e5c7ec79 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -949,10 +949,9 @@ bool EvalScript(vector >& stack, const CScript& script, un valtype& vchFulfillment = stacktop(-2); valtype& vchCondition = stacktop(-1); - CC *cond = (CC*) calloc(1, sizeof(CC)); char *fulfillmentBin = (char*) vchFulfillment.data(); - int rc = cc_readFulfillmentBinary(cond, fulfillmentBin, vchFulfillment.size()); - if (rc != 0) { + CC *cond = cc_readFulfillmentBinary(fulfillmentBin, vchFulfillment.size()); + if (!cond) { return set_error(serror, SCRIPT_ERR_CRYPTOCONDITION_INVALID_FULFILLMENT); } From 691b8708f1bbbab2df2163ad17d9d0b6a2abb67f Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Wed, 21 Feb 2018 19:28:52 -0300 Subject: [PATCH 032/339] Komodo CC aux callback has access to transaction via checker --- src/Makefile.am | 2 ++ src/cryptoconditions | 2 +- src/komodo_cryptoconditions.cpp | 8 ++++++++ src/komodo_cryptoconditions.h | 7 ------- src/script/interpreter.cpp | 32 ++++++++++++++++++++------------ src/script/interpreter.h | 14 ++++++++++---- 6 files changed, 41 insertions(+), 24 deletions(-) create mode 100644 src/komodo_cryptoconditions.cpp diff --git a/src/Makefile.am b/src/Makefile.am index 815d75d4c..4ec21614d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -336,6 +336,7 @@ libbitcoin_common_a_SOURCES = \ script/script_error.cpp \ script/sign.cpp \ script/standard.cpp \ + komodo_cryptoconditions.cpp \ $(BITCOIN_CORE_H) \ $(LIBZCASH_H) @@ -505,6 +506,7 @@ libzcashconsensus_la_SOURCES = \ script/zcashconsensus.cpp \ script/interpreter.cpp \ script/script.cpp \ + komodo_cryptoconditions.cpp \ uint256.cpp \ utilstrencodings.cpp diff --git a/src/cryptoconditions b/src/cryptoconditions index 6b859e63a..e33203ae3 160000 --- a/src/cryptoconditions +++ b/src/cryptoconditions @@ -1 +1 @@ -Subproject commit 6b859e63a2bce5107f9b888823f2709a13dd3c26 +Subproject commit e33203ae3430d2682a4eb734ceaf63791eb0eb6d diff --git a/src/komodo_cryptoconditions.cpp b/src/komodo_cryptoconditions.cpp new file mode 100644 index 000000000..a7fcf9f99 --- /dev/null +++ b/src/komodo_cryptoconditions.cpp @@ -0,0 +1,8 @@ + +#include "cryptoconditions/include/cryptoconditions.h" +#include "script/interpreter.h" + + +int CryptoConditionChecker::CheckAuxCondition(const CC *cond) const { + return true; +} diff --git a/src/komodo_cryptoconditions.h b/src/komodo_cryptoconditions.h index 3cfc15e12..42cf3b077 100644 --- a/src/komodo_cryptoconditions.h +++ b/src/komodo_cryptoconditions.h @@ -9,11 +9,4 @@ static bool IsCryptoConditionsEnabled() { return 0 != ASSETCHAINS_CC; } -/* - * Method stub for aux conditions. Unimplemented, thus fails if an aux condition is encountered. - */ -static int komodoCCAux(CC *cond, void *context) { - return 0; -} - #endif /* KOMODO_CRYPTOCONDITIONS_H */ diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 1e5c7ec79..689dcf204 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -949,18 +949,15 @@ bool EvalScript(vector >& stack, const CScript& script, un valtype& vchFulfillment = stacktop(-2); valtype& vchCondition = stacktop(-1); - char *fulfillmentBin = (char*) vchFulfillment.data(); - CC *cond = cc_readFulfillmentBinary(fulfillmentBin, vchFulfillment.size()); + CC *cond = cc_readFulfillmentBinary((unsigned char*)vchFulfillment.data(), + vchFulfillment.size()); if (!cond) { return set_error(serror, SCRIPT_ERR_CRYPTOCONDITION_INVALID_FULFILLMENT); } - char *condBin = (char*) &vchCondition[0]; - // TODO: Should nHashType be hardcoded? - // Other types use the last byte of the signature - char *msg = (char*) checker.GetMessage(script, SIGHASH_ALL).begin(); + bool fSuccess = checker.CheckCryptoCondition(cond, vchCondition, script); - bool fSuccess = cc_verify(cond, msg, 32, condBin, vchCondition.size(), komodoCCAux, NULL); + cc_free(cond); popstack(stack); popstack(stack); @@ -1155,6 +1152,22 @@ bool TransactionSignatureChecker::CheckSig(const vector& vchSigIn return true; } +extern "C" +{ + static int komodoCCAux(CC *cond, void *transactionSignatureChecker); +} + +static int komodoCCAux(CC *cond, void *checker) { + return ((CryptoConditionChecker*)checker)->CheckAuxCondition(cond); +} + +bool TransactionSignatureChecker::CheckCryptoCondition(const CC *cond, const std::vector& condBin, const CScript& scriptCode) const +{ + uint256 message = SignatureHash(scriptCode, *txTo, nIn, SIGHASH_ALL); + return cc_verify(cond, (const unsigned char*)&message, 32, + condBin.data(), condBin.size(), komodoCCAux, (void*)this); +} + bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) const { // There are two times of nLockTime: lock-by-blockheight @@ -1191,11 +1204,6 @@ bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) con return true; } -uint256 TransactionSignatureChecker::GetMessage(const CScript& scriptCode, int nHashType) const -{ - return SignatureHash(scriptCode, *txTo, nIn, nHashType); -} - bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror) { diff --git a/src/script/interpreter.h b/src/script/interpreter.h index fad2d9a91..90c50eff6 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -8,6 +8,7 @@ #include "script_error.h" #include "primitives/transaction.h" +#include "komodo_cryptoconditions.h" #include #include @@ -102,10 +103,9 @@ public: return false; } - virtual uint256 GetMessage(const CScript& scriptCode, int nHashType) const + virtual bool CheckCryptoCondition(const CC *cond, const std::vector& condBin, const CScript& scriptCode) const { - uint256 blob; - return blob; + return false; } virtual ~BaseSignatureChecker() {} @@ -124,7 +124,7 @@ public: TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn) : txTo(txToIn), nIn(nInIn) {} bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode) const; bool CheckLockTime(const CScriptNum& nLockTime) const; - uint256 GetMessage(const CScript& scriptCode, int nHashType) const; + bool CheckCryptoCondition(const CC *cond, const std::vector& condBin, const CScript& scriptCode) const; }; class MutableTransactionSignatureChecker : public TransactionSignatureChecker @@ -139,4 +139,10 @@ public: bool EvalScript(std::vector >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = NULL); bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = NULL); +class CryptoConditionChecker : public TransactionSignatureChecker +{ +public: + int CheckAuxCondition(const CC *cond) const; +}; + #endif // BITCOIN_SCRIPT_INTERPRETER_H From db2df2c37ba98cf7490122a9176f0cad17d94f85 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Thu, 22 Feb 2018 00:59:15 -0300 Subject: [PATCH 033/339] integration test for basic aux condition --- qa/cryptoconditions/test_integration.py | 42 ++++++++++++++++++++++++- src/cryptoconditions | 2 +- src/komodo_cryptoconditions.cpp | 7 ++++- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/qa/cryptoconditions/test_integration.py b/qa/cryptoconditions/test_integration.py index 24792cc60..d5b456953 100644 --- a/qa/cryptoconditions/test_integration.py +++ b/qa/cryptoconditions/test_integration.py @@ -74,7 +74,7 @@ def test_invalid_condition(inp): assert 'Script evaluated without error but finished with a false/empty top stack element' in str(e), str(e) -@fanout_input(19) +@fanout_input(5) def test_oversize_fulfillment(inp): # Create oversize fulfillment script where the total length is <2000 binscript = b'\x4d%s%s' % (struct.pack('h', 2000), b'a' * 2000) @@ -87,6 +87,46 @@ def test_oversize_fulfillment(inp): assert 'scriptsig-size' in str(e), str(e) +@fanout_input(6) +def test_aux_basic(inp): + aux_cond = { + 'type': 'aux-sha-256', + 'method': 'equals', + 'conditionAux': 'LTE', + 'fulfillmentAux': 'LTE' + } + + # Setup some aux outputs + spend0 = { + 'inputs': [inp], + 'outputs': [ + {'amount': 500, 'script': {'condition': aux_cond}}, + {'amount': 500, 'script': {'condition': aux_cond}} + ] + } + spend0_txid = submit(sign(spend0)) + assert rpc.getrawtransaction(spend0_txid) + + # Test a good fulfillment + spend1 = { + 'inputs': [{'txid': spend0_txid, 'idx': 0, 'script': {'fulfillment': aux_cond}}], + 'outputs': [{'amount': 500, 'script': {'condition': aux_cond}}] + } + spend1_txid = submit(sign(spend1)) + assert rpc.getrawtransaction(spend1_txid) + + # Test a bad fulfillment + aux_cond['fulfillmentAux'] = 'WYW' + spend2 = { + 'inputs': [{'txid': spend0_txid, 'idx': 1, 'script': {'fulfillment': aux_cond}}], + 'outputs': [{'amount': 500, 'script': {'condition': aux_cond}}] + } + try: + assert not submit(sign(spend2)), 'should raise an error' + except RPCError as e: + assert 'Script evaluated without error but finished with a false/empty top stack element' in str(e), str(e) + + if __name__ == '__main__': logging.basicConfig(level=logging.INFO) for name, f in globals().items(): diff --git a/src/cryptoconditions b/src/cryptoconditions index e33203ae3..0dcac79cf 160000 --- a/src/cryptoconditions +++ b/src/cryptoconditions @@ -1 +1 @@ -Subproject commit e33203ae3430d2682a4eb734ceaf63791eb0eb6d +Subproject commit 0dcac79cf9ffeda8aff9d3e9e41fa23ac8208486 diff --git a/src/komodo_cryptoconditions.cpp b/src/komodo_cryptoconditions.cpp index a7fcf9f99..9617add50 100644 --- a/src/komodo_cryptoconditions.cpp +++ b/src/komodo_cryptoconditions.cpp @@ -4,5 +4,10 @@ int CryptoConditionChecker::CheckAuxCondition(const CC *cond) const { - return true; + if (0 == strcmp((const char*)cond->method, "equals")) { + return (cond->conditionAuxLength == cond->fulfillmentAuxLength) && + (0 == memcmp(cond->conditionAux, cond->fulfillmentAux, cond->conditionAuxLength)); + } + printf("no defined behaviour for method:%s\n", cond->method); + return 0; } From 46d1bcc607ee5b795ed72351b24f978ab6952633 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Thu, 22 Feb 2018 01:43:43 -0300 Subject: [PATCH 034/339] integration test for complex aux condition --- qa/cryptoconditions/test_integration.py | 44 +++++++++++++++++++++++++ src/komodo_cryptoconditions.cpp | 13 +++++++- src/script/interpreter.cpp | 2 +- src/script/interpreter.h | 7 +--- 4 files changed, 58 insertions(+), 8 deletions(-) diff --git a/qa/cryptoconditions/test_integration.py b/qa/cryptoconditions/test_integration.py index d5b456953..6d60ee921 100644 --- a/qa/cryptoconditions/test_integration.py +++ b/qa/cryptoconditions/test_integration.py @@ -127,6 +127,50 @@ def test_aux_basic(inp): assert 'Script evaluated without error but finished with a false/empty top stack element' in str(e), str(e) +@fanout_input(7) +def test_aux_complex(inp): + aux_cond = { + 'type': 'aux-sha-256', + 'method': 'inputIsReturn', + 'conditionAux': '', + 'fulfillmentAux': 'AQ' # \1 (tx.vout[1]) + } + + # Setup some aux outputs + spend0 = { + 'inputs': [inp], + 'outputs': [ + {'amount': 500, 'script': {'condition': aux_cond}}, + {'amount': 500, 'script': {'condition': aux_cond}} + ] + } + spend0_txid = submit(sign(spend0)) + assert rpc.getrawtransaction(spend0_txid) + + # Test a good fulfillment + spend1 = { + 'inputs': [{'txid': spend0_txid, 'idx': 0, 'script': {'fulfillment': aux_cond}}], + 'outputs': [ + {'amount': 250, 'script': {'condition': aux_cond}}, + {'amount': 250, 'script': "6A0B68656C6C6F207468657265"} # OP_RETURN somedata + ] + } + spend1_txid = submit(sign(spend1)) + assert rpc.getrawtransaction(spend1_txid) + + # Test a bad fulfillment + spend2 = { + 'inputs': [{'txid': spend0_txid, 'idx': 1, 'script': {'fulfillment': aux_cond}}], + 'outputs': [ + {'amount': 500, 'script': "6A0B68656C6C6F207468657265"} # OP_RETURN somedata + ] + } + try: + assert not submit(sign(spend2)), 'should raise an error' + except RPCError as e: + assert 'Script evaluated without error but finished with a false/empty top stack element' in str(e), str(e) + + if __name__ == '__main__': logging.basicConfig(level=logging.INFO) for name, f in globals().items(): diff --git a/src/komodo_cryptoconditions.cpp b/src/komodo_cryptoconditions.cpp index 9617add50..c807df7c9 100644 --- a/src/komodo_cryptoconditions.cpp +++ b/src/komodo_cryptoconditions.cpp @@ -3,11 +3,22 @@ #include "script/interpreter.h" -int CryptoConditionChecker::CheckAuxCondition(const CC *cond) const { +int TransactionSignatureChecker::CheckAuxCondition(const CC *cond) const { + + // Check that condition is equal to fulfillment if (0 == strcmp((const char*)cond->method, "equals")) { return (cond->conditionAuxLength == cond->fulfillmentAuxLength) && (0 == memcmp(cond->conditionAux, cond->fulfillmentAux, cond->conditionAuxLength)); } + + // Check that pubKeyScript specified in fulfillment is OP_RETURN + if (0 == strcmp((const char*)cond->method, "inputIsReturn")) { + if (cond->fulfillmentAuxLength != 1) return 0; + int n = (int) cond->fulfillmentAux[0]; + if (n >= txTo->vout.size()) return 0; + uint8_t *ptr = (uint8_t *)txTo->vout[n].scriptPubKey.data(); + return ptr[0] == OP_RETURN; + } printf("no defined behaviour for method:%s\n", cond->method); return 0; } diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 689dcf204..709b566f6 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1158,7 +1158,7 @@ extern "C" } static int komodoCCAux(CC *cond, void *checker) { - return ((CryptoConditionChecker*)checker)->CheckAuxCondition(cond); + return ((TransactionSignatureChecker*)checker)->CheckAuxCondition(cond); } bool TransactionSignatureChecker::CheckCryptoCondition(const CC *cond, const std::vector& condBin, const CScript& scriptCode) const diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 90c50eff6..8936fde7a 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -125,6 +125,7 @@ public: bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode) const; bool CheckLockTime(const CScriptNum& nLockTime) const; bool CheckCryptoCondition(const CC *cond, const std::vector& condBin, const CScript& scriptCode) const; + int CheckAuxCondition(const CC *cond) const; }; class MutableTransactionSignatureChecker : public TransactionSignatureChecker @@ -139,10 +140,4 @@ public: bool EvalScript(std::vector >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = NULL); bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = NULL); -class CryptoConditionChecker : public TransactionSignatureChecker -{ -public: - int CheckAuxCondition(const CC *cond) const; -}; - #endif // BITCOIN_SCRIPT_INTERPRETER_H From 7d937f290e08522beaf10d6ffe237a756a06361b Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Sat, 24 Feb 2018 19:43:37 -0300 Subject: [PATCH 035/339] add secp256k1 condition type to cryptoconditions --- .gitmodules | 2 +- qa/cryptoconditions/test_integration.py | 53 ++++++++++++++++++++++--- qa/cryptoconditions/testsupport.py | 22 ++++++++-- src/cryptoconditions | 2 +- src/komodo_cryptoconditions.cpp | 4 +- src/script/interpreter.cpp | 2 +- src/secp256k1/src/ecdsa_impl.h | 10 ++++- 7 files changed, 81 insertions(+), 14 deletions(-) diff --git a/.gitmodules b/.gitmodules index 83942a053..bf76cc359 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "cryptoconditions"] path = src/cryptoconditions url = https://github.com/libscott/libcryptoconditions.git - branch = komodo-integration + branch = komodo diff --git a/qa/cryptoconditions/test_integration.py b/qa/cryptoconditions/test_integration.py index 6d60ee921..f764fcb81 100644 --- a/qa/cryptoconditions/test_integration.py +++ b/qa/cryptoconditions/test_integration.py @@ -7,6 +7,9 @@ import struct from testsupport import * +SCRIPT_FALSE = 'Script evaluated without error but finished with a false/empty top stack element' + + @fanout_input(0) def test_basic_spend(inp): spend = {'inputs': [inp], "outputs": [nospend]} @@ -27,7 +30,7 @@ def test_fulfillment_wrong_signature(inp): try: assert not submit(signed), 'should raise an error' except RPCError as e: - assert 'Script evaluated without error but finished with a false/empty top stack element' in str(e), str(e) + assert SCRIPT_FALSE in str(e), str(e) @fanout_input(2) @@ -41,7 +44,7 @@ def test_fulfillment_wrong_pubkey(inp): try: assert not submit(signed), 'should raise an error' except RPCError as e: - assert 'Script evaluated without error but finished with a false/empty top stack element' in str(e), str(e) + assert SCRIPT_FALSE in str(e), str(e) @fanout_input(3) @@ -71,7 +74,7 @@ def test_invalid_condition(inp): try: assert not submit(sign(spend1)), 'should raise an error' except RPCError as e: - assert 'Script evaluated without error but finished with a false/empty top stack element' in str(e), str(e) + assert SCRIPT_FALSE in str(e), str(e) @fanout_input(5) @@ -124,7 +127,7 @@ def test_aux_basic(inp): try: assert not submit(sign(spend2)), 'should raise an error' except RPCError as e: - assert 'Script evaluated without error but finished with a false/empty top stack element' in str(e), str(e) + assert SCRIPT_FALSE in str(e), str(e) @fanout_input(7) @@ -168,7 +171,47 @@ def test_aux_complex(inp): try: assert not submit(sign(spend2)), 'should raise an error' except RPCError as e: - assert 'Script evaluated without error but finished with a false/empty top stack element' in str(e), str(e) + assert SCRIPT_FALSE in str(e), str(e) + + +@fanout_input(8) +def test_secp256k1_condition(inp): + ec_cond = { + 'type': 'secp256k1-sha-256', + 'publicKey': notary_pk + } + + # Create some secp256k1 outputs + spend0 = { + 'inputs': [inp], + 'outputs': [ + {'amount': 500, 'script': {'condition': ec_cond}}, + {'amount': 500, 'script': {'condition': ec_cond}} + ] + } + spend0_txid = submit(sign(spend0)) + assert rpc.getrawtransaction(spend0_txid) + + # Test a good fulfillment + spend1 = { + 'inputs': [{'txid': spend0_txid, 'idx': 0, 'script': {'fulfillment': ec_cond}}], + 'outputs': [{'amount': 500, 'script': {'condition': ec_cond}}] + } + spend1_txid = submit(sign(spend1)) + assert rpc.getrawtransaction(spend1_txid) + + # Test a bad fulfillment + spend2 = { + 'inputs': [{'txid': spend0_txid, 'idx': 1, 'script': {'fulfillment': ec_cond}}], + 'outputs': [{'amount': 500, 'script': {'condition': ec_cond}}] + } + signed = sign(spend2) + signed['tx']['inputs'][0]['script']['fulfillment']['publicKey'] = \ + '0275cef12fc5c49be64f5aab3d1fbba08cd7b0d02908b5112fbd8504218d14bc7d' + try: + assert not submit(signed), 'should raise an error' + except RPCError as e: + assert SCRIPT_FALSE in str(e), str(e) if __name__ == '__main__': diff --git a/qa/cryptoconditions/testsupport.py b/qa/cryptoconditions/testsupport.py index e6025c0bc..35b7ecdf6 100644 --- a/qa/cryptoconditions/testsupport.py +++ b/qa/cryptoconditions/testsupport.py @@ -74,7 +74,8 @@ def wait_for_block(height): def sign(tx): signed = hoek.signTxBitcoin({'tx': tx, 'privateKeys': [notary_sk]}) - return hoek.signTxEd25519({'tx': signed['tx'], 'privateKeys': [alice_sk, bob_sk]}) + signed = hoek.signTxEd25519({'tx': signed['tx'], 'privateKeys': [alice_sk, bob_sk]}) + return hoek.signTxSecp256k1({'tx': signed['tx'], 'privateKeys': [notary_sk]}) def submit(tx): @@ -96,14 +97,14 @@ def get_fanout_txid(): reward_tx = hoek.decodeTx({'hex': reward_tx_raw}) balance = reward_tx['tx']['outputs'][0]['amount'] - n_outs = 100 + n_outs = 16 remainder = balance - n_outs * 1000 fanout = { 'inputs': [ {'txid': reward_txid, 'idx': 0, 'script': {'pubkey': notary_pk}} ], - "outputs": (100 * [ + "outputs": (n_outs * [ {"amount": 1000, "script": {"condition": cond_alice}} ] + [{"amount": remainder, 'script': {'address': notary_addr}}]) } @@ -122,6 +123,21 @@ def fanout_input(n): return decorate +def decode_base64(data): + """Decode base64, padding being optional. + + :param data: Base64 data as an ASCII byte string + :returns: The decoded byte string. + """ + missing_padding = len(data) % 4 + if missing_padding: + data += '=' * (4 - missing_padding) + return base64.urlsafe_b64decode(data) + + +def encode_base64(data): + return base64.urlsafe_b64encode(data).rstrip(b'=') + notary_addr = 'RXSwmXKtDURwXP7sdqNfsJ6Ga8RaxTchxE' notary_pk = '0205a8ad0c1dbc515f149af377981aab58b836af008d4d7ab21bd76faf80550b47' diff --git a/src/cryptoconditions b/src/cryptoconditions index 0dcac79cf..863d92661 160000 --- a/src/cryptoconditions +++ b/src/cryptoconditions @@ -1 +1 @@ -Subproject commit 0dcac79cf9ffeda8aff9d3e9e41fa23ac8208486 +Subproject commit 863d9266141667b469a6574ce7285134665427c6 diff --git a/src/komodo_cryptoconditions.cpp b/src/komodo_cryptoconditions.cpp index c807df7c9..4c516b320 100644 --- a/src/komodo_cryptoconditions.cpp +++ b/src/komodo_cryptoconditions.cpp @@ -3,8 +3,8 @@ #include "script/interpreter.h" -int TransactionSignatureChecker::CheckAuxCondition(const CC *cond) const { - +int TransactionSignatureChecker::CheckAuxCondition(const CC *cond) const +{ // Check that condition is equal to fulfillment if (0 == strcmp((const char*)cond->method, "equals")) { return (cond->conditionAuxLength == cond->fulfillmentAuxLength) && diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 709b566f6..91b22039e 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1164,7 +1164,7 @@ static int komodoCCAux(CC *cond, void *checker) { bool TransactionSignatureChecker::CheckCryptoCondition(const CC *cond, const std::vector& condBin, const CScript& scriptCode) const { uint256 message = SignatureHash(scriptCode, *txTo, nIn, SIGHASH_ALL); - return cc_verify(cond, (const unsigned char*)&message, 32, + return cc_verify(cond, (const unsigned char*)&message, 32, 0, condBin.data(), condBin.size(), komodoCCAux, (void*)this); } diff --git a/src/secp256k1/src/ecdsa_impl.h b/src/secp256k1/src/ecdsa_impl.h index ed1d22818..8d97db946 100644 --- a/src/secp256k1/src/ecdsa_impl.h +++ b/src/secp256k1/src/ecdsa_impl.h @@ -47,12 +47,20 @@ static const secp256k1_fe_t secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_C ); static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size) { + + /* libscott had to add this to get this version of the library to read compact sigs */ + int overflow = 0; + if (size == 64) { + secp256k1_scalar_set_b32(&r->r, sig, &overflow); + secp256k1_scalar_set_b32(&r->s, sig+32, &overflow); + return 1; + } + unsigned char ra[32] = {0}, sa[32] = {0}; const unsigned char *rp; const unsigned char *sp; int lenr; int lens; - int overflow; if (sig[0] != 0x30) { return 0; } From 28658719eab23190d0a9c4910254372eda1a0980 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Sun, 25 Feb 2018 16:22:12 -0300 Subject: [PATCH 036/339] tweak hoek interface --- qa/cryptoconditions/test_integration.py | 10 +++++----- qa/cryptoconditions/testsupport.py | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/qa/cryptoconditions/test_integration.py b/qa/cryptoconditions/test_integration.py index f764fcb81..bd72b961d 100644 --- a/qa/cryptoconditions/test_integration.py +++ b/qa/cryptoconditions/test_integration.py @@ -25,7 +25,7 @@ def test_fulfillment_wrong_signature(inp): signed = sign(spend) # Set the correct pubkey, signature is bob's - signed['tx']['inputs'][0]['script']['fulfillment']['publicKey'] = alice_pk + signed['inputs'][0]['script']['fulfillment']['publicKey'] = alice_pk try: assert not submit(signed), 'should raise an error' @@ -39,7 +39,7 @@ def test_fulfillment_wrong_pubkey(inp): signed = sign(spend) # Set the wrong pubkey, signature is correct - signed['tx']['inputs'][0]['script']['fulfillment']['publicKey'] = bob_pk + signed['inputs'][0]['script']['fulfillment']['publicKey'] = bob_pk try: assert not submit(signed), 'should raise an error' @@ -54,7 +54,7 @@ def test_invalid_fulfillment_binary(inp): spend = {'inputs': [inp], 'outputs': [nospend]} try: - assert not submit({'tx': spend}), 'should raise an error' + assert not submit(spend), 'should raise an error' except RPCError as e: assert 'Crypto-Condition payload is invalid' in str(e), str(e) @@ -85,7 +85,7 @@ def test_oversize_fulfillment(inp): spend = {'inputs': [inp], 'outputs': [nospend]} try: - assert not submit({'tx': spend}), 'should raise an error' + assert not submit(spend), 'should raise an error' except RPCError as e: assert 'scriptsig-size' in str(e), str(e) @@ -206,7 +206,7 @@ def test_secp256k1_condition(inp): 'outputs': [{'amount': 500, 'script': {'condition': ec_cond}}] } signed = sign(spend2) - signed['tx']['inputs'][0]['script']['fulfillment']['publicKey'] = \ + signed['inputs'][0]['script']['fulfillment']['publicKey'] = \ '0275cef12fc5c49be64f5aab3d1fbba08cd7b0d02908b5112fbd8504218d14bc7d' try: assert not submit(signed), 'should raise an error' diff --git a/qa/cryptoconditions/testsupport.py b/qa/cryptoconditions/testsupport.py index 35b7ecdf6..e22520f3f 100644 --- a/qa/cryptoconditions/testsupport.py +++ b/qa/cryptoconditions/testsupport.py @@ -74,8 +74,8 @@ def wait_for_block(height): def sign(tx): signed = hoek.signTxBitcoin({'tx': tx, 'privateKeys': [notary_sk]}) - signed = hoek.signTxEd25519({'tx': signed['tx'], 'privateKeys': [alice_sk, bob_sk]}) - return hoek.signTxSecp256k1({'tx': signed['tx'], 'privateKeys': [notary_sk]}) + signed = hoek.signTxEd25519({'tx': signed, 'privateKeys': [alice_sk, bob_sk]}) + return hoek.signTxSecp256k1({'tx': signed, 'privateKeys': [notary_sk]}) def submit(tx): @@ -95,7 +95,7 @@ def get_fanout_txid(): reward_txid = block['tx'][0] reward_tx_raw = rpc.getrawtransaction(reward_txid) reward_tx = hoek.decodeTx({'hex': reward_tx_raw}) - balance = reward_tx['tx']['outputs'][0]['amount'] + balance = reward_tx['outputs'][0]['amount'] n_outs = 16 remainder = balance - n_outs * 1000 From 80ea0d26b01a8cff6f064f9e4b1db09a4effc6b8 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Mon, 26 Feb 2018 02:10:58 -0300 Subject: [PATCH 037/339] latest cryptoconditions --- src/cryptoconditions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cryptoconditions b/src/cryptoconditions index 863d92661..9ba2d4545 160000 --- a/src/cryptoconditions +++ b/src/cryptoconditions @@ -1 +1 @@ -Subproject commit 863d9266141667b469a6574ce7285134665427c6 +Subproject commit 9ba2d454564c3bb31446a2a2d1db8cb992e6cbe0 From b21d2e0f9d433c413ddc5f0ce852d8bedfe86e7c Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Thu, 8 Mar 2018 13:08:37 -0300 Subject: [PATCH 038/339] gitignore binaries --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 5b8b361e1..6f82717db 100644 --- a/.gitignore +++ b/.gitignore @@ -116,3 +116,6 @@ contrib/debian/files contrib/debian/substvars src/rpcmisc~.cpp +src/komodo-cli +src/komodod +src/komodo-tx From 2b2c75de29fc45e9de269e47aba44589ed561160 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Thu, 8 Mar 2018 15:15:01 -0300 Subject: [PATCH 039/339] basic implementation of transaction replacement. requires cleanup and testing --- qa/cryptoconditions/test_integration.py | 126 +++++++++++++----------- qa/cryptoconditions/testsupport.py | 6 +- src/Makefile.am | 7 +- src/cryptoconditions | 2 +- src/komodo_cryptoconditions.cpp | 97 +++++++++++++++--- src/komodo_cryptoconditions.h | 7 ++ src/main.cpp | 62 +++++++++++- src/main.h | 2 +- src/replacementpool.cpp | 96 ++++++++++++++++++ src/replacementpool.h | 68 +++++++++++++ src/script/interpreter.cpp | 8 +- src/script/interpreter.h | 2 +- 12 files changed, 396 insertions(+), 87 deletions(-) create mode 100644 src/replacementpool.cpp create mode 100644 src/replacementpool.h diff --git a/qa/cryptoconditions/test_integration.py b/qa/cryptoconditions/test_integration.py index bd72b961d..1f6746b69 100644 --- a/qa/cryptoconditions/test_integration.py +++ b/qa/cryptoconditions/test_integration.py @@ -4,6 +4,7 @@ import json import logging import binascii import struct +import base64 from testsupport import * @@ -91,20 +92,19 @@ def test_oversize_fulfillment(inp): @fanout_input(6) -def test_aux_basic(inp): - aux_cond = { - 'type': 'aux-sha-256', - 'method': 'equals', - 'conditionAux': 'LTE', - 'fulfillmentAux': 'LTE' +def test_eval_basic(inp): + eval_cond = { + 'type': 'eval-sha-256', + 'method': 'testEval', + 'params': encode_base64('testEval') } - # Setup some aux outputs + # Setup some eval outputs spend0 = { 'inputs': [inp], 'outputs': [ - {'amount': 500, 'script': {'condition': aux_cond}}, - {'amount': 500, 'script': {'condition': aux_cond}} + {'amount': 500, 'script': {'condition': eval_cond}}, + {'amount': 500, 'script': {'condition': eval_cond}} ] } spend0_txid = submit(sign(spend0)) @@ -112,17 +112,17 @@ def test_aux_basic(inp): # Test a good fulfillment spend1 = { - 'inputs': [{'txid': spend0_txid, 'idx': 0, 'script': {'fulfillment': aux_cond}}], - 'outputs': [{'amount': 500, 'script': {'condition': aux_cond}}] + 'inputs': [{'txid': spend0_txid, 'idx': 0, 'script': {'fulfillment': eval_cond}}], + 'outputs': [{'amount': 500, 'script': {'condition': eval_cond}}] } spend1_txid = submit(sign(spend1)) assert rpc.getrawtransaction(spend1_txid) # Test a bad fulfillment - aux_cond['fulfillmentAux'] = 'WYW' + eval_cond['params'] = '' spend2 = { - 'inputs': [{'txid': spend0_txid, 'idx': 1, 'script': {'fulfillment': aux_cond}}], - 'outputs': [{'amount': 500, 'script': {'condition': aux_cond}}] + 'inputs': [{'txid': spend0_txid, 'idx': 1, 'script': {'fulfillment': eval_cond}}], + 'outputs': [{'amount': 500, 'script': {'condition': eval_cond}}] } try: assert not submit(sign(spend2)), 'should raise an error' @@ -131,50 +131,6 @@ def test_aux_basic(inp): @fanout_input(7) -def test_aux_complex(inp): - aux_cond = { - 'type': 'aux-sha-256', - 'method': 'inputIsReturn', - 'conditionAux': '', - 'fulfillmentAux': 'AQ' # \1 (tx.vout[1]) - } - - # Setup some aux outputs - spend0 = { - 'inputs': [inp], - 'outputs': [ - {'amount': 500, 'script': {'condition': aux_cond}}, - {'amount': 500, 'script': {'condition': aux_cond}} - ] - } - spend0_txid = submit(sign(spend0)) - assert rpc.getrawtransaction(spend0_txid) - - # Test a good fulfillment - spend1 = { - 'inputs': [{'txid': spend0_txid, 'idx': 0, 'script': {'fulfillment': aux_cond}}], - 'outputs': [ - {'amount': 250, 'script': {'condition': aux_cond}}, - {'amount': 250, 'script': "6A0B68656C6C6F207468657265"} # OP_RETURN somedata - ] - } - spend1_txid = submit(sign(spend1)) - assert rpc.getrawtransaction(spend1_txid) - - # Test a bad fulfillment - spend2 = { - 'inputs': [{'txid': spend0_txid, 'idx': 1, 'script': {'fulfillment': aux_cond}}], - 'outputs': [ - {'amount': 500, 'script': "6A0B68656C6C6F207468657265"} # OP_RETURN somedata - ] - } - try: - assert not submit(sign(spend2)), 'should raise an error' - except RPCError as e: - assert SCRIPT_FALSE in str(e), str(e) - - -@fanout_input(8) def test_secp256k1_condition(inp): ec_cond = { 'type': 'secp256k1-sha-256', @@ -214,6 +170,60 @@ def test_secp256k1_condition(inp): assert SCRIPT_FALSE in str(e), str(e) +@fanout_input(20) +def test_eval_replacement(inp): + eval_cond = { + 'type': 'eval-sha-256', + 'method': 'testReplace', + 'params': '', + } + + # Setup replaceable output + spend0 = { + 'inputs': [inp], + 'outputs': [ + {'amount': 1000, 'script': {'condition': eval_cond}}, + ] + } + spend0_txid = submit(sign(spend0)) + assert rpc.getrawtransaction(spend0_txid) + + b64_1 = 'AQ==' + spend1 = { + 'inputs': [{'txid': spend0_txid, 'idx': 0, 'script': {'fulfillment': eval_cond}}], + 'outputs': [{'amount': 1000, 'script': {'op_return': b64_1}}] + } + + b64_2 = 'Ag==' + spend2 = { + 'inputs': [{'txid': spend0_txid, 'idx': 0, 'script': {'fulfillment': eval_cond}}], + 'outputs': [{'amount': 1000, 'script': {'op_return': b64_2}}] + } + + # If spend2 is already registered, return true, as this test has already been performed + spend2_txid = hoek.encodeTx(sign(spend2))['txid'] + try: + rpc.getrawtransaction(spend2_txid) + return + except RPCError: + pass + + # Send replaceable + spend1_txid = submit(sign(spend1)) + assert rpc.getrawtransaction(spend1_txid) + + + # Send replacement (higher OP_RETURN data) + spend2_txid = submit(sign(spend2)) + assert rpc.getrawtransaction(spend2_txid) + + # Now the first transaction has gone + try: + assert not rpc.getrawtransaction(spend1_txid), "should raise an error" + except RPCError as e: + assert 'No information available about transaction' in str(e), str(e) + + if __name__ == '__main__': logging.basicConfig(level=logging.INFO) for name, f in globals().items(): diff --git a/qa/cryptoconditions/testsupport.py b/qa/cryptoconditions/testsupport.py index e22520f3f..a127379f6 100644 --- a/qa/cryptoconditions/testsupport.py +++ b/qa/cryptoconditions/testsupport.py @@ -97,7 +97,7 @@ def get_fanout_txid(): reward_tx = hoek.decodeTx({'hex': reward_tx_raw}) balance = reward_tx['outputs'][0]['amount'] - n_outs = 16 + n_outs = 40 remainder = balance - n_outs * 1000 fanout = { @@ -109,7 +109,9 @@ def get_fanout_txid(): ] + [{"amount": remainder, 'script': {'address': notary_addr}}]) } - return submit(sign(fanout)) + txid = submit(sign(fanout)) + rpc.getrawtransaction(txid) + return txid def fanout_input(n): diff --git a/src/Makefile.am b/src/Makefile.am index 4ec21614d..865960ec6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -137,6 +137,7 @@ BITCOIN_CORE_H = \ init.h \ key.h \ keystore.h \ + komodo_cryptoconditions.h \ leveldbwrapper.h \ limitedmap.h \ main.h \ @@ -155,6 +156,7 @@ BITCOIN_CORE_H = \ protocol.h \ pubkey.h \ random.h \ + replacementpool.h \ reverselock.h \ rpcclient.h \ rpcprotocol.h \ @@ -223,6 +225,7 @@ libbitcoin_server_a_SOURCES = \ httprpc.cpp \ httpserver.cpp \ init.cpp \ + komodo_cryptoconditions.cpp \ leveldbwrapper.cpp \ main.cpp \ merkleblock.cpp \ @@ -232,6 +235,7 @@ libbitcoin_server_a_SOURCES = \ noui.cpp \ policy/fees.cpp \ pow.cpp \ + replacementpool.cpp \ rest.cpp \ rpcblockchain.cpp \ rpcmining.cpp \ @@ -325,6 +329,7 @@ libbitcoin_common_a_SOURCES = \ hash.cpp \ key.cpp \ keystore.cpp \ + komodo_cryptoconditions.cpp \ netbase.cpp \ primitives/block.cpp \ primitives/transaction.cpp \ @@ -336,7 +341,6 @@ libbitcoin_common_a_SOURCES = \ script/script_error.cpp \ script/sign.cpp \ script/standard.cpp \ - komodo_cryptoconditions.cpp \ $(BITCOIN_CORE_H) \ $(LIBZCASH_H) @@ -506,7 +510,6 @@ libzcashconsensus_la_SOURCES = \ script/zcashconsensus.cpp \ script/interpreter.cpp \ script/script.cpp \ - komodo_cryptoconditions.cpp \ uint256.cpp \ utilstrencodings.cpp diff --git a/src/cryptoconditions b/src/cryptoconditions index 9ba2d4545..f606567ce 160000 --- a/src/cryptoconditions +++ b/src/cryptoconditions @@ -1 +1 @@ -Subproject commit 9ba2d454564c3bb31446a2a2d1db8cb992e6cbe0 +Subproject commit f606567ce30780c28880094718b5b27c5c426827 diff --git a/src/komodo_cryptoconditions.cpp b/src/komodo_cryptoconditions.cpp index 4c516b320..77e4c6c8a 100644 --- a/src/komodo_cryptoconditions.cpp +++ b/src/komodo_cryptoconditions.cpp @@ -1,24 +1,93 @@ +#include "replacementpool.h" +#include "komodo_cryptoconditions.h" #include "cryptoconditions/include/cryptoconditions.h" #include "script/interpreter.h" +#include "coins.h" -int TransactionSignatureChecker::CheckAuxCondition(const CC *cond) const +#define REPLACEMENT_WINDOW_BLOCKS 2 + + +bool GetOpReturnData(const CScript &sig, std::vector &data) { - // Check that condition is equal to fulfillment - if (0 == strcmp((const char*)cond->method, "equals")) { - return (cond->conditionAuxLength == cond->fulfillmentAuxLength) && - (0 == memcmp(cond->conditionAux, cond->fulfillmentAux, cond->conditionAuxLength)); - } + auto pc = sig.begin(); + opcodetype opcode; + if (sig.GetOp(pc, opcode)) + if (opcode == OP_RETURN) + if (sig.GetOp(pc, opcode, data)) + return opcode > OP_0 && opcode <= OP_PUSHDATA4; + return false; +} - // Check that pubKeyScript specified in fulfillment is OP_RETURN - if (0 == strcmp((const char*)cond->method, "inputIsReturn")) { - if (cond->fulfillmentAuxLength != 1) return 0; - int n = (int) cond->fulfillmentAux[0]; - if (n >= txTo->vout.size()) return 0; - uint8_t *ptr = (uint8_t *)txTo->vout[n].scriptPubKey.data(); - return ptr[0] == OP_RETURN; + +bool EvalConditionBool(const CC *cond, const CTransaction *txTo) +{ + if (strcmp(cond->method, "testEval") == 0) { + return cond->paramsBinLength == 8 && + memcmp(cond->paramsBin, "testEval", 8) == 0; } - printf("no defined behaviour for method:%s\n", cond->method); + if (strcmp(cond->method, "testReplace") == 0) { + return true; + } + fprintf(stderr, "no defined behaviour for method: %s\n", cond->method); return 0; } + + +bool GetConditionPriority(const CC *cond, CTxReplacementPoolItem *rep) +{ + if (strcmp((const char*)cond->method, "testReplace") == 0) { + std::vector data; + if (GetOpReturnData(rep->tx.vout[0].scriptPubKey, data)) { + rep->priority = (uint64_t) data[0]; + rep->replacementWindow = REPLACEMENT_WINDOW_BLOCKS; + return true; + } + } + return false; +} + + +bool TransactionSignatureChecker::CheckEvalCondition(const CC *cond) const +{ + return EvalConditionBool(cond, txTo); +} + + +extern "C" +{ + int visitConditionPriority(CC *cond, struct CCVisitor visitor); +} + + +int visitConditionPriority(CC *cond, struct CCVisitor visitor) +{ + if (cc_typeId(cond) == CC_Eval) { + if (GetConditionPriority(cond, (CTxReplacementPoolItem*)visitor.context)) { + return 0; // stop + } + } + return 1; // continue +} + + +bool SetReplacementParams(CTxReplacementPoolItem &rep) +{ + // first, see if we have a cryptocondition + const CScript &sig = rep.tx.vin[0].scriptSig; + if (!sig.IsPushOnly()) return false; + CScript::const_iterator pc = sig.begin(); + std::vector data; + opcodetype opcode; + if (!sig.GetOp(pc, opcode, data)) return false; + CC *cond = cc_readFulfillmentBinary((unsigned char*)data.data(), data.size()); + if (!cond) return false; + + // now, see if it has a replacement node + CC *replacementNode = 0; + CCVisitor visitor = {&visitConditionPriority, (const unsigned char*)"", 0, &rep}; + bool out = cc_visit(cond, visitor); + cc_free(cond); + return !out; +} diff --git a/src/komodo_cryptoconditions.h b/src/komodo_cryptoconditions.h index 42cf3b077..406b2f100 100644 --- a/src/komodo_cryptoconditions.h +++ b/src/komodo_cryptoconditions.h @@ -1,12 +1,19 @@ #ifndef KOMODO_CRYPTOCONDITIONS_H #define KOMODO_CRYPTOCONDITIONS_H +#include "coins.h" +#include "replacementpool.h" #include "cryptoconditions/include/cryptoconditions.h" extern int32_t ASSETCHAINS_CC; +extern CTxReplacementPool replacementPool; + static bool IsCryptoConditionsEnabled() { return 0 != ASSETCHAINS_CC; } +bool EvalConditionBool(const CC *cond, const CTransaction *tx); +//uint64_t EvalConditionPriority(const CC *cond, const CTransaction *tx); +bool SetReplacementParams(CTxReplacementPoolItem &rep); #endif /* KOMODO_CRYPTOCONDITIONS_H */ diff --git a/src/main.cpp b/src/main.cpp index 72f25f1fc..2ff543b8c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -21,6 +21,8 @@ #include "pow.h" #include "txdb.h" #include "txmempool.h" +#include "replacementpool.h" +#include "komodo_cryptoconditions.h" #include "ui_interface.h" #include "undo.h" #include "util.h" @@ -53,6 +55,7 @@ extern uint8_t NOTARY_PUBKEY33[33]; BlockMap mapBlockIndex; CChain chainActive; + CBlockIndex *pindexBestHeader = NULL; int64_t nTimeBestReceived = 0; CWaitableCriticalSection csBestBlock; @@ -1107,7 +1110,7 @@ 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) +bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,bool* pfMissingInputs, bool fRejectAbsurdFee, bool fAcceptReplacement) { AssertLockHeld(cs_main); if (pfMissingInputs) @@ -1178,6 +1181,8 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa } } + CTxReplacementPoolResult rpr = RP_NotReplace; + { CCoinsView dummy; CCoinsViewCache view(&dummy); @@ -1331,13 +1336,35 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa return error("AcceptToMemoryPool: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s", hash.ToString()); } - // Store transaction in memory if ( komodo_is_notarytx(tx) == 0 ) KOMODO_ON_DEMAND++; - pool.addUnchecked(hash, entry, !IsInitialBlockDownload()); + + if (fAcceptReplacement) { + CTxReplacementPoolItem item(tx, GetHeight()); + if (SetReplacementParams(item)) { + rpr = replacementPool.replace(item); + } + } + + if (rpr == RP_Invalid) { + // already have a better one + // TODO: Shouldn't neccesary log this as invalid, not sure if punishing peers is the best idea + fprintf(stderr,"accept failure.20\n"); + return error("AcceptToMemoryPool: Replacement is worse %s", hash.ToString()); + } + + // If there is no replacement action happening... + if (rpr == RP_NotReplace) { + // Store transaction in memory + pool.addUnchecked(hash, entry, !IsInitialBlockDownload()); + } } - SyncWithWallets(tx, NULL); + // in order for replaceable transactions to sync with wallet, replacementpool should advise + // wallet of transaction eviction + if (rpr == RP_NotReplace) { + SyncWithWallets(tx, NULL); + } return true; } @@ -1354,6 +1381,12 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock return true; } + // replacementPool lookup is O(n) since there's no index by txid + if (fAllowSlow && replacementPool.lookup(hash, txOut)) + { + return true; + } + if (fTxIndex) { CDiskTxPos postx; if (pblocktree->ReadTxIndex(hash, postx)) { @@ -1403,6 +1436,17 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock return false; } + +void ProcessReplacementPool(int newHeight) +{ + std::vector pending; + replacementPool.removePending(newHeight, pending); + CValidationState stateDummy; + BOOST_FOREACH(CTransaction tx, pending) { + AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, false, false); + } +} + /*char *komodo_getspendscript(uint256 hash,int32_t n) { CTransaction tx; uint256 hashBlock; @@ -2702,6 +2746,13 @@ bool static DisconnectTip(CValidationState &state) { // Update cached incremental witnesses //fprintf(stderr,"chaintip false\n"); GetMainSignals().ChainTip(pindexDelete, &block, newTree, false); + + /* if chain tip disconnects, some transactions may return to the replacementPool + * via AcceptToMemoryPool. + * + * No double send conflicts may result as the winning transaction will be picked. + */ + return true; } @@ -2761,6 +2812,8 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * mempool.check(pcoinsTip); // Update chainActive & related variables. UpdateTip(pindexNew); + // Process pending replacements + ProcessReplacementPool(pindexNew->nHeight-1); // Tell wallet about transactions that went from mempool // to conflicted: BOOST_FOREACH(const CTransaction &tx, txConflicted) { @@ -2770,6 +2823,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * BOOST_FOREACH(const CTransaction &tx, pblock->vtx) { SyncWithWallets(tx, pblock); } + // Update cached incremental witnesses //fprintf(stderr,"chaintip true\n"); GetMainSignals().ChainTip(pindexNew, pblock, oldTree, true); diff --git a/src/main.h b/src/main.h index bcdd04a5e..061dcfcc5 100644 --- a/src/main.h +++ b/src/main.h @@ -250,7 +250,7 @@ void PruneAndFlush(); /** (try to) add transaction to memory pool **/ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree, - bool* pfMissingInputs, bool fRejectAbsurdFee=false); + bool* pfMissingInputs, bool fRejectAbsurdFee=false, bool fAcceptReplacement=true); struct CNodeStateStats { diff --git a/src/replacementpool.cpp b/src/replacementpool.cpp new file mode 100644 index 000000000..0a509ef37 --- /dev/null +++ b/src/replacementpool.cpp @@ -0,0 +1,96 @@ + +#include +#include +#include + +#include "main.h" +#include "coins.h" +#include "replacementpool.h" + + +CTxReplacementPool replacementPool; + + +/* + * Add a transaction to the pool, with a priority. + * Return true if valid, false if not valid. */ +bool ValidateReplacementPoolItem(CTxReplacementPoolItem item) +{ + // Perform some validations. + if (item.tx.vin.size() > 1) { + // Replaceable transactions with multiple inputs are disabled for now. It's not yet clear + // what edge cases may arise. It is speculated that it will "just work", since if + // replaceable transactions spend multiple outputs using the replacement protocol, + // they will never conflict in the replaceMap data structure. But for now, to be prudent, disable. + return false; + } + + // A transaction with 0 priority is not valid. + if (item.priority == 0) { + return false; + } + + return true; +} + + +/* + * Validate the item + * + * Compare the item with any current replacement candidate + * + * Ensure that the item is not passed the replacement window + * + * Insert the item into the map + */ +CTxReplacementPoolResult CTxReplacementPool::replace(CTxReplacementPoolItem &item) +{ + if (!ValidateReplacementPoolItem(item)) { + return RP_Invalid; + } + + auto it = replaceMap.find(item.tx.vin[0].prevout); + + if (it != replaceMap.end()) { + if (it->second.priority >= item.priority) { + // Already have a transaction with equal or greater priority; this is not valid + return RP_Invalid; + } + // copy the previous starting block over + item.startBlock = it->second.startBlock; + } + + // This transaction has higher priority + replaceMap[item.tx.vin[0].prevout] = item; + + return RP_Valid; +} + + +void CTxReplacementPool::removePending(int height, std::vector &txs) +{ + for (auto it = replaceMap.begin(); it != replaceMap.end(); /**/) { + CTxReplacementPoolItem &rep = it->second; + if (rep.GetTargetBlock() <= height) { + txs.push_back(rep.tx); + replaceMap.erase(it++); + } else { + ++it; + } + } +} + + +/* + * O(n) lookup of tx by hash + */ +bool CTxReplacementPool::lookup(uint256 txHash, CTransaction &tx) +{ + for (auto it = replaceMap.begin(); it != replaceMap.end(); it++) { + if (it->second.tx.GetHash() == txHash) { + tx = it->second.tx; + return true; + } + } + return false; +} diff --git a/src/replacementpool.h b/src/replacementpool.h new file mode 100644 index 000000000..71cb775fd --- /dev/null +++ b/src/replacementpool.h @@ -0,0 +1,68 @@ +// Copyright (c) 2018 The Komodo Developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KOMODO_REPLACEMENTCACHE_H +#define KOMODO_REPLACEMENTCACHE_H + +#include "coins.h" +#include "primitives/transaction.h" + + +enum CTxReplacementPoolResult { RP_NotReplace, RP_Valid, RP_Invalid }; + +class CTxReplacementPoolItem +{ +public: + CTransaction tx; + int startBlock; + uint64_t priority; + uint32_t replacementWindow; + + CTxReplacementPoolItem() {} + + CTxReplacementPoolItem(const CTransaction &_tx, int _startBlock) { + tx = _tx; + startBlock = _startBlock; + priority = 0; + replacementWindow = 0; + } + + int GetTargetBlock() + { + return startBlock + replacementWindow; + } +}; + +/** + * CTxReplacementPool stores valid-according-to-the-current-best-chain (??? do we need to do this?) + * transactions that are valid but held for period of time during which + * they may be replaced. + * + * Transactions are added when they are found to be valid but not added + * to the mempool until a timeout. + * + * Replacement pool is like another mempool before the main mempool. + */ +class CTxReplacementPool +{ +private: + // A potential replacement is first stored here, not in the replaceMap. + // This is in case some other checks fail, during AcceptToMemoryPool. + // Later on, if all checks pass, processReplacement() is called. + + /* Index of spends that may be replaced */ + std::map replaceMap; +public: + CTxReplacementPoolResult replace(CTxReplacementPoolItem &item); + + // Remove and return all transactions up to a given block height. + void removePending(int height, std::vector &txs); + + bool lookup(uint256 txHash, CTransaction &tx); +}; + + +extern CTxReplacementPool replacementPool; + +#endif // KOMODO_REPLACEMENTCACHE_H diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 91b22039e..09c09ced3 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1154,18 +1154,18 @@ bool TransactionSignatureChecker::CheckSig(const vector& vchSigIn extern "C" { - static int komodoCCAux(CC *cond, void *transactionSignatureChecker); + static int komodoCCEval(CC *cond, void *transactionSignatureChecker); } -static int komodoCCAux(CC *cond, void *checker) { - return ((TransactionSignatureChecker*)checker)->CheckAuxCondition(cond); +static int komodoCCEval(CC *cond, void *checker) { + return ((TransactionSignatureChecker*)checker)->CheckEvalCondition(cond); } bool TransactionSignatureChecker::CheckCryptoCondition(const CC *cond, const std::vector& condBin, const CScript& scriptCode) const { uint256 message = SignatureHash(scriptCode, *txTo, nIn, SIGHASH_ALL); return cc_verify(cond, (const unsigned char*)&message, 32, 0, - condBin.data(), condBin.size(), komodoCCAux, (void*)this); + condBin.data(), condBin.size(), komodoCCEval, (void*)this); } bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) const diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 8936fde7a..2cdeb8f8e 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -125,7 +125,7 @@ public: bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode) const; bool CheckLockTime(const CScriptNum& nLockTime) const; bool CheckCryptoCondition(const CC *cond, const std::vector& condBin, const CScript& scriptCode) const; - int CheckAuxCondition(const CC *cond) const; + bool CheckEvalCondition(const CC *cond) const; }; class MutableTransactionSignatureChecker : public TransactionSignatureChecker From e102037e61a2274cc807983f3aa150611e471740 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Thu, 8 Mar 2018 16:35:39 -0300 Subject: [PATCH 040/339] cleanup transaction replacement return codes --- src/consensus/validation.h | 1 + src/main.cpp | 23 ++++++++++++----- src/replacementpool.cpp | 53 ++++++++++++++------------------------ src/replacementpool.h | 30 +++++++++++---------- 4 files changed, 52 insertions(+), 55 deletions(-) diff --git a/src/consensus/validation.h b/src/consensus/validation.h index c62adcd8f..6c4db4c59 100644 --- a/src/consensus/validation.h +++ b/src/consensus/validation.h @@ -17,6 +17,7 @@ static const unsigned char REJECT_NONSTANDARD = 0x40; static const unsigned char REJECT_DUST = 0x41; static const unsigned char REJECT_INSUFFICIENTFEE = 0x42; static const unsigned char REJECT_CHECKPOINT = 0x43; +static const unsigned char REJECT_HAVEBETTER = 0x44; /** Capture information about block/transaction validation */ class CValidationState { diff --git a/src/main.cpp b/src/main.cpp index 2ff543b8c..09ff2871c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1181,7 +1181,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa } } - CTxReplacementPoolResult rpr = RP_NotReplace; + CTxReplacementPoolResult rpr = RP_NotReplaceable; { CCoinsView dummy; @@ -1339,22 +1339,31 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa if ( komodo_is_notarytx(tx) == 0 ) KOMODO_ON_DEMAND++; - if (fAcceptReplacement) { + if (fAcceptReplacement) + { CTxReplacementPoolItem item(tx, GetHeight()); if (SetReplacementParams(item)) { rpr = replacementPool.replace(item); } } - if (rpr == RP_Invalid) { + if (rpr == RP_HaveBetter) + { // already have a better one - // TODO: Shouldn't neccesary log this as invalid, not sure if punishing peers is the best idea fprintf(stderr,"accept failure.20\n"); - return error("AcceptToMemoryPool: Replacement is worse %s", hash.ToString()); + return state.DoS(0, error("AcceptToMemoryPool: Replacement is worse"), REJECT_HAVEBETTER, "replacement-is-worse"); + } + + if (rpr == RP_Invalid) + { + // Not valid according to replaceability rules + fprintf(stderr,"accept failure.21\n"); + return state.DoS(0, error("AcceptToMemoryPool: Replacement is invalid"), REJECT_INVALID, "replacement-is-worse"); } // If there is no replacement action happening... - if (rpr == RP_NotReplace) { + if (rpr == RP_NotReplaceable) + { // Store transaction in memory pool.addUnchecked(hash, entry, !IsInitialBlockDownload()); } @@ -1362,7 +1371,7 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa // in order for replaceable transactions to sync with wallet, replacementpool should advise // wallet of transaction eviction - if (rpr == RP_NotReplace) { + if (rpr == RP_NotReplaceable) { SyncWithWallets(tx, NULL); } diff --git a/src/replacementpool.cpp b/src/replacementpool.cpp index 0a509ef37..42da4fa7c 100644 --- a/src/replacementpool.cpp +++ b/src/replacementpool.cpp @@ -1,39 +1,11 @@ -#include -#include -#include - #include "main.h" -#include "coins.h" #include "replacementpool.h" CTxReplacementPool replacementPool; -/* - * Add a transaction to the pool, with a priority. - * Return true if valid, false if not valid. */ -bool ValidateReplacementPoolItem(CTxReplacementPoolItem item) -{ - // Perform some validations. - if (item.tx.vin.size() > 1) { - // Replaceable transactions with multiple inputs are disabled for now. It's not yet clear - // what edge cases may arise. It is speculated that it will "just work", since if - // replaceable transactions spend multiple outputs using the replacement protocol, - // they will never conflict in the replaceMap data structure. But for now, to be prudent, disable. - return false; - } - - // A transaction with 0 priority is not valid. - if (item.priority == 0) { - return false; - } - - return true; -} - - /* * Validate the item * @@ -45,7 +17,17 @@ bool ValidateReplacementPoolItem(CTxReplacementPoolItem item) */ CTxReplacementPoolResult CTxReplacementPool::replace(CTxReplacementPoolItem &item) { - if (!ValidateReplacementPoolItem(item)) { + AssertLockHeld(cs_main); + + // Perform some validations. + if (item.tx.vin.size() > 1) { + // Replaceable transactions with multiple inputs are disabled. + // It seems like quite alot of additional complexity. + return RP_Invalid; + } + + // A transaction with 0 priority is not valid. + if (item.priority == 0) { return RP_Invalid; } @@ -53,22 +35,25 @@ CTxReplacementPoolResult CTxReplacementPool::replace(CTxReplacementPoolItem &ite if (it != replaceMap.end()) { if (it->second.priority >= item.priority) { - // Already have a transaction with equal or greater priority; this is not valid - return RP_Invalid; + return RP_HaveBetter; // (ThanksThough) } - // copy the previous starting block over - item.startBlock = it->second.startBlock; } // This transaction has higher priority replaceMap[item.tx.vin[0].prevout] = item; + replaceMap[item.tx.vin[0].prevout].startBlock = it->second.startBlock; - return RP_Valid; + return RP_Accepted; } +/* + * Remove and return any spends that have matured + */ void CTxReplacementPool::removePending(int height, std::vector &txs) { + AssertLockHeld(cs_main); + for (auto it = replaceMap.begin(); it != replaceMap.end(); /**/) { CTxReplacementPoolItem &rep = it->second; if (rep.GetTargetBlock() <= height) { diff --git a/src/replacementpool.h b/src/replacementpool.h index 71cb775fd..6bf577999 100644 --- a/src/replacementpool.h +++ b/src/replacementpool.h @@ -5,11 +5,11 @@ #ifndef KOMODO_REPLACEMENTCACHE_H #define KOMODO_REPLACEMENTCACHE_H -#include "coins.h" #include "primitives/transaction.h" -enum CTxReplacementPoolResult { RP_NotReplace, RP_Valid, RP_Invalid }; +enum CTxReplacementPoolResult { RP_Accepted, RP_HaveBetter, RP_Invalid, RP_NotReplaceable }; + class CTxReplacementPoolItem { @@ -28,41 +28,43 @@ public: replacementWindow = 0; } - int GetTargetBlock() - { - return startBlock + replacementWindow; - } + int GetTargetBlock() { return startBlock + replacementWindow; } }; /** - * CTxReplacementPool stores valid-according-to-the-current-best-chain (??? do we need to do this?) - * transactions that are valid but held for period of time during which - * they may be replaced. + * CTxReplacementPool stores transactions that are valid but held for + * period of time during which they may be replaced. * * Transactions are added when they are found to be valid but not added * to the mempool until a timeout. * * Replacement pool is like another mempool before the main mempool. + * + * Transactions in the replacement pool are indexed by the output + * that they are spending. Once a replaceable transaction tries to + * spend an output, a countdown of blocks begins at the current block + * plus a window that is set by "userland" code. If another, better + * transaction replaces the spend that's already pending, the countdown + * start block remains the same. */ class CTxReplacementPool { private: - // A potential replacement is first stored here, not in the replaceMap. - // This is in case some other checks fail, during AcceptToMemoryPool. - // Later on, if all checks pass, processReplacement() is called. - /* Index of spends that may be replaced */ std::map replaceMap; public: + /* Try to replace a transaction in the index */ CTxReplacementPoolResult replace(CTxReplacementPoolItem &item); - // Remove and return all transactions up to a given block height. + /* Remove and return all transactions up to a given block height */ void removePending(int height, std::vector &txs); + /* Find a transaction in the index by it's hash. */ bool lookup(uint256 txHash, CTransaction &tx); }; +/* Global instance */ extern CTxReplacementPool replacementPool; #endif // KOMODO_REPLACEMENTCACHE_H From 1fe68cf52a8b6db3626d7fd8bc9cf9f47d612f01 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Thu, 8 Mar 2018 23:01:00 -0300 Subject: [PATCH 041/339] process orphan transactions after processing replacements --- src/komodo_cryptoconditions.h | 8 +-- src/main.cpp | 126 +++++++++++++++++++--------------- 2 files changed, 74 insertions(+), 60 deletions(-) diff --git a/src/komodo_cryptoconditions.h b/src/komodo_cryptoconditions.h index 406b2f100..24eb341ed 100644 --- a/src/komodo_cryptoconditions.h +++ b/src/komodo_cryptoconditions.h @@ -1,19 +1,19 @@ #ifndef KOMODO_CRYPTOCONDITIONS_H #define KOMODO_CRYPTOCONDITIONS_H -#include "coins.h" #include "replacementpool.h" #include "cryptoconditions/include/cryptoconditions.h" extern int32_t ASSETCHAINS_CC; -extern CTxReplacementPool replacementPool; - static bool IsCryptoConditionsEnabled() { return 0 != ASSETCHAINS_CC; } +extern CTxReplacementPool replacementPool; + bool EvalConditionBool(const CC *cond, const CTransaction *tx); -//uint64_t EvalConditionPriority(const CC *cond, const CTransaction *tx); + bool SetReplacementParams(CTxReplacementPoolItem &rep); + #endif /* KOMODO_CRYPTOCONDITIONS_H */ diff --git a/src/main.cpp b/src/main.cpp index 09ff2871c..ecf0e4f30 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1446,13 +1446,17 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock } +void ProcessOrphanTransactions(uint256 initialHash); + void ProcessReplacementPool(int newHeight) { std::vector pending; replacementPool.removePending(newHeight, pending); CValidationState stateDummy; BOOST_FOREACH(CTransaction tx, pending) { - AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, false, false); + if (AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, false, false)) + ProcessOrphanTransactions(tx.GetHash()); + // otherwise silently drop. TODO: log } } @@ -4690,6 +4694,70 @@ void static ProcessGetData(CNode* pfrom) } } + +void ProcessOrphanTransactions(uint256 parentHash) +{ + AssertLockHeld(cs_main); + + vector vWorkQueue, vEraseQueue; + // Recursively process any orphan transactions that depended on this one + vWorkQueue.push_back(parentHash); + set setMisbehaving; + + for (unsigned int i = 0; i < vWorkQueue.size(); i++) + { + map >::iterator itByPrev = mapOrphanTransactionsByPrev.find(vWorkQueue[i]); + if (itByPrev == mapOrphanTransactionsByPrev.end()) + continue; + for (set::iterator mi = itByPrev->second.begin(); + mi != itByPrev->second.end(); + ++mi) + { + const uint256& orphanHash = *mi; + const CTransaction& orphanTx = mapOrphanTransactions[orphanHash].tx; + NodeId fromPeer = mapOrphanTransactions[orphanHash].fromPeer; + bool fMissingInputs2 = false; + // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan + // resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get + // anyone relaying LegitTxX banned) + CValidationState stateDummy; + + + if (setMisbehaving.count(fromPeer)) + continue; + if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) + { + LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString()); + RelayTransaction(orphanTx); + vWorkQueue.push_back(orphanHash); + vEraseQueue.push_back(orphanHash); + } + else if (!fMissingInputs2) + { + int nDos = 0; + if (stateDummy.IsInvalid(nDos) && nDos > 0) + { + // Punish peer that gave us an invalid orphan tx + Misbehaving(fromPeer, nDos); + setMisbehaving.insert(fromPeer); + LogPrint("mempool", " invalid orphan tx %s\n", orphanHash.ToString()); + } + // Has inputs but not accepted to mempool + // Probably non-standard or insufficient fee/priority + LogPrint("mempool", " removed orphan tx %s\n", orphanHash.ToString()); + vEraseQueue.push_back(orphanHash); + assert(recentRejects); + recentRejects->insert(orphanHash); + } + mempool.check(pcoinsTip); + } + } + + BOOST_FOREACH(uint256 hash, vEraseQueue) + EraseOrphanTx(hash); +} + + bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived) { const CChainParams& chainparams = Params(); @@ -5090,8 +5158,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, else if (strCommand == "tx") { - vector vWorkQueue; - vector vEraseQueue; CTransaction tx; vRecv >> tx; @@ -5110,66 +5176,14 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, { mempool.check(pcoinsTip); RelayTransaction(tx); - vWorkQueue.push_back(inv.hash); LogPrint("mempool", "AcceptToMemoryPool: peer=%d %s: accepted %s (poolsz %u)\n", pfrom->id, pfrom->cleanSubVer, tx.GetHash().ToString(), mempool.mapTx.size()); - // Recursively process any orphan transactions that depended on this one - set setMisbehaving; - for (unsigned int i = 0; i < vWorkQueue.size(); i++) - { - map >::iterator itByPrev = mapOrphanTransactionsByPrev.find(vWorkQueue[i]); - if (itByPrev == mapOrphanTransactionsByPrev.end()) - continue; - for (set::iterator mi = itByPrev->second.begin(); - mi != itByPrev->second.end(); - ++mi) - { - const uint256& orphanHash = *mi; - const CTransaction& orphanTx = mapOrphanTransactions[orphanHash].tx; - NodeId fromPeer = mapOrphanTransactions[orphanHash].fromPeer; - bool fMissingInputs2 = false; - // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan - // resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get - // anyone relaying LegitTxX banned) - CValidationState stateDummy; + ProcessOrphanTransactions(inv.hash); - - if (setMisbehaving.count(fromPeer)) - continue; - if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) - { - LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString()); - RelayTransaction(orphanTx); - vWorkQueue.push_back(orphanHash); - vEraseQueue.push_back(orphanHash); - } - else if (!fMissingInputs2) - { - int nDos = 0; - if (stateDummy.IsInvalid(nDos) && nDos > 0) - { - // Punish peer that gave us an invalid orphan tx - Misbehaving(fromPeer, nDos); - setMisbehaving.insert(fromPeer); - LogPrint("mempool", " invalid orphan tx %s\n", orphanHash.ToString()); - } - // Has inputs but not accepted to mempool - // Probably non-standard or insufficient fee/priority - LogPrint("mempool", " removed orphan tx %s\n", orphanHash.ToString()); - vEraseQueue.push_back(orphanHash); - assert(recentRejects); - recentRejects->insert(orphanHash); - } - mempool.check(pcoinsTip); - } - } - - BOOST_FOREACH(uint256 hash, vEraseQueue) - EraseOrphanTx(hash); } // TODO: currently, prohibit joinsplits from entering mapOrphans else if (fMissingInputs && tx.vjoinsplit.size() == 0) From 346eb4ae255ef6cfd1072680a1a559609d25c1c7 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Fri, 9 Mar 2018 09:40:31 -0300 Subject: [PATCH 042/339] small refactor --- src/komodo_cryptoconditions.cpp | 69 ++++++++++++++++----------------- src/komodo_cryptoconditions.h | 6 ++- src/script/interpreter.cpp | 11 ++++-- 3 files changed, 47 insertions(+), 39 deletions(-) diff --git a/src/komodo_cryptoconditions.cpp b/src/komodo_cryptoconditions.cpp index 77e4c6c8a..debc2182f 100644 --- a/src/komodo_cryptoconditions.cpp +++ b/src/komodo_cryptoconditions.cpp @@ -2,26 +2,15 @@ #include "replacementpool.h" #include "komodo_cryptoconditions.h" #include "cryptoconditions/include/cryptoconditions.h" -#include "script/interpreter.h" -#include "coins.h" #define REPLACEMENT_WINDOW_BLOCKS 2 -bool GetOpReturnData(const CScript &sig, std::vector &data) -{ - auto pc = sig.begin(); - opcodetype opcode; - if (sig.GetOp(pc, opcode)) - if (opcode == OP_RETURN) - if (sig.GetOp(pc, opcode, data)) - return opcode > OP_0 && opcode <= OP_PUSHDATA4; - return false; -} - - -bool EvalConditionBool(const CC *cond, const CTransaction *txTo) +/* + * Evaluate the validity of an Eval node + */ +bool EvalConditionValidity(const CC *cond, const CTransaction *txTo) { if (strcmp(cond->method, "testEval") == 0) { return cond->paramsBinLength == 8 && @@ -35,7 +24,16 @@ bool EvalConditionBool(const CC *cond, const CTransaction *txTo) } -bool GetConditionPriority(const CC *cond, CTxReplacementPoolItem *rep) +/* + * Evaluate the priority of an eval node. + * + * This method should set the ->priority and ->replacementWindow (in blocks) + * of the provided replacement pool item. Priority is a 64 bit unsigned int and + * 0 is invalid. + * + * This method does not need to validate, that is done separately. + */ +bool EvalConditionPriority(const CC *cond, CTxReplacementPoolItem *rep) { if (strcmp((const char*)cond->method, "testReplace") == 0) { std::vector data; @@ -49,30 +47,18 @@ bool GetConditionPriority(const CC *cond, CTxReplacementPoolItem *rep) } -bool TransactionSignatureChecker::CheckEvalCondition(const CC *cond) const -{ - return EvalConditionBool(cond, txTo); -} - - -extern "C" -{ - int visitConditionPriority(CC *cond, struct CCVisitor visitor); -} - - int visitConditionPriority(CC *cond, struct CCVisitor visitor) { - if (cc_typeId(cond) == CC_Eval) { - if (GetConditionPriority(cond, (CTxReplacementPoolItem*)visitor.context)) { - return 0; // stop - } - } - return 1; // continue + auto rep = (CTxReplacementPoolItem*)visitor.context; + // visitor protocol is 1 for continue, 0 for stop + return !(cc_typeId(cond) == CC_Eval && EvalConditionPriority(cond, rep)); } -bool SetReplacementParams(CTxReplacementPoolItem &rep) +/* + * Try to get replacement parameters from a transaction in &rep. + */ +bool PutReplacementParams(CTxReplacementPoolItem &rep) { // first, see if we have a cryptocondition const CScript &sig = rep.tx.vin[0].scriptSig; @@ -82,6 +68,7 @@ bool SetReplacementParams(CTxReplacementPoolItem &rep) opcodetype opcode; if (!sig.GetOp(pc, opcode, data)) return false; CC *cond = cc_readFulfillmentBinary((unsigned char*)data.data(), data.size()); + auto wat = {1, ""}; if (!cond) return false; // now, see if it has a replacement node @@ -91,3 +78,15 @@ bool SetReplacementParams(CTxReplacementPoolItem &rep) cc_free(cond); return !out; } + + +bool GetOpReturnData(const CScript &sig, std::vector &data) +{ + auto pc = sig.begin(); + opcodetype opcode; + if (sig.GetOp(pc, opcode)) + if (opcode == OP_RETURN) + if (sig.GetOp(pc, opcode, data)) + return opcode > OP_0 && opcode <= OP_PUSHDATA4; + return false; +} diff --git a/src/komodo_cryptoconditions.h b/src/komodo_cryptoconditions.h index 24eb341ed..926cd0be9 100644 --- a/src/komodo_cryptoconditions.h +++ b/src/komodo_cryptoconditions.h @@ -3,6 +3,8 @@ #include "replacementpool.h" #include "cryptoconditions/include/cryptoconditions.h" +#include "script/script.h" + extern int32_t ASSETCHAINS_CC; @@ -12,8 +14,10 @@ static bool IsCryptoConditionsEnabled() { extern CTxReplacementPool replacementPool; -bool EvalConditionBool(const CC *cond, const CTransaction *tx); +bool EvalConditionValidity(const CC *cond, const CTransaction *tx); bool SetReplacementParams(CTxReplacementPoolItem &rep); +bool GetOpReturnData(const CScript &sig, std::vector &data); + #endif /* KOMODO_CRYPTOCONDITIONS_H */ diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 09c09ced3..208f19c31 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1152,15 +1152,19 @@ bool TransactionSignatureChecker::CheckSig(const vector& vchSigIn return true; } -extern "C" + +bool TransactionSignatureChecker::CheckEvalCondition(const CC *cond) const { - static int komodoCCEval(CC *cond, void *transactionSignatureChecker); + return EvalConditionValidity(cond, txTo); } -static int komodoCCEval(CC *cond, void *checker) { + +static int komodoCCEval(CC *cond, void *checker) +{ return ((TransactionSignatureChecker*)checker)->CheckEvalCondition(cond); } + bool TransactionSignatureChecker::CheckCryptoCondition(const CC *cond, const std::vector& condBin, const CScript& scriptCode) const { uint256 message = SignatureHash(scriptCode, *txTo, nIn, SIGHASH_ALL); @@ -1168,6 +1172,7 @@ bool TransactionSignatureChecker::CheckCryptoCondition(const CC *cond, const std condBin.data(), condBin.size(), komodoCCEval, (void*)this); } + bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) const { // There are two times of nLockTime: lock-by-blockheight From a8acafb3548e57096287313ccdd9782717b7df5a Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Mon, 12 Mar 2018 01:57:35 -0300 Subject: [PATCH 043/339] test suite for replacementPool --- .gitignore | 1 + src/Makefile.am | 5 +- src/Makefile.ktest.include | 16 + src/cryptoconditions | 2 +- src/komodo_cryptoconditions.cpp | 41 +- src/komodo_cryptoconditions.h | 1 + src/main.cpp | 80 ++-- src/replacementpool.cpp | 44 ++- src/replacementpool.h | 9 +- src/rpcmining.cpp | 5 + src/test-komodo/main.cpp | 9 + src/test-komodo/test_replacementpool.cpp | 461 +++++++++++++++++++++++ 12 files changed, 603 insertions(+), 71 deletions(-) create mode 100644 src/Makefile.ktest.include create mode 100644 src/test-komodo/main.cpp create mode 100644 src/test-komodo/test_replacementpool.cpp diff --git a/.gitignore b/.gitignore index 6f82717db..bebcef932 100644 --- a/.gitignore +++ b/.gitignore @@ -119,3 +119,4 @@ src/rpcmisc~.cpp src/komodo-cli src/komodod src/komodo-tx +src/komodo-test diff --git a/src/Makefile.am b/src/Makefile.am index 865960ec6..7c0200623 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -562,9 +562,10 @@ endif @test -f $(PROTOC) $(AM_V_GEN) $(PROTOC) --cpp_out=$(@D) --proto_path=$(abspath $(method, "testEval") == 0) { - return cond->paramsBinLength == 8 && - memcmp(cond->paramsBin, "testEval", 8) == 0; - } - if (strcmp(cond->method, "testReplace") == 0) { - return true; + if (ASSETCHAINS_CC_TEST) { + if (strcmp(cond->method, "testEval") == 0) { + return cond->paramsBinLength == 8 && + memcmp(cond->paramsBin, "testEval", 8) == 0; + } + if (strcmp(cond->method, "testReplace") == 0) { + std::vector data; + auto out = txTo->vout[txTo->vout.size()-1]; // Last output is data + return GetOpReturnData(out.scriptPubKey, data) && data.size() == 2; + } } fprintf(stderr, "no defined behaviour for method: %s\n", cond->method); return 0; @@ -31,16 +35,22 @@ bool EvalConditionValidity(const CC *cond, const CTransaction *txTo) * of the provided replacement pool item. Priority is a 64 bit unsigned int and * 0 is invalid. * - * This method does not need to validate, that is done separately. + * This method does not need to validate, that is done separately. Actually, + * this method will nearly always be called with the same condition and transaction + * in sequence after EvalConditionValidity. If performance became an issue, a very + * small LRU cache could be used to cache a result. */ bool EvalConditionPriority(const CC *cond, CTxReplacementPoolItem *rep) { - if (strcmp((const char*)cond->method, "testReplace") == 0) { - std::vector data; - if (GetOpReturnData(rep->tx.vout[0].scriptPubKey, data)) { - rep->priority = (uint64_t) data[0]; - rep->replacementWindow = REPLACEMENT_WINDOW_BLOCKS; - return true; + if (ASSETCHAINS_CC_TEST) { + if (strcmp((const char*)cond->method, "testReplace") == 0) { + std::vector data; + auto out = rep->tx.vout[rep->tx.vout.size()-1]; // Last output is data + if (GetOpReturnData(out.scriptPubKey, data)) { + rep->replacementWindow = (int) data[0]; + rep->priority = (uint64_t) data[1]; + return true; + } } } return false; @@ -58,7 +68,7 @@ int visitConditionPriority(CC *cond, struct CCVisitor visitor) /* * Try to get replacement parameters from a transaction in &rep. */ -bool PutReplacementParams(CTxReplacementPoolItem &rep) +bool SetReplacementParams(CTxReplacementPoolItem &rep) { // first, see if we have a cryptocondition const CScript &sig = rep.tx.vin[0].scriptSig; @@ -68,7 +78,6 @@ bool PutReplacementParams(CTxReplacementPoolItem &rep) opcodetype opcode; if (!sig.GetOp(pc, opcode, data)) return false; CC *cond = cc_readFulfillmentBinary((unsigned char*)data.data(), data.size()); - auto wat = {1, ""}; if (!cond) return false; // now, see if it has a replacement node diff --git a/src/komodo_cryptoconditions.h b/src/komodo_cryptoconditions.h index 926cd0be9..de12140ef 100644 --- a/src/komodo_cryptoconditions.h +++ b/src/komodo_cryptoconditions.h @@ -7,6 +7,7 @@ extern int32_t ASSETCHAINS_CC; +extern bool ASSETCHAINS_CC_TEST; static bool IsCryptoConditionsEnabled() { return 0 != ASSETCHAINS_CC; diff --git a/src/main.cpp b/src/main.cpp index ecf0e4f30..6c25f1fe8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1110,6 +1110,45 @@ CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowF } +/* + * This should be called from AcceptToMemoryPool in order + * to perform all validations. + */ +bool AcceptToReplacementPool(const CTransaction &tx, CValidationState &state) +{ + CTxReplacementPoolItem item(tx, GetHeight()); + if (!SetReplacementParams(item)) return false; + + switch (replacementPool.replace(item)) { + + case RP_Accept: + return true; + + case RP_HaveBetter: + // already have a better one + fprintf(stderr,"accept failure.20\n"); + return state.Invalid(error("AcceptToMemoryPool: Replacement is worse"), + REJECT_HAVEBETTER, "replacement-is-worse"); + + case RP_InvalidZeroPriority: + // Not valid according to replaceability rules + fprintf(stderr,"accept failure.21\n"); + return state.Invalid(error("AcceptToMemoryPool: Replacement has 0 priority"), + REJECT_INVALID, "replacement-invalid-zero-priority"); + + case RP_InvalidStructure: + // Not valid according to replaceability rules + fprintf(stderr,"accept failure.22\n"); + return state.Invalid(error("AcceptToMemoryPool: Replacement has multiple inputs"), + REJECT_INVALID, "replacement-has-invalid-structure"); + + default: + return false; + } +} + + + bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,bool* pfMissingInputs, bool fRejectAbsurdFee, bool fAcceptReplacement) { AssertLockHeld(cs_main); @@ -1181,8 +1220,6 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa } } - CTxReplacementPoolResult rpr = RP_NotReplaceable; - { CCoinsView dummy; CCoinsViewCache view(&dummy); @@ -1341,40 +1378,15 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa if (fAcceptReplacement) { - CTxReplacementPoolItem item(tx, GetHeight()); - if (SetReplacementParams(item)) { - rpr = replacementPool.replace(item); - } + if (AcceptToReplacementPool(tx, state)) return true; + if (state.IsInvalid()) return false; } - if (rpr == RP_HaveBetter) - { - // already have a better one - fprintf(stderr,"accept failure.20\n"); - return state.DoS(0, error("AcceptToMemoryPool: Replacement is worse"), REJECT_HAVEBETTER, "replacement-is-worse"); - } - - if (rpr == RP_Invalid) - { - // Not valid according to replaceability rules - fprintf(stderr,"accept failure.21\n"); - return state.DoS(0, error("AcceptToMemoryPool: Replacement is invalid"), REJECT_INVALID, "replacement-is-worse"); - } - - // If there is no replacement action happening... - if (rpr == RP_NotReplaceable) - { - // Store transaction in memory - pool.addUnchecked(hash, entry, !IsInitialBlockDownload()); - } - } - - // in order for replaceable transactions to sync with wallet, replacementpool should advise - // wallet of transaction eviction - if (rpr == RP_NotReplaceable) { - SyncWithWallets(tx, NULL); + // Store transaction in memory + pool.addUnchecked(hash, entry, !IsInitialBlockDownload()); } + SyncWithWallets(tx, NULL); return true; } @@ -1989,7 +2001,7 @@ bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, cons // as to the correct behavior - we may want to continue // peering with non-upgraded nodes even after a soft-fork // super-majority vote has passed. - return state.DoS(100,false, REJECT_INVALID, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError()))); + return state.DoS(100, false, REJECT_INVALID, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError()))); } } } @@ -2826,7 +2838,7 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * // Update chainActive & related variables. UpdateTip(pindexNew); // Process pending replacements - ProcessReplacementPool(pindexNew->nHeight-1); + ProcessReplacementPool(pindexNew->nHeight); // Tell wallet about transactions that went from mempool // to conflicted: BOOST_FOREACH(const CTransaction &tx, txConflicted) { diff --git a/src/replacementpool.cpp b/src/replacementpool.cpp index 42da4fa7c..306fa5460 100644 --- a/src/replacementpool.cpp +++ b/src/replacementpool.cpp @@ -1,9 +1,11 @@ #include "main.h" #include "replacementpool.h" +#include "sync.h" CTxReplacementPool replacementPool; +CCriticalSection cs_replacementPool; /* @@ -17,33 +19,39 @@ CTxReplacementPool replacementPool; */ CTxReplacementPoolResult CTxReplacementPool::replace(CTxReplacementPoolItem &item) { - AssertLockHeld(cs_main); + LOCK(cs_replacementPool); - // Perform some validations. - if (item.tx.vin.size() > 1) { - // Replaceable transactions with multiple inputs are disabled. - // It seems like quite alot of additional complexity. - return RP_Invalid; - } + // Replaceable transactions with multiple inputs are disabled + // until someone figures out how they would work. + if (item.tx.vin.size() > 1) return RP_InvalidStructure; // A transaction with 0 priority is not valid. - if (item.priority == 0) { - return RP_Invalid; + if (item.priority == 0) return RP_InvalidZeroPriority; + + // replacementWindow of 0 goes direct to mempool + if (item.replacementWindow == 0) + { + // But we also need to remove replacement candidates + replaceMap.erase(item.tx.vin[0].prevout); + return RP_NoReplace; } - auto it = replaceMap.find(item.tx.vin[0].prevout); + int startBlock = item.startBlock; - if (it != replaceMap.end()) { - if (it->second.priority >= item.priority) { - return RP_HaveBetter; // (ThanksThough) + auto it = replaceMap.find(item.tx.vin[0].prevout); + if (it != replaceMap.end()) + { + if (it->second.replacementWindow <= item.replacementWindow && + it->second.priority >= item.priority) { + return RP_HaveBetter; } + startBlock = it->second.startBlock; } // This transaction has higher priority replaceMap[item.tx.vin[0].prevout] = item; - replaceMap[item.tx.vin[0].prevout].startBlock = it->second.startBlock; - - return RP_Accepted; + replaceMap[item.tx.vin[0].prevout].startBlock = startBlock; + return RP_Accept; } @@ -52,10 +60,11 @@ CTxReplacementPoolResult CTxReplacementPool::replace(CTxReplacementPoolItem &ite */ void CTxReplacementPool::removePending(int height, std::vector &txs) { - AssertLockHeld(cs_main); + LOCK(cs_replacementPool); for (auto it = replaceMap.begin(); it != replaceMap.end(); /**/) { CTxReplacementPoolItem &rep = it->second; + if (rep.GetTargetBlock() <= height) { txs.push_back(rep.tx); replaceMap.erase(it++); @@ -71,6 +80,7 @@ void CTxReplacementPool::removePending(int height, std::vector &tx */ bool CTxReplacementPool::lookup(uint256 txHash, CTransaction &tx) { + LOCK(cs_replacementPool); for (auto it = replaceMap.begin(); it != replaceMap.end(); it++) { if (it->second.tx.GetHash() == txHash) { tx = it->second.tx; diff --git a/src/replacementpool.h b/src/replacementpool.h index 6bf577999..4642f28c5 100644 --- a/src/replacementpool.h +++ b/src/replacementpool.h @@ -8,7 +8,14 @@ #include "primitives/transaction.h" -enum CTxReplacementPoolResult { RP_Accepted, RP_HaveBetter, RP_Invalid, RP_NotReplaceable }; +// My kingdom for a proper sum type... +enum CTxReplacementPoolResult { + RP_Accept, + RP_HaveBetter, + RP_InvalidZeroPriority, + RP_InvalidStructure, + RP_NoReplace +}; class CTxReplacementPoolItem diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp index f2fdc1415..da1d5207f 100644 --- a/src/rpcmining.cpp +++ b/src/rpcmining.cpp @@ -206,8 +206,13 @@ UniValue generate(const UniValue& params, bool fHelp) UniValue blockHashes(UniValue::VARR); unsigned int n = Params().EquihashN(); unsigned int k = Params().EquihashK(); + uint64_t lastTime = 0; while (nHeight < nHeightEnd) { + // Validation may fail if block generation is too fast + if (GetTime() == lastTime) MilliSleep(1001); + lastTime = GetTime(); + #ifdef ENABLE_WALLET std::unique_ptr pblocktemplate(CreateNewBlockWithKey(reservekey)); #else diff --git a/src/test-komodo/main.cpp b/src/test-komodo/main.cpp new file mode 100644 index 000000000..7811d5f9a --- /dev/null +++ b/src/test-komodo/main.cpp @@ -0,0 +1,9 @@ +#include "gtest/gtest.h" +#include "crypto/common.h" + +int main(int argc, char **argv) { + assert(init_and_check_sodium() != -1); + + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/src/test-komodo/test_replacementpool.cpp b/src/test-komodo/test_replacementpool.cpp new file mode 100644 index 000000000..fa081204a --- /dev/null +++ b/src/test-komodo/test_replacementpool.cpp @@ -0,0 +1,461 @@ +#include +#include + +#include "base58.h" +#include "core_io.h" +#include "key.h" +#include "komodo_cryptoconditions.h" +#include "main.h" +#include "miner.h" +#include "random.h" +#include "rpcserver.h" +#include "rpcprotocol.h" +#include "replacementpool.h" +#include "txdb.h" +#include "util.h" +#include "utilstrencodings.h" +#include "utiltime.h" +#include "consensus/validation.h" +#include "primitives/transaction.h" +#include "script/interpreter.h" +#include "cryptoconditions/include/cryptoconditions.h" + + +extern int32_t USE_EXTERNAL_PUBKEY; +extern std::string NOTARY_PUBKEY; +std::string _NOTARY_PUBKEY = "0205a8ad0c1dbc515f149af377981aab58b836af008d4d7ab21bd76faf80550b47"; +std::string NOTARY_SECRET = "UxFWWxsf1d7w7K5TvAWSkeX4H95XQKwdwGv49DXwWUTzPTTjHBbU"; +CKey notaryKey; + +#define VCH(a,b) std::vector(a, a + b) + + +/* + * We need to have control of clock, + * otherwise block production can fail. + */ +int64_t nMockTime; + + +void testSetup() +{ + SelectParams(CBaseChainParams::REGTEST); + + // enable CC + ASSETCHAINS_CC = 1; + ASSETCHAINS_CC_TEST = true; + + // Settings to get block reward + NOTARY_PUBKEY = _NOTARY_PUBKEY; + USE_EXTERNAL_PUBKEY = 1; + mapArgs["-mineraddress"] = "bogus"; + COINBASE_MATURITY = 1; + // Global mock time + nMockTime = GetTime(); + + // Init blockchain + ClearDatadirCache(); + auto pathTemp = GetTempPath() / strprintf("test_komodo_%li_%i", GetTime(), GetRand(100000)); + boost::filesystem::create_directories(pathTemp); + mapArgs["-datadir"] = pathTemp.string(); + pblocktree = new CBlockTreeDB(1 << 20, true); + CCoinsViewDB *pcoinsdbview = new CCoinsViewDB(1 << 23, true); + pcoinsTip = new CCoinsViewCache(pcoinsdbview); + InitBlockIndex(); + + // Set address + ECC_Start(); + + // Notary key + CBitcoinSecret vchSecret; + // this returns false due to network prefix mismatch but works anyway + vchSecret.SetString(NOTARY_SECRET); + notaryKey = vchSecret.GetKey(); +} + + +void generateBlock(CBlock *block=NULL) +{ + UniValue params; + params.setArray(); + params.push_back(1); + uint256 blockId; + + SetMockTime(nMockTime++); // CreateNewBlock can fail if not enough time passes + + try { + UniValue out = generate(params, false); + blockId.SetHex(out[0].getValStr()); + } catch (const UniValue& e) { + FAIL() << "failed to create block: " << e.write().data(); + } + if (block) ASSERT_TRUE(ReadBlockFromDisk(*block, mapBlockIndex[blockId])); +} + + +void acceptTx(const CTransaction tx) +{ + CValidationState state; + LOCK(cs_main); + if (!AcceptToMemoryPool(mempool, state, tx, false, NULL)) + FAIL() << state.GetRejectReason(); +} + + +static CMutableTransaction spendTx(const CTransaction &txIn, int nOut=0) +{ + CMutableTransaction mtx; + mtx.vin.resize(1); + mtx.vin[0].prevout.hash = txIn.GetHash(); + mtx.vin[0].prevout.n = nOut; + mtx.vout.resize(1); + mtx.vout[0].nValue = txIn.vout[nOut].nValue - 1000; + return mtx; +} + + +/* + * In order to do tests there needs to be inputs to spend. + * This method creates a block and returns a transaction that spends the coinbase. + */ +void getInputTx(CScript scriptPubKey, CTransaction &txIn) +{ + // Get coinbase + CBlock block; + generateBlock(&block); + CTransaction coinbase = block.vtx[0]; + + // Create tx + auto mtx = spendTx(coinbase); + mtx.vout[0].scriptPubKey = scriptPubKey; + uint256 hash = SignatureHash(coinbase.vout[0].scriptPubKey, mtx, 0, SIGHASH_ALL); + std::vector vchSig; + notaryKey.Sign(hash, vchSig); + vchSig.push_back((unsigned char)SIGHASH_ALL); + mtx.vin[0].scriptSig << vchSig; + + // Accept + acceptTx(mtx); + txIn = CTransaction(mtx); +} + + +std::string HexToB64(std::string hexStr) +{ + auto d = ParseHex(hexStr); + return EncodeBase64(d.data(), d.size()); +} + + +CC *getReplaceCond() +{ + const char *condJsonTpl = R"V0G0N( + { "type": "threshold-sha-256", + "threshold": 2, + "subfulfillments": [ + { "type": "secp256k1-sha-256", "publicKey": "%s"}, + { "type": "eval-sha-256", "method": "testReplace", "params": "" } + ] })V0G0N"; + char condJson[1000]; + sprintf(condJson, condJsonTpl, (char*)HexToB64(NOTARY_PUBKEY).data()); + + unsigned char err[1000] = "\0"; + return cc_conditionFromJSONString((const unsigned char*)condJson, err); + // above could fail +} + +CScript condPK(CC *cond) +{ + unsigned char buf[1000]; + size_t bufLen = cc_conditionBinary(cond, buf); + return CScript() << VCH(buf, bufLen) << OP_CHECKCRYPTOCONDITION; +} + +void setFulfillment(CMutableTransaction &mtx, CC *cond, const CScript &spk, int nIn=0) +{ + uint256 hash = SignatureHash(spk, mtx, nIn, SIGHASH_ALL); + int nSigned = cc_signTreeSecp256k1Msg32(cond, notaryKey.begin(), hash.begin()); + unsigned char buf[1000]; + size_t bufLen = cc_fulfillmentBinary(cond, buf, 1000); + mtx.vin[nIn].scriptSig = CScript() << VCH(buf, bufLen); +} + + +CScript getReplaceOut(unsigned char replacementWindow, unsigned char priority) +{ + std::vector v = {replacementWindow, priority}; + return CScript() << OP_RETURN << v; +} + + +CTransaction _txout; +#define ASSERT_REPLACEMENT_POOL(hash) ASSERT_TRUE(replacementPool.lookup(hash, _txout)); \ + ASSERT_FALSE(mempool.lookup(hash, _txout)); +#define ASSERT_MEM_POOL(hash) ASSERT_FALSE(replacementPool.lookup(hash, _txout)); \ + ASSERT_TRUE(mempool.lookup(hash, _txout)); + + + +// Setup environment and perform basic spend as test +TEST(replacementpool, 0_setup) +{ + testSetup(); // Only call this method here + + CTransaction txIn; + getInputTx(CScript() << OP_RETURN << VCH("1", 1), txIn); +} + + +// Perform replaceable spend +TEST(replacementpool, 1_basic) +{ + CTransaction txIn; + CC *cond = getReplaceCond(); + getInputTx(condPK(cond), txIn); + + // Spend output to replaceable + auto mtx = spendTx(txIn); + mtx.vout[0].scriptPubKey = getReplaceOut(2, 100); + setFulfillment(mtx, cond, txIn.vout[0].scriptPubKey); + + acceptTx(mtx); + + ASSERT_REPLACEMENT_POOL(mtx.GetHash()); + generateBlock(); + ASSERT_REPLACEMENT_POOL(mtx.GetHash()); + generateBlock(); + ASSERT_MEM_POOL(mtx.GetHash()); +} + + +/* + * replacementWindow is 0, transaction should go direct to mempool + */ +TEST(replacementpool, 2_noWindow) +{ + CTransaction txIn; + CC *cond = getReplaceCond(); + getInputTx(condPK(cond), txIn); + + // First set a tx with a 1 block wait. It should stay in the replacement pool. + auto mtx = spendTx(txIn); + mtx.vout[0].scriptPubKey = getReplaceOut(1, 100); + setFulfillment(mtx, cond, txIn.vout[0].scriptPubKey); + acceptTx(mtx); + ASSERT_REPLACEMENT_POOL(mtx.GetHash()); + + // Now set a transaction with a 0 block wait and higher priority. + // It should go direct to the mem pool. + auto mtx2 = spendTx(txIn); + mtx2.vout[0].scriptPubKey = getReplaceOut(0, 101); + setFulfillment(mtx2, cond, txIn.vout[0].scriptPubKey); + acceptTx(mtx2); + ASSERT_MEM_POOL(mtx2.GetHash()); + + // Additionally, there should be no replacement remaining for txIn in the mempool + ASSERT_FALSE(replacementPool.lookup(mtx.GetHash(), _txout)); +} + + +/* + * Multiple replaceable transactions dont interfere + */ +TEST(replacementpool, 3_noInterfere) +{ + CTransaction txIn1, txIn2; + CC *cond = getReplaceCond(); + getInputTx(condPK(cond), txIn1); + getInputTx(condPK(cond), txIn2); + + // First set a transaction with a low window + auto mtx = spendTx(txIn1); + mtx.vout[0].scriptPubKey = getReplaceOut(1, 100); + setFulfillment(mtx, cond, txIn1.vout[0].scriptPubKey); + acceptTx(mtx); + ASSERT_REPLACEMENT_POOL(mtx.GetHash()); + + // Now, a different spend with a higher window + auto mtx2 = spendTx(txIn2); + mtx2.vout[0].scriptPubKey = getReplaceOut(10, 100); + setFulfillment(mtx2, cond, txIn2.vout[0].scriptPubKey); + acceptTx(mtx2); + ASSERT_REPLACEMENT_POOL(mtx2.GetHash()); + + generateBlock(); + + // mtx has gone to mempool + ASSERT_MEM_POOL(mtx.GetHash()); + + // mtx2 still in replacementpool + ASSERT_REPLACEMENT_POOL(mtx2.GetHash()); + + // But 9 blocks later... + for (int i=0; i<9; i++) + { + generateBlock(); + ASSERT_EQ(i == 8, mempool.lookup(mtx2.GetHash(), _txout)); + } +} + + +/* + * 0 priority is invalid + */ +TEST(replacementpool, 4_invalidZeroPriority) +{ + LOCK(cs_main); + + CTransaction txIn; + CC *cond = getReplaceCond(); + getInputTx(condPK(cond), txIn); + + auto mtx = spendTx(txIn); + mtx.vout[0].scriptPubKey = getReplaceOut(1, 0); + setFulfillment(mtx, cond, txIn.vout[0].scriptPubKey); + + CValidationState state; + ASSERT_FALSE(AcceptToMemoryPool(mempool, state, mtx, false, NULL)); + ASSERT_EQ("replacement-invalid-zero-priority", state.GetRejectReason()); +} + + +/* + * Multiple inputs is invalid + */ +TEST(replacementpool, 5_invalidMultipleInputs) +{ + LOCK(cs_main); + + CTransaction txIn, txIn2; + CC *cond = getReplaceCond(); + getInputTx(condPK(cond), txIn); + getInputTx(condPK(cond), txIn2); + + CMutableTransaction mtx; + mtx.vout.resize(1); + mtx.vout[0].nValue = txIn.vout[0].nValue * 2 - 1000; + mtx.vout[0].scriptPubKey = getReplaceOut(1, 100); + mtx.vin.resize(2); + mtx.vin[0].prevout.hash = txIn.GetHash(); + mtx.vin[0].prevout.n = 0; + mtx.vin[1].prevout.hash = txIn2.GetHash(); + mtx.vin[1].prevout.n = 0; + setFulfillment(mtx, cond, txIn.vout[0].scriptPubKey); + setFulfillment(mtx, cond, txIn2.vout[0].scriptPubKey, 1); + + CValidationState state; + ASSERT_FALSE(AcceptToMemoryPool(mempool, state, mtx, false, NULL)); + ASSERT_EQ("replacement-has-invalid-structure", state.GetRejectReason()); +} + + +extern bool AddOrphanTx(const CTransaction& tx, NodeId peer); +extern void ProcessOrphanTransactions(uint256 parentHash); +struct COrphanTx { CTransaction tx; NodeId fromPeer; }; +extern std::map mapOrphanTransactions; + +/* + * Orphans are processed + */ +TEST(replacementpool, 6_orphansAreProcessed) +{ + LOCK(cs_main); + + CTransaction txIn; + CC *cond = getReplaceCond(); + getInputTx(condPK(cond), txIn); + + // Make basic replaceable spend and dont submit + auto mtx = spendTx(txIn); + mtx.vout.resize(2); + mtx.vout[0].nValue = txIn.vout[0].nValue - 1000; + mtx.vout[0].scriptPubKey = condPK(cond); + mtx.vout[1].nValue = 1; + mtx.vout[1].scriptPubKey = getReplaceOut(1, 100); + setFulfillment(mtx, cond, txIn.vout[0].scriptPubKey); + + // Make an orphan and add it + auto orphan = spendTx(mtx); + orphan.vout[0].scriptPubKey = getReplaceOut(0, 100); + setFulfillment(orphan, cond, mtx.vout[0].scriptPubKey); + ASSERT_TRUE(AddOrphanTx(orphan, 1001)); + ASSERT_EQ(1, mapOrphanTransactions.count(orphan.GetHash())); + + // parent goes into replacement pool + acceptTx(mtx); + ASSERT_REPLACEMENT_POOL(mtx.GetHash()); + + // this should not result in the movement of any orphans + ProcessOrphanTransactions(mtx.GetHash()); + ASSERT_EQ(1, mapOrphanTransactions.count(orphan.GetHash())); + + // Processing of parent transaction also un-orphanises orphan + generateBlock(); + ASSERT_MEM_POOL(mtx.GetHash()); + ASSERT_MEM_POOL(orphan.GetHash()); + ASSERT_EQ(0, mapOrphanTransactions.count(orphan.GetHash())); +} + + +/* + * Add transaction with lower priority, already have better + */ +TEST(replacementpool, 7_haveBetter) +{ + LOCK(cs_main); + + CTransaction txIn; + CC *cond = getReplaceCond(); + getInputTx(condPK(cond), txIn); + + // A replaceable tx. + auto mtx = spendTx(txIn); + mtx.vout[0].scriptPubKey = getReplaceOut(2, 100); + setFulfillment(mtx, cond, txIn.vout[0].scriptPubKey); + acceptTx(mtx); + ASSERT_REPLACEMENT_POOL(mtx.GetHash()); + + // Another one, but not as good. + auto mtx2 = spendTx(txIn); + mtx2.vout[0].scriptPubKey = getReplaceOut(2, 99); + setFulfillment(mtx2, cond, txIn.vout[0].scriptPubKey); + CValidationState state; + ASSERT_FALSE(AcceptToMemoryPool(mempool, state, mtx, false, NULL)); + ASSERT_EQ("replacement-is-worse", state.GetRejectReason()); + ASSERT_REPLACEMENT_POOL(mtx.GetHash()); +} + + +/* + * Add transaction with lower priority, but shorter replacementWindow + */ +TEST(replacementpool, 8_shorterReplacementWindow) +{ + LOCK(cs_main); + + CTransaction txIn; + CC *cond = getReplaceCond(); + getInputTx(condPK(cond), txIn); + + // A replaceable tx. + auto mtx = spendTx(txIn); + mtx.vout[0].scriptPubKey = getReplaceOut(2, 100); + setFulfillment(mtx, cond, txIn.vout[0].scriptPubKey); + acceptTx(mtx); + ASSERT_REPLACEMENT_POOL(mtx.GetHash()); + + // Another one, lower priority but shorter replacementWindow so wins. + auto mtx2 = spendTx(txIn); + mtx2.vout[0].scriptPubKey = getReplaceOut(1, 99); + setFulfillment(mtx2, cond, txIn.vout[0].scriptPubKey); + acceptTx(mtx2); + ASSERT_REPLACEMENT_POOL(mtx2.GetHash()); + ASSERT_FALSE(replacementPool.lookup(mtx.GetHash(), _txout)); + + // Shorter still, in fact direct to mem pool + auto mtx3 = spendTx(txIn); + mtx3.vout[0].scriptPubKey = getReplaceOut(0, 98); + setFulfillment(mtx3, cond, txIn.vout[0].scriptPubKey); + acceptTx(mtx3); + ASSERT_MEM_POOL(mtx3.GetHash()); +} From bd7ecdec066600a3a0f76161daba2773541b6721 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Mon, 12 Mar 2018 17:27:50 -0300 Subject: [PATCH 044/339] fix build, allow 0 priority --- src/cryptoconditions | 2 +- src/main.cpp | 10 +-- src/replacementpool.cpp | 5 +- src/replacementpool.h | 3 +- src/test-komodo/test_replacementpool.cpp | 79 +++++++++--------------- 5 files changed, 34 insertions(+), 65 deletions(-) diff --git a/src/cryptoconditions b/src/cryptoconditions index 3200bc78e..96303cb0a 160000 --- a/src/cryptoconditions +++ b/src/cryptoconditions @@ -1 +1 @@ -Subproject commit 3200bc78e82fe7af54c5b3bc89029070349ed430 +Subproject commit 96303cb0ad2a03fc09338e310dbd90be13bec743 diff --git a/src/main.cpp b/src/main.cpp index 6c25f1fe8..3c2baeae0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1130,17 +1130,11 @@ bool AcceptToReplacementPool(const CTransaction &tx, CValidationState &state) return state.Invalid(error("AcceptToMemoryPool: Replacement is worse"), REJECT_HAVEBETTER, "replacement-is-worse"); - case RP_InvalidZeroPriority: - // Not valid according to replaceability rules - fprintf(stderr,"accept failure.21\n"); - return state.Invalid(error("AcceptToMemoryPool: Replacement has 0 priority"), - REJECT_INVALID, "replacement-invalid-zero-priority"); - - case RP_InvalidStructure: + case RP_Invalid: // Not valid according to replaceability rules fprintf(stderr,"accept failure.22\n"); return state.Invalid(error("AcceptToMemoryPool: Replacement has multiple inputs"), - REJECT_INVALID, "replacement-has-invalid-structure"); + REJECT_INVALID, "replacement-invalid"); default: return false; diff --git a/src/replacementpool.cpp b/src/replacementpool.cpp index 306fa5460..168c30b6e 100644 --- a/src/replacementpool.cpp +++ b/src/replacementpool.cpp @@ -23,10 +23,7 @@ CTxReplacementPoolResult CTxReplacementPool::replace(CTxReplacementPoolItem &ite // Replaceable transactions with multiple inputs are disabled // until someone figures out how they would work. - if (item.tx.vin.size() > 1) return RP_InvalidStructure; - - // A transaction with 0 priority is not valid. - if (item.priority == 0) return RP_InvalidZeroPriority; + if (item.tx.vin.size() > 1) return RP_Invalid; // replacementWindow of 0 goes direct to mempool if (item.replacementWindow == 0) diff --git a/src/replacementpool.h b/src/replacementpool.h index 4642f28c5..d6ab2ed28 100644 --- a/src/replacementpool.h +++ b/src/replacementpool.h @@ -12,8 +12,7 @@ enum CTxReplacementPoolResult { RP_Accept, RP_HaveBetter, - RP_InvalidZeroPriority, - RP_InvalidStructure, + RP_Invalid, RP_NoReplace }; diff --git a/src/test-komodo/test_replacementpool.cpp b/src/test-komodo/test_replacementpool.cpp index fa081204a..b0ccc4278 100644 --- a/src/test-komodo/test_replacementpool.cpp +++ b/src/test-komodo/test_replacementpool.cpp @@ -189,10 +189,10 @@ CScript getReplaceOut(unsigned char replacementWindow, unsigned char priority) CTransaction _txout; -#define ASSERT_REPLACEMENT_POOL(hash) ASSERT_TRUE(replacementPool.lookup(hash, _txout)); \ - ASSERT_FALSE(mempool.lookup(hash, _txout)); -#define ASSERT_MEM_POOL(hash) ASSERT_FALSE(replacementPool.lookup(hash, _txout)); \ - ASSERT_TRUE(mempool.lookup(hash, _txout)); +#define ONLY_REPLACEMENT_POOL(hash) ASSERT_TRUE(replacementPool.lookup(hash, _txout)); \ + ASSERT_FALSE(mempool.lookup(hash, _txout)); +#define ONLY_MEM_POOL(hash) ASSERT_FALSE(replacementPool.lookup(hash, _txout)); \ + ASSERT_TRUE(mempool.lookup(hash, _txout)); @@ -207,7 +207,7 @@ TEST(replacementpool, 0_setup) // Perform replaceable spend -TEST(replacementpool, 1_basic) +TEST(replacementpool, basic) { CTransaction txIn; CC *cond = getReplaceCond(); @@ -220,18 +220,18 @@ TEST(replacementpool, 1_basic) acceptTx(mtx); - ASSERT_REPLACEMENT_POOL(mtx.GetHash()); + ONLY_REPLACEMENT_POOL(mtx.GetHash()); generateBlock(); - ASSERT_REPLACEMENT_POOL(mtx.GetHash()); + ONLY_REPLACEMENT_POOL(mtx.GetHash()); generateBlock(); - ASSERT_MEM_POOL(mtx.GetHash()); + ONLY_MEM_POOL(mtx.GetHash()); } /* * replacementWindow is 0, transaction should go direct to mempool */ -TEST(replacementpool, 2_noWindow) +TEST(replacementpool, noWindow) { CTransaction txIn; CC *cond = getReplaceCond(); @@ -242,7 +242,7 @@ TEST(replacementpool, 2_noWindow) mtx.vout[0].scriptPubKey = getReplaceOut(1, 100); setFulfillment(mtx, cond, txIn.vout[0].scriptPubKey); acceptTx(mtx); - ASSERT_REPLACEMENT_POOL(mtx.GetHash()); + ONLY_REPLACEMENT_POOL(mtx.GetHash()); // Now set a transaction with a 0 block wait and higher priority. // It should go direct to the mem pool. @@ -250,7 +250,7 @@ TEST(replacementpool, 2_noWindow) mtx2.vout[0].scriptPubKey = getReplaceOut(0, 101); setFulfillment(mtx2, cond, txIn.vout[0].scriptPubKey); acceptTx(mtx2); - ASSERT_MEM_POOL(mtx2.GetHash()); + ONLY_MEM_POOL(mtx2.GetHash()); // Additionally, there should be no replacement remaining for txIn in the mempool ASSERT_FALSE(replacementPool.lookup(mtx.GetHash(), _txout)); @@ -260,7 +260,7 @@ TEST(replacementpool, 2_noWindow) /* * Multiple replaceable transactions dont interfere */ -TEST(replacementpool, 3_noInterfere) +TEST(replacementpool, noInterfere) { CTransaction txIn1, txIn2; CC *cond = getReplaceCond(); @@ -272,22 +272,22 @@ TEST(replacementpool, 3_noInterfere) mtx.vout[0].scriptPubKey = getReplaceOut(1, 100); setFulfillment(mtx, cond, txIn1.vout[0].scriptPubKey); acceptTx(mtx); - ASSERT_REPLACEMENT_POOL(mtx.GetHash()); + ONLY_REPLACEMENT_POOL(mtx.GetHash()); // Now, a different spend with a higher window auto mtx2 = spendTx(txIn2); mtx2.vout[0].scriptPubKey = getReplaceOut(10, 100); setFulfillment(mtx2, cond, txIn2.vout[0].scriptPubKey); acceptTx(mtx2); - ASSERT_REPLACEMENT_POOL(mtx2.GetHash()); + ONLY_REPLACEMENT_POOL(mtx2.GetHash()); generateBlock(); // mtx has gone to mempool - ASSERT_MEM_POOL(mtx.GetHash()); + ONLY_MEM_POOL(mtx.GetHash()); // mtx2 still in replacementpool - ASSERT_REPLACEMENT_POOL(mtx2.GetHash()); + ONLY_REPLACEMENT_POOL(mtx2.GetHash()); // But 9 blocks later... for (int i=0; i<9; i++) @@ -298,31 +298,10 @@ TEST(replacementpool, 3_noInterfere) } -/* - * 0 priority is invalid - */ -TEST(replacementpool, 4_invalidZeroPriority) -{ - LOCK(cs_main); - - CTransaction txIn; - CC *cond = getReplaceCond(); - getInputTx(condPK(cond), txIn); - - auto mtx = spendTx(txIn); - mtx.vout[0].scriptPubKey = getReplaceOut(1, 0); - setFulfillment(mtx, cond, txIn.vout[0].scriptPubKey); - - CValidationState state; - ASSERT_FALSE(AcceptToMemoryPool(mempool, state, mtx, false, NULL)); - ASSERT_EQ("replacement-invalid-zero-priority", state.GetRejectReason()); -} - - /* * Multiple inputs is invalid */ -TEST(replacementpool, 5_invalidMultipleInputs) +TEST(replacementpool, invalidMultipleInputs) { LOCK(cs_main); @@ -345,7 +324,7 @@ TEST(replacementpool, 5_invalidMultipleInputs) CValidationState state; ASSERT_FALSE(AcceptToMemoryPool(mempool, state, mtx, false, NULL)); - ASSERT_EQ("replacement-has-invalid-structure", state.GetRejectReason()); + ASSERT_EQ("replacement-invalid", state.GetRejectReason()); } @@ -357,7 +336,7 @@ extern std::map mapOrphanTransactions; /* * Orphans are processed */ -TEST(replacementpool, 6_orphansAreProcessed) +TEST(replacementpool, orphansAreProcessed) { LOCK(cs_main); @@ -383,7 +362,7 @@ TEST(replacementpool, 6_orphansAreProcessed) // parent goes into replacement pool acceptTx(mtx); - ASSERT_REPLACEMENT_POOL(mtx.GetHash()); + ONLY_REPLACEMENT_POOL(mtx.GetHash()); // this should not result in the movement of any orphans ProcessOrphanTransactions(mtx.GetHash()); @@ -391,8 +370,8 @@ TEST(replacementpool, 6_orphansAreProcessed) // Processing of parent transaction also un-orphanises orphan generateBlock(); - ASSERT_MEM_POOL(mtx.GetHash()); - ASSERT_MEM_POOL(orphan.GetHash()); + ONLY_MEM_POOL(mtx.GetHash()); + ONLY_MEM_POOL(orphan.GetHash()); ASSERT_EQ(0, mapOrphanTransactions.count(orphan.GetHash())); } @@ -400,7 +379,7 @@ TEST(replacementpool, 6_orphansAreProcessed) /* * Add transaction with lower priority, already have better */ -TEST(replacementpool, 7_haveBetter) +TEST(replacementpool, haveBetter) { LOCK(cs_main); @@ -413,7 +392,7 @@ TEST(replacementpool, 7_haveBetter) mtx.vout[0].scriptPubKey = getReplaceOut(2, 100); setFulfillment(mtx, cond, txIn.vout[0].scriptPubKey); acceptTx(mtx); - ASSERT_REPLACEMENT_POOL(mtx.GetHash()); + ONLY_REPLACEMENT_POOL(mtx.GetHash()); // Another one, but not as good. auto mtx2 = spendTx(txIn); @@ -422,14 +401,14 @@ TEST(replacementpool, 7_haveBetter) CValidationState state; ASSERT_FALSE(AcceptToMemoryPool(mempool, state, mtx, false, NULL)); ASSERT_EQ("replacement-is-worse", state.GetRejectReason()); - ASSERT_REPLACEMENT_POOL(mtx.GetHash()); + ONLY_REPLACEMENT_POOL(mtx.GetHash()); } /* * Add transaction with lower priority, but shorter replacementWindow */ -TEST(replacementpool, 8_shorterReplacementWindow) +TEST(replacementpool, shorterReplacementWindow) { LOCK(cs_main); @@ -442,14 +421,14 @@ TEST(replacementpool, 8_shorterReplacementWindow) mtx.vout[0].scriptPubKey = getReplaceOut(2, 100); setFulfillment(mtx, cond, txIn.vout[0].scriptPubKey); acceptTx(mtx); - ASSERT_REPLACEMENT_POOL(mtx.GetHash()); + ONLY_REPLACEMENT_POOL(mtx.GetHash()); // Another one, lower priority but shorter replacementWindow so wins. auto mtx2 = spendTx(txIn); mtx2.vout[0].scriptPubKey = getReplaceOut(1, 99); setFulfillment(mtx2, cond, txIn.vout[0].scriptPubKey); acceptTx(mtx2); - ASSERT_REPLACEMENT_POOL(mtx2.GetHash()); + ONLY_REPLACEMENT_POOL(mtx2.GetHash()); ASSERT_FALSE(replacementPool.lookup(mtx.GetHash(), _txout)); // Shorter still, in fact direct to mem pool @@ -457,5 +436,5 @@ TEST(replacementpool, 8_shorterReplacementWindow) mtx3.vout[0].scriptPubKey = getReplaceOut(0, 98); setFulfillment(mtx3, cond, txIn.vout[0].scriptPubKey); acceptTx(mtx3); - ASSERT_MEM_POOL(mtx3.GetHash()); + ONLY_MEM_POOL(mtx3.GetHash()); } From 76b5216cf6cdc07e77ed7e5864a2d1643660336c Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Mon, 12 Mar 2018 17:54:30 -0300 Subject: [PATCH 045/339] remove cryptoconditions submodule --- .gitmodules | 4 ---- src/cryptoconditions | 1 - 2 files changed, 5 deletions(-) delete mode 160000 src/cryptoconditions diff --git a/.gitmodules b/.gitmodules index bf76cc359..e69de29bb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +0,0 @@ -[submodule "cryptoconditions"] - path = src/cryptoconditions - url = https://github.com/libscott/libcryptoconditions.git - branch = komodo diff --git a/src/cryptoconditions b/src/cryptoconditions deleted file mode 160000 index 96303cb0a..000000000 --- a/src/cryptoconditions +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 96303cb0ad2a03fc09338e310dbd90be13bec743 From c6fa342bd6a04bd708932b35d7c49fc5e3e67149 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Mon, 12 Mar 2018 17:57:18 -0300 Subject: [PATCH 046/339] no more cryptoconditions submodule --- src/cryptoconditions/.gitignore | 24 + src/cryptoconditions/.gitmodules | 3 + src/cryptoconditions/.travis.yml | 10 + src/cryptoconditions/LICENSE | 13 + src/cryptoconditions/Makefile.am | 75 + src/cryptoconditions/README.md | 165 + src/cryptoconditions/autogen.sh | 3 + src/cryptoconditions/compile | 347 +++ src/cryptoconditions/configure.ac | 42 + src/cryptoconditions/cryptoconditions.py | 62 + .../include/cryptoconditions.h | 93 + src/cryptoconditions/src/anon.c | 79 + .../src/asn/AuxFingerprintContents.c | 94 + .../src/asn/AuxFingerprintContents.h | 38 + src/cryptoconditions/src/asn/AuxFulfillment.c | 78 + src/cryptoconditions/src/asn/AuxFulfillment.h | 39 + .../src/asn/AuxSha512Fulfillment.c | 78 + .../src/asn/AuxSha512Fulfillment.h | 39 + src/cryptoconditions/src/asn/BIT_STRING.c | 189 ++ src/cryptoconditions/src/asn/BIT_STRING.h | 33 + .../src/asn/CompoundSha256Condition.c | 235 ++ .../src/asn/CompoundSha256Condition.h | 42 + src/cryptoconditions/src/asn/Condition.c | 114 + src/cryptoconditions/src/asn/Condition.h | 59 + src/cryptoconditions/src/asn/ConditionTypes.c | 108 + src/cryptoconditions/src/asn/ConditionTypes.h | 49 + .../src/asn/CryptoConditions.asn | 118 + .../src/asn/Ed25519FingerprintContents.c | 84 + .../src/asn/Ed25519FingerprintContents.h | 37 + .../src/asn/Ed25519Sha512Fulfillment.c | 120 + .../src/asn/Ed25519Sha512Fulfillment.h | 38 + .../src/asn/EvalFingerprintContents.c | 94 + .../src/asn/EvalFingerprintContents.h | 38 + .../src/asn/EvalFulfillment.c | 94 + .../src/asn/EvalFulfillment.h | 38 + src/cryptoconditions/src/asn/Fulfillment.c | 114 + src/cryptoconditions/src/asn/Fulfillment.h | 70 + src/cryptoconditions/src/asn/INTEGER.c | 1025 +++++++ src/cryptoconditions/src/asn/INTEGER.h | 82 + .../src/asn/Makefile.am.sample | 122 + .../src/asn/NativeEnumerated.c | 207 ++ .../src/asn/NativeEnumerated.h | 32 + src/cryptoconditions/src/asn/NativeInteger.c | 332 ++ src/cryptoconditions/src/asn/NativeInteger.h | 37 + src/cryptoconditions/src/asn/OCTET_STRING.c | 1807 +++++++++++ src/cryptoconditions/src/asn/OCTET_STRING.h | 86 + .../src/asn/PrefixFingerprintContents.c | 209 ++ .../src/asn/PrefixFingerprintContents.h | 42 + .../src/asn/PrefixFulfillment.c | 209 ++ .../src/asn/PrefixFulfillment.h | 47 + .../src/asn/PreimageFulfillment.c | 58 + .../src/asn/PreimageFulfillment.h | 37 + .../src/asn/RsaFingerprintContents.c | 58 + .../src/asn/RsaFingerprintContents.h | 37 + .../src/asn/RsaSha256Fulfillment.c | 68 + .../src/asn/RsaSha256Fulfillment.h | 38 + .../src/asn/Secp256k1FingerprintContents.c | 84 + .../src/asn/Secp256k1FingerprintContents.h | 37 + .../src/asn/Secp256k1Fulfillment.c | 120 + .../src/asn/Secp256k1Fulfillment.h | 38 + .../src/asn/SimpleSha256Condition.c | 225 ++ .../src/asn/SimpleSha256Condition.h | 40 + .../src/asn/ThresholdFingerprintContents.c | 138 + .../src/asn/ThresholdFingerprintContents.h | 51 + .../src/asn/ThresholdFulfillment.c | 158 + .../src/asn/ThresholdFulfillment.h | 57 + src/cryptoconditions/src/asn/asn_SET_OF.c | 88 + src/cryptoconditions/src/asn/asn_SET_OF.h | 62 + .../src/asn/asn_application.h | 47 + src/cryptoconditions/src/asn/asn_codecs.h | 109 + .../src/asn/asn_codecs_prim.c | 312 ++ .../src/asn/asn_codecs_prim.h | 53 + src/cryptoconditions/src/asn/asn_internal.h | 128 + src/cryptoconditions/src/asn/asn_system.h | 138 + src/cryptoconditions/src/asn/ber_decoder.c | 283 ++ src/cryptoconditions/src/asn/ber_decoder.h | 64 + src/cryptoconditions/src/asn/ber_tlv_length.c | 178 ++ src/cryptoconditions/src/asn/ber_tlv_length.h | 50 + src/cryptoconditions/src/asn/ber_tlv_tag.c | 144 + src/cryptoconditions/src/asn/ber_tlv_tag.h | 60 + src/cryptoconditions/src/asn/constr_CHOICE.c | 1114 +++++++ src/cryptoconditions/src/asn/constr_CHOICE.h | 57 + .../src/asn/constr_SEQUENCE.c | 1425 +++++++++ .../src/asn/constr_SEQUENCE.h | 60 + src/cryptoconditions/src/asn/constr_SET_OF.c | 954 ++++++ src/cryptoconditions/src/asn/constr_SET_OF.h | 42 + src/cryptoconditions/src/asn/constr_TYPE.c | 77 + src/cryptoconditions/src/asn/constr_TYPE.h | 180 ++ src/cryptoconditions/src/asn/constraints.c | 93 + src/cryptoconditions/src/asn/constraints.h | 63 + src/cryptoconditions/src/asn/der_encoder.c | 201 ++ src/cryptoconditions/src/asn/der_encoder.h | 68 + src/cryptoconditions/src/asn/per_decoder.c | 93 + src/cryptoconditions/src/asn/per_decoder.h | 56 + src/cryptoconditions/src/asn/per_encoder.c | 151 + src/cryptoconditions/src/asn/per_encoder.h | 69 + src/cryptoconditions/src/asn/per_opentype.c | 378 +++ src/cryptoconditions/src/asn/per_opentype.h | 22 + src/cryptoconditions/src/asn/per_support.c | 483 +++ src/cryptoconditions/src/asn/per_support.h | 135 + src/cryptoconditions/src/asn/xer_decoder.c | 368 +++ src/cryptoconditions/src/asn/xer_decoder.h | 106 + src/cryptoconditions/src/asn/xer_encoder.c | 67 + src/cryptoconditions/src/asn/xer_encoder.h | 59 + src/cryptoconditions/src/asn/xer_support.c | 227 ++ src/cryptoconditions/src/asn/xer_support.h | 55 + .../src/cryptoconditions-config.h.in | 176 ++ src/cryptoconditions/src/cryptoconditions.c | 267 ++ src/cryptoconditions/src/ed25519.c | 170 ++ src/cryptoconditions/src/eval.c | 142 + src/cryptoconditions/src/include/cJSON.c | 2699 +++++++++++++++++ src/cryptoconditions/src/include/cJSON.h | 263 ++ .../src/include/ed25519/license.txt | 16 + .../src/include/ed25519/readme.md | 166 + .../src/include/ed25519/src/add_scalar.c | 69 + .../src/include/ed25519/src/ed25519.h | 38 + .../src/include/ed25519/src/fe.c | 1491 +++++++++ .../src/include/ed25519/src/fe.h | 41 + .../src/include/ed25519/src/fixedint.h | 72 + .../src/include/ed25519/src/ge.c | 467 +++ .../src/include/ed25519/src/ge.h | 74 + .../src/include/ed25519/src/key_exchange.c | 79 + .../src/include/ed25519/src/keypair.c | 16 + .../src/include/ed25519/src/precomp_data.h | 1391 +++++++++ .../src/include/ed25519/src/sc.c | 809 +++++ .../src/include/ed25519/src/sc.h | 12 + .../src/include/ed25519/src/seed.c | 40 + .../src/include/ed25519/src/sha512.c | 275 ++ .../src/include/ed25519/src/sha512.h | 21 + .../src/include/ed25519/src/sign.c | 31 + .../src/include/ed25519/src/verify.c | 77 + .../src/include/ed25519/test.c | 150 + src/cryptoconditions/src/include/libbase58.h | 23 + .../src/include/secp256k1/.gitignore | 37 + .../src/include/secp256k1/.travis.yml | 59 + .../src/include/secp256k1/COPYING | 19 + .../src/include/secp256k1/Makefile.am | 77 + .../src/include/secp256k1/README.md | 61 + .../src/include/secp256k1/TODO | 3 + .../src/include/secp256k1/autogen.sh | 3 + .../src/include/secp256k1/configure.ac | 330 ++ .../src/include/secp256k1/include/secp256k1.h | 347 +++ .../src/include/secp256k1/libsecp256k1.pc.in | 13 + .../src/include/secp256k1/obj/.gitignore | 0 .../src/include/secp256k1/src/bench.h | 56 + .../include/secp256k1/src/bench_internal.c | 318 ++ .../src/include/secp256k1/src/bench_recover.c | 51 + .../src/include/secp256k1/src/bench_sign.c | 50 + .../src/include/secp256k1/src/bench_verify.c | 56 + .../src/include/secp256k1/src/ecdsa.h | 24 + .../src/include/secp256k1/src/ecdsa_impl.h | 271 ++ .../src/include/secp256k1/src/eckey.h | 26 + .../src/include/secp256k1/src/eckey_impl.h | 202 ++ .../src/include/secp256k1/src/ecmult.h | 31 + .../src/include/secp256k1/src/ecmult_gen.h | 43 + .../include/secp256k1/src/ecmult_gen_impl.h | 184 ++ .../src/include/secp256k1/src/ecmult_impl.h | 317 ++ .../src/include/secp256k1/src/field.h | 119 + .../src/include/secp256k1/src/field_10x26.h | 47 + .../include/secp256k1/src/field_10x26_impl.h | 1136 +++++++ .../src/include/secp256k1/src/field_5x52.h | 47 + .../secp256k1/src/field_5x52_asm_impl.h | 502 +++ .../include/secp256k1/src/field_5x52_impl.h | 454 +++ .../secp256k1/src/field_5x52_int128_impl.h | 277 ++ .../src/include/secp256k1/src/field_impl.h | 263 ++ .../src/include/secp256k1/src/group.h | 121 + .../src/include/secp256k1/src/group_impl.h | 443 +++ .../src/include/secp256k1/src/hash.h | 41 + .../src/include/secp256k1/src/hash_impl.h | 293 ++ .../src/java/org/bitcoin/NativeSecp256k1.java | 60 + .../src/java/org_bitcoin_NativeSecp256k1.c | 23 + .../src/java/org_bitcoin_NativeSecp256k1.h | 21 + .../src/include/secp256k1/src/num.h | 68 + .../src/include/secp256k1/src/num_gmp.h | 20 + .../src/include/secp256k1/src/num_gmp_impl.h | 260 ++ .../src/include/secp256k1/src/num_impl.h | 24 + .../src/include/secp256k1/src/scalar.h | 93 + .../src/include/secp256k1/src/scalar_4x64.h | 19 + .../include/secp256k1/src/scalar_4x64_impl.h | 920 ++++++ .../src/include/secp256k1/src/scalar_8x32.h | 19 + .../include/secp256k1/src/scalar_8x32_impl.h | 681 +++++ .../src/include/secp256k1/src/scalar_impl.h | 327 ++ .../src/include/secp256k1/src/secp256k1.c | 419 +++ .../src/include/secp256k1/src/testrand.h | 28 + .../src/include/secp256k1/src/testrand_impl.h | 60 + .../src/include/secp256k1/src/tests.c | 2083 +++++++++++++ .../src/include/secp256k1/src/util.h | 104 + src/cryptoconditions/src/include/sha256.c | 264 ++ src/cryptoconditions/src/include/sha256.h | 114 + src/cryptoconditions/src/include/tweetnacl.c | 809 +++++ src/cryptoconditions/src/include/tweetnacl.h | 272 ++ src/cryptoconditions/src/internal.h | 76 + src/cryptoconditions/src/json_rpc.c | 332 ++ src/cryptoconditions/src/prefix.c | 126 + src/cryptoconditions/src/preimage.c | 83 + src/cryptoconditions/src/secp256k1.c | 253 ++ src/cryptoconditions/src/stamp-h1 | 1 + src/cryptoconditions/src/threshold.c | 206 ++ src/cryptoconditions/src/utils.c | 208 ++ src/cryptoconditions/test-requirements.txt | 3 + src/cryptoconditions/tests/__init__.py | 0 .../1000_test-minimal-eval.json | 14 + .../1001_test-minimal-secp256k1.json | 14 + src/cryptoconditions/tests/test_ed25519.py | 73 + .../tests/test_failure_modes.py | 63 + src/cryptoconditions/tests/test_secp256k1.py | 62 + src/cryptoconditions/tests/test_vectors.py | 149 + 207 files changed, 40503 insertions(+) create mode 100644 src/cryptoconditions/.gitignore create mode 100644 src/cryptoconditions/.gitmodules create mode 100644 src/cryptoconditions/.travis.yml create mode 100644 src/cryptoconditions/LICENSE create mode 100644 src/cryptoconditions/Makefile.am create mode 100644 src/cryptoconditions/README.md create mode 100755 src/cryptoconditions/autogen.sh create mode 100755 src/cryptoconditions/compile create mode 100644 src/cryptoconditions/configure.ac create mode 100755 src/cryptoconditions/cryptoconditions.py create mode 100644 src/cryptoconditions/include/cryptoconditions.h create mode 100644 src/cryptoconditions/src/anon.c create mode 100644 src/cryptoconditions/src/asn/AuxFingerprintContents.c create mode 100644 src/cryptoconditions/src/asn/AuxFingerprintContents.h create mode 100644 src/cryptoconditions/src/asn/AuxFulfillment.c create mode 100644 src/cryptoconditions/src/asn/AuxFulfillment.h create mode 100644 src/cryptoconditions/src/asn/AuxSha512Fulfillment.c create mode 100644 src/cryptoconditions/src/asn/AuxSha512Fulfillment.h create mode 100644 src/cryptoconditions/src/asn/BIT_STRING.c create mode 100644 src/cryptoconditions/src/asn/BIT_STRING.h create mode 100644 src/cryptoconditions/src/asn/CompoundSha256Condition.c create mode 100644 src/cryptoconditions/src/asn/CompoundSha256Condition.h create mode 100644 src/cryptoconditions/src/asn/Condition.c create mode 100644 src/cryptoconditions/src/asn/Condition.h create mode 100644 src/cryptoconditions/src/asn/ConditionTypes.c create mode 100644 src/cryptoconditions/src/asn/ConditionTypes.h create mode 100644 src/cryptoconditions/src/asn/CryptoConditions.asn create mode 100644 src/cryptoconditions/src/asn/Ed25519FingerprintContents.c create mode 100644 src/cryptoconditions/src/asn/Ed25519FingerprintContents.h create mode 100644 src/cryptoconditions/src/asn/Ed25519Sha512Fulfillment.c create mode 100644 src/cryptoconditions/src/asn/Ed25519Sha512Fulfillment.h create mode 100644 src/cryptoconditions/src/asn/EvalFingerprintContents.c create mode 100644 src/cryptoconditions/src/asn/EvalFingerprintContents.h create mode 100644 src/cryptoconditions/src/asn/EvalFulfillment.c create mode 100644 src/cryptoconditions/src/asn/EvalFulfillment.h create mode 100644 src/cryptoconditions/src/asn/Fulfillment.c create mode 100644 src/cryptoconditions/src/asn/Fulfillment.h create mode 100644 src/cryptoconditions/src/asn/INTEGER.c create mode 100644 src/cryptoconditions/src/asn/INTEGER.h create mode 100644 src/cryptoconditions/src/asn/Makefile.am.sample create mode 100644 src/cryptoconditions/src/asn/NativeEnumerated.c create mode 100644 src/cryptoconditions/src/asn/NativeEnumerated.h create mode 100644 src/cryptoconditions/src/asn/NativeInteger.c create mode 100644 src/cryptoconditions/src/asn/NativeInteger.h create mode 100644 src/cryptoconditions/src/asn/OCTET_STRING.c create mode 100644 src/cryptoconditions/src/asn/OCTET_STRING.h create mode 100644 src/cryptoconditions/src/asn/PrefixFingerprintContents.c create mode 100644 src/cryptoconditions/src/asn/PrefixFingerprintContents.h create mode 100644 src/cryptoconditions/src/asn/PrefixFulfillment.c create mode 100644 src/cryptoconditions/src/asn/PrefixFulfillment.h create mode 100644 src/cryptoconditions/src/asn/PreimageFulfillment.c create mode 100644 src/cryptoconditions/src/asn/PreimageFulfillment.h create mode 100644 src/cryptoconditions/src/asn/RsaFingerprintContents.c create mode 100644 src/cryptoconditions/src/asn/RsaFingerprintContents.h create mode 100644 src/cryptoconditions/src/asn/RsaSha256Fulfillment.c create mode 100644 src/cryptoconditions/src/asn/RsaSha256Fulfillment.h create mode 100644 src/cryptoconditions/src/asn/Secp256k1FingerprintContents.c create mode 100644 src/cryptoconditions/src/asn/Secp256k1FingerprintContents.h create mode 100644 src/cryptoconditions/src/asn/Secp256k1Fulfillment.c create mode 100644 src/cryptoconditions/src/asn/Secp256k1Fulfillment.h create mode 100644 src/cryptoconditions/src/asn/SimpleSha256Condition.c create mode 100644 src/cryptoconditions/src/asn/SimpleSha256Condition.h create mode 100644 src/cryptoconditions/src/asn/ThresholdFingerprintContents.c create mode 100644 src/cryptoconditions/src/asn/ThresholdFingerprintContents.h create mode 100644 src/cryptoconditions/src/asn/ThresholdFulfillment.c create mode 100644 src/cryptoconditions/src/asn/ThresholdFulfillment.h create mode 100644 src/cryptoconditions/src/asn/asn_SET_OF.c create mode 100644 src/cryptoconditions/src/asn/asn_SET_OF.h create mode 100644 src/cryptoconditions/src/asn/asn_application.h create mode 100644 src/cryptoconditions/src/asn/asn_codecs.h create mode 100644 src/cryptoconditions/src/asn/asn_codecs_prim.c create mode 100644 src/cryptoconditions/src/asn/asn_codecs_prim.h create mode 100644 src/cryptoconditions/src/asn/asn_internal.h create mode 100644 src/cryptoconditions/src/asn/asn_system.h create mode 100644 src/cryptoconditions/src/asn/ber_decoder.c create mode 100644 src/cryptoconditions/src/asn/ber_decoder.h create mode 100644 src/cryptoconditions/src/asn/ber_tlv_length.c create mode 100644 src/cryptoconditions/src/asn/ber_tlv_length.h create mode 100644 src/cryptoconditions/src/asn/ber_tlv_tag.c create mode 100644 src/cryptoconditions/src/asn/ber_tlv_tag.h create mode 100644 src/cryptoconditions/src/asn/constr_CHOICE.c create mode 100644 src/cryptoconditions/src/asn/constr_CHOICE.h create mode 100644 src/cryptoconditions/src/asn/constr_SEQUENCE.c create mode 100644 src/cryptoconditions/src/asn/constr_SEQUENCE.h create mode 100644 src/cryptoconditions/src/asn/constr_SET_OF.c create mode 100644 src/cryptoconditions/src/asn/constr_SET_OF.h create mode 100644 src/cryptoconditions/src/asn/constr_TYPE.c create mode 100644 src/cryptoconditions/src/asn/constr_TYPE.h create mode 100644 src/cryptoconditions/src/asn/constraints.c create mode 100644 src/cryptoconditions/src/asn/constraints.h create mode 100644 src/cryptoconditions/src/asn/der_encoder.c create mode 100644 src/cryptoconditions/src/asn/der_encoder.h create mode 100644 src/cryptoconditions/src/asn/per_decoder.c create mode 100644 src/cryptoconditions/src/asn/per_decoder.h create mode 100644 src/cryptoconditions/src/asn/per_encoder.c create mode 100644 src/cryptoconditions/src/asn/per_encoder.h create mode 100644 src/cryptoconditions/src/asn/per_opentype.c create mode 100644 src/cryptoconditions/src/asn/per_opentype.h create mode 100644 src/cryptoconditions/src/asn/per_support.c create mode 100644 src/cryptoconditions/src/asn/per_support.h create mode 100644 src/cryptoconditions/src/asn/xer_decoder.c create mode 100644 src/cryptoconditions/src/asn/xer_decoder.h create mode 100644 src/cryptoconditions/src/asn/xer_encoder.c create mode 100644 src/cryptoconditions/src/asn/xer_encoder.h create mode 100644 src/cryptoconditions/src/asn/xer_support.c create mode 100644 src/cryptoconditions/src/asn/xer_support.h create mode 100644 src/cryptoconditions/src/cryptoconditions-config.h.in create mode 100644 src/cryptoconditions/src/cryptoconditions.c create mode 100644 src/cryptoconditions/src/ed25519.c create mode 100644 src/cryptoconditions/src/eval.c create mode 100644 src/cryptoconditions/src/include/cJSON.c create mode 100644 src/cryptoconditions/src/include/cJSON.h create mode 100644 src/cryptoconditions/src/include/ed25519/license.txt create mode 100644 src/cryptoconditions/src/include/ed25519/readme.md create mode 100644 src/cryptoconditions/src/include/ed25519/src/add_scalar.c create mode 100644 src/cryptoconditions/src/include/ed25519/src/ed25519.h create mode 100644 src/cryptoconditions/src/include/ed25519/src/fe.c create mode 100644 src/cryptoconditions/src/include/ed25519/src/fe.h create mode 100644 src/cryptoconditions/src/include/ed25519/src/fixedint.h create mode 100644 src/cryptoconditions/src/include/ed25519/src/ge.c create mode 100644 src/cryptoconditions/src/include/ed25519/src/ge.h create mode 100644 src/cryptoconditions/src/include/ed25519/src/key_exchange.c create mode 100644 src/cryptoconditions/src/include/ed25519/src/keypair.c create mode 100644 src/cryptoconditions/src/include/ed25519/src/precomp_data.h create mode 100644 src/cryptoconditions/src/include/ed25519/src/sc.c create mode 100644 src/cryptoconditions/src/include/ed25519/src/sc.h create mode 100644 src/cryptoconditions/src/include/ed25519/src/seed.c create mode 100644 src/cryptoconditions/src/include/ed25519/src/sha512.c create mode 100644 src/cryptoconditions/src/include/ed25519/src/sha512.h create mode 100644 src/cryptoconditions/src/include/ed25519/src/sign.c create mode 100644 src/cryptoconditions/src/include/ed25519/src/verify.c create mode 100644 src/cryptoconditions/src/include/ed25519/test.c create mode 100644 src/cryptoconditions/src/include/libbase58.h create mode 100644 src/cryptoconditions/src/include/secp256k1/.gitignore create mode 100644 src/cryptoconditions/src/include/secp256k1/.travis.yml create mode 100644 src/cryptoconditions/src/include/secp256k1/COPYING create mode 100644 src/cryptoconditions/src/include/secp256k1/Makefile.am create mode 100644 src/cryptoconditions/src/include/secp256k1/README.md create mode 100644 src/cryptoconditions/src/include/secp256k1/TODO create mode 100755 src/cryptoconditions/src/include/secp256k1/autogen.sh create mode 100644 src/cryptoconditions/src/include/secp256k1/configure.ac create mode 100644 src/cryptoconditions/src/include/secp256k1/include/secp256k1.h create mode 100644 src/cryptoconditions/src/include/secp256k1/libsecp256k1.pc.in create mode 100644 src/cryptoconditions/src/include/secp256k1/obj/.gitignore create mode 100644 src/cryptoconditions/src/include/secp256k1/src/bench.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/bench_internal.c create mode 100644 src/cryptoconditions/src/include/secp256k1/src/bench_recover.c create mode 100644 src/cryptoconditions/src/include/secp256k1/src/bench_sign.c create mode 100644 src/cryptoconditions/src/include/secp256k1/src/bench_verify.c create mode 100644 src/cryptoconditions/src/include/secp256k1/src/ecdsa.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/ecdsa_impl.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/eckey.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/eckey_impl.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/ecmult.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/ecmult_gen.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/ecmult_gen_impl.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/ecmult_impl.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/field.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/field_10x26.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/field_10x26_impl.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/field_5x52.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/field_5x52_asm_impl.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/field_5x52_impl.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/field_5x52_int128_impl.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/field_impl.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/group.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/group_impl.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/hash.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/hash_impl.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java create mode 100644 src/cryptoconditions/src/include/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c create mode 100644 src/cryptoconditions/src/include/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/num.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/num_gmp.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/num_gmp_impl.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/num_impl.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/scalar.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/scalar_4x64.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/scalar_4x64_impl.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/scalar_8x32.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/scalar_8x32_impl.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/scalar_impl.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/secp256k1.c create mode 100644 src/cryptoconditions/src/include/secp256k1/src/testrand.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/testrand_impl.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/tests.c create mode 100644 src/cryptoconditions/src/include/secp256k1/src/util.h create mode 100644 src/cryptoconditions/src/include/sha256.c create mode 100644 src/cryptoconditions/src/include/sha256.h create mode 100644 src/cryptoconditions/src/include/tweetnacl.c create mode 100644 src/cryptoconditions/src/include/tweetnacl.h create mode 100644 src/cryptoconditions/src/internal.h create mode 100644 src/cryptoconditions/src/json_rpc.c create mode 100644 src/cryptoconditions/src/prefix.c create mode 100644 src/cryptoconditions/src/preimage.c create mode 100644 src/cryptoconditions/src/secp256k1.c create mode 100644 src/cryptoconditions/src/stamp-h1 create mode 100644 src/cryptoconditions/src/threshold.c create mode 100644 src/cryptoconditions/src/utils.c create mode 100644 src/cryptoconditions/test-requirements.txt create mode 100644 src/cryptoconditions/tests/__init__.py create mode 100644 src/cryptoconditions/tests/custom-vectors/1000_test-minimal-eval.json create mode 100644 src/cryptoconditions/tests/custom-vectors/1001_test-minimal-secp256k1.json create mode 100644 src/cryptoconditions/tests/test_ed25519.py create mode 100644 src/cryptoconditions/tests/test_failure_modes.py create mode 100644 src/cryptoconditions/tests/test_secp256k1.py create mode 100644 src/cryptoconditions/tests/test_vectors.py diff --git a/src/cryptoconditions/.gitignore b/src/cryptoconditions/.gitignore new file mode 100644 index 000000000..1d84f2618 --- /dev/null +++ b/src/cryptoconditions/.gitignore @@ -0,0 +1,24 @@ +*.pyc +.cache +/Makefile +/Makefile.in +/aclocal.m4 +/autom4te.cache/ +/src/cryptoconditions-config.h +/configure +/depcomp +/install-sh +/libtool +/ltmain.sh +/m4/ +/missing +/stamp-h? +.deps/ +.dirstamp +.libs/ +*.l[ao] +*.[ao] +*~ +converter-sample.c +config.* +.pytest_cache diff --git a/src/cryptoconditions/.gitmodules b/src/cryptoconditions/.gitmodules new file mode 100644 index 000000000..635f6c43d --- /dev/null +++ b/src/cryptoconditions/.gitmodules @@ -0,0 +1,3 @@ +[submodule "ext/crypto-conditions"] + path = ext/crypto-conditions + url = http://github.com/libscott/crypto-conditions.git diff --git a/src/cryptoconditions/.travis.yml b/src/cryptoconditions/.travis.yml new file mode 100644 index 000000000..166cc9def --- /dev/null +++ b/src/cryptoconditions/.travis.yml @@ -0,0 +1,10 @@ +language: C +sudo: true +compiler: + - clang + - gcc +before_script: ./autogen.sh +addons: + apt: + packages: + - gdb diff --git a/src/cryptoconditions/LICENSE b/src/cryptoconditions/LICENSE new file mode 100644 index 000000000..bd423f56e --- /dev/null +++ b/src/cryptoconditions/LICENSE @@ -0,0 +1,13 @@ +Copyright 2017 Scott Sadler + +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. diff --git a/src/cryptoconditions/Makefile.am b/src/cryptoconditions/Makefile.am new file mode 100644 index 000000000..ab6259b56 --- /dev/null +++ b/src/cryptoconditions/Makefile.am @@ -0,0 +1,75 @@ +lib_LTLIBRARIES=libcryptoconditions.la +SUBDIRS = src/include/secp256k1 + +AM_CFLAGS = -I$(top_srcdir)/src/asn -I$(top_srcdir)/include -I$(top_srcdir)/src/include \ + -Wall -Wno-pointer-sign -Wno-discarded-qualifiers + +LIBSECP256K1=src/include/secp256k1/libsecp256k1.la + +$(LIBSECP256K1): $(wildcard src/secp256k1/*) + $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) + +libcryptoconditions_la_LIBADD = $(LIBSECP256K1) +libcryptoconditions_la_SOURCES = \ + src/cryptoconditions.c \ + src/include/cJSON.c \ + src/include/sha256.c \ + src/include/ed25519/src/keypair.c \ + src/include/ed25519/src/seed.c \ + src/include/ed25519/src/verify.c \ + src/include/ed25519/src/sign.c \ + src/include/ed25519/src/fe.c \ + src/include/ed25519/src/sc.c \ + src/include/ed25519/src/sha512.c \ + src/include/ed25519/src/ge.c \ + src/include/ed25519/src/add_scalar.c \ + src/include/ed25519/src/key_exchange.c \ + src/asn/Condition.c \ + src/asn/SimpleSha256Condition.c \ + src/asn/CompoundSha256Condition.c \ + src/asn/ConditionTypes.c \ + src/asn/Fulfillment.c \ + src/asn/PreimageFulfillment.c \ + src/asn/PrefixFulfillment.c \ + src/asn/ThresholdFulfillment.c \ + src/asn/RsaSha256Fulfillment.c \ + src/asn/Ed25519Sha512Fulfillment.c \ + src/asn/PrefixFingerprintContents.c \ + src/asn/ThresholdFingerprintContents.c \ + src/asn/RsaFingerprintContents.c \ + src/asn/Ed25519FingerprintContents.c \ + src/asn/EvalFingerprintContents.c \ + src/asn/EvalFulfillment.c \ + src/asn/Secp256k1FingerprintContents.c \ + src/asn/Secp256k1Fulfillment.c \ + src/asn/INTEGER.c \ + src/asn/NativeEnumerated.c \ + src/asn/NativeInteger.c \ + src/asn/asn_SET_OF.c \ + src/asn/constr_CHOICE.c \ + src/asn/constr_SEQUENCE.c \ + src/asn/constr_SET_OF.c \ + src/asn/OCTET_STRING.c \ + src/asn/BIT_STRING.c \ + src/asn/asn_codecs_prim.c \ + src/asn/ber_tlv_length.c \ + src/asn/ber_tlv_tag.c \ + src/asn/ber_decoder.c \ + src/asn/der_encoder.c \ + src/asn/constr_TYPE.c \ + src/asn/constraints.c \ + src/asn/xer_support.c \ + src/asn/xer_decoder.c \ + src/asn/xer_encoder.c \ + src/asn/per_support.c \ + src/asn/per_decoder.c \ + src/asn/per_encoder.c \ + src/asn/per_opentype.c + +test: + bash -c '[ -d .env ] || virtualenv .env' + .env/bin/pip install pytest + gdb -batch -ex run -ex bt --args .env/bin/python -m pytest -s -x -v 2>&1 | grep -v ^"No stack."$ + +test-debug-interactive: + gdb -ex run --args python3 -m pytest -s -x -v diff --git a/src/cryptoconditions/README.md b/src/cryptoconditions/README.md new file mode 100644 index 000000000..45418b62a --- /dev/null +++ b/src/cryptoconditions/README.md @@ -0,0 +1,165 @@ +# libcryptoconditions [![Build Status](https://travis-ci.org/libscott/libcryptoconditions.svg?branch=komodo)](https://travis-ci.org/libscott/libcryptoconditions) + +Interledger Crypto-Conditions in C, targeting spec [draft-thomas-crypto-conditions-03](https://tools.ietf.org/html/draft-thomas-crypto-conditions-03). + +Features shared object and easy to use JSON api, as well as a command line interface written in Python. + +## Quickstart + +```shell +git clone --recursive https://github.com/libscott/libcryptoconditions +cd libcryptoconditions +./autogen.sh +./configure +make +./cryptoconditions.py --help +``` + +## Status + +JSON interface not particularly safe. The rest is getting there. + +## Embedding + +For the binary interface, see [cryptoconditions.h](./include/cryptoconditions.h). + +To embed in other languages, the easiest way may be to call the JSON RPC method via FFI. This is how it looks in Python: + +```python +import json +from ctypes import * + +so = cdll.LoadLibrary('.libs/libcryptoconditions.so') +so.jsonRPC.restype = c_char_p + +def call_cryptoconditions_rpc(method, params): + out = so.jsonRPC(json.dumps({ + 'method': method, + 'params': params, + })) + return json.loads(out) +``` + +## JSON methods + +### encodeCondition + +Encode a JSON condition to a base64 binary string + +```shell +cryptoconditions encodeCondition '{ + "type": "ed25519-sha-256", + "publicKey": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo" +}' +{ + "bin": "pCeAIHmSOauo_E_36r-8TETmnovf7ZkzJOEu1keSq-KJzx1fgQMCAAA", + "uri": "ni:///sha-256;eZI5q6j8T_fqv7xMROaei9_tmTMk4S7WR5Kr4onPHV8?fpt=ed25519-sha-256&cost=131072" +} +``` + +### decodeCondition + +Decode a binary condition + +```shell +cryptoconditions decodeCondition '{ + "bin": "pCeAIHmSOauo_E_36r-8TETmnovf7ZkzJOEu1keSq-KJzx1fgQMCAAA" +}' +{ + "bin": "pCeAIHmSOauo_E_36r-8TETmnovf7ZkzJOEu1keSq-KJzx1fgQMCAAA", + "uri": "ni:///sha-256;eZI5q6j8T_fqv7xMROaei9_tmTMk4S7WR5Kr4onPHV8?fpt=ed25519-sha-256&cost=131072" +} +``` + +### encodeFulfillment + +Encode a JSON condition to a binary fulfillment. The condition must be fulfilled, that is, +it needs to have signatures present. + +```shell +cryptoconditions encodeFulfillment '{ +{ + "type": "ed25519-sha-256", + "publicKey": "E0x0Ws4GhWhO_zBoUyaLbuqCz6hDdq11Ft1Dgbe9y9k", + "signature": "jcuovSRpHwqiC781KzSM1Jd0Qtyfge0cMGttUdLOVdjJlSBFLTtgpinASOaJpd-VGjhSGWkp1hPWuMAAZq6pAg" +}' +{ + "fulfillment": "pGSAIBNMdFrOBoVoTv8waFMmi27qgs-oQ3atdRbdQ4G3vcvZgUCNy6i9JGkfCqILvzUrNIzUl3RC3J-B7Rwwa21R0s5V2MmVIEUtO2CmKcBI5oml35UaOFIZaSnWE9a4wABmrqkC" +} + +``` + +### decodeFulfillment + +Decode a binary fulfillment + +```shell +cryptoconditions decodeFulfillment '{ + "fulfillment": "pGSAINdamAGCsQq31Uv-08lkBzoO4XLz2qYjJa8CGmj3B1EagUDlVkMAw2CscpCG4syAboKKhId_Hrjl2XTYc-BlIkkBVV-4ghWQozusxh45cBz5tGvSW_XwWVu-JGVRQUOOehAL" +}' +{ + "bin": "pCeAIHmSOauo_E_36r-8TETmnovf7ZkzJOEu1keSq-KJzx1fgQMCAAA", + "uri": "ni:///sha-256;eZI5q6j8T_fqv7xMROaei9_tmTMk4S7WR5Kr4onPHV8?fpt=ed25519-sha-256&cost=131072" +} +``` + +### verifyFulfillment + +Verify a fulfillment against a message and a condition URL + +```shell +cryptoconditions verifyFulfillment '{ + "message": "", + "fulfillment": "pGSAINdamAGCsQq31Uv-08lkBzoO4XLz2qYjJa8CGmj3B1EagUDlVkMAw2CscpCG4syAboKKhId_Hrjl2XTYc-BlIkkBVV-4ghWQozusxh45cBz5tGvSW_XwWVu-JGVRQUOOehAL", + "condition": "pCeAIHmSOauo_E_36r-8TETmnovf7ZkzJOEu1keSq-KJzx1fgQMCAAA" +} +{ + "valid": true +} +``` + +### signTreeEd25519 + +Sign all ed25519 nodes in a condition tree + +```shell +cryptoconditions signTreeEd25519 '{ + "condition": { + "type": "ed25519-sha-256", + "publicKey": "E0x0Ws4GhWhO_zBoUyaLbuqCz6hDdq11Ft1Dgbe9y9k", + }, + "privateKey": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo", + "message": "", +}' +{ + "num_signed": 1, + "condition": { + "type": "ed25519-sha-256", + "publicKey": "E0x0Ws4GhWhO_zBoUyaLbuqCz6hDdq11Ft1Dgbe9y9k", + "signature": "jcuovSRpHwqiC781KzSM1Jd0Qtyfge0cMGttUdLOVdjJlSBFLTtgpinASOaJpd-VGjhSGWkp1hPWuMAAZq6pAg" + } +} +``` + +### signTreeSecp256k1 + +Sign all secp256k1 nodes in a condition tree + +```shell +cryptoconditions signTreeSecp256k1 '{ + "condition": { + "type": "secp256k1-sha-256", + "publicKey": "AmkauD4tVL5-I7NN9hE_A8SlA0WdCIeJe_1Nac_km1hr", + }, + "privateKey": "Bxwd5hOLZcTvzrR5Cupm3IV7TWHHl8nNLeO4UhYfRs4", + "message": "", +}' +{ + "num_signed": 1, + "condition": { + "type": "secp256k1-sha-256", + "publicKey": "AmkauD4tVL5-I7NN9hE_A8SlA0WdCIeJe_1Nac_km1hr", + "signature": "LSQLzZo4cmt04KoCdoFcbIJX5MZ9CM6324SqkdqV1PppfUwquiWa7HD97hf4jdkdqU3ep8ZS9AU7zEJoUAl_Gg" + } +} +``` diff --git a/src/cryptoconditions/autogen.sh b/src/cryptoconditions/autogen.sh new file mode 100755 index 000000000..65286b935 --- /dev/null +++ b/src/cryptoconditions/autogen.sh @@ -0,0 +1,3 @@ +#!/bin/sh +set -e +autoreconf -if --warnings=all diff --git a/src/cryptoconditions/compile b/src/cryptoconditions/compile new file mode 100755 index 000000000..a85b723c7 --- /dev/null +++ b/src/cryptoconditions/compile @@ -0,0 +1,347 @@ +#! /bin/sh +# Wrapper for compilers which do not understand '-c -o'. + +scriptversion=2012-10-14.11; # UTC + +# Copyright (C) 1999-2014 Free Software Foundation, Inc. +# Written by Tom Tromey . +# +# 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 2, 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 to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to or send patches to +# . + +nl=' +' + +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent tools from complaining about whitespace usage. +IFS=" "" $nl" + +file_conv= + +# func_file_conv build_file lazy +# Convert a $build file to $host form and store it in $file +# Currently only supports Windows hosts. If the determined conversion +# type is listed in (the comma separated) LAZY, no conversion will +# take place. +func_file_conv () +{ + file=$1 + case $file in + / | /[!/]*) # absolute file, and not a UNC file + if test -z "$file_conv"; then + # lazily determine how to convert abs files + case `uname -s` in + MINGW*) + file_conv=mingw + ;; + CYGWIN*) + file_conv=cygwin + ;; + *) + file_conv=wine + ;; + esac + fi + case $file_conv/,$2, in + *,$file_conv,*) + ;; + mingw/*) + file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` + ;; + cygwin/*) + file=`cygpath -m "$file" || echo "$file"` + ;; + wine/*) + file=`winepath -w "$file" || echo "$file"` + ;; + esac + ;; + esac +} + +# func_cl_dashL linkdir +# Make cl look for libraries in LINKDIR +func_cl_dashL () +{ + func_file_conv "$1" + if test -z "$lib_path"; then + lib_path=$file + else + lib_path="$lib_path;$file" + fi + linker_opts="$linker_opts -LIBPATH:$file" +} + +# func_cl_dashl library +# Do a library search-path lookup for cl +func_cl_dashl () +{ + lib=$1 + found=no + save_IFS=$IFS + IFS=';' + for dir in $lib_path $LIB + do + IFS=$save_IFS + if $shared && test -f "$dir/$lib.dll.lib"; then + found=yes + lib=$dir/$lib.dll.lib + break + fi + if test -f "$dir/$lib.lib"; then + found=yes + lib=$dir/$lib.lib + break + fi + if test -f "$dir/lib$lib.a"; then + found=yes + lib=$dir/lib$lib.a + break + fi + done + IFS=$save_IFS + + if test "$found" != yes; then + lib=$lib.lib + fi +} + +# func_cl_wrapper cl arg... +# Adjust compile command to suit cl +func_cl_wrapper () +{ + # Assume a capable shell + lib_path= + shared=: + linker_opts= + for arg + do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as 'compile cc -o foo foo.c'. + eat=1 + case $2 in + *.o | *.[oO][bB][jJ]) + func_file_conv "$2" + set x "$@" -Fo"$file" + shift + ;; + *) + func_file_conv "$2" + set x "$@" -Fe"$file" + shift + ;; + esac + ;; + -I) + eat=1 + func_file_conv "$2" mingw + set x "$@" -I"$file" + shift + ;; + -I*) + func_file_conv "${1#-I}" mingw + set x "$@" -I"$file" + shift + ;; + -l) + eat=1 + func_cl_dashl "$2" + set x "$@" "$lib" + shift + ;; + -l*) + func_cl_dashl "${1#-l}" + set x "$@" "$lib" + shift + ;; + -L) + eat=1 + func_cl_dashL "$2" + ;; + -L*) + func_cl_dashL "${1#-L}" + ;; + -static) + shared=false + ;; + -Wl,*) + arg=${1#-Wl,} + save_ifs="$IFS"; IFS=',' + for flag in $arg; do + IFS="$save_ifs" + linker_opts="$linker_opts $flag" + done + IFS="$save_ifs" + ;; + -Xlinker) + eat=1 + linker_opts="$linker_opts $2" + ;; + -*) + set x "$@" "$1" + shift + ;; + *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) + func_file_conv "$1" + set x "$@" -Tp"$file" + shift + ;; + *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) + func_file_conv "$1" mingw + set x "$@" "$file" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift + done + if test -n "$linker_opts"; then + linker_opts="-link$linker_opts" + fi + exec "$@" $linker_opts + exit 1 +} + +eat= + +case $1 in + '') + echo "$0: No command. Try '$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: compile [--help] [--version] PROGRAM [ARGS] + +Wrapper for compilers which do not understand '-c -o'. +Remove '-o dest.o' from ARGS, run PROGRAM with the remaining +arguments, and rename the output as expected. + +If you are trying to build a whole package this is not the +right script to run: please start by reading the file 'INSTALL'. + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "compile $scriptversion" + exit $? + ;; + cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) + func_cl_wrapper "$@" # Doesn't return... + ;; +esac + +ofile= +cfile= + +for arg +do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as 'compile cc -o foo foo.c'. + # So we strip '-o arg' only if arg is an object. + eat=1 + case $2 in + *.o | *.obj) + ofile=$2 + ;; + *) + set x "$@" -o "$2" + shift + ;; + esac + ;; + *.c) + cfile=$1 + set x "$@" "$1" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift +done + +if test -z "$ofile" || test -z "$cfile"; then + # If no '-o' option was seen then we might have been invoked from a + # pattern rule where we don't need one. That is ok -- this is a + # normal compilation that the losing compiler can handle. If no + # '.c' file was seen then we are probably linking. That is also + # ok. + exec "$@" +fi + +# Name of file we expect compiler to create. +cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` + +# Create the lock directory. +# Note: use '[/\\:.-]' here to ensure that we don't use the same name +# that we are using for the .o file. Also, base the name on the expected +# object file name, since that is what matters with a parallel build. +lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d +while true; do + if mkdir "$lockdir" >/dev/null 2>&1; then + break + fi + sleep 1 +done +# FIXME: race condition here if user kills between mkdir and trap. +trap "rmdir '$lockdir'; exit 1" 1 2 15 + +# Run the compile. +"$@" +ret=$? + +if test -f "$cofile"; then + test "$cofile" = "$ofile" || mv "$cofile" "$ofile" +elif test -f "${cofile}bj"; then + test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" +fi + +rmdir "$lockdir" +exit $ret + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/src/cryptoconditions/configure.ac b/src/cryptoconditions/configure.ac new file mode 100644 index 000000000..d6b45159a --- /dev/null +++ b/src/cryptoconditions/configure.ac @@ -0,0 +1,42 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ([2.69]) +AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS]) +AC_CONFIG_HEADERS([src/cryptoconditions-config.h]) +AC_CONFIG_MACRO_DIRS([m4]) +AC_CONFIG_SUBDIRS([src/include/secp256k1]) + +AM_INIT_AUTOMAKE([foreign subdir-objects]) +LT_INIT + +# Checks for programs. +AC_PROG_CC +AC_PROG_CC_STDC + +# Checks for libraries. + +# Checks for header files. +AC_FUNC_ALLOCA +AC_CHECK_HEADERS([arpa/inet.h float.h inttypes.h limits.h locale.h malloc.h netinet/in.h stddef.h stdint.h stdlib.h string.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_CHECK_HEADER_STDBOOL +AC_TYPE_INT16_T +AC_TYPE_INT32_T +AC_TYPE_INT8_T +AC_TYPE_SIZE_T +AC_TYPE_SSIZE_T +AC_TYPE_UINT16_T +AC_TYPE_UINT32_T +AC_TYPE_UINT64_T +AC_TYPE_UINT8_T +AC_CHECK_TYPES([ptrdiff_t]) + +# Checks for library functions. +AC_FUNC_MALLOC +AC_FUNC_STRTOD +AC_CHECK_FUNCS([localeconv memchr memset]) + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/src/cryptoconditions/cryptoconditions.py b/src/cryptoconditions/cryptoconditions.py new file mode 100755 index 000000000..4ffd86ce3 --- /dev/null +++ b/src/cryptoconditions/cryptoconditions.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python + +import sys +import json +import ctypes +import base64 +import os.path +import argparse +from ctypes import * + + +so = cdll.LoadLibrary('.libs/libcryptoconditions.so') +so.jsonRPC.restype = c_char_p + + +def jsonRPC(method, params, load=True): + out = so.cc_jsonRPC(json.dumps({ + 'method': method, + 'params': params, + })) + return json.loads(out) if load else out + + +def b16_to_b64(b16): + return base64.urlsafe_b64encode(base64.b16decode(b16)).rstrip('=') + + +USAGE = "cryptoconditions [-h] {method} {request_json}" + +def get_help(): + methods = jsonRPC("listMethods", {})['methods'] + + txt = USAGE + "\n\nmethods:\n" + + for method in methods: + txt += ' %s: %s\n' % (method['name'], method['description']) + + txt += """\noptional arguments: + -h, --help show this help message and exit +""" + return txt + + +def get_parser(): + class Parser(argparse.ArgumentParser): + def format_help(self): + return get_help() + + parser = Parser(description='Crypto Conditions JSON interface', usage=USAGE) + + json_loads = lambda r: json.loads(r) + json_loads.__name__ = 'json' + + parser.add_argument("method") + parser.add_argument("request", type=json_loads) + + return parser + + +if __name__ == '__main__': + args = get_parser().parse_args() + print(jsonRPC(args.method, args.request, load=False)) diff --git a/src/cryptoconditions/include/cryptoconditions.h b/src/cryptoconditions/include/cryptoconditions.h new file mode 100644 index 000000000..22370d4d0 --- /dev/null +++ b/src/cryptoconditions/include/cryptoconditions.h @@ -0,0 +1,93 @@ +#include + + +#ifndef CRYPTOCONDITIONS_H +#define CRYPTOCONDITIONS_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +struct CC; +struct CCType; + + +enum CCTypeId { + CC_Preimage = 0, + CC_Prefix = 1, + CC_Threshold = 2, + CC_Ed25519 = 4, + CC_Secp256k1 = 5, + CC_Eval = 15 +}; + + +/* + * Evaliliary verification callback + */ +typedef int (*VerifyEval)(struct CC *cond, void *context); + + +/* + * Crypto Condition + */ +typedef struct CC { + struct CCType *type; + union { + struct { unsigned char *publicKey, *signature; }; + struct { unsigned char *preimage; size_t preimageLength; }; + struct { long threshold; int size; struct CC **subconditions; }; + struct { unsigned char *prefix; size_t prefixLength; struct CC *subcondition; + unsigned long maxMessageLength; }; + struct { char method[64]; unsigned char *paramsBin; size_t paramsBinLength; }; + struct { unsigned char fingerprint[32]; uint32_t subtypes; unsigned long cost; }; + }; +} CC; + + + +/* + * Crypto Condition Visitor + */ +typedef struct CCVisitor { + int (*visit)(CC *cond, struct CCVisitor visitor); + const unsigned char *msg; + size_t msgLength; + void *context; +} CCVisitor; + + +/* + * Public methods + */ +int cc_isFulfilled(const CC *cond); +int cc_verify(const struct CC *cond, const unsigned char *msg, size_t msgLength, + int doHashMessage, const unsigned char *condBin, size_t condBinLength, + VerifyEval verifyEval, void *evalContext); +int cc_visit(CC *cond, struct CCVisitor visitor); +int cc_signTreeEd25519(CC *cond, const unsigned char *privateKey, + const unsigned char *msg, size_t msgLength); +int cc_signTreeSecp256k1Msg32(CC *cond, const unsigned char *privateKey, const unsigned char *msg32); +size_t cc_conditionBinary(const CC *cond, unsigned char *buf); +size_t cc_fulfillmentBinary(const CC *cond, unsigned char *buf, size_t bufLength); +static int cc_secp256k1VerifyTreeMsg32(const CC *cond, const unsigned char *msg32); +struct CC* cc_conditionFromJSON(cJSON *params, unsigned char *err); +struct CC* cc_conditionFromJSONString(const unsigned char *json, unsigned char *err); +struct CC* cc_readConditionBinary(unsigned char *cond_bin, size_t cond_bin_len); +struct CC* cc_readFulfillmentBinary(unsigned char *ffill_bin, size_t ffill_bin_len); +struct cJSON* cc_conditionToJSON(const CC *cond); +unsigned char* cc_conditionToJSONString(const CC *cond); +unsigned char* cc_conditionUri(const CC *cond); +unsigned char* cc_jsonRPC(unsigned char *request); +unsigned long cc_getCost(const CC *cond); +enum CCTypeId cc_typeId(const CC *cond); +void cc_free(struct CC *cond); + + +#ifdef __cplusplus +} +#endif + +#endif /* CRYPTOCONDITIONS_H */ diff --git a/src/cryptoconditions/src/anon.c b/src/cryptoconditions/src/anon.c new file mode 100644 index 000000000..e23fffe3e --- /dev/null +++ b/src/cryptoconditions/src/anon.c @@ -0,0 +1,79 @@ + +#include "asn/Condition.h" +#include "asn/Fulfillment.h" +#include "asn/PrefixFingerprintContents.h" +#include "asn/OCTET_STRING.h" +#include "include/cJSON.h" +#include "cryptoconditions.h" + + +struct CCType cc_anonType; + + +static CC *mkAnon(const Condition_t *asnCond) { + CCType *realType = getTypeByAsnEnum(asnCond->present); + if (!realType) { + printf("Unknown ASN type: %i", asnCond->present); + return 0; + } + CC *cond = calloc(1, sizeof(CC)); + cond->type = (CCType*) calloc(1, sizeof(CCType)); + *cond->type = cc_anonType; + strcpy(cond->type->name, realType->name); + cond->type->hasSubtypes = realType->hasSubtypes; + cond->type->typeId = realType->typeId; + cond->type->asnType = realType->asnType; + const CompoundSha256Condition_t *deets = &asnCond->choice.thresholdSha256; + memcpy(cond->fingerprint, deets->fingerprint.buf, 32); + cond->cost = deets->cost; + if (realType->hasSubtypes) { + cond->subtypes = fromAsnSubtypes(deets->subtypes); + } + return cond; +} + + + +static void anonToJSON(const CC *cond, cJSON *params) { + unsigned char *b64 = base64_encode(cond->fingerprint, 32); + cJSON_AddItemToObject(params, "fingerprint", cJSON_CreateString(b64)); + free(b64); + cJSON_AddItemToObject(params, "cost", cJSON_CreateNumber(cond->cost)); + cJSON_AddItemToObject(params, "subtypes", cJSON_CreateNumber(cond->subtypes)); +} + + +static unsigned char *anonFingerprint(const CC *cond) { + unsigned char *out = calloc(1, 32); + memcpy(out, cond->fingerprint, 32); + return out; +} + + +static unsigned long anonCost(const CC *cond) { + return cond->cost; +} + + +static uint32_t anonSubtypes(const CC *cond) { + return cond->subtypes; +} + + +static Fulfillment_t *anonFulfillment(const CC *cond) { + return NULL; +} + + +static void anonFree(CC *cond) { + free(cond->type); + free(cond); +} + + +static int anonIsFulfilled(const CC *cond) { + return 0; +} + + +struct CCType cc_anonType = { -1, "anon (a buffer large enough to accomodate any type name)", Condition_PR_NOTHING, 0, NULL, &anonFingerprint, &anonCost, &anonSubtypes, NULL, &anonToJSON, NULL, &anonFulfillment, &anonIsFulfilled, &anonFree }; diff --git a/src/cryptoconditions/src/asn/AuxFingerprintContents.c b/src/cryptoconditions/src/asn/AuxFingerprintContents.c new file mode 100644 index 000000000..cc8aefa3f --- /dev/null +++ b/src/cryptoconditions/src/asn/AuxFingerprintContents.c @@ -0,0 +1,94 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#include "AuxFingerprintContents.h" + +static int +memb_method_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + size_t size; + + if(!sptr) { + ASN__CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + size = st->size; + + if((size == 64)) { + /* Constraint check succeeded */ + return 0; + } else { + ASN__CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } +} + +static asn_TYPE_member_t asn_MBR_AuxFingerprintContents_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct AuxFingerprintContents, method), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + memb_method_constraint_1, + 0, /* PER is not compiled, use -gen-PER */ + 0, + "method" + }, + { ATF_NOFLAGS, 0, offsetof(struct AuxFingerprintContents, conditionAux), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "conditionAux" + }, +}; +static const ber_tlv_tag_t asn_DEF_AuxFingerprintContents_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static const asn_TYPE_tag2member_t asn_MAP_AuxFingerprintContents_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* method */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* conditionAux */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_AuxFingerprintContents_specs_1 = { + sizeof(struct AuxFingerprintContents), + offsetof(struct AuxFingerprintContents, _asn_ctx), + asn_MAP_AuxFingerprintContents_tag2el_1, + 2, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_AuxFingerprintContents = { + "AuxFingerprintContents", + "AuxFingerprintContents", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_AuxFingerprintContents_tags_1, + sizeof(asn_DEF_AuxFingerprintContents_tags_1) + /sizeof(asn_DEF_AuxFingerprintContents_tags_1[0]), /* 1 */ + asn_DEF_AuxFingerprintContents_tags_1, /* Same as above */ + sizeof(asn_DEF_AuxFingerprintContents_tags_1) + /sizeof(asn_DEF_AuxFingerprintContents_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_AuxFingerprintContents_1, + 2, /* Elements count */ + &asn_SPC_AuxFingerprintContents_specs_1 /* Additional specs */ +}; + diff --git a/src/cryptoconditions/src/asn/AuxFingerprintContents.h b/src/cryptoconditions/src/asn/AuxFingerprintContents.h new file mode 100644 index 000000000..9f14a1bac --- /dev/null +++ b/src/cryptoconditions/src/asn/AuxFingerprintContents.h @@ -0,0 +1,38 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#ifndef _AuxFingerprintContents_H_ +#define _AuxFingerprintContents_H_ + + +#include + +/* Including external dependencies */ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* AuxFingerprintContents */ +typedef struct AuxFingerprintContents { + OCTET_STRING_t method; + OCTET_STRING_t conditionAux; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} AuxFingerprintContents_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_AuxFingerprintContents; + +#ifdef __cplusplus +} +#endif + +#endif /* _AuxFingerprintContents_H_ */ +#include diff --git a/src/cryptoconditions/src/asn/AuxFulfillment.c b/src/cryptoconditions/src/asn/AuxFulfillment.c new file mode 100644 index 000000000..84362f79d --- /dev/null +++ b/src/cryptoconditions/src/asn/AuxFulfillment.c @@ -0,0 +1,78 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#include "AuxFulfillment.h" + +static asn_TYPE_member_t asn_MBR_AuxFulfillment_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct AuxFulfillment, method), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "method" + }, + { ATF_NOFLAGS, 0, offsetof(struct AuxFulfillment, conditionAux), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "conditionAux" + }, + { ATF_NOFLAGS, 0, offsetof(struct AuxFulfillment, fulfillmentAux), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "fulfillmentAux" + }, +}; +static const ber_tlv_tag_t asn_DEF_AuxFulfillment_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static const asn_TYPE_tag2member_t asn_MAP_AuxFulfillment_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* method */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* conditionAux */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* fulfillmentAux */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_AuxFulfillment_specs_1 = { + sizeof(struct AuxFulfillment), + offsetof(struct AuxFulfillment, _asn_ctx), + asn_MAP_AuxFulfillment_tag2el_1, + 3, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_AuxFulfillment = { + "AuxFulfillment", + "AuxFulfillment", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_AuxFulfillment_tags_1, + sizeof(asn_DEF_AuxFulfillment_tags_1) + /sizeof(asn_DEF_AuxFulfillment_tags_1[0]), /* 1 */ + asn_DEF_AuxFulfillment_tags_1, /* Same as above */ + sizeof(asn_DEF_AuxFulfillment_tags_1) + /sizeof(asn_DEF_AuxFulfillment_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_AuxFulfillment_1, + 3, /* Elements count */ + &asn_SPC_AuxFulfillment_specs_1 /* Additional specs */ +}; + diff --git a/src/cryptoconditions/src/asn/AuxFulfillment.h b/src/cryptoconditions/src/asn/AuxFulfillment.h new file mode 100644 index 000000000..89b514b77 --- /dev/null +++ b/src/cryptoconditions/src/asn/AuxFulfillment.h @@ -0,0 +1,39 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#ifndef _AuxFulfillment_H_ +#define _AuxFulfillment_H_ + + +#include + +/* Including external dependencies */ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* AuxFulfillment */ +typedef struct AuxFulfillment { + OCTET_STRING_t method; + OCTET_STRING_t conditionAux; + OCTET_STRING_t fulfillmentAux; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} AuxFulfillment_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_AuxFulfillment; + +#ifdef __cplusplus +} +#endif + +#endif /* _AuxFulfillment_H_ */ +#include diff --git a/src/cryptoconditions/src/asn/AuxSha512Fulfillment.c b/src/cryptoconditions/src/asn/AuxSha512Fulfillment.c new file mode 100644 index 000000000..62ad8a76f --- /dev/null +++ b/src/cryptoconditions/src/asn/AuxSha512Fulfillment.c @@ -0,0 +1,78 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#include "AuxSha512Fulfillment.h" + +static asn_TYPE_member_t asn_MBR_AuxSha512Fulfillment_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct AuxSha512Fulfillment, method), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "method" + }, + { ATF_NOFLAGS, 0, offsetof(struct AuxSha512Fulfillment, conditionAux), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "conditionAux" + }, + { ATF_NOFLAGS, 0, offsetof(struct AuxSha512Fulfillment, fulfillmentAux), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "fulfillmentAux" + }, +}; +static const ber_tlv_tag_t asn_DEF_AuxSha512Fulfillment_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static const asn_TYPE_tag2member_t asn_MAP_AuxSha512Fulfillment_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* method */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* conditionAux */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* fulfillmentAux */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_AuxSha512Fulfillment_specs_1 = { + sizeof(struct AuxSha512Fulfillment), + offsetof(struct AuxSha512Fulfillment, _asn_ctx), + asn_MAP_AuxSha512Fulfillment_tag2el_1, + 3, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_AuxSha512Fulfillment = { + "AuxSha512Fulfillment", + "AuxSha512Fulfillment", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_AuxSha512Fulfillment_tags_1, + sizeof(asn_DEF_AuxSha512Fulfillment_tags_1) + /sizeof(asn_DEF_AuxSha512Fulfillment_tags_1[0]), /* 1 */ + asn_DEF_AuxSha512Fulfillment_tags_1, /* Same as above */ + sizeof(asn_DEF_AuxSha512Fulfillment_tags_1) + /sizeof(asn_DEF_AuxSha512Fulfillment_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_AuxSha512Fulfillment_1, + 3, /* Elements count */ + &asn_SPC_AuxSha512Fulfillment_specs_1 /* Additional specs */ +}; + diff --git a/src/cryptoconditions/src/asn/AuxSha512Fulfillment.h b/src/cryptoconditions/src/asn/AuxSha512Fulfillment.h new file mode 100644 index 000000000..81a7fa140 --- /dev/null +++ b/src/cryptoconditions/src/asn/AuxSha512Fulfillment.h @@ -0,0 +1,39 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#ifndef _AuxSha512Fulfillment_H_ +#define _AuxSha512Fulfillment_H_ + + +#include + +/* Including external dependencies */ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* AuxSha512Fulfillment */ +typedef struct AuxSha512Fulfillment { + OCTET_STRING_t method; + OCTET_STRING_t conditionAux; + OCTET_STRING_t fulfillmentAux; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} AuxSha512Fulfillment_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_AuxSha512Fulfillment; + +#ifdef __cplusplus +} +#endif + +#endif /* _AuxSha512Fulfillment_H_ */ +#include diff --git a/src/cryptoconditions/src/asn/BIT_STRING.c b/src/cryptoconditions/src/asn/BIT_STRING.c new file mode 100644 index 000000000..997ff4161 --- /dev/null +++ b/src/cryptoconditions/src/asn/BIT_STRING.c @@ -0,0 +1,189 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +/* + * BIT STRING basic type description. + */ +static const ber_tlv_tag_t asn_DEF_BIT_STRING_tags[] = { + (ASN_TAG_CLASS_UNIVERSAL | (3 << 2)) +}; +static asn_OCTET_STRING_specifics_t asn_DEF_BIT_STRING_specs = { + sizeof(BIT_STRING_t), + offsetof(BIT_STRING_t, _asn_ctx), + ASN_OSUBV_BIT +}; +asn_TYPE_descriptor_t asn_DEF_BIT_STRING = { + "BIT STRING", + "BIT_STRING", + OCTET_STRING_free, /* Implemented in terms of OCTET STRING */ + BIT_STRING_print, + BIT_STRING_constraint, + OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */ + OCTET_STRING_encode_der, /* Implemented in terms of OCTET STRING */ + OCTET_STRING_decode_xer_binary, + BIT_STRING_encode_xer, + OCTET_STRING_decode_uper, /* Unaligned PER decoder */ + OCTET_STRING_encode_uper, /* Unaligned PER encoder */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_BIT_STRING_tags, + sizeof(asn_DEF_BIT_STRING_tags) + / sizeof(asn_DEF_BIT_STRING_tags[0]), + asn_DEF_BIT_STRING_tags, /* Same as above */ + sizeof(asn_DEF_BIT_STRING_tags) + / sizeof(asn_DEF_BIT_STRING_tags[0]), + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + &asn_DEF_BIT_STRING_specs +}; + +/* + * BIT STRING generic constraint. + */ +int +BIT_STRING_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + + if(st && st->buf) { + if((st->size == 0 && st->bits_unused) + || st->bits_unused < 0 || st->bits_unused > 7) { + ASN__CTFAIL(app_key, td, sptr, + "%s: invalid padding byte (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + } else { + ASN__CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + return 0; +} + +static char *_bit_pattern[16] = { + "0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111", + "1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111" +}; + +asn_enc_rval_t +BIT_STRING_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_enc_rval_t er; + char scratch[128]; + char *p = scratch; + char *scend = scratch + (sizeof(scratch) - 10); + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + int xcan = (flags & XER_F_CANONICAL); + uint8_t *buf; + uint8_t *end; + + if(!st || !st->buf) + ASN__ENCODE_FAILED; + + er.encoded = 0; + + buf = st->buf; + end = buf + st->size - 1; /* Last byte is special */ + + /* + * Binary dump + */ + for(; buf < end; buf++) { + int v = *buf; + int nline = xcan?0:(((buf - st->buf) % 8) == 0); + if(p >= scend || nline) { + er.encoded += p - scratch; + ASN__CALLBACK(scratch, p - scratch); + p = scratch; + if(nline) ASN__TEXT_INDENT(1, ilevel); + } + memcpy(p + 0, _bit_pattern[v >> 4], 4); + memcpy(p + 4, _bit_pattern[v & 0x0f], 4); + p += 8; + } + + if(!xcan && ((buf - st->buf) % 8) == 0) + ASN__TEXT_INDENT(1, ilevel); + er.encoded += p - scratch; + ASN__CALLBACK(scratch, p - scratch); + p = scratch; + + if(buf == end) { + int v = *buf; + int ubits = st->bits_unused; + int i; + for(i = 7; i >= ubits; i--) + *p++ = (v & (1 << i)) ? 0x31 : 0x30; + er.encoded += p - scratch; + ASN__CALLBACK(scratch, p - scratch); + } + + if(!xcan) ASN__TEXT_INDENT(1, ilevel - 1); + + ASN__ENCODED_OK(er); +cb_failed: + ASN__ENCODE_FAILED; +} + + +/* + * BIT STRING specific contents printer. + */ +int +BIT_STRING_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, + asn_app_consume_bytes_f *cb, void *app_key) { + const char * const h2c = "0123456789ABCDEF"; + char scratch[64]; + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + uint8_t *buf; + uint8_t *end; + char *p = scratch; + + (void)td; /* Unused argument */ + + if(!st || !st->buf) + return (cb("", 8, app_key) < 0) ? -1 : 0; + + ilevel++; + buf = st->buf; + end = buf + st->size; + + /* + * Hexadecimal dump. + */ + for(; buf < end; buf++) { + if((buf - st->buf) % 16 == 0 && (st->size > 16) + && buf != st->buf) { + _i_INDENT(1); + /* Dump the string */ + if(cb(scratch, p - scratch, app_key) < 0) return -1; + p = scratch; + } + *p++ = h2c[*buf >> 4]; + *p++ = h2c[*buf & 0x0F]; + *p++ = 0x20; + } + + if(p > scratch) { + p--; /* Eat the tailing space */ + + if((st->size > 16)) { + _i_INDENT(1); + } + + /* Dump the incomplete 16-bytes row */ + if(cb(scratch, p - scratch, app_key) < 0) + return -1; + } + + return 0; +} + diff --git a/src/cryptoconditions/src/asn/BIT_STRING.h b/src/cryptoconditions/src/asn/BIT_STRING.h new file mode 100644 index 000000000..732e878bc --- /dev/null +++ b/src/cryptoconditions/src/asn/BIT_STRING.h @@ -0,0 +1,33 @@ +/*- + * Copyright (c) 2003 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _BIT_STRING_H_ +#define _BIT_STRING_H_ + +#include /* Some help from OCTET STRING */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct BIT_STRING_s { + uint8_t *buf; /* BIT STRING body */ + int size; /* Size of the above buffer */ + + int bits_unused;/* Unused trailing bits in the last octet (0..7) */ + + asn_struct_ctx_t _asn_ctx; /* Parsing across buffer boundaries */ +} BIT_STRING_t; + +extern asn_TYPE_descriptor_t asn_DEF_BIT_STRING; + +asn_struct_print_f BIT_STRING_print; /* Human-readable output */ +asn_constr_check_f BIT_STRING_constraint; +xer_type_encoder_f BIT_STRING_encode_xer; + +#ifdef __cplusplus +} +#endif + +#endif /* _BIT_STRING_H_ */ diff --git a/src/cryptoconditions/src/asn/CompoundSha256Condition.c b/src/cryptoconditions/src/asn/CompoundSha256Condition.c new file mode 100644 index 000000000..31c276bf6 --- /dev/null +++ b/src/cryptoconditions/src/asn/CompoundSha256Condition.c @@ -0,0 +1,235 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#include "CompoundSha256Condition.h" + +static int +cost_3_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + + if(!sptr) { + ASN__CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + + /* Constraint check succeeded */ + return 0; +} + +/* + * This type is implemented using NativeInteger, + * so here we adjust the DEF accordingly. + */ +static void +cost_3_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { + td->free_struct = asn_DEF_NativeInteger.free_struct; + td->print_struct = asn_DEF_NativeInteger.print_struct; + td->check_constraints = asn_DEF_NativeInteger.check_constraints; + td->ber_decoder = asn_DEF_NativeInteger.ber_decoder; + td->der_encoder = asn_DEF_NativeInteger.der_encoder; + td->xer_decoder = asn_DEF_NativeInteger.xer_decoder; + td->xer_encoder = asn_DEF_NativeInteger.xer_encoder; + td->uper_decoder = asn_DEF_NativeInteger.uper_decoder; + td->uper_encoder = asn_DEF_NativeInteger.uper_encoder; + if(!td->per_constraints) + td->per_constraints = asn_DEF_NativeInteger.per_constraints; + td->elements = asn_DEF_NativeInteger.elements; + td->elements_count = asn_DEF_NativeInteger.elements_count; + /* td->specifics = asn_DEF_NativeInteger.specifics; // Defined explicitly */ +} + +static void +cost_3_free(asn_TYPE_descriptor_t *td, + void *struct_ptr, int contents_only) { + cost_3_inherit_TYPE_descriptor(td); + td->free_struct(td, struct_ptr, contents_only); +} + +static int +cost_3_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + cost_3_inherit_TYPE_descriptor(td); + return td->print_struct(td, struct_ptr, ilevel, cb, app_key); +} + +static asn_dec_rval_t +cost_3_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const void *bufptr, size_t size, int tag_mode) { + cost_3_inherit_TYPE_descriptor(td); + return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); +} + +static asn_enc_rval_t +cost_3_encode_der(asn_TYPE_descriptor_t *td, + void *structure, int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + cost_3_inherit_TYPE_descriptor(td); + return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); +} + +static asn_dec_rval_t +cost_3_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const char *opt_mname, const void *bufptr, size_t size) { + cost_3_inherit_TYPE_descriptor(td); + return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); +} + +static asn_enc_rval_t +cost_3_encode_xer(asn_TYPE_descriptor_t *td, void *structure, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + cost_3_inherit_TYPE_descriptor(td); + return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); +} + +static int +memb_fingerprint_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + size_t size; + + if(!sptr) { + ASN__CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + size = st->size; + + if((size == 32)) { + /* Constraint check succeeded */ + return 0; + } else { + ASN__CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } +} + +static int +memb_cost_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + + if(!sptr) { + ASN__CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + + /* Constraint check succeeded */ + return 0; +} + +static const asn_INTEGER_specifics_t asn_SPC_cost_specs_3 = { + 0, 0, 0, 0, 0, + 0, /* Native long size */ + 1 /* Unsigned representation */ +}; +static const ber_tlv_tag_t asn_DEF_cost_tags_3[] = { + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)) +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_cost_3 = { + "cost", + "cost", + cost_3_free, + cost_3_print, + cost_3_constraint, + cost_3_decode_ber, + cost_3_encode_der, + cost_3_decode_xer, + cost_3_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_cost_tags_3, + sizeof(asn_DEF_cost_tags_3) + /sizeof(asn_DEF_cost_tags_3[0]) - 1, /* 1 */ + asn_DEF_cost_tags_3, /* Same as above */ + sizeof(asn_DEF_cost_tags_3) + /sizeof(asn_DEF_cost_tags_3[0]), /* 2 */ + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + &asn_SPC_cost_specs_3 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_CompoundSha256Condition_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct CompoundSha256Condition, fingerprint), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + memb_fingerprint_constraint_1, + 0, /* PER is not compiled, use -gen-PER */ + 0, + "fingerprint" + }, + { ATF_NOFLAGS, 0, offsetof(struct CompoundSha256Condition, cost), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_cost_3, + memb_cost_constraint_1, + 0, /* PER is not compiled, use -gen-PER */ + 0, + "cost" + }, + { ATF_NOFLAGS, 0, offsetof(struct CompoundSha256Condition, subtypes), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_ConditionTypes, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "subtypes" + }, +}; +static const ber_tlv_tag_t asn_DEF_CompoundSha256Condition_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static const asn_TYPE_tag2member_t asn_MAP_CompoundSha256Condition_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* fingerprint */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* cost */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* subtypes */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_CompoundSha256Condition_specs_1 = { + sizeof(struct CompoundSha256Condition), + offsetof(struct CompoundSha256Condition, _asn_ctx), + asn_MAP_CompoundSha256Condition_tag2el_1, + 3, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_CompoundSha256Condition = { + "CompoundSha256Condition", + "CompoundSha256Condition", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_CompoundSha256Condition_tags_1, + sizeof(asn_DEF_CompoundSha256Condition_tags_1) + /sizeof(asn_DEF_CompoundSha256Condition_tags_1[0]), /* 1 */ + asn_DEF_CompoundSha256Condition_tags_1, /* Same as above */ + sizeof(asn_DEF_CompoundSha256Condition_tags_1) + /sizeof(asn_DEF_CompoundSha256Condition_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_CompoundSha256Condition_1, + 3, /* Elements count */ + &asn_SPC_CompoundSha256Condition_specs_1 /* Additional specs */ +}; + diff --git a/src/cryptoconditions/src/asn/CompoundSha256Condition.h b/src/cryptoconditions/src/asn/CompoundSha256Condition.h new file mode 100644 index 000000000..5d791be4f --- /dev/null +++ b/src/cryptoconditions/src/asn/CompoundSha256Condition.h @@ -0,0 +1,42 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#ifndef _CompoundSha256Condition_H_ +#define _CompoundSha256Condition_H_ + + +#include + +/* Including external dependencies */ +#include +#include +#include "ConditionTypes.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* CompoundSha256Condition */ +typedef struct CompoundSha256Condition { + OCTET_STRING_t fingerprint; + unsigned long cost; + ConditionTypes_t subtypes; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} CompoundSha256Condition_t; + +/* Implementation */ +/* extern asn_TYPE_descriptor_t asn_DEF_cost_3; // (Use -fall-defs-global to expose) */ +extern asn_TYPE_descriptor_t asn_DEF_CompoundSha256Condition; + +#ifdef __cplusplus +} +#endif + +#endif /* _CompoundSha256Condition_H_ */ +#include diff --git a/src/cryptoconditions/src/asn/Condition.c b/src/cryptoconditions/src/asn/Condition.c new file mode 100644 index 000000000..49ec83e3b --- /dev/null +++ b/src/cryptoconditions/src/asn/Condition.c @@ -0,0 +1,114 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#include "Condition.h" + +static asn_TYPE_member_t asn_MBR_Condition_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct Condition, choice.preimageSha256), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_SimpleSha256Condition, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "preimageSha256" + }, + { ATF_NOFLAGS, 0, offsetof(struct Condition, choice.prefixSha256), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_CompoundSha256Condition, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "prefixSha256" + }, + { ATF_NOFLAGS, 0, offsetof(struct Condition, choice.thresholdSha256), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_CompoundSha256Condition, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "thresholdSha256" + }, + { ATF_NOFLAGS, 0, offsetof(struct Condition, choice.rsaSha256), + (ASN_TAG_CLASS_CONTEXT | (3 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_SimpleSha256Condition, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "rsaSha256" + }, + { ATF_NOFLAGS, 0, offsetof(struct Condition, choice.ed25519Sha256), + (ASN_TAG_CLASS_CONTEXT | (4 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_SimpleSha256Condition, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "ed25519Sha256" + }, + { ATF_NOFLAGS, 0, offsetof(struct Condition, choice.secp256k1Sha256), + (ASN_TAG_CLASS_CONTEXT | (5 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_SimpleSha256Condition, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "secp256k1Sha256" + }, + { ATF_NOFLAGS, 0, offsetof(struct Condition, choice.evalSha256), + (ASN_TAG_CLASS_CONTEXT | (15 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_SimpleSha256Condition, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "evalSha256" + }, +}; +static const asn_TYPE_tag2member_t asn_MAP_Condition_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* preimageSha256 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* prefixSha256 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 }, /* thresholdSha256 */ + { (ASN_TAG_CLASS_CONTEXT | (3 << 2)), 3, 0, 0 }, /* rsaSha256 */ + { (ASN_TAG_CLASS_CONTEXT | (4 << 2)), 4, 0, 0 }, /* ed25519Sha256 */ + { (ASN_TAG_CLASS_CONTEXT | (5 << 2)), 5, 0, 0 }, /* secp256k1Sha256 */ + { (ASN_TAG_CLASS_CONTEXT | (15 << 2)), 6, 0, 0 } /* evalSha256 */ +}; +static asn_CHOICE_specifics_t asn_SPC_Condition_specs_1 = { + sizeof(struct Condition), + offsetof(struct Condition, _asn_ctx), + offsetof(struct Condition, present), + sizeof(((struct Condition *)0)->present), + asn_MAP_Condition_tag2el_1, + 7, /* Count of tags in the map */ + 0, + -1 /* Extensions start */ +}; +asn_TYPE_descriptor_t asn_DEF_Condition = { + "Condition", + "Condition", + CHOICE_free, + CHOICE_print, + CHOICE_constraint, + CHOICE_decode_ber, + CHOICE_encode_der, + CHOICE_decode_xer, + CHOICE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + CHOICE_outmost_tag, + 0, /* No effective tags (pointer) */ + 0, /* No effective tags (count) */ + 0, /* No tags (pointer) */ + 0, /* No tags (count) */ + 0, /* No PER visible constraints */ + asn_MBR_Condition_1, + 7, /* Elements count */ + &asn_SPC_Condition_specs_1 /* Additional specs */ +}; + diff --git a/src/cryptoconditions/src/asn/Condition.h b/src/cryptoconditions/src/asn/Condition.h new file mode 100644 index 000000000..ad32b18aa --- /dev/null +++ b/src/cryptoconditions/src/asn/Condition.h @@ -0,0 +1,59 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#ifndef _Condition_H_ +#define _Condition_H_ + + +#include + +/* Including external dependencies */ +#include "SimpleSha256Condition.h" +#include "CompoundSha256Condition.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Dependencies */ +typedef enum Condition_PR { + Condition_PR_NOTHING, /* No components present */ + Condition_PR_preimageSha256, + Condition_PR_prefixSha256, + Condition_PR_thresholdSha256, + Condition_PR_rsaSha256, + Condition_PR_ed25519Sha256, + Condition_PR_secp256k1Sha256, + Condition_PR_evalSha256 +} Condition_PR; + +/* Condition */ +typedef struct Condition { + Condition_PR present; + union Condition_u { + SimpleSha256Condition_t preimageSha256; + CompoundSha256Condition_t prefixSha256; + CompoundSha256Condition_t thresholdSha256; + SimpleSha256Condition_t rsaSha256; + SimpleSha256Condition_t ed25519Sha256; + SimpleSha256Condition_t secp256k1Sha256; + SimpleSha256Condition_t evalSha256; + } choice; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} Condition_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_Condition; + +#ifdef __cplusplus +} +#endif + +#endif /* _Condition_H_ */ +#include diff --git a/src/cryptoconditions/src/asn/ConditionTypes.c b/src/cryptoconditions/src/asn/ConditionTypes.c new file mode 100644 index 000000000..16ca9d19c --- /dev/null +++ b/src/cryptoconditions/src/asn/ConditionTypes.c @@ -0,0 +1,108 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#include "ConditionTypes.h" + +int +ConditionTypes_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + /* Replace with underlying type checker */ + td->check_constraints = asn_DEF_BIT_STRING.check_constraints; + return td->check_constraints(td, sptr, ctfailcb, app_key); +} + +/* + * This type is implemented using BIT_STRING, + * so here we adjust the DEF accordingly. + */ +static void +ConditionTypes_1_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { + td->free_struct = asn_DEF_BIT_STRING.free_struct; + td->print_struct = asn_DEF_BIT_STRING.print_struct; + td->check_constraints = asn_DEF_BIT_STRING.check_constraints; + td->ber_decoder = asn_DEF_BIT_STRING.ber_decoder; + td->der_encoder = asn_DEF_BIT_STRING.der_encoder; + td->xer_decoder = asn_DEF_BIT_STRING.xer_decoder; + td->xer_encoder = asn_DEF_BIT_STRING.xer_encoder; + td->uper_decoder = asn_DEF_BIT_STRING.uper_decoder; + td->uper_encoder = asn_DEF_BIT_STRING.uper_encoder; + if(!td->per_constraints) + td->per_constraints = asn_DEF_BIT_STRING.per_constraints; + td->elements = asn_DEF_BIT_STRING.elements; + td->elements_count = asn_DEF_BIT_STRING.elements_count; + td->specifics = asn_DEF_BIT_STRING.specifics; +} + +void +ConditionTypes_free(asn_TYPE_descriptor_t *td, + void *struct_ptr, int contents_only) { + ConditionTypes_1_inherit_TYPE_descriptor(td); + td->free_struct(td, struct_ptr, contents_only); +} + +int +ConditionTypes_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + ConditionTypes_1_inherit_TYPE_descriptor(td); + return td->print_struct(td, struct_ptr, ilevel, cb, app_key); +} + +asn_dec_rval_t +ConditionTypes_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const void *bufptr, size_t size, int tag_mode) { + ConditionTypes_1_inherit_TYPE_descriptor(td); + return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); +} + +asn_enc_rval_t +ConditionTypes_encode_der(asn_TYPE_descriptor_t *td, + void *structure, int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + ConditionTypes_1_inherit_TYPE_descriptor(td); + return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); +} + +asn_dec_rval_t +ConditionTypes_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const char *opt_mname, const void *bufptr, size_t size) { + ConditionTypes_1_inherit_TYPE_descriptor(td); + return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); +} + +asn_enc_rval_t +ConditionTypes_encode_xer(asn_TYPE_descriptor_t *td, void *structure, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + ConditionTypes_1_inherit_TYPE_descriptor(td); + return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); +} + +static const ber_tlv_tag_t asn_DEF_ConditionTypes_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (3 << 2)) +}; +asn_TYPE_descriptor_t asn_DEF_ConditionTypes = { + "ConditionTypes", + "ConditionTypes", + ConditionTypes_free, + ConditionTypes_print, + ConditionTypes_constraint, + ConditionTypes_decode_ber, + ConditionTypes_encode_der, + ConditionTypes_decode_xer, + ConditionTypes_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_ConditionTypes_tags_1, + sizeof(asn_DEF_ConditionTypes_tags_1) + /sizeof(asn_DEF_ConditionTypes_tags_1[0]), /* 1 */ + asn_DEF_ConditionTypes_tags_1, /* Same as above */ + sizeof(asn_DEF_ConditionTypes_tags_1) + /sizeof(asn_DEF_ConditionTypes_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + 0, 0, /* Defined elsewhere */ + 0 /* No specifics */ +}; + diff --git a/src/cryptoconditions/src/asn/ConditionTypes.h b/src/cryptoconditions/src/asn/ConditionTypes.h new file mode 100644 index 000000000..3d391eb36 --- /dev/null +++ b/src/cryptoconditions/src/asn/ConditionTypes.h @@ -0,0 +1,49 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#ifndef _ConditionTypes_H_ +#define _ConditionTypes_H_ + + +#include + +/* Including external dependencies */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Dependencies */ +typedef enum ConditionTypes { + ConditionTypes_preImageSha256 = 0, + ConditionTypes_prefixSha256 = 1, + ConditionTypes_thresholdSha256 = 2, + ConditionTypes_rsaSha256 = 3, + ConditionTypes_ed25519Sha256 = 4, + ConditionTypes_secp256k1Sha256 = 5, + ConditionTypes_evalSha256 = 15 +} e_ConditionTypes; + +/* ConditionTypes */ +typedef BIT_STRING_t ConditionTypes_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_ConditionTypes; +asn_struct_free_f ConditionTypes_free; +asn_struct_print_f ConditionTypes_print; +asn_constr_check_f ConditionTypes_constraint; +ber_type_decoder_f ConditionTypes_decode_ber; +der_type_encoder_f ConditionTypes_encode_der; +xer_type_decoder_f ConditionTypes_decode_xer; +xer_type_encoder_f ConditionTypes_encode_xer; + +#ifdef __cplusplus +} +#endif + +#endif /* _ConditionTypes_H_ */ +#include diff --git a/src/cryptoconditions/src/asn/CryptoConditions.asn b/src/cryptoconditions/src/asn/CryptoConditions.asn new file mode 100644 index 000000000..8aa1e365b --- /dev/null +++ b/src/cryptoconditions/src/asn/CryptoConditions.asn @@ -0,0 +1,118 @@ +---- + +Crypto-Conditions DEFINITIONS AUTOMATIC TAGS ::= BEGIN + + -- Conditions + + Condition ::= CHOICE { + preimageSha256 [0] SimpleSha256Condition, + prefixSha256 [1] CompoundSha256Condition, + thresholdSha256 [2] CompoundSha256Condition, + rsaSha256 [3] SimpleSha256Condition, + ed25519Sha256 [4] SimpleSha256Condition, + secp256k1Sha256 [5] SimpleSha256Condition, + evalSha256 [15] SimpleSha256Condition + } + + SimpleSha256Condition ::= SEQUENCE { + fingerprint OCTET STRING (SIZE(32)), + cost INTEGER (0..4294967295) + } + + CompoundSha256Condition ::= SEQUENCE { + fingerprint OCTET STRING (SIZE(32)), + cost INTEGER (0..4294967295), + subtypes ConditionTypes + } + + ConditionTypes ::= BIT STRING { + preImageSha256 (0), + prefixSha256 (1), + thresholdSha256 (2), + rsaSha256 (3), + ed25519Sha256 (4), + secp256k1Sha256 (5), + evalSha256 (15) + } + + -- Fulfillments + + Fulfillment ::= CHOICE { + preimageSha256 [0] PreimageFulfillment , + prefixSha256 [1] PrefixFulfillment, + thresholdSha256 [2] ThresholdFulfillment, + rsaSha256 [3] RsaSha256Fulfillment, + ed25519Sha256 [4] Ed25519Sha512Fulfillment, + secp256k1Sha256 [5] Secp256k1Fulfillment, + evalSha256 [15] EvalFulfillment + } + + PreimageFulfillment ::= SEQUENCE { + preimage OCTET STRING + } + + PrefixFulfillment ::= SEQUENCE { + prefix OCTET STRING, + maxMessageLength INTEGER (0..4294967295), + subfulfillment Fulfillment + } + + ThresholdFulfillment ::= SEQUENCE { + subfulfillments SET OF Fulfillment, + subconditions SET OF Condition + } + + RsaSha256Fulfillment ::= SEQUENCE { + modulus OCTET STRING, + signature OCTET STRING + } + + Ed25519Sha512Fulfillment ::= SEQUENCE { + publicKey OCTET STRING (SIZE(32)), + signature OCTET STRING (SIZE(64)) + } + + Secp256k1Fulfillment ::= SEQUENCE { + publicKey OCTET STRING (SIZE(33)), + signature OCTET STRING (SIZE(64)) + } + + EvalFulfillment ::= SEQUENCE { + method OCTET STRING (SIZE(64)), + paramsBin OCTET STRING + } + + -- Fingerprint Content + + -- The PREIMAGE-SHA-256 condition fingerprint content is not DER encoded + -- The fingerprint content is the preimage + + PrefixFingerprintContents ::= SEQUENCE { + prefix OCTET STRING, + maxMessageLength INTEGER (0..4294967295), + subcondition Condition + } + + ThresholdFingerprintContents ::= SEQUENCE { + threshold INTEGER (1..65535), + subconditions2 SET OF Condition + } + + RsaFingerprintContents ::= SEQUENCE { + modulus OCTET STRING + } + + Ed25519FingerprintContents ::= SEQUENCE { + publicKey OCTET STRING (SIZE(32)) + } + + Secp256k1FingerprintContents ::= SEQUENCE { + publicKey OCTET STRING (SIZE(33)) + } + + EvalFingerprintContents ::= SEQUENCE { + method OCTET STRING (SIZE(64)), + paramsBin OCTET STRING + } + +END diff --git a/src/cryptoconditions/src/asn/Ed25519FingerprintContents.c b/src/cryptoconditions/src/asn/Ed25519FingerprintContents.c new file mode 100644 index 000000000..c47213100 --- /dev/null +++ b/src/cryptoconditions/src/asn/Ed25519FingerprintContents.c @@ -0,0 +1,84 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#include "Ed25519FingerprintContents.h" + +static int +memb_publicKey_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + size_t size; + + if(!sptr) { + ASN__CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + size = st->size; + + if((size == 32)) { + /* Constraint check succeeded */ + return 0; + } else { + ASN__CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } +} + +static asn_TYPE_member_t asn_MBR_Ed25519FingerprintContents_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct Ed25519FingerprintContents, publicKey), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + memb_publicKey_constraint_1, + 0, /* PER is not compiled, use -gen-PER */ + 0, + "publicKey" + }, +}; +static const ber_tlv_tag_t asn_DEF_Ed25519FingerprintContents_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static const asn_TYPE_tag2member_t asn_MAP_Ed25519FingerprintContents_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 } /* publicKey */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_Ed25519FingerprintContents_specs_1 = { + sizeof(struct Ed25519FingerprintContents), + offsetof(struct Ed25519FingerprintContents, _asn_ctx), + asn_MAP_Ed25519FingerprintContents_tag2el_1, + 1, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_Ed25519FingerprintContents = { + "Ed25519FingerprintContents", + "Ed25519FingerprintContents", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_Ed25519FingerprintContents_tags_1, + sizeof(asn_DEF_Ed25519FingerprintContents_tags_1) + /sizeof(asn_DEF_Ed25519FingerprintContents_tags_1[0]), /* 1 */ + asn_DEF_Ed25519FingerprintContents_tags_1, /* Same as above */ + sizeof(asn_DEF_Ed25519FingerprintContents_tags_1) + /sizeof(asn_DEF_Ed25519FingerprintContents_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_Ed25519FingerprintContents_1, + 1, /* Elements count */ + &asn_SPC_Ed25519FingerprintContents_specs_1 /* Additional specs */ +}; + diff --git a/src/cryptoconditions/src/asn/Ed25519FingerprintContents.h b/src/cryptoconditions/src/asn/Ed25519FingerprintContents.h new file mode 100644 index 000000000..7ef9e188e --- /dev/null +++ b/src/cryptoconditions/src/asn/Ed25519FingerprintContents.h @@ -0,0 +1,37 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#ifndef _Ed25519FingerprintContents_H_ +#define _Ed25519FingerprintContents_H_ + + +#include + +/* Including external dependencies */ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Ed25519FingerprintContents */ +typedef struct Ed25519FingerprintContents { + OCTET_STRING_t publicKey; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} Ed25519FingerprintContents_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_Ed25519FingerprintContents; + +#ifdef __cplusplus +} +#endif + +#endif /* _Ed25519FingerprintContents_H_ */ +#include diff --git a/src/cryptoconditions/src/asn/Ed25519Sha512Fulfillment.c b/src/cryptoconditions/src/asn/Ed25519Sha512Fulfillment.c new file mode 100644 index 000000000..6f756fb56 --- /dev/null +++ b/src/cryptoconditions/src/asn/Ed25519Sha512Fulfillment.c @@ -0,0 +1,120 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#include "Ed25519Sha512Fulfillment.h" + +static int +memb_publicKey_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + size_t size; + + if(!sptr) { + ASN__CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + size = st->size; + + if((size == 32)) { + /* Constraint check succeeded */ + return 0; + } else { + ASN__CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } +} + +static int +memb_signature_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + size_t size; + + if(!sptr) { + ASN__CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + size = st->size; + + if((size == 64)) { + /* Constraint check succeeded */ + return 0; + } else { + ASN__CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } +} + +static asn_TYPE_member_t asn_MBR_Ed25519Sha512Fulfillment_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct Ed25519Sha512Fulfillment, publicKey), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + memb_publicKey_constraint_1, + 0, /* PER is not compiled, use -gen-PER */ + 0, + "publicKey" + }, + { ATF_NOFLAGS, 0, offsetof(struct Ed25519Sha512Fulfillment, signature), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + memb_signature_constraint_1, + 0, /* PER is not compiled, use -gen-PER */ + 0, + "signature" + }, +}; +static const ber_tlv_tag_t asn_DEF_Ed25519Sha512Fulfillment_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static const asn_TYPE_tag2member_t asn_MAP_Ed25519Sha512Fulfillment_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* publicKey */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* signature */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_Ed25519Sha512Fulfillment_specs_1 = { + sizeof(struct Ed25519Sha512Fulfillment), + offsetof(struct Ed25519Sha512Fulfillment, _asn_ctx), + asn_MAP_Ed25519Sha512Fulfillment_tag2el_1, + 2, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_Ed25519Sha512Fulfillment = { + "Ed25519Sha512Fulfillment", + "Ed25519Sha512Fulfillment", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_Ed25519Sha512Fulfillment_tags_1, + sizeof(asn_DEF_Ed25519Sha512Fulfillment_tags_1) + /sizeof(asn_DEF_Ed25519Sha512Fulfillment_tags_1[0]), /* 1 */ + asn_DEF_Ed25519Sha512Fulfillment_tags_1, /* Same as above */ + sizeof(asn_DEF_Ed25519Sha512Fulfillment_tags_1) + /sizeof(asn_DEF_Ed25519Sha512Fulfillment_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_Ed25519Sha512Fulfillment_1, + 2, /* Elements count */ + &asn_SPC_Ed25519Sha512Fulfillment_specs_1 /* Additional specs */ +}; + diff --git a/src/cryptoconditions/src/asn/Ed25519Sha512Fulfillment.h b/src/cryptoconditions/src/asn/Ed25519Sha512Fulfillment.h new file mode 100644 index 000000000..603839803 --- /dev/null +++ b/src/cryptoconditions/src/asn/Ed25519Sha512Fulfillment.h @@ -0,0 +1,38 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#ifndef _Ed25519Sha512Fulfillment_H_ +#define _Ed25519Sha512Fulfillment_H_ + + +#include + +/* Including external dependencies */ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Ed25519Sha512Fulfillment */ +typedef struct Ed25519Sha512Fulfillment { + OCTET_STRING_t publicKey; + OCTET_STRING_t signature; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} Ed25519Sha512Fulfillment_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_Ed25519Sha512Fulfillment; + +#ifdef __cplusplus +} +#endif + +#endif /* _Ed25519Sha512Fulfillment_H_ */ +#include diff --git a/src/cryptoconditions/src/asn/EvalFingerprintContents.c b/src/cryptoconditions/src/asn/EvalFingerprintContents.c new file mode 100644 index 000000000..d23e3c386 --- /dev/null +++ b/src/cryptoconditions/src/asn/EvalFingerprintContents.c @@ -0,0 +1,94 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#include "EvalFingerprintContents.h" + +static int +memb_method_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + size_t size; + + if(!sptr) { + ASN__CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + size = st->size; + + if((size == 64)) { + /* Constraint check succeeded */ + return 0; + } else { + ASN__CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } +} + +static asn_TYPE_member_t asn_MBR_EvalFingerprintContents_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct EvalFingerprintContents, method), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + memb_method_constraint_1, + 0, /* PER is not compiled, use -gen-PER */ + 0, + "method" + }, + { ATF_NOFLAGS, 0, offsetof(struct EvalFingerprintContents, paramsBin), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "paramsBin" + }, +}; +static const ber_tlv_tag_t asn_DEF_EvalFingerprintContents_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static const asn_TYPE_tag2member_t asn_MAP_EvalFingerprintContents_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* method */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* paramsBin */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_EvalFingerprintContents_specs_1 = { + sizeof(struct EvalFingerprintContents), + offsetof(struct EvalFingerprintContents, _asn_ctx), + asn_MAP_EvalFingerprintContents_tag2el_1, + 2, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_EvalFingerprintContents = { + "EvalFingerprintContents", + "EvalFingerprintContents", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_EvalFingerprintContents_tags_1, + sizeof(asn_DEF_EvalFingerprintContents_tags_1) + /sizeof(asn_DEF_EvalFingerprintContents_tags_1[0]), /* 1 */ + asn_DEF_EvalFingerprintContents_tags_1, /* Same as above */ + sizeof(asn_DEF_EvalFingerprintContents_tags_1) + /sizeof(asn_DEF_EvalFingerprintContents_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_EvalFingerprintContents_1, + 2, /* Elements count */ + &asn_SPC_EvalFingerprintContents_specs_1 /* Additional specs */ +}; + diff --git a/src/cryptoconditions/src/asn/EvalFingerprintContents.h b/src/cryptoconditions/src/asn/EvalFingerprintContents.h new file mode 100644 index 000000000..52fb9ba62 --- /dev/null +++ b/src/cryptoconditions/src/asn/EvalFingerprintContents.h @@ -0,0 +1,38 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#ifndef _EvalFingerprintContents_H_ +#define _EvalFingerprintContents_H_ + + +#include + +/* Including external dependencies */ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* EvalFingerprintContents */ +typedef struct EvalFingerprintContents { + OCTET_STRING_t method; + OCTET_STRING_t paramsBin; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} EvalFingerprintContents_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_EvalFingerprintContents; + +#ifdef __cplusplus +} +#endif + +#endif /* _EvalFingerprintContents_H_ */ +#include diff --git a/src/cryptoconditions/src/asn/EvalFulfillment.c b/src/cryptoconditions/src/asn/EvalFulfillment.c new file mode 100644 index 000000000..e56b80317 --- /dev/null +++ b/src/cryptoconditions/src/asn/EvalFulfillment.c @@ -0,0 +1,94 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#include "EvalFulfillment.h" + +static int +memb_method_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + size_t size; + + if(!sptr) { + ASN__CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + size = st->size; + + if((size == 64)) { + /* Constraint check succeeded */ + return 0; + } else { + ASN__CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } +} + +static asn_TYPE_member_t asn_MBR_EvalFulfillment_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct EvalFulfillment, method), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + memb_method_constraint_1, + 0, /* PER is not compiled, use -gen-PER */ + 0, + "method" + }, + { ATF_NOFLAGS, 0, offsetof(struct EvalFulfillment, paramsBin), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "paramsBin" + }, +}; +static const ber_tlv_tag_t asn_DEF_EvalFulfillment_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static const asn_TYPE_tag2member_t asn_MAP_EvalFulfillment_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* method */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* paramsBin */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_EvalFulfillment_specs_1 = { + sizeof(struct EvalFulfillment), + offsetof(struct EvalFulfillment, _asn_ctx), + asn_MAP_EvalFulfillment_tag2el_1, + 2, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_EvalFulfillment = { + "EvalFulfillment", + "EvalFulfillment", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_EvalFulfillment_tags_1, + sizeof(asn_DEF_EvalFulfillment_tags_1) + /sizeof(asn_DEF_EvalFulfillment_tags_1[0]), /* 1 */ + asn_DEF_EvalFulfillment_tags_1, /* Same as above */ + sizeof(asn_DEF_EvalFulfillment_tags_1) + /sizeof(asn_DEF_EvalFulfillment_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_EvalFulfillment_1, + 2, /* Elements count */ + &asn_SPC_EvalFulfillment_specs_1 /* Additional specs */ +}; + diff --git a/src/cryptoconditions/src/asn/EvalFulfillment.h b/src/cryptoconditions/src/asn/EvalFulfillment.h new file mode 100644 index 000000000..a513ed160 --- /dev/null +++ b/src/cryptoconditions/src/asn/EvalFulfillment.h @@ -0,0 +1,38 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#ifndef _EvalFulfillment_H_ +#define _EvalFulfillment_H_ + + +#include + +/* Including external dependencies */ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* EvalFulfillment */ +typedef struct EvalFulfillment { + OCTET_STRING_t method; + OCTET_STRING_t paramsBin; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} EvalFulfillment_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_EvalFulfillment; + +#ifdef __cplusplus +} +#endif + +#endif /* _EvalFulfillment_H_ */ +#include diff --git a/src/cryptoconditions/src/asn/Fulfillment.c b/src/cryptoconditions/src/asn/Fulfillment.c new file mode 100644 index 000000000..faf43b772 --- /dev/null +++ b/src/cryptoconditions/src/asn/Fulfillment.c @@ -0,0 +1,114 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#include "Fulfillment.h" + +static asn_TYPE_member_t asn_MBR_Fulfillment_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct Fulfillment, choice.preimageSha256), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_PreimageFulfillment, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "preimageSha256" + }, + { ATF_POINTER, 0, offsetof(struct Fulfillment, choice.prefixSha256), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_PrefixFulfillment, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "prefixSha256" + }, + { ATF_POINTER, 0, offsetof(struct Fulfillment, choice.thresholdSha256), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_ThresholdFulfillment, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "thresholdSha256" + }, + { ATF_NOFLAGS, 0, offsetof(struct Fulfillment, choice.rsaSha256), + (ASN_TAG_CLASS_CONTEXT | (3 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_RsaSha256Fulfillment, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "rsaSha256" + }, + { ATF_NOFLAGS, 0, offsetof(struct Fulfillment, choice.ed25519Sha256), + (ASN_TAG_CLASS_CONTEXT | (4 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Ed25519Sha512Fulfillment, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "ed25519Sha256" + }, + { ATF_NOFLAGS, 0, offsetof(struct Fulfillment, choice.secp256k1Sha256), + (ASN_TAG_CLASS_CONTEXT | (5 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_Secp256k1Fulfillment, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "secp256k1Sha256" + }, + { ATF_NOFLAGS, 0, offsetof(struct Fulfillment, choice.evalSha256), + (ASN_TAG_CLASS_CONTEXT | (15 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_EvalFulfillment, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "evalSha256" + }, +}; +static const asn_TYPE_tag2member_t asn_MAP_Fulfillment_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* preimageSha256 */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* prefixSha256 */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 }, /* thresholdSha256 */ + { (ASN_TAG_CLASS_CONTEXT | (3 << 2)), 3, 0, 0 }, /* rsaSha256 */ + { (ASN_TAG_CLASS_CONTEXT | (4 << 2)), 4, 0, 0 }, /* ed25519Sha256 */ + { (ASN_TAG_CLASS_CONTEXT | (5 << 2)), 5, 0, 0 }, /* secp256k1Sha256 */ + { (ASN_TAG_CLASS_CONTEXT | (15 << 2)), 6, 0, 0 } /* evalSha256 */ +}; +static asn_CHOICE_specifics_t asn_SPC_Fulfillment_specs_1 = { + sizeof(struct Fulfillment), + offsetof(struct Fulfillment, _asn_ctx), + offsetof(struct Fulfillment, present), + sizeof(((struct Fulfillment *)0)->present), + asn_MAP_Fulfillment_tag2el_1, + 7, /* Count of tags in the map */ + 0, + -1 /* Extensions start */ +}; +asn_TYPE_descriptor_t asn_DEF_Fulfillment = { + "Fulfillment", + "Fulfillment", + CHOICE_free, + CHOICE_print, + CHOICE_constraint, + CHOICE_decode_ber, + CHOICE_encode_der, + CHOICE_decode_xer, + CHOICE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + CHOICE_outmost_tag, + 0, /* No effective tags (pointer) */ + 0, /* No effective tags (count) */ + 0, /* No tags (pointer) */ + 0, /* No tags (count) */ + 0, /* No PER visible constraints */ + asn_MBR_Fulfillment_1, + 7, /* Elements count */ + &asn_SPC_Fulfillment_specs_1 /* Additional specs */ +}; + diff --git a/src/cryptoconditions/src/asn/Fulfillment.h b/src/cryptoconditions/src/asn/Fulfillment.h new file mode 100644 index 000000000..01799e949 --- /dev/null +++ b/src/cryptoconditions/src/asn/Fulfillment.h @@ -0,0 +1,70 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#ifndef _Fulfillment_H_ +#define _Fulfillment_H_ + + +#include + +/* Including external dependencies */ +#include "PreimageFulfillment.h" +#include "RsaSha256Fulfillment.h" +#include "Ed25519Sha512Fulfillment.h" +#include "Secp256k1Fulfillment.h" +#include "EvalFulfillment.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Dependencies */ +typedef enum Fulfillment_PR { + Fulfillment_PR_NOTHING, /* No components present */ + Fulfillment_PR_preimageSha256, + Fulfillment_PR_prefixSha256, + Fulfillment_PR_thresholdSha256, + Fulfillment_PR_rsaSha256, + Fulfillment_PR_ed25519Sha256, + Fulfillment_PR_secp256k1Sha256, + Fulfillment_PR_evalSha256 +} Fulfillment_PR; + +/* Forward declarations */ +struct PrefixFulfillment; +struct ThresholdFulfillment; + +/* Fulfillment */ +typedef struct Fulfillment { + Fulfillment_PR present; + union Fulfillment_u { + PreimageFulfillment_t preimageSha256; + struct PrefixFulfillment *prefixSha256; + struct ThresholdFulfillment *thresholdSha256; + RsaSha256Fulfillment_t rsaSha256; + Ed25519Sha512Fulfillment_t ed25519Sha256; + Secp256k1Fulfillment_t secp256k1Sha256; + EvalFulfillment_t evalSha256; + } choice; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} Fulfillment_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_Fulfillment; + +#ifdef __cplusplus +} +#endif + +/* Referred external types */ +#include "PrefixFulfillment.h" +#include "ThresholdFulfillment.h" + +#endif /* _Fulfillment_H_ */ +#include diff --git a/src/cryptoconditions/src/asn/INTEGER.c b/src/cryptoconditions/src/asn/INTEGER.c new file mode 100644 index 000000000..eed82176b --- /dev/null +++ b/src/cryptoconditions/src/asn/INTEGER.c @@ -0,0 +1,1025 @@ +/*- + * Copyright (c) 2003-2014 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include /* Encoder and decoder of a primitive type */ +#include + +/* + * INTEGER basic type description. + */ +static const ber_tlv_tag_t asn_DEF_INTEGER_tags[] = { + (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)) +}; +asn_TYPE_descriptor_t asn_DEF_INTEGER = { + "INTEGER", + "INTEGER", + ASN__PRIMITIVE_TYPE_free, + INTEGER_print, + asn_generic_no_constraint, + ber_decode_primitive, + INTEGER_encode_der, + INTEGER_decode_xer, + INTEGER_encode_xer, +#ifdef ASN_DISABLE_PER_SUPPORT + 0, + 0, +#else + INTEGER_decode_uper, /* Unaligned PER decoder */ + INTEGER_encode_uper, /* Unaligned PER encoder */ +#endif /* ASN_DISABLE_PER_SUPPORT */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_INTEGER_tags, + sizeof(asn_DEF_INTEGER_tags) / sizeof(asn_DEF_INTEGER_tags[0]), + asn_DEF_INTEGER_tags, /* Same as above */ + sizeof(asn_DEF_INTEGER_tags) / sizeof(asn_DEF_INTEGER_tags[0]), + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + 0 /* No specifics */ +}; + +/* + * Encode INTEGER type using DER. + */ +asn_enc_rval_t +INTEGER_encode_der(asn_TYPE_descriptor_t *td, void *sptr, + int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + INTEGER_t *st = (INTEGER_t *)sptr; + + ASN_DEBUG("%s %s as INTEGER (tm=%d)", + cb?"Encoding":"Estimating", td->name, tag_mode); + + /* + * Canonicalize integer in the buffer. + * (Remove too long sign extension, remove some first 0x00 bytes) + */ + if(st->buf) { + uint8_t *buf = st->buf; + uint8_t *end1 = buf + st->size - 1; + int shift; + + /* Compute the number of superfluous leading bytes */ + for(; buf < end1; buf++) { + /* + * If the contents octets of an integer value encoding + * consist of more than one octet, then the bits of the + * first octet and bit 8 of the second octet: + * a) shall not all be ones; and + * b) shall not all be zero. + */ + switch(*buf) { + case 0x00: if((buf[1] & 0x80) == 0) + continue; + break; + case 0xff: if((buf[1] & 0x80)) + continue; + break; + } + break; + } + + /* Remove leading superfluous bytes from the integer */ + shift = buf - st->buf; + if(shift) { + uint8_t *nb = st->buf; + uint8_t *end; + + st->size -= shift; /* New size, minus bad bytes */ + end = nb + st->size; + + for(; nb < end; nb++, buf++) + *nb = *buf; + } + + } /* if(1) */ + + return der_encode_primitive(td, sptr, tag_mode, tag, cb, app_key); +} + +static const asn_INTEGER_enum_map_t *INTEGER_map_enum2value(asn_INTEGER_specifics_t *specs, const char *lstart, const char *lstop); + +/* + * INTEGER specific human-readable output. + */ +static ssize_t +INTEGER__dump(const asn_TYPE_descriptor_t *td, const INTEGER_t *st, asn_app_consume_bytes_f *cb, void *app_key, int plainOrXER) { + asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; + char scratch[32]; /* Enough for 64-bit integer */ + uint8_t *buf = st->buf; + uint8_t *buf_end = st->buf + st->size; + signed long value; + ssize_t wrote = 0; + char *p; + int ret; + + if(specs && specs->field_unsigned) + ret = asn_INTEGER2ulong(st, (unsigned long *)&value); + else + ret = asn_INTEGER2long(st, &value); + + /* Simple case: the integer size is small */ + if(ret == 0) { + const asn_INTEGER_enum_map_t *el; + size_t scrsize; + char *scr; + + el = (value >= 0 || !specs || !specs->field_unsigned) + ? INTEGER_map_value2enum(specs, value) : 0; + if(el) { + scrsize = el->enum_len + 32; + scr = (char *)alloca(scrsize); + if(plainOrXER == 0) + ret = snprintf(scr, scrsize, + "%ld (%s)", value, el->enum_name); + else + ret = snprintf(scr, scrsize, + "<%s/>", el->enum_name); + } else if(plainOrXER && specs && specs->strict_enumeration) { + ASN_DEBUG("ASN.1 forbids dealing with " + "unknown value of ENUMERATED type"); + errno = EPERM; + return -1; + } else { + scrsize = sizeof(scratch); + scr = scratch; + ret = snprintf(scr, scrsize, + (specs && specs->field_unsigned) + ?"%lu":"%ld", value); + } + assert(ret > 0 && (size_t)ret < scrsize); + return (cb(scr, ret, app_key) < 0) ? -1 : ret; + } else if(plainOrXER && specs && specs->strict_enumeration) { + /* + * Here and earlier, we cannot encode the ENUMERATED values + * if there is no corresponding identifier. + */ + ASN_DEBUG("ASN.1 forbids dealing with " + "unknown value of ENUMERATED type"); + errno = EPERM; + return -1; + } + + /* Output in the long xx:yy:zz... format */ + /* TODO: replace with generic algorithm (Knuth TAOCP Vol 2, 4.3.1) */ + for(p = scratch; buf < buf_end; buf++) { + const char * const h2c = "0123456789ABCDEF"; + if((p - scratch) >= (ssize_t)(sizeof(scratch) - 4)) { + /* Flush buffer */ + if(cb(scratch, p - scratch, app_key) < 0) + return -1; + wrote += p - scratch; + p = scratch; + } + *p++ = h2c[*buf >> 4]; + *p++ = h2c[*buf & 0x0F]; + *p++ = 0x3a; /* ":" */ + } + if(p != scratch) + p--; /* Remove the last ":" */ + + wrote += p - scratch; + return (cb(scratch, p - scratch, app_key) < 0) ? -1 : wrote; +} + +/* + * INTEGER specific human-readable output. + */ +int +INTEGER_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, + asn_app_consume_bytes_f *cb, void *app_key) { + const INTEGER_t *st = (const INTEGER_t *)sptr; + ssize_t ret; + + (void)td; + (void)ilevel; + + if(!st || !st->buf) + ret = cb("", 8, app_key); + else + ret = INTEGER__dump(td, st, cb, app_key, 0); + + return (ret < 0) ? -1 : 0; +} + +struct e2v_key { + const char *start; + const char *stop; + const asn_INTEGER_enum_map_t *vemap; + const unsigned int *evmap; +}; +static int +INTEGER__compar_enum2value(const void *kp, const void *am) { + const struct e2v_key *key = (const struct e2v_key *)kp; + const asn_INTEGER_enum_map_t *el = (const asn_INTEGER_enum_map_t *)am; + const char *ptr, *end, *name; + + /* Remap the element (sort by different criterion) */ + el = key->vemap + key->evmap[el - key->vemap]; + + /* Compare strings */ + for(ptr = key->start, end = key->stop, name = el->enum_name; + ptr < end; ptr++, name++) { + if(*ptr != *name) + return *(const unsigned char *)ptr + - *(const unsigned char *)name; + } + return name[0] ? -1 : 0; +} + +static const asn_INTEGER_enum_map_t * +INTEGER_map_enum2value(asn_INTEGER_specifics_t *specs, const char *lstart, const char *lstop) { + const asn_INTEGER_enum_map_t *el_found; + int count = specs ? specs->map_count : 0; + struct e2v_key key; + const char *lp; + + if(!count) return NULL; + + /* Guaranteed: assert(lstart < lstop); */ + /* Figure out the tag name */ + for(lstart++, lp = lstart; lp < lstop; lp++) { + switch(*lp) { + case 9: case 10: case 11: case 12: case 13: case 32: /* WSP */ + case 0x2f: /* '/' */ case 0x3e: /* '>' */ + break; + default: + continue; + } + break; + } + if(lp == lstop) return NULL; /* No tag found */ + lstop = lp; + + key.start = lstart; + key.stop = lstop; + key.vemap = specs->value2enum; + key.evmap = specs->enum2value; + el_found = (asn_INTEGER_enum_map_t *)bsearch(&key, + specs->value2enum, count, sizeof(specs->value2enum[0]), + INTEGER__compar_enum2value); + if(el_found) { + /* Remap enum2value into value2enum */ + el_found = key.vemap + key.evmap[el_found - key.vemap]; + } + return el_found; +} + +static int +INTEGER__compar_value2enum(const void *kp, const void *am) { + long a = *(const long *)kp; + const asn_INTEGER_enum_map_t *el = (const asn_INTEGER_enum_map_t *)am; + long b = el->nat_value; + if(a < b) return -1; + else if(a == b) return 0; + else return 1; +} + +const asn_INTEGER_enum_map_t * +INTEGER_map_value2enum(asn_INTEGER_specifics_t *specs, long value) { + int count = specs ? specs->map_count : 0; + if(!count) return 0; + return (asn_INTEGER_enum_map_t *)bsearch(&value, specs->value2enum, + count, sizeof(specs->value2enum[0]), + INTEGER__compar_value2enum); +} + +static int +INTEGER_st_prealloc(INTEGER_t *st, int min_size) { + void *p = MALLOC(min_size + 1); + if(p) { + void *b = st->buf; + st->size = 0; + st->buf = p; + FREEMEM(b); + return 0; + } else { + return -1; + } +} + +/* + * Decode the chunk of XML text encoding INTEGER. + */ +static enum xer_pbd_rval +INTEGER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chunk_buf, size_t chunk_size) { + INTEGER_t *st = (INTEGER_t *)sptr; + long dec_value; + long hex_value = 0; + const char *lp; + const char *lstart = (const char *)chunk_buf; + const char *lstop = lstart + chunk_size; + enum { + ST_LEADSPACE, + ST_SKIPSPHEX, + ST_WAITDIGITS, + ST_DIGITS, + ST_DIGITS_TRAILSPACE, + ST_HEXDIGIT1, + ST_HEXDIGIT2, + ST_HEXDIGITS_TRAILSPACE, + ST_HEXCOLON, + ST_END_ENUM, + ST_UNEXPECTED + } state = ST_LEADSPACE; + const char *dec_value_start = 0; /* INVARIANT: always !0 in ST_DIGITS */ + const char *dec_value_end = 0; + + if(chunk_size) + ASN_DEBUG("INTEGER body %ld 0x%2x..0x%2x", + (long)chunk_size, *lstart, lstop[-1]); + + if(INTEGER_st_prealloc(st, (chunk_size/3) + 1)) + return XPBD_SYSTEM_FAILURE; + + /* + * We may have received a tag here. It will be processed inline. + * Use strtoul()-like code and serialize the result. + */ + for(lp = lstart; lp < lstop; lp++) { + int lv = *lp; + switch(lv) { + case 0x09: case 0x0a: case 0x0d: case 0x20: + switch(state) { + case ST_LEADSPACE: + case ST_DIGITS_TRAILSPACE: + case ST_HEXDIGITS_TRAILSPACE: + case ST_SKIPSPHEX: + continue; + case ST_DIGITS: + dec_value_end = lp; + state = ST_DIGITS_TRAILSPACE; + continue; + case ST_HEXCOLON: + state = ST_HEXDIGITS_TRAILSPACE; + continue; + default: + break; + } + break; + case 0x2d: /* '-' */ + if(state == ST_LEADSPACE) { + dec_value = 0; + dec_value_start = lp; + state = ST_WAITDIGITS; + continue; + } + break; + case 0x2b: /* '+' */ + if(state == ST_LEADSPACE) { + dec_value = 0; + dec_value_start = lp; + state = ST_WAITDIGITS; + continue; + } + break; + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: + case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: + switch(state) { + case ST_DIGITS: continue; + case ST_SKIPSPHEX: /* Fall through */ + case ST_HEXDIGIT1: + hex_value = (lv - 0x30) << 4; + state = ST_HEXDIGIT2; + continue; + case ST_HEXDIGIT2: + hex_value += (lv - 0x30); + state = ST_HEXCOLON; + st->buf[st->size++] = (uint8_t)hex_value; + continue; + case ST_HEXCOLON: + return XPBD_BROKEN_ENCODING; + case ST_LEADSPACE: + dec_value = 0; + dec_value_start = lp; + /* FALL THROUGH */ + case ST_WAITDIGITS: + state = ST_DIGITS; + continue; + default: + break; + } + break; + case 0x3c: /* '<', start of XML encoded enumeration */ + if(state == ST_LEADSPACE) { + const asn_INTEGER_enum_map_t *el; + el = INTEGER_map_enum2value( + (asn_INTEGER_specifics_t *) + td->specifics, lstart, lstop); + if(el) { + ASN_DEBUG("Found \"%s\" => %ld", + el->enum_name, el->nat_value); + dec_value = el->nat_value; + state = ST_END_ENUM; + lp = lstop - 1; + continue; + } + ASN_DEBUG("Unknown identifier for INTEGER"); + } + return XPBD_BROKEN_ENCODING; + case 0x3a: /* ':' */ + if(state == ST_HEXCOLON) { + /* This colon is expected */ + state = ST_HEXDIGIT1; + continue; + } else if(state == ST_DIGITS) { + /* The colon here means that we have + * decoded the first two hexadecimal + * places as a decimal value. + * Switch decoding mode. */ + ASN_DEBUG("INTEGER re-evaluate as hex form"); + state = ST_SKIPSPHEX; + dec_value_start = 0; + lp = lstart - 1; + continue; + } else { + ASN_DEBUG("state %d at %ld", state, (long)(lp - lstart)); + break; + } + /* [A-Fa-f] */ + case 0x41:case 0x42:case 0x43:case 0x44:case 0x45:case 0x46: + case 0x61:case 0x62:case 0x63:case 0x64:case 0x65:case 0x66: + switch(state) { + case ST_SKIPSPHEX: + case ST_LEADSPACE: /* Fall through */ + case ST_HEXDIGIT1: + hex_value = lv - ((lv < 0x61) ? 0x41 : 0x61); + hex_value += 10; + hex_value <<= 4; + state = ST_HEXDIGIT2; + continue; + case ST_HEXDIGIT2: + hex_value += lv - ((lv < 0x61) ? 0x41 : 0x61); + hex_value += 10; + st->buf[st->size++] = (uint8_t)hex_value; + state = ST_HEXCOLON; + continue; + case ST_DIGITS: + ASN_DEBUG("INTEGER re-evaluate as hex form"); + state = ST_SKIPSPHEX; + dec_value_start = 0; + lp = lstart - 1; + continue; + default: + break; + } + break; + } + + /* Found extra non-numeric stuff */ + ASN_DEBUG("INTEGER :: Found non-numeric 0x%2x at %ld", + lv, (long)(lp - lstart)); + state = ST_UNEXPECTED; + break; + } + + switch(state) { + case ST_END_ENUM: + /* Got a complete and valid enumeration encoded as a tag. */ + break; + case ST_DIGITS: + dec_value_end = lstop; + /* FALL THROUGH */ + case ST_DIGITS_TRAILSPACE: + /* The last symbol encountered was a digit. */ + switch(asn_strtol_lim(dec_value_start, &dec_value_end, &dec_value)) { + case ASN_STRTOL_OK: + break; + case ASN_STRTOL_ERROR_RANGE: + return XPBD_DECODER_LIMIT; + case ASN_STRTOL_ERROR_INVAL: + case ASN_STRTOL_EXPECT_MORE: + case ASN_STRTOL_EXTRA_DATA: + return XPBD_BROKEN_ENCODING; + } + break; + case ST_HEXCOLON: + case ST_HEXDIGITS_TRAILSPACE: + st->buf[st->size] = 0; /* Just in case termination */ + return XPBD_BODY_CONSUMED; + case ST_HEXDIGIT1: + case ST_HEXDIGIT2: + case ST_SKIPSPHEX: + return XPBD_BROKEN_ENCODING; + case ST_LEADSPACE: + /* Content not found */ + return XPBD_NOT_BODY_IGNORE; + case ST_WAITDIGITS: + case ST_UNEXPECTED: + ASN_DEBUG("INTEGER: No useful digits (state %d)", state); + return XPBD_BROKEN_ENCODING; /* No digits */ + } + + /* + * Convert the result of parsing of enumeration or a straight + * decimal value into a BER representation. + */ + if(asn_long2INTEGER(st, dec_value)) + return XPBD_SYSTEM_FAILURE; + + return XPBD_BODY_CONSUMED; +} + +asn_dec_rval_t +INTEGER_decode_xer(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, void **sptr, const char *opt_mname, + const void *buf_ptr, size_t size) { + + return xer_decode_primitive(opt_codec_ctx, td, + sptr, sizeof(INTEGER_t), opt_mname, + buf_ptr, size, INTEGER__xer_body_decode); +} + +asn_enc_rval_t +INTEGER_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + const INTEGER_t *st = (const INTEGER_t *)sptr; + asn_enc_rval_t er; + + (void)ilevel; + (void)flags; + + if(!st || !st->buf) + ASN__ENCODE_FAILED; + + er.encoded = INTEGER__dump(td, st, cb, app_key, 1); + if(er.encoded < 0) ASN__ENCODE_FAILED; + + ASN__ENCODED_OK(er); +} + +#ifndef ASN_DISABLE_PER_SUPPORT + +asn_dec_rval_t +INTEGER_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { + asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; + asn_dec_rval_t rval = { RC_OK, 0 }; + INTEGER_t *st = (INTEGER_t *)*sptr; + asn_per_constraint_t *ct; + int repeat; + + (void)opt_codec_ctx; + + if(!st) { + st = (INTEGER_t *)(*sptr = CALLOC(1, sizeof(*st))); + if(!st) ASN__DECODE_FAILED; + } + + if(!constraints) constraints = td->per_constraints; + ct = constraints ? &constraints->value : 0; + + if(ct && ct->flags & APC_EXTENSIBLE) { + int inext = per_get_few_bits(pd, 1); + if(inext < 0) ASN__DECODE_STARVED; + if(inext) ct = 0; + } + + FREEMEM(st->buf); + st->buf = 0; + st->size = 0; + if(ct) { + if(ct->flags & APC_SEMI_CONSTRAINED) { + st->buf = (uint8_t *)CALLOC(1, 2); + if(!st->buf) ASN__DECODE_FAILED; + st->size = 1; + } else if(ct->flags & APC_CONSTRAINED && ct->range_bits >= 0) { + size_t size = (ct->range_bits + 7) >> 3; + st->buf = (uint8_t *)MALLOC(1 + size + 1); + if(!st->buf) ASN__DECODE_FAILED; + st->size = size; + } + } + + /* X.691-2008/11, #13.2.2, constrained whole number */ + if(ct && ct->flags != APC_UNCONSTRAINED) { + /* #11.5.6 */ + ASN_DEBUG("Integer with range %d bits", ct->range_bits); + if(ct->range_bits >= 0) { + if((size_t)ct->range_bits > 8 * sizeof(unsigned long)) + ASN__DECODE_FAILED; + + if(specs && specs->field_unsigned) { + unsigned long uvalue; + if(uper_get_constrained_whole_number(pd, + &uvalue, ct->range_bits)) + ASN__DECODE_STARVED; + ASN_DEBUG("Got value %lu + low %ld", + uvalue, ct->lower_bound); + uvalue += ct->lower_bound; + if(asn_ulong2INTEGER(st, uvalue)) + ASN__DECODE_FAILED; + } else { + unsigned long svalue; + if(uper_get_constrained_whole_number(pd, + &svalue, ct->range_bits)) + ASN__DECODE_STARVED; + ASN_DEBUG("Got value %ld + low %ld", + svalue, ct->lower_bound); + svalue += ct->lower_bound; + if(asn_long2INTEGER(st, svalue)) + ASN__DECODE_FAILED; + } + return rval; + } + } else { + ASN_DEBUG("Decoding unconstrained integer %s", td->name); + } + + /* X.691, #12.2.3, #12.2.4 */ + do { + ssize_t len; + void *p; + int ret; + + /* Get the PER length */ + len = uper_get_length(pd, -1, &repeat); + if(len < 0) ASN__DECODE_STARVED; + + p = REALLOC(st->buf, st->size + len + 1); + if(!p) ASN__DECODE_FAILED; + st->buf = (uint8_t *)p; + + ret = per_get_many_bits(pd, &st->buf[st->size], 0, 8 * len); + if(ret < 0) ASN__DECODE_STARVED; + st->size += len; + } while(repeat); + st->buf[st->size] = 0; /* JIC */ + + /* #12.2.3 */ + if(ct && ct->lower_bound) { + /* + * TODO: replace by in-place arithmetics. + */ + long value; + if(asn_INTEGER2long(st, &value)) + ASN__DECODE_FAILED; + if(asn_long2INTEGER(st, value + ct->lower_bound)) + ASN__DECODE_FAILED; + } + + return rval; +} + +asn_enc_rval_t +INTEGER_encode_uper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; + asn_enc_rval_t er; + INTEGER_t *st = (INTEGER_t *)sptr; + const uint8_t *buf; + const uint8_t *end; + asn_per_constraint_t *ct; + long value = 0; + unsigned long v = 0; + + if(!st || st->size == 0) ASN__ENCODE_FAILED; + + if(!constraints) constraints = td->per_constraints; + ct = constraints ? &constraints->value : 0; + + er.encoded = 0; + + if(ct) { + int inext = 0; + if(specs && specs->field_unsigned) { + unsigned long uval; + if(asn_INTEGER2ulong(st, &uval)) + ASN__ENCODE_FAILED; + /* Check proper range */ + if(ct->flags & APC_SEMI_CONSTRAINED) { + if(uval < (unsigned long)ct->lower_bound) + inext = 1; + } else if(ct->range_bits >= 0) { + if(uval < (unsigned long)ct->lower_bound + || uval > (unsigned long)ct->upper_bound) + inext = 1; + } + ASN_DEBUG("Value %lu (%02x/%d) lb %lu ub %lu %s", + uval, st->buf[0], st->size, + ct->lower_bound, ct->upper_bound, + inext ? "ext" : "fix"); + value = uval; + } else { + if(asn_INTEGER2long(st, &value)) + ASN__ENCODE_FAILED; + /* Check proper range */ + if(ct->flags & APC_SEMI_CONSTRAINED) { + if(value < ct->lower_bound) + inext = 1; + } else if(ct->range_bits >= 0) { + if(value < ct->lower_bound + || value > ct->upper_bound) + inext = 1; + } + ASN_DEBUG("Value %ld (%02x/%d) lb %ld ub %ld %s", + value, st->buf[0], st->size, + ct->lower_bound, ct->upper_bound, + inext ? "ext" : "fix"); + } + if(ct->flags & APC_EXTENSIBLE) { + if(per_put_few_bits(po, inext, 1)) + ASN__ENCODE_FAILED; + if(inext) ct = 0; + } else if(inext) { + ASN__ENCODE_FAILED; + } + } + + + /* X.691-11/2008, #13.2.2, test if constrained whole number */ + if(ct && ct->range_bits >= 0) { + /* #11.5.6 -> #11.3 */ + ASN_DEBUG("Encoding integer %ld (%lu) with range %d bits", + value, value - ct->lower_bound, ct->range_bits); + v = value - ct->lower_bound; + if(uper_put_constrained_whole_number_u(po, v, ct->range_bits)) + ASN__ENCODE_FAILED; + ASN__ENCODED_OK(er); + } + + if(ct && ct->lower_bound) { + ASN_DEBUG("Adjust lower bound to %ld", ct->lower_bound); + /* TODO: adjust lower bound */ + ASN__ENCODE_FAILED; + } + + for(buf = st->buf, end = st->buf + st->size; buf < end;) { + ssize_t mayEncode = uper_put_length(po, end - buf); + if(mayEncode < 0) + ASN__ENCODE_FAILED; + if(per_put_many_bits(po, buf, 8 * mayEncode)) + ASN__ENCODE_FAILED; + buf += mayEncode; + } + + ASN__ENCODED_OK(er); +} + +#endif /* ASN_DISABLE_PER_SUPPORT */ + +int +asn_INTEGER2long(const INTEGER_t *iptr, long *lptr) { + uint8_t *b, *end; + size_t size; + long l; + + /* Sanity checking */ + if(!iptr || !iptr->buf || !lptr) { + errno = EINVAL; + return -1; + } + + /* Cache the begin/end of the buffer */ + b = iptr->buf; /* Start of the INTEGER buffer */ + size = iptr->size; + end = b + size; /* Where to stop */ + + if(size > sizeof(long)) { + uint8_t *end1 = end - 1; + /* + * Slightly more advanced processing, + * able to >sizeof(long) bytes, + * when the actual value is small + * (0x0000000000abcdef would yield a fine 0x00abcdef) + */ + /* Skip out the insignificant leading bytes */ + for(; b < end1; b++) { + switch(*b) { + case 0x00: if((b[1] & 0x80) == 0) continue; break; + case 0xff: if((b[1] & 0x80) != 0) continue; break; + } + break; + } + + size = end - b; + if(size > sizeof(long)) { + /* Still cannot fit the long */ + errno = ERANGE; + return -1; + } + } + + /* Shortcut processing of a corner case */ + if(end == b) { + *lptr = 0; + return 0; + } + + /* Perform the sign initialization */ + /* Actually l = -(*b >> 7); gains nothing, yet unreadable! */ + if((*b >> 7)) l = -1; else l = 0; + + /* Conversion engine */ + for(; b < end; b++) + l = (l << 8) | *b; + + *lptr = l; + return 0; +} + +int +asn_INTEGER2ulong(const INTEGER_t *iptr, unsigned long *lptr) { + uint8_t *b, *end; + unsigned long l; + size_t size; + + if(!iptr || !iptr->buf || !lptr) { + errno = EINVAL; + return -1; + } + + b = iptr->buf; + size = iptr->size; + end = b + size; + + /* If all extra leading bytes are zeroes, ignore them */ + for(; size > sizeof(unsigned long); b++, size--) { + if(*b) { + /* Value won't fit unsigned long */ + errno = ERANGE; + return -1; + } + } + + /* Conversion engine */ + for(l = 0; b < end; b++) + l = (l << 8) | *b; + + *lptr = l; + return 0; +} + +int +asn_ulong2INTEGER(INTEGER_t *st, unsigned long value) { + uint8_t *buf; + uint8_t *end; + uint8_t *b; + int shr; + + if(value <= LONG_MAX) + return asn_long2INTEGER(st, value); + + buf = (uint8_t *)MALLOC(1 + sizeof(value)); + if(!buf) return -1; + + end = buf + (sizeof(value) + 1); + buf[0] = 0; + for(b = buf + 1, shr = (sizeof(long)-1)*8; b < end; shr -= 8, b++) + *b = (uint8_t)(value >> shr); + + if(st->buf) FREEMEM(st->buf); + st->buf = buf; + st->size = 1 + sizeof(value); + + return 0; +} + +int +asn_long2INTEGER(INTEGER_t *st, long value) { + uint8_t *buf, *bp; + uint8_t *p; + uint8_t *pstart; + uint8_t *pend1; + int littleEndian = 1; /* Run-time detection */ + int add; + + if(!st) { + errno = EINVAL; + return -1; + } + + buf = (uint8_t *)MALLOC(sizeof(value)); + if(!buf) return -1; + + if(*(char *)&littleEndian) { + pstart = (uint8_t *)&value + sizeof(value) - 1; + pend1 = (uint8_t *)&value; + add = -1; + } else { + pstart = (uint8_t *)&value; + pend1 = pstart + sizeof(value) - 1; + add = 1; + } + + /* + * If the contents octet consists of more than one octet, + * then bits of the first octet and bit 8 of the second octet: + * a) shall not all be ones; and + * b) shall not all be zero. + */ + for(p = pstart; p != pend1; p += add) { + switch(*p) { + case 0x00: if((*(p+add) & 0x80) == 0) + continue; + break; + case 0xff: if((*(p+add) & 0x80)) + continue; + break; + } + break; + } + /* Copy the integer body */ + for(pstart = p, bp = buf, pend1 += add; p != pend1; p += add) + *bp++ = *p; + + if(st->buf) FREEMEM(st->buf); + st->buf = buf; + st->size = bp - buf; + + return 0; +} + +/* + * This function is going to be DEPRECATED soon. + */ +enum asn_strtol_result_e +asn_strtol(const char *str, const char *end, long *lp) { + const char *endp = end; + + switch(asn_strtol_lim(str, &endp, lp)) { + case ASN_STRTOL_ERROR_RANGE: + return ASN_STRTOL_ERROR_RANGE; + case ASN_STRTOL_ERROR_INVAL: + return ASN_STRTOL_ERROR_INVAL; + case ASN_STRTOL_EXPECT_MORE: + return ASN_STRTOL_ERROR_INVAL; /* Retain old behavior */ + case ASN_STRTOL_OK: + return ASN_STRTOL_OK; + case ASN_STRTOL_EXTRA_DATA: + return ASN_STRTOL_ERROR_INVAL; /* Retain old behavior */ + } + + return ASN_STRTOL_ERROR_INVAL; /* Retain old behavior */ +} + +/* + * Parse the number in the given string until the given *end position, + * returning the position after the last parsed character back using the + * same (*end) pointer. + * WARNING: This behavior is different from the standard strtol(3). + */ +enum asn_strtol_result_e +asn_strtol_lim(const char *str, const char **end, long *lp) { + int sign = 1; + long l; + + const long upper_boundary = LONG_MAX / 10; + long last_digit_max = LONG_MAX % 10; + + if(str >= *end) return ASN_STRTOL_ERROR_INVAL; + + switch(*str) { + case '-': + last_digit_max++; + sign = -1; + /* FALL THROUGH */ + case '+': + str++; + if(str >= *end) { + *end = str; + return ASN_STRTOL_EXPECT_MORE; + } + } + + for(l = 0; str < (*end); str++) { + switch(*str) { + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: + case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: { + int d = *str - '0'; + if(l < upper_boundary) { + l = l * 10 + d; + } else if(l == upper_boundary) { + if(d <= last_digit_max) { + if(sign > 0) { + l = l * 10 + d; + } else { + sign = 1; + l = -l * 10 - d; + } + } else { + *end = str; + return ASN_STRTOL_ERROR_RANGE; + } + } else { + *end = str; + return ASN_STRTOL_ERROR_RANGE; + } + } + continue; + default: + *end = str; + *lp = sign * l; + return ASN_STRTOL_EXTRA_DATA; + } + } + + *end = str; + *lp = sign * l; + return ASN_STRTOL_OK; +} + diff --git a/src/cryptoconditions/src/asn/INTEGER.h b/src/cryptoconditions/src/asn/INTEGER.h new file mode 100644 index 000000000..9a8809707 --- /dev/null +++ b/src/cryptoconditions/src/asn/INTEGER.h @@ -0,0 +1,82 @@ +/*- + * Copyright (c) 2003, 2005 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _INTEGER_H_ +#define _INTEGER_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef ASN__PRIMITIVE_TYPE_t INTEGER_t; + +extern asn_TYPE_descriptor_t asn_DEF_INTEGER; + +/* Map with to integer value association */ +typedef struct asn_INTEGER_enum_map_s { + long nat_value; /* associated native integer value */ + size_t enum_len; /* strlen("tag") */ + const char *enum_name; /* "tag" */ +} asn_INTEGER_enum_map_t; + +/* This type describes an enumeration for INTEGER and ENUMERATED types */ +typedef const struct asn_INTEGER_specifics_s { + const asn_INTEGER_enum_map_t *value2enum; /* N -> "tag"; sorted by N */ + const unsigned int *enum2value; /* "tag" => N; sorted by tag */ + int map_count; /* Elements in either map */ + int extension; /* This map is extensible */ + int strict_enumeration; /* Enumeration set is fixed */ + int field_width; /* Size of native integer */ + int field_unsigned; /* Signed=0, unsigned=1 */ +} asn_INTEGER_specifics_t; + +asn_struct_print_f INTEGER_print; +ber_type_decoder_f INTEGER_decode_ber; +der_type_encoder_f INTEGER_encode_der; +xer_type_decoder_f INTEGER_decode_xer; +xer_type_encoder_f INTEGER_encode_xer; +per_type_decoder_f INTEGER_decode_uper; +per_type_encoder_f INTEGER_encode_uper; + +/*********************************** + * Some handy conversion routines. * + ***********************************/ + +/* + * Returns 0 if it was possible to convert, -1 otherwise. + * -1/EINVAL: Mandatory argument missing + * -1/ERANGE: Value encoded is out of range for long representation + * -1/ENOMEM: Memory allocation failed (in asn_long2INTEGER()). + */ +int asn_INTEGER2long(const INTEGER_t *i, long *l); +int asn_INTEGER2ulong(const INTEGER_t *i, unsigned long *l); +int asn_long2INTEGER(INTEGER_t *i, long l); +int asn_ulong2INTEGER(INTEGER_t *i, unsigned long l); + +/* A a reified version of strtol(3) with nicer error reporting. */ +enum asn_strtol_result_e { + ASN_STRTOL_ERROR_RANGE = -3, /* Input outside of numeric range for long type */ + ASN_STRTOL_ERROR_INVAL = -2, /* Invalid data encountered (e.g., "+-") */ + ASN_STRTOL_EXPECT_MORE = -1, /* More data expected (e.g. "+") */ + ASN_STRTOL_OK = 0, /* Conversion succeded, number ends at (*end) */ + ASN_STRTOL_EXTRA_DATA = 1 /* Conversion succeded, but the string has extra stuff */ +}; +enum asn_strtol_result_e asn_strtol_lim(const char *str, const char **end, long *l); + +/* The asn_strtol is going to be DEPRECATED soon */ +enum asn_strtol_result_e asn_strtol(const char *str, const char *end, long *l); + +/* + * Convert the integer value into the corresponding enumeration map entry. + */ +const asn_INTEGER_enum_map_t *INTEGER_map_value2enum(asn_INTEGER_specifics_t *specs, long value); + +#ifdef __cplusplus +} +#endif + +#endif /* _INTEGER_H_ */ diff --git a/src/cryptoconditions/src/asn/Makefile.am.sample b/src/cryptoconditions/src/asn/Makefile.am.sample new file mode 100644 index 000000000..0bf696a74 --- /dev/null +++ b/src/cryptoconditions/src/asn/Makefile.am.sample @@ -0,0 +1,122 @@ +ASN_MODULE_SOURCES= \ + Condition.c \ + SimpleSha256Condition.c \ + CompoundSha256Condition.c \ + ConditionTypes.c \ + Fulfillment.c \ + PreimageFulfillment.c \ + PrefixFulfillment.c \ + ThresholdFulfillment.c \ + RsaSha256Fulfillment.c \ + Ed25519Sha512Fulfillment.c \ + Secp256k1Fulfillment.c \ + EvalFulfillment.c \ + PrefixFingerprintContents.c \ + ThresholdFingerprintContents.c \ + RsaFingerprintContents.c \ + Ed25519FingerprintContents.c \ + Secp256k1FingerprintContents.c \ + EvalFingerprintContents.c + +ASN_MODULE_HEADERS= \ + Condition.h \ + SimpleSha256Condition.h \ + CompoundSha256Condition.h \ + ConditionTypes.h \ + Fulfillment.h \ + PreimageFulfillment.h \ + PrefixFulfillment.h \ + ThresholdFulfillment.h \ + RsaSha256Fulfillment.h \ + Ed25519Sha512Fulfillment.h \ + Secp256k1Fulfillment.h \ + EvalFulfillment.h \ + PrefixFingerprintContents.h \ + ThresholdFingerprintContents.h \ + RsaFingerprintContents.h \ + Ed25519FingerprintContents.h \ + Secp256k1FingerprintContents.h \ + EvalFingerprintContents.h + +ASN_MODULE_HEADERS+=INTEGER.h +ASN_MODULE_HEADERS+=NativeEnumerated.h +ASN_MODULE_SOURCES+=INTEGER.c +ASN_MODULE_SOURCES+=NativeEnumerated.c +ASN_MODULE_HEADERS+=NativeInteger.h +ASN_MODULE_SOURCES+=NativeInteger.c +ASN_MODULE_HEADERS+=asn_SET_OF.h +ASN_MODULE_SOURCES+=asn_SET_OF.c +ASN_MODULE_HEADERS+=constr_CHOICE.h +ASN_MODULE_SOURCES+=constr_CHOICE.c +ASN_MODULE_HEADERS+=constr_SEQUENCE.h +ASN_MODULE_SOURCES+=constr_SEQUENCE.c +ASN_MODULE_HEADERS+=constr_SET_OF.h +ASN_MODULE_SOURCES+=constr_SET_OF.c +ASN_MODULE_HEADERS+=asn_application.h +ASN_MODULE_HEADERS+=asn_system.h +ASN_MODULE_HEADERS+=asn_codecs.h +ASN_MODULE_HEADERS+=asn_internal.h +ASN_MODULE_HEADERS+=OCTET_STRING.h +ASN_MODULE_SOURCES+=OCTET_STRING.c +ASN_MODULE_HEADERS+=BIT_STRING.h +ASN_MODULE_SOURCES+=BIT_STRING.c +ASN_MODULE_SOURCES+=asn_codecs_prim.c +ASN_MODULE_HEADERS+=asn_codecs_prim.h +ASN_MODULE_HEADERS+=ber_tlv_length.h +ASN_MODULE_SOURCES+=ber_tlv_length.c +ASN_MODULE_HEADERS+=ber_tlv_tag.h +ASN_MODULE_SOURCES+=ber_tlv_tag.c +ASN_MODULE_HEADERS+=ber_decoder.h +ASN_MODULE_SOURCES+=ber_decoder.c +ASN_MODULE_HEADERS+=der_encoder.h +ASN_MODULE_SOURCES+=der_encoder.c +ASN_MODULE_HEADERS+=constr_TYPE.h +ASN_MODULE_SOURCES+=constr_TYPE.c +ASN_MODULE_HEADERS+=constraints.h +ASN_MODULE_SOURCES+=constraints.c +ASN_MODULE_HEADERS+=xer_support.h +ASN_MODULE_SOURCES+=xer_support.c +ASN_MODULE_HEADERS+=xer_decoder.h +ASN_MODULE_SOURCES+=xer_decoder.c +ASN_MODULE_HEADERS+=xer_encoder.h +ASN_MODULE_SOURCES+=xer_encoder.c +ASN_MODULE_HEADERS+=per_support.h +ASN_MODULE_SOURCES+=per_support.c +ASN_MODULE_HEADERS+=per_decoder.h +ASN_MODULE_SOURCES+=per_decoder.c +ASN_MODULE_HEADERS+=per_encoder.h +ASN_MODULE_SOURCES+=per_encoder.c +ASN_MODULE_HEADERS+=per_opentype.h +ASN_MODULE_SOURCES+=per_opentype.c +ASN_CONVERTER_SOURCES+=converter-sample.c + + +lib_LTLIBRARIES=libsomething.la +libsomething_la_SOURCES=$(ASN_MODULE_SOURCES) $(ASN_MODULE_HEADERS) + +# This file may be used as an input for make(3) +# Remove the lines below to convert it into a pure .am file +TARGET = progname +CFLAGS += -I. +OBJS=${ASN_MODULE_SOURCES:.c=.o} ${ASN_CONVERTER_SOURCES:.c=.o} + +all: $(TARGET) + +$(TARGET): ${OBJS} + $(CC) $(CFLAGS) -o $(TARGET) ${OBJS} $(LDFLAGS) $(LIBS) + +.SUFFIXES: +.SUFFIXES: .c .o + +.c.o: + $(CC) $(CFLAGS) -o $@ -c $< + +clean: + rm -f $(TARGET) + rm -f $(OBJS) + +regen: regenerate-from-asn1-source + +regenerate-from-asn1-source: + asn1c CryptoConditions.asn + diff --git a/src/cryptoconditions/src/asn/NativeEnumerated.c b/src/cryptoconditions/src/asn/NativeEnumerated.c new file mode 100644 index 000000000..78366af31 --- /dev/null +++ b/src/cryptoconditions/src/asn/NativeEnumerated.c @@ -0,0 +1,207 @@ +/*- + * Copyright (c) 2004, 2007 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +/* + * Read the NativeInteger.h for the explanation wrt. differences between + * INTEGER and NativeInteger. + * Basically, both are decoders and encoders of ASN.1 INTEGER type, but this + * implementation deals with the standard (machine-specific) representation + * of them instead of using the platform-independent buffer. + */ +#include +#include + +/* + * NativeEnumerated basic type description. + */ +static const ber_tlv_tag_t asn_DEF_NativeEnumerated_tags[] = { + (ASN_TAG_CLASS_UNIVERSAL | (10 << 2)) +}; +asn_TYPE_descriptor_t asn_DEF_NativeEnumerated = { + "ENUMERATED", /* The ASN.1 type is still ENUMERATED */ + "ENUMERATED", + NativeInteger_free, + NativeInteger_print, + asn_generic_no_constraint, + NativeInteger_decode_ber, + NativeInteger_encode_der, + NativeInteger_decode_xer, + NativeEnumerated_encode_xer, + NativeEnumerated_decode_uper, + NativeEnumerated_encode_uper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_NativeEnumerated_tags, + sizeof(asn_DEF_NativeEnumerated_tags) / sizeof(asn_DEF_NativeEnumerated_tags[0]), + asn_DEF_NativeEnumerated_tags, /* Same as above */ + sizeof(asn_DEF_NativeEnumerated_tags) / sizeof(asn_DEF_NativeEnumerated_tags[0]), + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + 0 /* No specifics */ +}; + +asn_enc_rval_t +NativeEnumerated_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; + asn_enc_rval_t er; + const long *native = (const long *)sptr; + const asn_INTEGER_enum_map_t *el; + + (void)ilevel; + (void)flags; + + if(!native) ASN__ENCODE_FAILED; + + el = INTEGER_map_value2enum(specs, *native); + if(el) { + size_t srcsize = el->enum_len + 5; + char *src = (char *)alloca(srcsize); + + er.encoded = snprintf(src, srcsize, "<%s/>", el->enum_name); + assert(er.encoded > 0 && (size_t)er.encoded < srcsize); + if(cb(src, er.encoded, app_key) < 0) ASN__ENCODE_FAILED; + ASN__ENCODED_OK(er); + } else { + ASN_DEBUG("ASN.1 forbids dealing with " + "unknown value of ENUMERATED type"); + ASN__ENCODE_FAILED; + } +} + +asn_dec_rval_t +NativeEnumerated_decode_uper(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, + void **sptr, asn_per_data_t *pd) { + asn_INTEGER_specifics_t *specs = (asn_INTEGER_specifics_t *)td->specifics; + asn_dec_rval_t rval = { RC_OK, 0 }; + long *native = (long *)*sptr; + asn_per_constraint_t *ct; + long value; + + (void)opt_codec_ctx; + + if(constraints) ct = &constraints->value; + else if(td->per_constraints) ct = &td->per_constraints->value; + else ASN__DECODE_FAILED; /* Mandatory! */ + if(!specs) ASN__DECODE_FAILED; + + if(!native) { + native = (long *)(*sptr = CALLOC(1, sizeof(*native))); + if(!native) ASN__DECODE_FAILED; + } + + ASN_DEBUG("Decoding %s as NativeEnumerated", td->name); + + if(ct->flags & APC_EXTENSIBLE) { + int inext = per_get_few_bits(pd, 1); + if(inext < 0) ASN__DECODE_STARVED; + if(inext) ct = 0; + } + + if(ct && ct->range_bits >= 0) { + value = per_get_few_bits(pd, ct->range_bits); + if(value < 0) ASN__DECODE_STARVED; + if(value >= (specs->extension + ? specs->extension - 1 : specs->map_count)) + ASN__DECODE_FAILED; + } else { + if(!specs->extension) + ASN__DECODE_FAILED; + /* + * X.691, #10.6: normally small non-negative whole number; + */ + value = uper_get_nsnnwn(pd); + if(value < 0) ASN__DECODE_STARVED; + value += specs->extension - 1; + if(value >= specs->map_count) + ASN__DECODE_FAILED; + } + + *native = specs->value2enum[value].nat_value; + ASN_DEBUG("Decoded %s = %ld", td->name, *native); + + return rval; +} + +static int +NativeEnumerated__compar_value2enum(const void *ap, const void *bp) { + const asn_INTEGER_enum_map_t *a = ap; + const asn_INTEGER_enum_map_t *b = bp; + if(a->nat_value == b->nat_value) + return 0; + if(a->nat_value < b->nat_value) + return -1; + return 1; +} + +asn_enc_rval_t +NativeEnumerated_encode_uper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + asn_INTEGER_specifics_t *specs = (asn_INTEGER_specifics_t *)td->specifics; + asn_enc_rval_t er; + long native, value; + asn_per_constraint_t *ct; + int inext = 0; + asn_INTEGER_enum_map_t key; + const asn_INTEGER_enum_map_t *kf; + + if(!sptr) ASN__ENCODE_FAILED; + if(!specs) ASN__ENCODE_FAILED; + + if(constraints) ct = &constraints->value; + else if(td->per_constraints) ct = &td->per_constraints->value; + else ASN__ENCODE_FAILED; /* Mandatory! */ + + ASN_DEBUG("Encoding %s as NativeEnumerated", td->name); + + er.encoded = 0; + + native = *(long *)sptr; + if(native < 0) ASN__ENCODE_FAILED; + + key.nat_value = native; + kf = bsearch(&key, specs->value2enum, specs->map_count, + sizeof(key), NativeEnumerated__compar_value2enum); + if(!kf) { + ASN_DEBUG("No element corresponds to %ld", native); + ASN__ENCODE_FAILED; + } + value = kf - specs->value2enum; + + if(ct->range_bits >= 0) { + int cmpWith = specs->extension + ? specs->extension - 1 : specs->map_count; + if(value >= cmpWith) + inext = 1; + } + if(ct->flags & APC_EXTENSIBLE) { + if(per_put_few_bits(po, inext, 1)) + ASN__ENCODE_FAILED; + if(inext) ct = 0; + } else if(inext) { + ASN__ENCODE_FAILED; + } + + if(ct && ct->range_bits >= 0) { + if(per_put_few_bits(po, value, ct->range_bits)) + ASN__ENCODE_FAILED; + ASN__ENCODED_OK(er); + } + + if(!specs->extension) + ASN__ENCODE_FAILED; + + /* + * X.691, #10.6: normally small non-negative whole number; + */ + ASN_DEBUG("value = %ld, ext = %d, inext = %d, res = %ld", + value, specs->extension, inext, + value - (inext ? (specs->extension - 1) : 0)); + if(uper_put_nsnnwn(po, value - (inext ? (specs->extension - 1) : 0))) + ASN__ENCODE_FAILED; + + ASN__ENCODED_OK(er); +} + diff --git a/src/cryptoconditions/src/asn/NativeEnumerated.h b/src/cryptoconditions/src/asn/NativeEnumerated.h new file mode 100644 index 000000000..c59bb1ba9 --- /dev/null +++ b/src/cryptoconditions/src/asn/NativeEnumerated.h @@ -0,0 +1,32 @@ +/*- + * Copyright (c) 2004, 2005, 2006 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +/* + * This type differs from the standard ENUMERATED in that it is modelled using + * the fixed machine type (long, int, short), so it can hold only values of + * limited length. There is no type (i.e., NativeEnumerated_t, any integer type + * will do). + * This type may be used when integer range is limited by subtype constraints. + */ +#ifndef _NativeEnumerated_H_ +#define _NativeEnumerated_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern asn_TYPE_descriptor_t asn_DEF_NativeEnumerated; + +xer_type_encoder_f NativeEnumerated_encode_xer; +per_type_decoder_f NativeEnumerated_decode_uper; +per_type_encoder_f NativeEnumerated_encode_uper; + +#ifdef __cplusplus +} +#endif + +#endif /* _NativeEnumerated_H_ */ diff --git a/src/cryptoconditions/src/asn/NativeInteger.c b/src/cryptoconditions/src/asn/NativeInteger.c new file mode 100644 index 000000000..e8ce6d2c3 --- /dev/null +++ b/src/cryptoconditions/src/asn/NativeInteger.c @@ -0,0 +1,332 @@ +/*- + * Copyright (c) 2004, 2005, 2006 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +/* + * Read the NativeInteger.h for the explanation wrt. differences between + * INTEGER and NativeInteger. + * Basically, both are decoders and encoders of ASN.1 INTEGER type, but this + * implementation deals with the standard (machine-specific) representation + * of them instead of using the platform-independent buffer. + */ +#include +#include + +/* + * NativeInteger basic type description. + */ +static const ber_tlv_tag_t asn_DEF_NativeInteger_tags[] = { + (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)) +}; +asn_TYPE_descriptor_t asn_DEF_NativeInteger = { + "INTEGER", /* The ASN.1 type is still INTEGER */ + "INTEGER", + NativeInteger_free, + NativeInteger_print, + asn_generic_no_constraint, + NativeInteger_decode_ber, + NativeInteger_encode_der, + NativeInteger_decode_xer, + NativeInteger_encode_xer, + NativeInteger_decode_uper, /* Unaligned PER decoder */ + NativeInteger_encode_uper, /* Unaligned PER encoder */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_NativeInteger_tags, + sizeof(asn_DEF_NativeInteger_tags) / sizeof(asn_DEF_NativeInteger_tags[0]), + asn_DEF_NativeInteger_tags, /* Same as above */ + sizeof(asn_DEF_NativeInteger_tags) / sizeof(asn_DEF_NativeInteger_tags[0]), + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + 0 /* No specifics */ +}; + +/* + * Decode INTEGER type. + */ +asn_dec_rval_t +NativeInteger_decode_ber(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, + void **nint_ptr, const void *buf_ptr, size_t size, int tag_mode) { + asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; + long *native = (long *)*nint_ptr; + asn_dec_rval_t rval; + ber_tlv_len_t length; + + /* + * If the structure is not there, allocate it. + */ + if(native == NULL) { + native = (long *)(*nint_ptr = CALLOC(1, sizeof(*native))); + if(native == NULL) { + rval.code = RC_FAIL; + rval.consumed = 0; + return rval; + } + } + + ASN_DEBUG("Decoding %s as INTEGER (tm=%d)", + td->name, tag_mode); + + /* + * Check tags. + */ + rval = ber_check_tags(opt_codec_ctx, td, 0, buf_ptr, size, + tag_mode, 0, &length, 0); + if(rval.code != RC_OK) + return rval; + + ASN_DEBUG("%s length is %d bytes", td->name, (int)length); + + /* + * Make sure we have this length. + */ + buf_ptr = ((const char *)buf_ptr) + rval.consumed; + size -= rval.consumed; + if(length > (ber_tlv_len_t)size) { + rval.code = RC_WMORE; + rval.consumed = 0; + return rval; + } + + /* + * ASN.1 encoded INTEGER: buf_ptr, length + * Fill the native, at the same time checking for overflow. + * If overflow occured, return with RC_FAIL. + */ + { + INTEGER_t tmp; + union { + const void *constbuf; + void *nonconstbuf; + } unconst_buf; + long l; + + unconst_buf.constbuf = buf_ptr; + tmp.buf = (uint8_t *)unconst_buf.nonconstbuf; + tmp.size = length; + + if((specs&&specs->field_unsigned) + ? asn_INTEGER2ulong(&tmp, (unsigned long *)&l) /* sic */ + : asn_INTEGER2long(&tmp, &l)) { + rval.code = RC_FAIL; + rval.consumed = 0; + return rval; + } + + *native = l; + } + + rval.code = RC_OK; + rval.consumed += length; + + ASN_DEBUG("Took %ld/%ld bytes to encode %s (%ld)", + (long)rval.consumed, (long)length, td->name, (long)*native); + + return rval; +} + +/* + * Encode the NativeInteger using the standard INTEGER type DER encoder. + */ +asn_enc_rval_t +NativeInteger_encode_der(asn_TYPE_descriptor_t *sd, void *ptr, + int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + unsigned long native = *(unsigned long *)ptr; /* Disable sign ext. */ + asn_enc_rval_t erval; + INTEGER_t tmp; + +#ifdef WORDS_BIGENDIAN /* Opportunistic optimization */ + + tmp.buf = (uint8_t *)&native; + tmp.size = sizeof(native); + +#else /* Works even if WORDS_BIGENDIAN is not set where should've been */ + uint8_t buf[sizeof(native)]; + uint8_t *p; + + /* Prepare a fake INTEGER */ + for(p = buf + sizeof(buf) - 1; p >= buf; p--, native >>= 8) + *p = (uint8_t)native; + + tmp.buf = buf; + tmp.size = sizeof(buf); +#endif /* WORDS_BIGENDIAN */ + + /* Encode fake INTEGER */ + erval = INTEGER_encode_der(sd, &tmp, tag_mode, tag, cb, app_key); + if(erval.encoded == -1) { + assert(erval.structure_ptr == &tmp); + erval.structure_ptr = ptr; + } + return erval; +} + +/* + * Decode the chunk of XML text encoding INTEGER. + */ +asn_dec_rval_t +NativeInteger_decode_xer(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, void **sptr, const char *opt_mname, + const void *buf_ptr, size_t size) { + asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; + asn_dec_rval_t rval; + INTEGER_t st; + void *st_ptr = (void *)&st; + long *native = (long *)*sptr; + + if(!native) { + native = (long *)(*sptr = CALLOC(1, sizeof(*native))); + if(!native) ASN__DECODE_FAILED; + } + + memset(&st, 0, sizeof(st)); + rval = INTEGER_decode_xer(opt_codec_ctx, td, &st_ptr, + opt_mname, buf_ptr, size); + if(rval.code == RC_OK) { + long l; + if((specs&&specs->field_unsigned) + ? asn_INTEGER2ulong(&st, (unsigned long *)&l) /* sic */ + : asn_INTEGER2long(&st, &l)) { + rval.code = RC_FAIL; + rval.consumed = 0; + } else { + *native = l; + } + } else { + /* + * Cannot restart from the middle; + * there is no place to save state in the native type. + * Request a continuation from the very beginning. + */ + rval.consumed = 0; + } + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &st); + return rval; +} + + +asn_enc_rval_t +NativeInteger_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; + char scratch[32]; /* Enough for 64-bit int */ + asn_enc_rval_t er; + const long *native = (const long *)sptr; + + (void)ilevel; + (void)flags; + + if(!native) ASN__ENCODE_FAILED; + + er.encoded = snprintf(scratch, sizeof(scratch), + (specs && specs->field_unsigned) + ? "%lu" : "%ld", *native); + if(er.encoded <= 0 || (size_t)er.encoded >= sizeof(scratch) + || cb(scratch, er.encoded, app_key) < 0) + ASN__ENCODE_FAILED; + + ASN__ENCODED_OK(er); +} + +asn_dec_rval_t +NativeInteger_decode_uper(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { + + asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; + asn_dec_rval_t rval; + long *native = (long *)*sptr; + INTEGER_t tmpint; + void *tmpintptr = &tmpint; + + (void)opt_codec_ctx; + ASN_DEBUG("Decoding NativeInteger %s (UPER)", td->name); + + if(!native) { + native = (long *)(*sptr = CALLOC(1, sizeof(*native))); + if(!native) ASN__DECODE_FAILED; + } + + memset(&tmpint, 0, sizeof tmpint); + rval = INTEGER_decode_uper(opt_codec_ctx, td, constraints, + &tmpintptr, pd); + if(rval.code == RC_OK) { + if((specs&&specs->field_unsigned) + ? asn_INTEGER2ulong(&tmpint, (unsigned long *)native) + : asn_INTEGER2long(&tmpint, native)) + rval.code = RC_FAIL; + else + ASN_DEBUG("NativeInteger %s got value %ld", + td->name, *native); + } + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint); + + return rval; +} + +asn_enc_rval_t +NativeInteger_encode_uper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; + asn_enc_rval_t er; + long native; + INTEGER_t tmpint; + + if(!sptr) ASN__ENCODE_FAILED; + + native = *(long *)sptr; + + ASN_DEBUG("Encoding NativeInteger %s %ld (UPER)", td->name, native); + + memset(&tmpint, 0, sizeof(tmpint)); + if((specs&&specs->field_unsigned) + ? asn_ulong2INTEGER(&tmpint, native) + : asn_long2INTEGER(&tmpint, native)) + ASN__ENCODE_FAILED; + er = INTEGER_encode_uper(td, constraints, &tmpint, po); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint); + return er; +} + +/* + * INTEGER specific human-readable output. + */ +int +NativeInteger_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; + const long *native = (const long *)sptr; + char scratch[32]; /* Enough for 64-bit int */ + int ret; + + (void)td; /* Unused argument */ + (void)ilevel; /* Unused argument */ + + if(native) { + ret = snprintf(scratch, sizeof(scratch), + (specs && specs->field_unsigned) + ? "%lu" : "%ld", *native); + assert(ret > 0 && (size_t)ret < sizeof(scratch)); + return (cb(scratch, ret, app_key) < 0) ? -1 : 0; + } else { + return (cb("", 8, app_key) < 0) ? -1 : 0; + } +} + +void +NativeInteger_free(asn_TYPE_descriptor_t *td, void *ptr, int contents_only) { + + if(!td || !ptr) + return; + + ASN_DEBUG("Freeing %s as INTEGER (%d, %p, Native)", + td->name, contents_only, ptr); + + if(!contents_only) { + FREEMEM(ptr); + } +} + diff --git a/src/cryptoconditions/src/asn/NativeInteger.h b/src/cryptoconditions/src/asn/NativeInteger.h new file mode 100644 index 000000000..4e63a8355 --- /dev/null +++ b/src/cryptoconditions/src/asn/NativeInteger.h @@ -0,0 +1,37 @@ +/*- + * Copyright (c) 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +/* + * This type differs from the standard INTEGER in that it is modelled using + * the fixed machine type (long, int, short), so it can hold only values of + * limited length. There is no type (i.e., NativeInteger_t, any integer type + * will do). + * This type may be used when integer range is limited by subtype constraints. + */ +#ifndef _NativeInteger_H_ +#define _NativeInteger_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern asn_TYPE_descriptor_t asn_DEF_NativeInteger; + +asn_struct_free_f NativeInteger_free; +asn_struct_print_f NativeInteger_print; +ber_type_decoder_f NativeInteger_decode_ber; +der_type_encoder_f NativeInteger_encode_der; +xer_type_decoder_f NativeInteger_decode_xer; +xer_type_encoder_f NativeInteger_encode_xer; +per_type_decoder_f NativeInteger_decode_uper; +per_type_encoder_f NativeInteger_encode_uper; + +#ifdef __cplusplus +} +#endif + +#endif /* _NativeInteger_H_ */ diff --git a/src/cryptoconditions/src/asn/OCTET_STRING.c b/src/cryptoconditions/src/asn/OCTET_STRING.c new file mode 100644 index 000000000..5420dedec --- /dev/null +++ b/src/cryptoconditions/src/asn/OCTET_STRING.c @@ -0,0 +1,1807 @@ +/*- + * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include /* for .bits_unused member */ +#include + +/* + * OCTET STRING basic type description. + */ +static const ber_tlv_tag_t asn_DEF_OCTET_STRING_tags[] = { + (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) +}; +static const asn_OCTET_STRING_specifics_t asn_DEF_OCTET_STRING_specs = { + sizeof(OCTET_STRING_t), + offsetof(OCTET_STRING_t, _asn_ctx), + ASN_OSUBV_STR +}; +static const asn_per_constraints_t asn_DEF_OCTET_STRING_constraints = { + { APC_CONSTRAINED, 8, 8, 0, 255 }, + { APC_SEMI_CONSTRAINED, -1, -1, 0, 0 }, + 0, 0 +}; +asn_TYPE_descriptor_t asn_DEF_OCTET_STRING = { + "OCTET STRING", /* Canonical name */ + "OCTET_STRING", /* XML tag name */ + OCTET_STRING_free, + OCTET_STRING_print, /* non-ascii stuff, generally */ + asn_generic_no_constraint, + OCTET_STRING_decode_ber, + OCTET_STRING_encode_der, + OCTET_STRING_decode_xer_hex, + OCTET_STRING_encode_xer, + OCTET_STRING_decode_uper, /* Unaligned PER decoder */ + OCTET_STRING_encode_uper, /* Unaligned PER encoder */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_OCTET_STRING_tags, + sizeof(asn_DEF_OCTET_STRING_tags) + / sizeof(asn_DEF_OCTET_STRING_tags[0]), + asn_DEF_OCTET_STRING_tags, /* Same as above */ + sizeof(asn_DEF_OCTET_STRING_tags) + / sizeof(asn_DEF_OCTET_STRING_tags[0]), + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + &asn_DEF_OCTET_STRING_specs +}; + +#undef _CH_PHASE +#undef NEXT_PHASE +#undef PREV_PHASE +#define _CH_PHASE(ctx, inc) do { \ + if(ctx->phase == 0) \ + ctx->context = 0; \ + ctx->phase += inc; \ + } while(0) +#define NEXT_PHASE(ctx) _CH_PHASE(ctx, +1) +#define PREV_PHASE(ctx) _CH_PHASE(ctx, -1) + +#undef ADVANCE +#define ADVANCE(num_bytes) do { \ + size_t num = (num_bytes); \ + buf_ptr = ((const char *)buf_ptr) + num; \ + size -= num; \ + consumed_myself += num; \ + } while(0) + +#undef RETURN +#define RETURN(_code) do { \ + asn_dec_rval_t tmprval; \ + tmprval.code = _code; \ + tmprval.consumed = consumed_myself; \ + return tmprval; \ + } while(0) + +#undef APPEND +#define APPEND(bufptr, bufsize) do { \ + size_t _bs = (bufsize); /* Append size */ \ + size_t _ns = ctx->context; /* Allocated now */ \ + size_t _es = st->size + _bs; /* Expected size */ \ + /* int is really a typeof(st->size): */ \ + if((int)_es < 0) RETURN(RC_FAIL); \ + if(_ns <= _es) { \ + void *ptr; \ + /* Be nice and round to the memory allocator */ \ + do { _ns = _ns ? _ns << 1 : 16; } \ + while(_ns <= _es); \ + /* int is really a typeof(st->size): */ \ + if((int)_ns < 0) RETURN(RC_FAIL); \ + ptr = REALLOC(st->buf, _ns); \ + if(ptr) { \ + st->buf = (uint8_t *)ptr; \ + ctx->context = _ns; \ + } else { \ + RETURN(RC_FAIL); \ + } \ + ASN_DEBUG("Reallocating into %ld", (long)_ns); \ + } \ + memcpy(st->buf + st->size, bufptr, _bs); \ + /* Convenient nul-termination */ \ + st->buf[_es] = '\0'; \ + st->size = _es; \ + } while(0) + +/* + * The main reason why ASN.1 is still alive is that too much time and effort + * is necessary for learning it more or less adequately, thus creating a gut + * necessity to demonstrate that aquired skill everywhere afterwards. + * No, I am not going to explain what the following stuff is. + */ +struct _stack_el { + ber_tlv_len_t left; /* What's left to read (or -1) */ + ber_tlv_len_t got; /* What was actually processed */ + int cont_level; /* Depth of subcontainment */ + int want_nulls; /* Want null "end of content" octets? */ + int bits_chopped; /* Flag in BIT STRING mode */ + ber_tlv_tag_t tag; /* For debugging purposes */ + struct _stack_el *prev; + struct _stack_el *next; +}; +struct _stack { + struct _stack_el *tail; + struct _stack_el *cur_ptr; +}; + +static struct _stack_el * +OS__add_stack_el(struct _stack *st) { + struct _stack_el *nel; + + /* + * Reuse the old stack frame or allocate a new one. + */ + if(st->cur_ptr && st->cur_ptr->next) { + nel = st->cur_ptr->next; + nel->bits_chopped = 0; + nel->got = 0; + /* Retain the nel->cont_level, it's correct. */ + } else { + nel = (struct _stack_el *)CALLOC(1, sizeof(struct _stack_el)); + if(nel == NULL) + return NULL; + + if(st->tail) { + /* Increase a subcontainment depth */ + nel->cont_level = st->tail->cont_level + 1; + st->tail->next = nel; + } + nel->prev = st->tail; + st->tail = nel; + } + + st->cur_ptr = nel; + + return nel; +} + +static struct _stack * +_new_stack() { + return (struct _stack *)CALLOC(1, sizeof(struct _stack)); +} + +/* + * Decode OCTET STRING type. + */ +asn_dec_rval_t +OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, + void **sptr, const void *buf_ptr, size_t size, int tag_mode) { + asn_OCTET_STRING_specifics_t *specs = td->specifics + ? (asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_DEF_OCTET_STRING_specs; + BIT_STRING_t *st = (BIT_STRING_t *)*sptr; + asn_dec_rval_t rval; + asn_struct_ctx_t *ctx; + ssize_t consumed_myself = 0; + struct _stack *stck; /* Expectations stack structure */ + struct _stack_el *sel = 0; /* Stack element */ + int tlv_constr; + enum asn_OS_Subvariant type_variant = specs->subvariant; + + ASN_DEBUG("Decoding %s as %s (frame %ld)", + td->name, + (type_variant == ASN_OSUBV_STR) ? + "OCTET STRING" : "OS-SpecialCase", + (long)size); + + /* + * Create the string if does not exist. + */ + if(st == NULL) { + st = (BIT_STRING_t *)(*sptr = CALLOC(1, specs->struct_size)); + if(st == NULL) RETURN(RC_FAIL); + } + + /* Restore parsing context */ + ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); + + switch(ctx->phase) { + case 0: + /* + * Check tags. + */ + rval = ber_check_tags(opt_codec_ctx, td, ctx, + buf_ptr, size, tag_mode, -1, + &ctx->left, &tlv_constr); + if(rval.code != RC_OK) + return rval; + + if(tlv_constr) { + /* + * Complex operation, requires stack of expectations. + */ + ctx->ptr = _new_stack(); + if(ctx->ptr) { + stck = (struct _stack *)ctx->ptr; + } else { + RETURN(RC_FAIL); + } + } else { + /* + * Jump into stackless primitive decoding. + */ + _CH_PHASE(ctx, 3); + if(type_variant == ASN_OSUBV_ANY && tag_mode != 1) + APPEND(buf_ptr, rval.consumed); + ADVANCE(rval.consumed); + goto phase3; + } + + NEXT_PHASE(ctx); + /* Fall through */ + case 1: + phase1: + /* + * Fill the stack with expectations. + */ + stck = (struct _stack *)ctx->ptr; + sel = stck->cur_ptr; + do { + ber_tlv_tag_t tlv_tag; + ber_tlv_len_t tlv_len; + ber_tlv_tag_t expected_tag; + ssize_t tl, ll, tlvl; + /* This one works even if (sel->left == -1) */ + ssize_t Left = ((!sel||(size_t)sel->left >= size) + ?(ssize_t)size:sel->left); + + + ASN_DEBUG("%p, s->l=%ld, s->wn=%ld, s->g=%ld\n", sel, + (long)(sel?sel->left:0), + (long)(sel?sel->want_nulls:0), + (long)(sel?sel->got:0) + ); + if(sel && sel->left <= 0 && sel->want_nulls == 0) { + if(sel->prev) { + struct _stack_el *prev = sel->prev; + if(prev->left != -1) { + if(prev->left < sel->got) + RETURN(RC_FAIL); + prev->left -= sel->got; + } + prev->got += sel->got; + sel = stck->cur_ptr = prev; + if(!sel) break; + tlv_constr = 1; + continue; + } else { + sel = stck->cur_ptr = 0; + break; /* Nothing to wait */ + } + } + + tl = ber_fetch_tag(buf_ptr, Left, &tlv_tag); + ASN_DEBUG("fetch tag(size=%ld,L=%ld), %sstack, left=%ld, wn=%ld, tl=%ld", + (long)size, (long)Left, sel?"":"!", + (long)(sel?sel->left:0), + (long)(sel?sel->want_nulls:0), + (long)tl); + switch(tl) { + case -1: RETURN(RC_FAIL); + case 0: RETURN(RC_WMORE); + } + + tlv_constr = BER_TLV_CONSTRUCTED(buf_ptr); + + ll = ber_fetch_length(tlv_constr, + (const char *)buf_ptr + tl,Left - tl,&tlv_len); + ASN_DEBUG("Got tag=%s, tc=%d, left=%ld, tl=%ld, len=%ld, ll=%ld", + ber_tlv_tag_string(tlv_tag), tlv_constr, + (long)Left, (long)tl, (long)tlv_len, (long)ll); + switch(ll) { + case -1: RETURN(RC_FAIL); + case 0: RETURN(RC_WMORE); + } + + if(sel && sel->want_nulls + && ((const uint8_t *)buf_ptr)[0] == 0 + && ((const uint8_t *)buf_ptr)[1] == 0) + { + + ASN_DEBUG("Eat EOC; wn=%d--", sel->want_nulls); + + if(type_variant == ASN_OSUBV_ANY + && (tag_mode != 1 || sel->cont_level)) + APPEND("\0\0", 2); + + ADVANCE(2); + sel->got += 2; + if(sel->left != -1) { + sel->left -= 2; /* assert(sel->left >= 2) */ + } + + sel->want_nulls--; + if(sel->want_nulls == 0) { + /* Move to the next expectation */ + sel->left = 0; + tlv_constr = 1; + } + + continue; + } + + /* + * Set up expected tags, + * depending on ASN.1 type being decoded. + */ + switch(type_variant) { + case ASN_OSUBV_BIT: + /* X.690: 8.6.4.1, NOTE 2 */ + /* Fall through */ + case ASN_OSUBV_STR: + default: + if(sel) { + int level = sel->cont_level; + if(level < td->all_tags_count) { + expected_tag = td->all_tags[level]; + break; + } else if(td->all_tags_count) { + expected_tag = td->all_tags + [td->all_tags_count - 1]; + break; + } + /* else, Fall through */ + } + /* Fall through */ + case ASN_OSUBV_ANY: + expected_tag = tlv_tag; + break; + } + + + if(tlv_tag != expected_tag) { + char buf[2][32]; + ber_tlv_tag_snprint(tlv_tag, + buf[0], sizeof(buf[0])); + ber_tlv_tag_snprint(td->tags[td->tags_count-1], + buf[1], sizeof(buf[1])); + ASN_DEBUG("Tag does not match expectation: %s != %s", + buf[0], buf[1]); + RETURN(RC_FAIL); + } + + tlvl = tl + ll; /* Combined length of T and L encoding */ + if((tlv_len + tlvl) < 0) { + /* tlv_len value is too big */ + ASN_DEBUG("TLV encoding + length (%ld) is too big", + (long)tlv_len); + RETURN(RC_FAIL); + } + + /* + * Append a new expectation. + */ + sel = OS__add_stack_el(stck); + if(!sel) RETURN(RC_FAIL); + + sel->tag = tlv_tag; + + sel->want_nulls = (tlv_len==-1); + if(sel->prev && sel->prev->left != -1) { + /* Check that the parent frame is big enough */ + if(sel->prev->left < tlvl + (tlv_len==-1?0:tlv_len)) + RETURN(RC_FAIL); + if(tlv_len == -1) + sel->left = sel->prev->left - tlvl; + else + sel->left = tlv_len; + } else { + sel->left = tlv_len; + } + if(type_variant == ASN_OSUBV_ANY + && (tag_mode != 1 || sel->cont_level)) + APPEND(buf_ptr, tlvl); + sel->got += tlvl; + ADVANCE(tlvl); + + ASN_DEBUG("+EXPECT2 got=%ld left=%ld, wn=%d, clvl=%d", + (long)sel->got, (long)sel->left, + sel->want_nulls, sel->cont_level); + + } while(tlv_constr); + if(sel == NULL) { + /* Finished operation, "phase out" */ + ASN_DEBUG("Phase out"); + _CH_PHASE(ctx, +3); + break; + } + + NEXT_PHASE(ctx); + /* Fall through */ + case 2: + stck = (struct _stack *)ctx->ptr; + sel = stck->cur_ptr; + ASN_DEBUG("Phase 2: Need %ld bytes, size=%ld, alrg=%ld, wn=%d", + (long)sel->left, (long)size, (long)sel->got, + sel->want_nulls); + { + ber_tlv_len_t len; + + assert(sel->left >= 0); + + len = ((ber_tlv_len_t)size < sel->left) + ? (ber_tlv_len_t)size : sel->left; + if(len > 0) { + if(type_variant == ASN_OSUBV_BIT + && sel->bits_chopped == 0) { + /* Put the unused-bits-octet away */ + st->bits_unused = *(const uint8_t *)buf_ptr; + APPEND(((const char *)buf_ptr+1), (len - 1)); + sel->bits_chopped = 1; + } else { + APPEND(buf_ptr, len); + } + ADVANCE(len); + sel->left -= len; + sel->got += len; + } + + if(sel->left) { + ASN_DEBUG("OS left %ld, size = %ld, wn=%d\n", + (long)sel->left, (long)size, sel->want_nulls); + RETURN(RC_WMORE); + } + + PREV_PHASE(ctx); + goto phase1; + } + break; + case 3: + phase3: + /* + * Primitive form, no stack required. + */ + assert(ctx->left >= 0); + + if(size < (size_t)ctx->left) { + if(!size) RETURN(RC_WMORE); + if(type_variant == ASN_OSUBV_BIT && !ctx->context) { + st->bits_unused = *(const uint8_t *)buf_ptr; + ctx->left--; + ADVANCE(1); + } + APPEND(buf_ptr, size); + assert(ctx->context > 0); + ctx->left -= size; + ADVANCE(size); + RETURN(RC_WMORE); + } else { + if(type_variant == ASN_OSUBV_BIT + && !ctx->context && ctx->left) { + st->bits_unused = *(const uint8_t *)buf_ptr; + ctx->left--; + ADVANCE(1); + } + APPEND(buf_ptr, ctx->left); + ADVANCE(ctx->left); + ctx->left = 0; + + NEXT_PHASE(ctx); + } + break; + } + + if(sel) { + ASN_DEBUG("3sel p=%p, wn=%d, l=%ld, g=%ld, size=%ld", + sel->prev, sel->want_nulls, + (long)sel->left, (long)sel->got, (long)size); + if(sel->prev || sel->want_nulls > 1 || sel->left > 0) { + RETURN(RC_WMORE); + } + } + + /* + * BIT STRING-specific processing. + */ + if(type_variant == ASN_OSUBV_BIT && st->size) { + /* Finalize BIT STRING: zero out unused bits. */ + st->buf[st->size-1] &= 0xff << st->bits_unused; + } + + ASN_DEBUG("Took %ld bytes to encode %s: [%s]:%ld", + (long)consumed_myself, td->name, + (type_variant == ASN_OSUBV_STR) ? (char *)st->buf : "", + (long)st->size); + + + RETURN(RC_OK); +} + +/* + * Encode OCTET STRING type using DER. + */ +asn_enc_rval_t +OCTET_STRING_encode_der(asn_TYPE_descriptor_t *td, void *sptr, + int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_enc_rval_t er; + asn_OCTET_STRING_specifics_t *specs = td->specifics + ? (asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_DEF_OCTET_STRING_specs; + BIT_STRING_t *st = (BIT_STRING_t *)sptr; + enum asn_OS_Subvariant type_variant = specs->subvariant; + int fix_last_byte = 0; + + ASN_DEBUG("%s %s as OCTET STRING", + cb?"Estimating":"Encoding", td->name); + + /* + * Write tags. + */ + if(type_variant != ASN_OSUBV_ANY || tag_mode == 1) { + er.encoded = der_write_tags(td, + (type_variant == ASN_OSUBV_BIT) + st->size, + tag_mode, type_variant == ASN_OSUBV_ANY, tag, + cb, app_key); + if(er.encoded == -1) { + er.failed_type = td; + er.structure_ptr = sptr; + return er; + } + } else { + /* Disallow: [] IMPLICIT ANY */ + assert(type_variant != ASN_OSUBV_ANY || tag_mode != -1); + er.encoded = 0; + } + + if(!cb) { + er.encoded += (type_variant == ASN_OSUBV_BIT) + st->size; + ASN__ENCODED_OK(er); + } + + /* + * Prepare to deal with the last octet of BIT STRING. + */ + if(type_variant == ASN_OSUBV_BIT) { + uint8_t b = st->bits_unused & 0x07; + if(b && st->size) fix_last_byte = 1; + ASN__CALLBACK(&b, 1); + er.encoded++; + } + + /* Invoke callback for the main part of the buffer */ + ASN__CALLBACK(st->buf, st->size - fix_last_byte); + + /* The last octet should be stripped off the unused bits */ + if(fix_last_byte) { + uint8_t b = st->buf[st->size-1] & (0xff << st->bits_unused); + ASN__CALLBACK(&b, 1); + } + + er.encoded += st->size; + ASN__ENCODED_OK(er); +cb_failed: + ASN__ENCODE_FAILED; +} + +asn_enc_rval_t +OCTET_STRING_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + const char * const h2c = "0123456789ABCDEF"; + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + asn_enc_rval_t er; + char scratch[16 * 3 + 4]; + char *p = scratch; + uint8_t *buf; + uint8_t *end; + size_t i; + + if(!st || (!st->buf && st->size)) + ASN__ENCODE_FAILED; + + er.encoded = 0; + + /* + * Dump the contents of the buffer in hexadecimal. + */ + buf = st->buf; + end = buf + st->size; + if(flags & XER_F_CANONICAL) { + char *scend = scratch + (sizeof(scratch) - 2); + for(; buf < end; buf++) { + if(p >= scend) { + ASN__CALLBACK(scratch, p - scratch); + er.encoded += p - scratch; + p = scratch; + } + *p++ = h2c[(*buf >> 4) & 0x0F]; + *p++ = h2c[*buf & 0x0F]; + } + + ASN__CALLBACK(scratch, p-scratch); /* Dump the rest */ + er.encoded += p - scratch; + } else { + for(i = 0; buf < end; buf++, i++) { + if(!(i % 16) && (i || st->size > 16)) { + ASN__CALLBACK(scratch, p-scratch); + er.encoded += (p-scratch); + p = scratch; + ASN__TEXT_INDENT(1, ilevel); + } + *p++ = h2c[(*buf >> 4) & 0x0F]; + *p++ = h2c[*buf & 0x0F]; + *p++ = 0x20; + } + if(p - scratch) { + p--; /* Remove the tail space */ + ASN__CALLBACK(scratch, p-scratch); /* Dump the rest */ + er.encoded += p - scratch; + if(st->size > 16) + ASN__TEXT_INDENT(1, ilevel-1); + } + } + + ASN__ENCODED_OK(er); +cb_failed: + ASN__ENCODE_FAILED; +} + +static const struct OCTET_STRING__xer_escape_table_s { + const char *string; + int size; +} OCTET_STRING__xer_escape_table[] = { +#define OSXET(s) { s, sizeof(s) - 1 } + OSXET("\074\156\165\154\057\076"), /* */ + OSXET("\074\163\157\150\057\076"), /* */ + OSXET("\074\163\164\170\057\076"), /* */ + OSXET("\074\145\164\170\057\076"), /* */ + OSXET("\074\145\157\164\057\076"), /* */ + OSXET("\074\145\156\161\057\076"), /* */ + OSXET("\074\141\143\153\057\076"), /* */ + OSXET("\074\142\145\154\057\076"), /* */ + OSXET("\074\142\163\057\076"), /* */ + OSXET("\011"), /* \t */ + OSXET("\012"), /* \n */ + OSXET("\074\166\164\057\076"), /* */ + OSXET("\074\146\146\057\076"), /* */ + OSXET("\015"), /* \r */ + OSXET("\074\163\157\057\076"), /* */ + OSXET("\074\163\151\057\076"), /* */ + OSXET("\074\144\154\145\057\076"), /* */ + OSXET("\074\144\143\061\057\076"), /* */ + OSXET("\074\144\143\062\057\076"), /* */ + OSXET("\074\144\143\063\057\076"), /* */ + OSXET("\074\144\143\064\057\076"), /* */ + OSXET("\074\156\141\153\057\076"), /* */ + OSXET("\074\163\171\156\057\076"), /* */ + OSXET("\074\145\164\142\057\076"), /* */ + OSXET("\074\143\141\156\057\076"), /* */ + OSXET("\074\145\155\057\076"), /* */ + OSXET("\074\163\165\142\057\076"), /* */ + OSXET("\074\145\163\143\057\076"), /* */ + OSXET("\074\151\163\064\057\076"), /* */ + OSXET("\074\151\163\063\057\076"), /* */ + OSXET("\074\151\163\062\057\076"), /* */ + OSXET("\074\151\163\061\057\076"), /* */ + { 0, 0 }, /* " " */ + { 0, 0 }, /* ! */ + { 0, 0 }, /* \" */ + { 0, 0 }, /* # */ + { 0, 0 }, /* $ */ + { 0, 0 }, /* % */ + OSXET("\046\141\155\160\073"), /* & */ + { 0, 0 }, /* ' */ + {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, /* ()*+,-./ */ + {0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}, /* 01234567 */ + {0,0},{0,0},{0,0},{0,0}, /* 89:; */ + OSXET("\046\154\164\073"), /* < */ + { 0, 0 }, /* = */ + OSXET("\046\147\164\073"), /* > */ +}; + +static int +OS__check_escaped_control_char(const void *buf, int size) { + size_t i; + /* + * Inefficient algorithm which translates the escape sequences + * defined above into characters. Returns -1 if not found. + * TODO: replace by a faster algorithm (bsearch(), hash or + * nested table lookups). + */ + for(i = 0; i < 32 /* Don't spend time on the bottom half */; i++) { + const struct OCTET_STRING__xer_escape_table_s *el; + el = &OCTET_STRING__xer_escape_table[i]; + if(el->size == size && memcmp(buf, el->string, size) == 0) + return i; + } + return -1; +} + +static int +OCTET_STRING__handle_control_chars(void *struct_ptr, const void *chunk_buf, size_t chunk_size) { + /* + * This might be one of the escape sequences + * for control characters. Check it out. + * #11.15.5 + */ + int control_char = OS__check_escaped_control_char(chunk_buf,chunk_size); + if(control_char >= 0) { + OCTET_STRING_t *st = (OCTET_STRING_t *)struct_ptr; + void *p = REALLOC(st->buf, st->size + 2); + if(p) { + st->buf = (uint8_t *)p; + st->buf[st->size++] = control_char; + st->buf[st->size] = '\0'; /* nul-termination */ + return 0; + } + } + + return -1; /* No, it's not */ +} + +asn_enc_rval_t +OCTET_STRING_encode_xer_utf8(asn_TYPE_descriptor_t *td, void *sptr, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + asn_enc_rval_t er; + uint8_t *buf, *end; + uint8_t *ss; /* Sequence start */ + ssize_t encoded_len = 0; + + (void)ilevel; /* Unused argument */ + (void)flags; /* Unused argument */ + + if(!st || (!st->buf && st->size)) + ASN__ENCODE_FAILED; + + buf = st->buf; + end = buf + st->size; + for(ss = buf; buf < end; buf++) { + unsigned int ch = *buf; + int s_len; /* Special encoding sequence length */ + + /* + * Escape certain characters: X.680/11.15 + */ + if(ch < sizeof(OCTET_STRING__xer_escape_table) + /sizeof(OCTET_STRING__xer_escape_table[0]) + && (s_len = OCTET_STRING__xer_escape_table[ch].size)) { + if(((buf - ss) && cb(ss, buf - ss, app_key) < 0) + || cb(OCTET_STRING__xer_escape_table[ch].string, s_len, + app_key) < 0) + ASN__ENCODE_FAILED; + encoded_len += (buf - ss) + s_len; + ss = buf + 1; + } + } + + encoded_len += (buf - ss); + if((buf - ss) && cb(ss, buf - ss, app_key) < 0) + ASN__ENCODE_FAILED; + + er.encoded = encoded_len; + ASN__ENCODED_OK(er); +} + +/* + * Convert from hexadecimal format (cstring): "AB CD EF" + */ +static ssize_t OCTET_STRING__convert_hexadecimal(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) { + OCTET_STRING_t *st = (OCTET_STRING_t *)sptr; + const char *chunk_stop = (const char *)chunk_buf; + const char *p = chunk_stop; + const char *pend = p + chunk_size; + unsigned int clv = 0; + int half = 0; /* Half bit */ + uint8_t *buf; + + /* Reallocate buffer according to high cap estimation */ + ssize_t _ns = st->size + (chunk_size + 1) / 2; + void *nptr = REALLOC(st->buf, _ns + 1); + if(!nptr) return -1; + st->buf = (uint8_t *)nptr; + buf = st->buf + st->size; + + /* + * If something like " a b c " appears here, the " a b":3 will be + * converted, and the rest skipped. That is, unless buf_size is greater + * than chunk_size, then it'll be equivalent to "ABC0". + */ + for(; p < pend; p++) { + int ch = *(const unsigned char *)p; + switch(ch) { + case 0x09: case 0x0a: case 0x0c: case 0x0d: + case 0x20: + /* Ignore whitespace */ + continue; + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: /*01234*/ + case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: /*56789*/ + clv = (clv << 4) + (ch - 0x30); + break; + case 0x41: case 0x42: case 0x43: /* ABC */ + case 0x44: case 0x45: case 0x46: /* DEF */ + clv = (clv << 4) + (ch - 0x41 + 10); + break; + case 0x61: case 0x62: case 0x63: /* abc */ + case 0x64: case 0x65: case 0x66: /* def */ + clv = (clv << 4) + (ch - 0x61 + 10); + break; + default: + *buf = 0; /* JIC */ + return -1; + } + if(half++) { + half = 0; + *buf++ = clv; + chunk_stop = p + 1; + } + } + + /* + * Check partial decoding. + */ + if(half) { + if(have_more) { + /* + * Partial specification is fine, + * because no more more PXER_TEXT data is available. + */ + *buf++ = clv << 4; + chunk_stop = p; + } + } else { + chunk_stop = p; + } + + st->size = buf - st->buf; /* Adjust the buffer size */ + assert(st->size <= _ns); + st->buf[st->size] = 0; /* Courtesy termination */ + + return (chunk_stop - (const char *)chunk_buf); /* Converted size */ +} + +/* + * Convert from binary format: "00101011101" + */ +static ssize_t OCTET_STRING__convert_binary(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) { + BIT_STRING_t *st = (BIT_STRING_t *)sptr; + const char *p = (const char *)chunk_buf; + const char *pend = p + chunk_size; + int bits_unused = st->bits_unused & 0x7; + uint8_t *buf; + + /* Reallocate buffer according to high cap estimation */ + ssize_t _ns = st->size + (chunk_size + 7) / 8; + void *nptr = REALLOC(st->buf, _ns + 1); + if(!nptr) return -1; + st->buf = (uint8_t *)nptr; + buf = st->buf + st->size; + + (void)have_more; + + if(bits_unused == 0) + bits_unused = 8; + else if(st->size) + buf--; + + /* + * Convert series of 0 and 1 into the octet string. + */ + for(; p < pend; p++) { + int ch = *(const unsigned char *)p; + switch(ch) { + case 0x09: case 0x0a: case 0x0c: case 0x0d: + case 0x20: + /* Ignore whitespace */ + break; + case 0x30: + case 0x31: + if(bits_unused-- <= 0) { + *++buf = 0; /* Clean the cell */ + bits_unused = 7; + } + *buf |= (ch&1) << bits_unused; + break; + default: + st->bits_unused = bits_unused; + return -1; + } + } + + if(bits_unused == 8) { + st->size = buf - st->buf; + st->bits_unused = 0; + } else { + st->size = buf - st->buf + 1; + st->bits_unused = bits_unused; + } + + assert(st->size <= _ns); + st->buf[st->size] = 0; /* Courtesy termination */ + + return chunk_size; /* Converted in full */ +} + +/* + * Something like strtod(), but with stricter rules. + */ +static int +OS__strtoent(int base, const char *buf, const char *end, int32_t *ret_value) { + int32_t val = 0; + const char *p; + + for(p = buf; p < end; p++) { + int ch = *p; + + /* Strange huge value */ + if((val * base + base) < 0) + return -1; + + switch(ch) { + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: /*01234*/ + case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: /*56789*/ + val = val * base + (ch - 0x30); + break; + case 0x41: case 0x42: case 0x43: /* ABC */ + case 0x44: case 0x45: case 0x46: /* DEF */ + val = val * base + (ch - 0x41 + 10); + break; + case 0x61: case 0x62: case 0x63: /* abc */ + case 0x64: case 0x65: case 0x66: /* def */ + val = val * base + (ch - 0x61 + 10); + break; + case 0x3b: /* ';' */ + *ret_value = val; + return (p - buf) + 1; + default: + return -1; /* Character set error */ + } + } + + *ret_value = -1; + return (p - buf); +} + +/* + * Convert from the plain UTF-8 format, expanding entity references: "2 < 3" + */ +static ssize_t OCTET_STRING__convert_entrefs(void *sptr, const void *chunk_buf, size_t chunk_size, int have_more) { + OCTET_STRING_t *st = (OCTET_STRING_t *)sptr; + const char *p = (const char *)chunk_buf; + const char *pend = p + chunk_size; + uint8_t *buf; + + /* Reallocate buffer */ + ssize_t _ns = st->size + chunk_size; + void *nptr = REALLOC(st->buf, _ns + 1); + if(!nptr) return -1; + st->buf = (uint8_t *)nptr; + buf = st->buf + st->size; + + /* + * Convert series of 0 and 1 into the octet string. + */ + for(; p < pend; p++) { + int ch = *(const unsigned char *)p; + int len; /* Length of the rest of the chunk */ + + if(ch != 0x26 /* '&' */) { + *buf++ = ch; + continue; /* That was easy... */ + } + + /* + * Process entity reference. + */ + len = chunk_size - (p - (const char *)chunk_buf); + if(len == 1 /* "&" */) goto want_more; + if(p[1] == 0x23 /* '#' */) { + const char *pval; /* Pointer to start of digits */ + int32_t val = 0; /* Entity reference value */ + int base; + + if(len == 2 /* "&#" */) goto want_more; + if(p[2] == 0x78 /* 'x' */) + pval = p + 3, base = 16; + else + pval = p + 2, base = 10; + len = OS__strtoent(base, pval, p + len, &val); + if(len == -1) { + /* Invalid charset. Just copy verbatim. */ + *buf++ = ch; + continue; + } + if(!len || pval[len-1] != 0x3b) goto want_more; + assert(val > 0); + p += (pval - p) + len - 1; /* Advance past entref */ + + if(val < 0x80) { + *buf++ = (char)val; + } else if(val < 0x800) { + *buf++ = 0xc0 | ((val >> 6)); + *buf++ = 0x80 | ((val & 0x3f)); + } else if(val < 0x10000) { + *buf++ = 0xe0 | ((val >> 12)); + *buf++ = 0x80 | ((val >> 6) & 0x3f); + *buf++ = 0x80 | ((val & 0x3f)); + } else if(val < 0x200000) { + *buf++ = 0xf0 | ((val >> 18)); + *buf++ = 0x80 | ((val >> 12) & 0x3f); + *buf++ = 0x80 | ((val >> 6) & 0x3f); + *buf++ = 0x80 | ((val & 0x3f)); + } else if(val < 0x4000000) { + *buf++ = 0xf8 | ((val >> 24)); + *buf++ = 0x80 | ((val >> 18) & 0x3f); + *buf++ = 0x80 | ((val >> 12) & 0x3f); + *buf++ = 0x80 | ((val >> 6) & 0x3f); + *buf++ = 0x80 | ((val & 0x3f)); + } else { + *buf++ = 0xfc | ((val >> 30) & 0x1); + *buf++ = 0x80 | ((val >> 24) & 0x3f); + *buf++ = 0x80 | ((val >> 18) & 0x3f); + *buf++ = 0x80 | ((val >> 12) & 0x3f); + *buf++ = 0x80 | ((val >> 6) & 0x3f); + *buf++ = 0x80 | ((val & 0x3f)); + } + } else { + /* + * Ugly, limited parsing of & > < + */ + char *sc = (char *)memchr(p, 0x3b, len > 5 ? 5 : len); + if(!sc) goto want_more; + if((sc - p) == 4 + && p[1] == 0x61 /* 'a' */ + && p[2] == 0x6d /* 'm' */ + && p[3] == 0x70 /* 'p' */) { + *buf++ = 0x26; + p = sc; + continue; + } + if((sc - p) == 3) { + if(p[1] == 0x6c) { + *buf = 0x3c; /* '<' */ + } else if(p[1] == 0x67) { + *buf = 0x3e; /* '>' */ + } else { + /* Unsupported entity reference */ + *buf++ = ch; + continue; + } + if(p[2] != 0x74) { + /* Unsupported entity reference */ + *buf++ = ch; + continue; + } + buf++; + p = sc; + continue; + } + /* Unsupported entity reference */ + *buf++ = ch; + } + + continue; + want_more: + if(have_more) { + /* + * We know that no more data (of the same type) + * is coming. Copy the rest verbatim. + */ + *buf++ = ch; + continue; + } + chunk_size = (p - (const char *)chunk_buf); + /* Processing stalled: need more data */ + break; + } + + st->size = buf - st->buf; + assert(st->size <= _ns); + st->buf[st->size] = 0; /* Courtesy termination */ + + return chunk_size; /* Converted in full */ +} + +/* + * Decode OCTET STRING from the XML element's body. + */ +static asn_dec_rval_t +OCTET_STRING__decode_xer(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, void **sptr, + const char *opt_mname, const void *buf_ptr, size_t size, + int (*opt_unexpected_tag_decoder) + (void *struct_ptr, const void *chunk_buf, size_t chunk_size), + ssize_t (*body_receiver) + (void *struct_ptr, const void *chunk_buf, size_t chunk_size, + int have_more) +) { + OCTET_STRING_t *st = (OCTET_STRING_t *)*sptr; + asn_OCTET_STRING_specifics_t *specs = td->specifics + ? (asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_DEF_OCTET_STRING_specs; + const char *xml_tag = opt_mname ? opt_mname : td->xml_tag; + asn_struct_ctx_t *ctx; /* Per-structure parser context */ + asn_dec_rval_t rval; /* Return value from the decoder */ + int st_allocated; + + /* + * Create the string if does not exist. + */ + if(!st) { + st = (OCTET_STRING_t *)CALLOC(1, specs->struct_size); + *sptr = (void *)st; + if(!st) goto sta_failed; + st_allocated = 1; + } else { + st_allocated = 0; + } + if(!st->buf) { + /* This is separate from above section */ + st->buf = (uint8_t *)CALLOC(1, 1); + if(!st->buf) { + if(st_allocated) { + *sptr = 0; + goto stb_failed; + } else { + goto sta_failed; + } + } + } + + /* Restore parsing context */ + ctx = (asn_struct_ctx_t *)(((char *)*sptr) + specs->ctx_offset); + + return xer_decode_general(opt_codec_ctx, ctx, *sptr, xml_tag, + buf_ptr, size, opt_unexpected_tag_decoder, body_receiver); + +stb_failed: + FREEMEM(st); +sta_failed: + rval.code = RC_FAIL; + rval.consumed = 0; + return rval; +} + +/* + * Decode OCTET STRING from the hexadecimal data. + */ +asn_dec_rval_t +OCTET_STRING_decode_xer_hex(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, void **sptr, + const char *opt_mname, const void *buf_ptr, size_t size) { + return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname, + buf_ptr, size, 0, OCTET_STRING__convert_hexadecimal); +} + +/* + * Decode OCTET STRING from the binary (0/1) data. + */ +asn_dec_rval_t +OCTET_STRING_decode_xer_binary(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, void **sptr, + const char *opt_mname, const void *buf_ptr, size_t size) { + return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname, + buf_ptr, size, 0, OCTET_STRING__convert_binary); +} + +/* + * Decode OCTET STRING from the string (ASCII/UTF-8) data. + */ +asn_dec_rval_t +OCTET_STRING_decode_xer_utf8(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, void **sptr, + const char *opt_mname, const void *buf_ptr, size_t size) { + return OCTET_STRING__decode_xer(opt_codec_ctx, td, sptr, opt_mname, + buf_ptr, size, + OCTET_STRING__handle_control_chars, + OCTET_STRING__convert_entrefs); +} + +static int +OCTET_STRING_per_get_characters(asn_per_data_t *po, uint8_t *buf, + size_t units, unsigned int bpc, unsigned int unit_bits, + long lb, long ub, asn_per_constraints_t *pc) { + uint8_t *end = buf + units * bpc; + + ASN_DEBUG("Expanding %d characters into (%ld..%ld):%d", + (int)units, lb, ub, unit_bits); + + /* X.691: 27.5.4 */ + if((unsigned long)ub <= ((unsigned long)2 << (unit_bits - 1))) { + /* Decode without translation */ + lb = 0; + } else if(pc && pc->code2value) { + if(unit_bits > 16) + return 1; /* FATAL: can't have constrained + * UniversalString with more than + * 16 million code points */ + for(; buf < end; buf += bpc) { + int value; + int code = per_get_few_bits(po, unit_bits); + if(code < 0) return -1; /* WMORE */ + value = pc->code2value(code); + if(value < 0) { + ASN_DEBUG("Code %d (0x%02x) is" + " not in map (%ld..%ld)", + code, code, lb, ub); + return 1; /* FATAL */ + } + switch(bpc) { + case 1: *buf = value; break; + case 2: buf[0] = value >> 8; buf[1] = value; break; + case 4: buf[0] = value >> 24; buf[1] = value >> 16; + buf[2] = value >> 8; buf[3] = value; break; + } + } + return 0; + } + + /* Shortcut the no-op copying to the aligned structure */ + if(lb == 0 && (unit_bits == 8 * bpc)) { + return per_get_many_bits(po, buf, 0, unit_bits * units); + } + + for(; buf < end; buf += bpc) { + int code = per_get_few_bits(po, unit_bits); + int ch = code + lb; + if(code < 0) return -1; /* WMORE */ + if(ch > ub) { + ASN_DEBUG("Code %d is out of range (%ld..%ld)", + ch, lb, ub); + return 1; /* FATAL */ + } + switch(bpc) { + case 1: *buf = ch; break; + case 2: buf[0] = ch >> 8; buf[1] = ch; break; + case 4: buf[0] = ch >> 24; buf[1] = ch >> 16; + buf[2] = ch >> 8; buf[3] = ch; break; + } + } + + return 0; +} + +static int +OCTET_STRING_per_put_characters(asn_per_outp_t *po, const uint8_t *buf, + size_t units, unsigned int bpc, unsigned int unit_bits, + long lb, long ub, asn_per_constraints_t *pc) { + const uint8_t *end = buf + units * bpc; + + ASN_DEBUG("Squeezing %d characters into (%ld..%ld):%d (%d bpc)", + (int)units, lb, ub, unit_bits, bpc); + + /* X.691: 27.5.4 */ + if((unsigned long)ub <= ((unsigned long)2 << (unit_bits - 1))) { + /* Encode as is */ + lb = 0; + } else if(pc && pc->value2code) { + for(; buf < end; buf += bpc) { + int code; + uint32_t value; + switch(bpc) { + case 1: value = *(const uint8_t *)buf; break; + case 2: value = (buf[0] << 8) | buf[1]; break; + case 4: value = (buf[0] << 24) | (buf[1] << 16) + | (buf[2] << 8) | buf[3]; break; + default: return -1; + } + code = pc->value2code(value); + if(code < 0) { + ASN_DEBUG("Character %d (0x%02x) is" + " not in map (%ld..%ld)", + *buf, *buf, lb, ub); + return -1; + } + if(per_put_few_bits(po, code, unit_bits)) + return -1; + } + } + + /* Shortcut the no-op copying to the aligned structure */ + if(lb == 0 && (unit_bits == 8 * bpc)) { + return per_put_many_bits(po, buf, unit_bits * units); + } + + for(ub -= lb; buf < end; buf += bpc) { + int ch; + uint32_t value; + switch(bpc) { + case 1: value = *(const uint8_t *)buf; break; + case 2: value = (buf[0] << 8) | buf[1]; break; + case 4: value = (buf[0] << 24) | (buf[1] << 16) + | (buf[2] << 8) | buf[3]; break; + default: return -1; + } + ch = value - lb; + if(ch < 0 || ch > ub) { + ASN_DEBUG("Character %d (0x%02x)" + " is out of range (%ld..%ld)", + *buf, *buf, lb, ub + lb); + return -1; + } + if(per_put_few_bits(po, ch, unit_bits)) + return -1; + } + + return 0; +} + +asn_dec_rval_t +OCTET_STRING_decode_uper(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, + void **sptr, asn_per_data_t *pd) { + + asn_OCTET_STRING_specifics_t *specs = td->specifics + ? (asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_DEF_OCTET_STRING_specs; + asn_per_constraints_t *pc = constraints ? constraints + : td->per_constraints; + asn_per_constraint_t *cval; + asn_per_constraint_t *csiz; + asn_dec_rval_t rval = { RC_OK, 0 }; + BIT_STRING_t *st = (BIT_STRING_t *)*sptr; + ssize_t consumed_myself = 0; + int repeat; + enum { + OS__BPC_BIT = 0, + OS__BPC_CHAR = 1, + OS__BPC_U16 = 2, + OS__BPC_U32 = 4 + } bpc; /* Bytes per character */ + unsigned int unit_bits; + unsigned int canonical_unit_bits; + + (void)opt_codec_ctx; + + if(pc) { + cval = &pc->value; + csiz = &pc->size; + } else { + cval = &asn_DEF_OCTET_STRING_constraints.value; + csiz = &asn_DEF_OCTET_STRING_constraints.size; + } + + switch(specs->subvariant) { + default: + case ASN_OSUBV_ANY: + ASN_DEBUG("Unrecognized subvariant %d", specs->subvariant); + RETURN(RC_FAIL); + case ASN_OSUBV_BIT: + canonical_unit_bits = unit_bits = 1; + bpc = OS__BPC_BIT; + break; + case ASN_OSUBV_STR: + canonical_unit_bits = unit_bits = 8; + if(cval->flags & APC_CONSTRAINED) + unit_bits = cval->range_bits; + bpc = OS__BPC_CHAR; + break; + case ASN_OSUBV_U16: + canonical_unit_bits = unit_bits = 16; + if(cval->flags & APC_CONSTRAINED) + unit_bits = cval->range_bits; + bpc = OS__BPC_U16; + break; + case ASN_OSUBV_U32: + canonical_unit_bits = unit_bits = 32; + if(cval->flags & APC_CONSTRAINED) + unit_bits = cval->range_bits; + bpc = OS__BPC_U32; + break; + } + + /* + * Allocate the string. + */ + if(!st) { + st = (BIT_STRING_t *)(*sptr = CALLOC(1, specs->struct_size)); + if(!st) RETURN(RC_FAIL); + } + + ASN_DEBUG("PER Decoding %s size %ld .. %ld bits %d", + csiz->flags & APC_EXTENSIBLE ? "extensible" : "non-extensible", + csiz->lower_bound, csiz->upper_bound, csiz->effective_bits); + + if(csiz->flags & APC_EXTENSIBLE) { + int inext = per_get_few_bits(pd, 1); + if(inext < 0) RETURN(RC_WMORE); + if(inext) { + csiz = &asn_DEF_OCTET_STRING_constraints.size; + cval = &asn_DEF_OCTET_STRING_constraints.value; + unit_bits = canonical_unit_bits; + } + } + + if(csiz->effective_bits >= 0) { + FREEMEM(st->buf); + if(bpc) { + st->size = csiz->upper_bound * bpc; + } else { + st->size = (csiz->upper_bound + 7) >> 3; + } + st->buf = (uint8_t *)MALLOC(st->size + 1); + if(!st->buf) { st->size = 0; RETURN(RC_FAIL); } + } + + /* X.691, #16.5: zero-length encoding */ + /* X.691, #16.6: short fixed length encoding (up to 2 octets) */ + /* X.691, #16.7: long fixed length encoding (up to 64K octets) */ + if(csiz->effective_bits == 0) { + int ret; + if(bpc) { + ASN_DEBUG("Encoding OCTET STRING size %ld", + csiz->upper_bound); + ret = OCTET_STRING_per_get_characters(pd, st->buf, + csiz->upper_bound, bpc, unit_bits, + cval->lower_bound, cval->upper_bound, pc); + if(ret > 0) RETURN(RC_FAIL); + } else { + ASN_DEBUG("Encoding BIT STRING size %ld", + csiz->upper_bound); + ret = per_get_many_bits(pd, st->buf, 0, + unit_bits * csiz->upper_bound); + } + if(ret < 0) RETURN(RC_WMORE); + consumed_myself += unit_bits * csiz->upper_bound; + st->buf[st->size] = 0; + if(bpc == 0) { + int ubs = (csiz->upper_bound & 0x7); + st->bits_unused = ubs ? 8 - ubs : 0; + } + RETURN(RC_OK); + } + + st->size = 0; + do { + ssize_t raw_len; + ssize_t len_bytes; + ssize_t len_bits; + void *p; + int ret; + + /* Get the PER length */ + raw_len = uper_get_length(pd, csiz->effective_bits, &repeat); + if(raw_len < 0) RETURN(RC_WMORE); + raw_len += csiz->lower_bound; + + ASN_DEBUG("Got PER length eb %ld, len %ld, %s (%s)", + (long)csiz->effective_bits, (long)raw_len, + repeat ? "repeat" : "once", td->name); + if(bpc) { + len_bytes = raw_len * bpc; + len_bits = len_bytes * unit_bits; + } else { + len_bits = raw_len; + len_bytes = (len_bits + 7) >> 3; + if(len_bits & 0x7) + st->bits_unused = 8 - (len_bits & 0x7); + /* len_bits be multiple of 16K if repeat is set */ + } + p = REALLOC(st->buf, st->size + len_bytes + 1); + if(!p) RETURN(RC_FAIL); + st->buf = (uint8_t *)p; + + if(bpc) { + ret = OCTET_STRING_per_get_characters(pd, + &st->buf[st->size], raw_len, bpc, unit_bits, + cval->lower_bound, cval->upper_bound, pc); + if(ret > 0) RETURN(RC_FAIL); + } else { + ret = per_get_many_bits(pd, &st->buf[st->size], + 0, len_bits); + } + if(ret < 0) RETURN(RC_WMORE); + st->size += len_bytes; + } while(repeat); + st->buf[st->size] = 0; /* nul-terminate */ + + return rval; +} + +asn_enc_rval_t +OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + + asn_OCTET_STRING_specifics_t *specs = td->specifics + ? (asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_DEF_OCTET_STRING_specs; + asn_per_constraints_t *pc = constraints ? constraints + : td->per_constraints; + asn_per_constraint_t *cval; + asn_per_constraint_t *csiz; + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + asn_enc_rval_t er = { 0, 0, 0 }; + int inext = 0; /* Lies not within extension root */ + unsigned int unit_bits; + unsigned int canonical_unit_bits; + unsigned int sizeinunits; + const uint8_t *buf; + int ret; + enum { + OS__BPC_BIT = 0, + OS__BPC_CHAR = 1, + OS__BPC_U16 = 2, + OS__BPC_U32 = 4 + } bpc; /* Bytes per character */ + int ct_extensible; + + if(!st || (!st->buf && st->size)) + ASN__ENCODE_FAILED; + + if(pc) { + cval = &pc->value; + csiz = &pc->size; + } else { + cval = &asn_DEF_OCTET_STRING_constraints.value; + csiz = &asn_DEF_OCTET_STRING_constraints.size; + } + ct_extensible = csiz->flags & APC_EXTENSIBLE; + + switch(specs->subvariant) { + default: + case ASN_OSUBV_ANY: + ASN__ENCODE_FAILED; + case ASN_OSUBV_BIT: + canonical_unit_bits = unit_bits = 1; + bpc = OS__BPC_BIT; + sizeinunits = st->size * 8 - (st->bits_unused & 0x07); + ASN_DEBUG("BIT STRING of %d bytes, %d bits unused", + sizeinunits, st->bits_unused); + break; + case ASN_OSUBV_STR: + canonical_unit_bits = unit_bits = 8; + if(cval->flags & APC_CONSTRAINED) + unit_bits = cval->range_bits; + bpc = OS__BPC_CHAR; + sizeinunits = st->size; + break; + case ASN_OSUBV_U16: + canonical_unit_bits = unit_bits = 16; + if(cval->flags & APC_CONSTRAINED) + unit_bits = cval->range_bits; + bpc = OS__BPC_U16; + sizeinunits = st->size / 2; + break; + case ASN_OSUBV_U32: + canonical_unit_bits = unit_bits = 32; + if(cval->flags & APC_CONSTRAINED) + unit_bits = cval->range_bits; + bpc = OS__BPC_U32; + sizeinunits = st->size / 4; + break; + } + + ASN_DEBUG("Encoding %s into %d units of %d bits" + " (%ld..%ld, effective %d)%s", + td->name, sizeinunits, unit_bits, + csiz->lower_bound, csiz->upper_bound, + csiz->effective_bits, ct_extensible ? " EXT" : ""); + + /* Figure out whether size lies within PER visible constraint */ + + if(csiz->effective_bits >= 0) { + if((int)sizeinunits < csiz->lower_bound + || (int)sizeinunits > csiz->upper_bound) { + if(ct_extensible) { + cval = &asn_DEF_OCTET_STRING_constraints.value; + csiz = &asn_DEF_OCTET_STRING_constraints.size; + unit_bits = canonical_unit_bits; + inext = 1; + } else + ASN__ENCODE_FAILED; + } + } else { + inext = 0; + } + + if(ct_extensible) { + /* Declare whether length is [not] within extension root */ + if(per_put_few_bits(po, inext, 1)) + ASN__ENCODE_FAILED; + } + + /* X.691, #16.5: zero-length encoding */ + /* X.691, #16.6: short fixed length encoding (up to 2 octets) */ + /* X.691, #16.7: long fixed length encoding (up to 64K octets) */ + if(csiz->effective_bits >= 0) { + ASN_DEBUG("Encoding %d bytes (%ld), length in %d bits", + st->size, sizeinunits - csiz->lower_bound, + csiz->effective_bits); + ret = per_put_few_bits(po, sizeinunits - csiz->lower_bound, + csiz->effective_bits); + if(ret) ASN__ENCODE_FAILED; + if(bpc) { + ret = OCTET_STRING_per_put_characters(po, st->buf, + sizeinunits, bpc, unit_bits, + cval->lower_bound, cval->upper_bound, pc); + } else { + ret = per_put_many_bits(po, st->buf, + sizeinunits * unit_bits); + } + if(ret) ASN__ENCODE_FAILED; + ASN__ENCODED_OK(er); + } + + ASN_DEBUG("Encoding %d bytes", st->size); + + if(sizeinunits == 0) { + if(uper_put_length(po, 0)) + ASN__ENCODE_FAILED; + ASN__ENCODED_OK(er); + } + + buf = st->buf; + while(sizeinunits) { + ssize_t maySave = uper_put_length(po, sizeinunits); + if(maySave < 0) ASN__ENCODE_FAILED; + + ASN_DEBUG("Encoding %ld of %ld", + (long)maySave, (long)sizeinunits); + + if(bpc) { + ret = OCTET_STRING_per_put_characters(po, buf, + maySave, bpc, unit_bits, + cval->lower_bound, cval->upper_bound, pc); + } else { + ret = per_put_many_bits(po, buf, maySave * unit_bits); + } + if(ret) ASN__ENCODE_FAILED; + + if(bpc) + buf += maySave * bpc; + else + buf += maySave >> 3; + sizeinunits -= maySave; + assert(!(maySave & 0x07) || !sizeinunits); + } + + ASN__ENCODED_OK(er); +} + +int +OCTET_STRING_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, + asn_app_consume_bytes_f *cb, void *app_key) { + const char * const h2c = "0123456789ABCDEF"; + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + char scratch[16 * 3 + 4]; + char *p = scratch; + uint8_t *buf; + uint8_t *end; + size_t i; + + (void)td; /* Unused argument */ + + if(!st || (!st->buf && st->size)) + return (cb("", 8, app_key) < 0) ? -1 : 0; + + /* + * Dump the contents of the buffer in hexadecimal. + */ + buf = st->buf; + end = buf + st->size; + for(i = 0; buf < end; buf++, i++) { + if(!(i % 16) && (i || st->size > 16)) { + if(cb(scratch, p - scratch, app_key) < 0) + return -1; + _i_INDENT(1); + p = scratch; + } + *p++ = h2c[(*buf >> 4) & 0x0F]; + *p++ = h2c[*buf & 0x0F]; + *p++ = 0x20; + } + + if(p > scratch) { + p--; /* Remove the tail space */ + if(cb(scratch, p - scratch, app_key) < 0) + return -1; + } + + return 0; +} + +int +OCTET_STRING_print_utf8(asn_TYPE_descriptor_t *td, const void *sptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + + (void)td; /* Unused argument */ + (void)ilevel; /* Unused argument */ + + if(st && (st->buf || !st->size)) { + return (cb(st->buf, st->size, app_key) < 0) ? -1 : 0; + } else { + return (cb("", 8, app_key) < 0) ? -1 : 0; + } +} + +void +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; + struct _stack *stck; + + if(!td || !st) + return; + + specs = td->specifics + ? (asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_DEF_OCTET_STRING_specs; + ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); + + ASN_DEBUG("Freeing %s as OCTET STRING", td->name); + + if(st->buf) { + FREEMEM(st->buf); + st->buf = 0; + } + + /* + * Remove decode-time stack. + */ + stck = (struct _stack *)ctx->ptr; + if(stck) { + while(stck->tail) { + struct _stack_el *sel = stck->tail; + stck->tail = sel->prev; + FREEMEM(sel); + } + FREEMEM(stck); + } + + if(!contents_only) { + FREEMEM(st); + } +} + +/* + * Conversion routines. + */ +int +OCTET_STRING_fromBuf(OCTET_STRING_t *st, const char *str, int len) { + void *buf; + + if(st == 0 || (str == 0 && len)) { + errno = EINVAL; + return -1; + } + + /* + * Clear the OCTET STRING. + */ + if(str == NULL) { + FREEMEM(st->buf); + st->buf = 0; + st->size = 0; + return 0; + } + + /* Determine the original string size, if not explicitly given */ + if(len < 0) + len = strlen(str); + + /* Allocate and fill the memory */ + buf = MALLOC(len + 1); + if(buf == NULL) + return -1; + + memcpy(buf, str, len); + ((uint8_t *)buf)[len] = '\0'; /* Couldn't use memcpy(len+1)! */ + FREEMEM(st->buf); + st->buf = (uint8_t *)buf; + st->size = len; + + return 0; +} + +OCTET_STRING_t * +OCTET_STRING_new_fromBuf(asn_TYPE_descriptor_t *td, const char *str, int len) { + asn_OCTET_STRING_specifics_t *specs = td->specifics + ? (asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_DEF_OCTET_STRING_specs; + OCTET_STRING_t *st; + + st = (OCTET_STRING_t *)CALLOC(1, specs->struct_size); + if(st && str && OCTET_STRING_fromBuf(st, str, len)) { + FREEMEM(st); + st = NULL; + } + + return st; +} + diff --git a/src/cryptoconditions/src/asn/OCTET_STRING.h b/src/cryptoconditions/src/asn/OCTET_STRING.h new file mode 100644 index 000000000..013c7b13f --- /dev/null +++ b/src/cryptoconditions/src/asn/OCTET_STRING.h @@ -0,0 +1,86 @@ +/*- + * Copyright (c) 2003 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _OCTET_STRING_H_ +#define _OCTET_STRING_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct OCTET_STRING { + uint8_t *buf; /* Buffer with consecutive OCTET_STRING bits */ + int size; /* Size of the buffer */ + + asn_struct_ctx_t _asn_ctx; /* Parsing across buffer boundaries */ +} OCTET_STRING_t; + +extern asn_TYPE_descriptor_t asn_DEF_OCTET_STRING; + +asn_struct_free_f OCTET_STRING_free; +asn_struct_print_f OCTET_STRING_print; +asn_struct_print_f OCTET_STRING_print_utf8; +ber_type_decoder_f OCTET_STRING_decode_ber; +der_type_encoder_f OCTET_STRING_encode_der; +xer_type_decoder_f OCTET_STRING_decode_xer_hex; /* Hexadecimal */ +xer_type_decoder_f OCTET_STRING_decode_xer_binary; /* 01010111010 */ +xer_type_decoder_f OCTET_STRING_decode_xer_utf8; /* ASCII/UTF-8 */ +xer_type_encoder_f OCTET_STRING_encode_xer; +xer_type_encoder_f OCTET_STRING_encode_xer_utf8; +per_type_decoder_f OCTET_STRING_decode_uper; +per_type_encoder_f OCTET_STRING_encode_uper; + +/****************************** + * Handy conversion routines. * + ******************************/ + +/* + * This function clears the previous value of the OCTET STRING (if any) + * and then allocates a new memory with the specified content (str/size). + * If size = -1, the size of the original string will be determined + * using strlen(str). + * If str equals to NULL, the function will silently clear the + * current contents of the OCTET STRING. + * Returns 0 if it was possible to perform operation, -1 otherwise. + */ +int OCTET_STRING_fromBuf(OCTET_STRING_t *s, const char *str, int size); + +/* Handy conversion from the C string into the OCTET STRING. */ +#define OCTET_STRING_fromString(s, str) OCTET_STRING_fromBuf(s, str, -1) + +/* + * Allocate and fill the new OCTET STRING and return a pointer to the newly + * allocated object. NULL is permitted in str: the function will just allocate + * empty OCTET STRING. + */ +OCTET_STRING_t *OCTET_STRING_new_fromBuf(asn_TYPE_descriptor_t *td, + const char *str, int size); + +/**************************** + * Internally useful stuff. * + ****************************/ + +typedef const struct asn_OCTET_STRING_specifics_s { + /* + * Target structure description. + */ + int struct_size; /* Size of the structure */ + int ctx_offset; /* Offset of the asn_struct_ctx_t member */ + + enum asn_OS_Subvariant { + ASN_OSUBV_ANY, /* The open type (ANY) */ + ASN_OSUBV_BIT, /* BIT STRING */ + ASN_OSUBV_STR, /* String types, not {BMP,Universal}String */ + ASN_OSUBV_U16, /* 16-bit character (BMPString) */ + ASN_OSUBV_U32 /* 32-bit character (UniversalString) */ + } subvariant; +} asn_OCTET_STRING_specifics_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _OCTET_STRING_H_ */ diff --git a/src/cryptoconditions/src/asn/PrefixFingerprintContents.c b/src/cryptoconditions/src/asn/PrefixFingerprintContents.c new file mode 100644 index 000000000..13f54aaa1 --- /dev/null +++ b/src/cryptoconditions/src/asn/PrefixFingerprintContents.c @@ -0,0 +1,209 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#include "PrefixFingerprintContents.h" + +static int +maxMessageLength_3_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + + if(!sptr) { + ASN__CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + + /* Constraint check succeeded */ + return 0; +} + +/* + * This type is implemented using NativeInteger, + * so here we adjust the DEF accordingly. + */ +static void +maxMessageLength_3_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { + td->free_struct = asn_DEF_NativeInteger.free_struct; + td->print_struct = asn_DEF_NativeInteger.print_struct; + td->check_constraints = asn_DEF_NativeInteger.check_constraints; + td->ber_decoder = asn_DEF_NativeInteger.ber_decoder; + td->der_encoder = asn_DEF_NativeInteger.der_encoder; + td->xer_decoder = asn_DEF_NativeInteger.xer_decoder; + td->xer_encoder = asn_DEF_NativeInteger.xer_encoder; + td->uper_decoder = asn_DEF_NativeInteger.uper_decoder; + td->uper_encoder = asn_DEF_NativeInteger.uper_encoder; + if(!td->per_constraints) + td->per_constraints = asn_DEF_NativeInteger.per_constraints; + td->elements = asn_DEF_NativeInteger.elements; + td->elements_count = asn_DEF_NativeInteger.elements_count; + /* td->specifics = asn_DEF_NativeInteger.specifics; // Defined explicitly */ +} + +static void +maxMessageLength_3_free(asn_TYPE_descriptor_t *td, + void *struct_ptr, int contents_only) { + maxMessageLength_3_inherit_TYPE_descriptor(td); + td->free_struct(td, struct_ptr, contents_only); +} + +static int +maxMessageLength_3_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + maxMessageLength_3_inherit_TYPE_descriptor(td); + return td->print_struct(td, struct_ptr, ilevel, cb, app_key); +} + +static asn_dec_rval_t +maxMessageLength_3_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const void *bufptr, size_t size, int tag_mode) { + maxMessageLength_3_inherit_TYPE_descriptor(td); + return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); +} + +static asn_enc_rval_t +maxMessageLength_3_encode_der(asn_TYPE_descriptor_t *td, + void *structure, int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + maxMessageLength_3_inherit_TYPE_descriptor(td); + return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); +} + +static asn_dec_rval_t +maxMessageLength_3_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const char *opt_mname, const void *bufptr, size_t size) { + maxMessageLength_3_inherit_TYPE_descriptor(td); + return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); +} + +static asn_enc_rval_t +maxMessageLength_3_encode_xer(asn_TYPE_descriptor_t *td, void *structure, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + maxMessageLength_3_inherit_TYPE_descriptor(td); + return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); +} + +static int +memb_maxMessageLength_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + + if(!sptr) { + ASN__CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + + /* Constraint check succeeded */ + return 0; +} + +static const asn_INTEGER_specifics_t asn_SPC_maxMessageLength_specs_3 = { + 0, 0, 0, 0, 0, + 0, /* Native long size */ + 1 /* Unsigned representation */ +}; +static const ber_tlv_tag_t asn_DEF_maxMessageLength_tags_3[] = { + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)) +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_maxMessageLength_3 = { + "maxMessageLength", + "maxMessageLength", + maxMessageLength_3_free, + maxMessageLength_3_print, + maxMessageLength_3_constraint, + maxMessageLength_3_decode_ber, + maxMessageLength_3_encode_der, + maxMessageLength_3_decode_xer, + maxMessageLength_3_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_maxMessageLength_tags_3, + sizeof(asn_DEF_maxMessageLength_tags_3) + /sizeof(asn_DEF_maxMessageLength_tags_3[0]) - 1, /* 1 */ + asn_DEF_maxMessageLength_tags_3, /* Same as above */ + sizeof(asn_DEF_maxMessageLength_tags_3) + /sizeof(asn_DEF_maxMessageLength_tags_3[0]), /* 2 */ + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + &asn_SPC_maxMessageLength_specs_3 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_PrefixFingerprintContents_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct PrefixFingerprintContents, prefix), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "prefix" + }, + { ATF_NOFLAGS, 0, offsetof(struct PrefixFingerprintContents, maxMessageLength), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_maxMessageLength_3, + memb_maxMessageLength_constraint_1, + 0, /* PER is not compiled, use -gen-PER */ + 0, + "maxMessageLength" + }, + { ATF_NOFLAGS, 0, offsetof(struct PrefixFingerprintContents, subcondition), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + +1, /* EXPLICIT tag at current level */ + &asn_DEF_Condition, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "subcondition" + }, +}; +static const ber_tlv_tag_t asn_DEF_PrefixFingerprintContents_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static const asn_TYPE_tag2member_t asn_MAP_PrefixFingerprintContents_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* prefix */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* maxMessageLength */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* subcondition */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_PrefixFingerprintContents_specs_1 = { + sizeof(struct PrefixFingerprintContents), + offsetof(struct PrefixFingerprintContents, _asn_ctx), + asn_MAP_PrefixFingerprintContents_tag2el_1, + 3, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_PrefixFingerprintContents = { + "PrefixFingerprintContents", + "PrefixFingerprintContents", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_PrefixFingerprintContents_tags_1, + sizeof(asn_DEF_PrefixFingerprintContents_tags_1) + /sizeof(asn_DEF_PrefixFingerprintContents_tags_1[0]), /* 1 */ + asn_DEF_PrefixFingerprintContents_tags_1, /* Same as above */ + sizeof(asn_DEF_PrefixFingerprintContents_tags_1) + /sizeof(asn_DEF_PrefixFingerprintContents_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_PrefixFingerprintContents_1, + 3, /* Elements count */ + &asn_SPC_PrefixFingerprintContents_specs_1 /* Additional specs */ +}; + diff --git a/src/cryptoconditions/src/asn/PrefixFingerprintContents.h b/src/cryptoconditions/src/asn/PrefixFingerprintContents.h new file mode 100644 index 000000000..5d1254cd4 --- /dev/null +++ b/src/cryptoconditions/src/asn/PrefixFingerprintContents.h @@ -0,0 +1,42 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#ifndef _PrefixFingerprintContents_H_ +#define _PrefixFingerprintContents_H_ + + +#include + +/* Including external dependencies */ +#include +#include +#include "Condition.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* PrefixFingerprintContents */ +typedef struct PrefixFingerprintContents { + OCTET_STRING_t prefix; + unsigned long maxMessageLength; + Condition_t subcondition; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} PrefixFingerprintContents_t; + +/* Implementation */ +/* extern asn_TYPE_descriptor_t asn_DEF_maxMessageLength_3; // (Use -fall-defs-global to expose) */ +extern asn_TYPE_descriptor_t asn_DEF_PrefixFingerprintContents; + +#ifdef __cplusplus +} +#endif + +#endif /* _PrefixFingerprintContents_H_ */ +#include diff --git a/src/cryptoconditions/src/asn/PrefixFulfillment.c b/src/cryptoconditions/src/asn/PrefixFulfillment.c new file mode 100644 index 000000000..f4c854807 --- /dev/null +++ b/src/cryptoconditions/src/asn/PrefixFulfillment.c @@ -0,0 +1,209 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#include "PrefixFulfillment.h" + +static int +maxMessageLength_3_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + + if(!sptr) { + ASN__CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + + /* Constraint check succeeded */ + return 0; +} + +/* + * This type is implemented using NativeInteger, + * so here we adjust the DEF accordingly. + */ +static void +maxMessageLength_3_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { + td->free_struct = asn_DEF_NativeInteger.free_struct; + td->print_struct = asn_DEF_NativeInteger.print_struct; + td->check_constraints = asn_DEF_NativeInteger.check_constraints; + td->ber_decoder = asn_DEF_NativeInteger.ber_decoder; + td->der_encoder = asn_DEF_NativeInteger.der_encoder; + td->xer_decoder = asn_DEF_NativeInteger.xer_decoder; + td->xer_encoder = asn_DEF_NativeInteger.xer_encoder; + td->uper_decoder = asn_DEF_NativeInteger.uper_decoder; + td->uper_encoder = asn_DEF_NativeInteger.uper_encoder; + if(!td->per_constraints) + td->per_constraints = asn_DEF_NativeInteger.per_constraints; + td->elements = asn_DEF_NativeInteger.elements; + td->elements_count = asn_DEF_NativeInteger.elements_count; + /* td->specifics = asn_DEF_NativeInteger.specifics; // Defined explicitly */ +} + +static void +maxMessageLength_3_free(asn_TYPE_descriptor_t *td, + void *struct_ptr, int contents_only) { + maxMessageLength_3_inherit_TYPE_descriptor(td); + td->free_struct(td, struct_ptr, contents_only); +} + +static int +maxMessageLength_3_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + maxMessageLength_3_inherit_TYPE_descriptor(td); + return td->print_struct(td, struct_ptr, ilevel, cb, app_key); +} + +static asn_dec_rval_t +maxMessageLength_3_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const void *bufptr, size_t size, int tag_mode) { + maxMessageLength_3_inherit_TYPE_descriptor(td); + return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); +} + +static asn_enc_rval_t +maxMessageLength_3_encode_der(asn_TYPE_descriptor_t *td, + void *structure, int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + maxMessageLength_3_inherit_TYPE_descriptor(td); + return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); +} + +static asn_dec_rval_t +maxMessageLength_3_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const char *opt_mname, const void *bufptr, size_t size) { + maxMessageLength_3_inherit_TYPE_descriptor(td); + return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); +} + +static asn_enc_rval_t +maxMessageLength_3_encode_xer(asn_TYPE_descriptor_t *td, void *structure, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + maxMessageLength_3_inherit_TYPE_descriptor(td); + return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); +} + +static int +memb_maxMessageLength_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + + if(!sptr) { + ASN__CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + + /* Constraint check succeeded */ + return 0; +} + +static const asn_INTEGER_specifics_t asn_SPC_maxMessageLength_specs_3 = { + 0, 0, 0, 0, 0, + 0, /* Native long size */ + 1 /* Unsigned representation */ +}; +static const ber_tlv_tag_t asn_DEF_maxMessageLength_tags_3[] = { + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)) +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_maxMessageLength_3 = { + "maxMessageLength", + "maxMessageLength", + maxMessageLength_3_free, + maxMessageLength_3_print, + maxMessageLength_3_constraint, + maxMessageLength_3_decode_ber, + maxMessageLength_3_encode_der, + maxMessageLength_3_decode_xer, + maxMessageLength_3_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_maxMessageLength_tags_3, + sizeof(asn_DEF_maxMessageLength_tags_3) + /sizeof(asn_DEF_maxMessageLength_tags_3[0]) - 1, /* 1 */ + asn_DEF_maxMessageLength_tags_3, /* Same as above */ + sizeof(asn_DEF_maxMessageLength_tags_3) + /sizeof(asn_DEF_maxMessageLength_tags_3[0]), /* 2 */ + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + &asn_SPC_maxMessageLength_specs_3 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_PrefixFulfillment_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct PrefixFulfillment, prefix), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "prefix" + }, + { ATF_NOFLAGS, 0, offsetof(struct PrefixFulfillment, maxMessageLength), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_maxMessageLength_3, + memb_maxMessageLength_constraint_1, + 0, /* PER is not compiled, use -gen-PER */ + 0, + "maxMessageLength" + }, + { ATF_POINTER, 0, offsetof(struct PrefixFulfillment, subfulfillment), + (ASN_TAG_CLASS_CONTEXT | (2 << 2)), + +1, /* EXPLICIT tag at current level */ + &asn_DEF_Fulfillment, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "subfulfillment" + }, +}; +static const ber_tlv_tag_t asn_DEF_PrefixFulfillment_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static const asn_TYPE_tag2member_t asn_MAP_PrefixFulfillment_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* prefix */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* maxMessageLength */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* subfulfillment */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_PrefixFulfillment_specs_1 = { + sizeof(struct PrefixFulfillment), + offsetof(struct PrefixFulfillment, _asn_ctx), + asn_MAP_PrefixFulfillment_tag2el_1, + 3, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_PrefixFulfillment = { + "PrefixFulfillment", + "PrefixFulfillment", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_PrefixFulfillment_tags_1, + sizeof(asn_DEF_PrefixFulfillment_tags_1) + /sizeof(asn_DEF_PrefixFulfillment_tags_1[0]), /* 1 */ + asn_DEF_PrefixFulfillment_tags_1, /* Same as above */ + sizeof(asn_DEF_PrefixFulfillment_tags_1) + /sizeof(asn_DEF_PrefixFulfillment_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_PrefixFulfillment_1, + 3, /* Elements count */ + &asn_SPC_PrefixFulfillment_specs_1 /* Additional specs */ +}; + diff --git a/src/cryptoconditions/src/asn/PrefixFulfillment.h b/src/cryptoconditions/src/asn/PrefixFulfillment.h new file mode 100644 index 000000000..1c06cbc8d --- /dev/null +++ b/src/cryptoconditions/src/asn/PrefixFulfillment.h @@ -0,0 +1,47 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#ifndef _PrefixFulfillment_H_ +#define _PrefixFulfillment_H_ + + +#include + +/* Including external dependencies */ +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward declarations */ +struct Fulfillment; + +/* PrefixFulfillment */ +typedef struct PrefixFulfillment { + OCTET_STRING_t prefix; + unsigned long maxMessageLength; + struct Fulfillment *subfulfillment; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} PrefixFulfillment_t; + +/* Implementation */ +/* extern asn_TYPE_descriptor_t asn_DEF_maxMessageLength_3; // (Use -fall-defs-global to expose) */ +extern asn_TYPE_descriptor_t asn_DEF_PrefixFulfillment; + +#ifdef __cplusplus +} +#endif + +/* Referred external types */ +#include "Fulfillment.h" + +#endif /* _PrefixFulfillment_H_ */ +#include diff --git a/src/cryptoconditions/src/asn/PreimageFulfillment.c b/src/cryptoconditions/src/asn/PreimageFulfillment.c new file mode 100644 index 000000000..e7b918824 --- /dev/null +++ b/src/cryptoconditions/src/asn/PreimageFulfillment.c @@ -0,0 +1,58 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#include "PreimageFulfillment.h" + +static asn_TYPE_member_t asn_MBR_PreimageFulfillment_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct PreimageFulfillment, preimage), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "preimage" + }, +}; +static const ber_tlv_tag_t asn_DEF_PreimageFulfillment_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static const asn_TYPE_tag2member_t asn_MAP_PreimageFulfillment_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 } /* preimage */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_PreimageFulfillment_specs_1 = { + sizeof(struct PreimageFulfillment), + offsetof(struct PreimageFulfillment, _asn_ctx), + asn_MAP_PreimageFulfillment_tag2el_1, + 1, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_PreimageFulfillment = { + "PreimageFulfillment", + "PreimageFulfillment", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_PreimageFulfillment_tags_1, + sizeof(asn_DEF_PreimageFulfillment_tags_1) + /sizeof(asn_DEF_PreimageFulfillment_tags_1[0]), /* 1 */ + asn_DEF_PreimageFulfillment_tags_1, /* Same as above */ + sizeof(asn_DEF_PreimageFulfillment_tags_1) + /sizeof(asn_DEF_PreimageFulfillment_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_PreimageFulfillment_1, + 1, /* Elements count */ + &asn_SPC_PreimageFulfillment_specs_1 /* Additional specs */ +}; + diff --git a/src/cryptoconditions/src/asn/PreimageFulfillment.h b/src/cryptoconditions/src/asn/PreimageFulfillment.h new file mode 100644 index 000000000..04df5bd3b --- /dev/null +++ b/src/cryptoconditions/src/asn/PreimageFulfillment.h @@ -0,0 +1,37 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#ifndef _PreimageFulfillment_H_ +#define _PreimageFulfillment_H_ + + +#include + +/* Including external dependencies */ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* PreimageFulfillment */ +typedef struct PreimageFulfillment { + OCTET_STRING_t preimage; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} PreimageFulfillment_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_PreimageFulfillment; + +#ifdef __cplusplus +} +#endif + +#endif /* _PreimageFulfillment_H_ */ +#include diff --git a/src/cryptoconditions/src/asn/RsaFingerprintContents.c b/src/cryptoconditions/src/asn/RsaFingerprintContents.c new file mode 100644 index 000000000..63d9f5296 --- /dev/null +++ b/src/cryptoconditions/src/asn/RsaFingerprintContents.c @@ -0,0 +1,58 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#include "RsaFingerprintContents.h" + +static asn_TYPE_member_t asn_MBR_RsaFingerprintContents_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct RsaFingerprintContents, modulus), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "modulus" + }, +}; +static const ber_tlv_tag_t asn_DEF_RsaFingerprintContents_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static const asn_TYPE_tag2member_t asn_MAP_RsaFingerprintContents_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 } /* modulus */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_RsaFingerprintContents_specs_1 = { + sizeof(struct RsaFingerprintContents), + offsetof(struct RsaFingerprintContents, _asn_ctx), + asn_MAP_RsaFingerprintContents_tag2el_1, + 1, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_RsaFingerprintContents = { + "RsaFingerprintContents", + "RsaFingerprintContents", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_RsaFingerprintContents_tags_1, + sizeof(asn_DEF_RsaFingerprintContents_tags_1) + /sizeof(asn_DEF_RsaFingerprintContents_tags_1[0]), /* 1 */ + asn_DEF_RsaFingerprintContents_tags_1, /* Same as above */ + sizeof(asn_DEF_RsaFingerprintContents_tags_1) + /sizeof(asn_DEF_RsaFingerprintContents_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_RsaFingerprintContents_1, + 1, /* Elements count */ + &asn_SPC_RsaFingerprintContents_specs_1 /* Additional specs */ +}; + diff --git a/src/cryptoconditions/src/asn/RsaFingerprintContents.h b/src/cryptoconditions/src/asn/RsaFingerprintContents.h new file mode 100644 index 000000000..8637cd911 --- /dev/null +++ b/src/cryptoconditions/src/asn/RsaFingerprintContents.h @@ -0,0 +1,37 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#ifndef _RsaFingerprintContents_H_ +#define _RsaFingerprintContents_H_ + + +#include + +/* Including external dependencies */ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* RsaFingerprintContents */ +typedef struct RsaFingerprintContents { + OCTET_STRING_t modulus; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} RsaFingerprintContents_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_RsaFingerprintContents; + +#ifdef __cplusplus +} +#endif + +#endif /* _RsaFingerprintContents_H_ */ +#include diff --git a/src/cryptoconditions/src/asn/RsaSha256Fulfillment.c b/src/cryptoconditions/src/asn/RsaSha256Fulfillment.c new file mode 100644 index 000000000..3072a6bea --- /dev/null +++ b/src/cryptoconditions/src/asn/RsaSha256Fulfillment.c @@ -0,0 +1,68 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#include "RsaSha256Fulfillment.h" + +static asn_TYPE_member_t asn_MBR_RsaSha256Fulfillment_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct RsaSha256Fulfillment, modulus), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "modulus" + }, + { ATF_NOFLAGS, 0, offsetof(struct RsaSha256Fulfillment, signature), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "signature" + }, +}; +static const ber_tlv_tag_t asn_DEF_RsaSha256Fulfillment_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static const asn_TYPE_tag2member_t asn_MAP_RsaSha256Fulfillment_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* modulus */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* signature */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_RsaSha256Fulfillment_specs_1 = { + sizeof(struct RsaSha256Fulfillment), + offsetof(struct RsaSha256Fulfillment, _asn_ctx), + asn_MAP_RsaSha256Fulfillment_tag2el_1, + 2, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_RsaSha256Fulfillment = { + "RsaSha256Fulfillment", + "RsaSha256Fulfillment", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_RsaSha256Fulfillment_tags_1, + sizeof(asn_DEF_RsaSha256Fulfillment_tags_1) + /sizeof(asn_DEF_RsaSha256Fulfillment_tags_1[0]), /* 1 */ + asn_DEF_RsaSha256Fulfillment_tags_1, /* Same as above */ + sizeof(asn_DEF_RsaSha256Fulfillment_tags_1) + /sizeof(asn_DEF_RsaSha256Fulfillment_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_RsaSha256Fulfillment_1, + 2, /* Elements count */ + &asn_SPC_RsaSha256Fulfillment_specs_1 /* Additional specs */ +}; + diff --git a/src/cryptoconditions/src/asn/RsaSha256Fulfillment.h b/src/cryptoconditions/src/asn/RsaSha256Fulfillment.h new file mode 100644 index 000000000..fda524276 --- /dev/null +++ b/src/cryptoconditions/src/asn/RsaSha256Fulfillment.h @@ -0,0 +1,38 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#ifndef _RsaSha256Fulfillment_H_ +#define _RsaSha256Fulfillment_H_ + + +#include + +/* Including external dependencies */ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* RsaSha256Fulfillment */ +typedef struct RsaSha256Fulfillment { + OCTET_STRING_t modulus; + OCTET_STRING_t signature; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} RsaSha256Fulfillment_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_RsaSha256Fulfillment; + +#ifdef __cplusplus +} +#endif + +#endif /* _RsaSha256Fulfillment_H_ */ +#include diff --git a/src/cryptoconditions/src/asn/Secp256k1FingerprintContents.c b/src/cryptoconditions/src/asn/Secp256k1FingerprintContents.c new file mode 100644 index 000000000..e31887f75 --- /dev/null +++ b/src/cryptoconditions/src/asn/Secp256k1FingerprintContents.c @@ -0,0 +1,84 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#include "Secp256k1FingerprintContents.h" + +static int +memb_publicKey_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + size_t size; + + if(!sptr) { + ASN__CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + size = st->size; + + if((size == 33)) { + /* Constraint check succeeded */ + return 0; + } else { + ASN__CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } +} + +static asn_TYPE_member_t asn_MBR_Secp256k1FingerprintContents_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct Secp256k1FingerprintContents, publicKey), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + memb_publicKey_constraint_1, + 0, /* PER is not compiled, use -gen-PER */ + 0, + "publicKey" + }, +}; +static const ber_tlv_tag_t asn_DEF_Secp256k1FingerprintContents_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static const asn_TYPE_tag2member_t asn_MAP_Secp256k1FingerprintContents_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 } /* publicKey */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_Secp256k1FingerprintContents_specs_1 = { + sizeof(struct Secp256k1FingerprintContents), + offsetof(struct Secp256k1FingerprintContents, _asn_ctx), + asn_MAP_Secp256k1FingerprintContents_tag2el_1, + 1, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_Secp256k1FingerprintContents = { + "Secp256k1FingerprintContents", + "Secp256k1FingerprintContents", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_Secp256k1FingerprintContents_tags_1, + sizeof(asn_DEF_Secp256k1FingerprintContents_tags_1) + /sizeof(asn_DEF_Secp256k1FingerprintContents_tags_1[0]), /* 1 */ + asn_DEF_Secp256k1FingerprintContents_tags_1, /* Same as above */ + sizeof(asn_DEF_Secp256k1FingerprintContents_tags_1) + /sizeof(asn_DEF_Secp256k1FingerprintContents_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_Secp256k1FingerprintContents_1, + 1, /* Elements count */ + &asn_SPC_Secp256k1FingerprintContents_specs_1 /* Additional specs */ +}; + diff --git a/src/cryptoconditions/src/asn/Secp256k1FingerprintContents.h b/src/cryptoconditions/src/asn/Secp256k1FingerprintContents.h new file mode 100644 index 000000000..d0a3b0b39 --- /dev/null +++ b/src/cryptoconditions/src/asn/Secp256k1FingerprintContents.h @@ -0,0 +1,37 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#ifndef _Secp256k1FingerprintContents_H_ +#define _Secp256k1FingerprintContents_H_ + + +#include + +/* Including external dependencies */ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Secp256k1FingerprintContents */ +typedef struct Secp256k1FingerprintContents { + OCTET_STRING_t publicKey; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} Secp256k1FingerprintContents_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_Secp256k1FingerprintContents; + +#ifdef __cplusplus +} +#endif + +#endif /* _Secp256k1FingerprintContents_H_ */ +#include diff --git a/src/cryptoconditions/src/asn/Secp256k1Fulfillment.c b/src/cryptoconditions/src/asn/Secp256k1Fulfillment.c new file mode 100644 index 000000000..cf8d65512 --- /dev/null +++ b/src/cryptoconditions/src/asn/Secp256k1Fulfillment.c @@ -0,0 +1,120 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#include "Secp256k1Fulfillment.h" + +static int +memb_publicKey_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + size_t size; + + if(!sptr) { + ASN__CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + size = st->size; + + if((size == 33)) { + /* Constraint check succeeded */ + return 0; + } else { + ASN__CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } +} + +static int +memb_signature_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + size_t size; + + if(!sptr) { + ASN__CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + size = st->size; + + if((size == 64)) { + /* Constraint check succeeded */ + return 0; + } else { + ASN__CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } +} + +static asn_TYPE_member_t asn_MBR_Secp256k1Fulfillment_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct Secp256k1Fulfillment, publicKey), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + memb_publicKey_constraint_1, + 0, /* PER is not compiled, use -gen-PER */ + 0, + "publicKey" + }, + { ATF_NOFLAGS, 0, offsetof(struct Secp256k1Fulfillment, signature), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + memb_signature_constraint_1, + 0, /* PER is not compiled, use -gen-PER */ + 0, + "signature" + }, +}; +static const ber_tlv_tag_t asn_DEF_Secp256k1Fulfillment_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static const asn_TYPE_tag2member_t asn_MAP_Secp256k1Fulfillment_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* publicKey */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* signature */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_Secp256k1Fulfillment_specs_1 = { + sizeof(struct Secp256k1Fulfillment), + offsetof(struct Secp256k1Fulfillment, _asn_ctx), + asn_MAP_Secp256k1Fulfillment_tag2el_1, + 2, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_Secp256k1Fulfillment = { + "Secp256k1Fulfillment", + "Secp256k1Fulfillment", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_Secp256k1Fulfillment_tags_1, + sizeof(asn_DEF_Secp256k1Fulfillment_tags_1) + /sizeof(asn_DEF_Secp256k1Fulfillment_tags_1[0]), /* 1 */ + asn_DEF_Secp256k1Fulfillment_tags_1, /* Same as above */ + sizeof(asn_DEF_Secp256k1Fulfillment_tags_1) + /sizeof(asn_DEF_Secp256k1Fulfillment_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_Secp256k1Fulfillment_1, + 2, /* Elements count */ + &asn_SPC_Secp256k1Fulfillment_specs_1 /* Additional specs */ +}; + diff --git a/src/cryptoconditions/src/asn/Secp256k1Fulfillment.h b/src/cryptoconditions/src/asn/Secp256k1Fulfillment.h new file mode 100644 index 000000000..79221317f --- /dev/null +++ b/src/cryptoconditions/src/asn/Secp256k1Fulfillment.h @@ -0,0 +1,38 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#ifndef _Secp256k1Fulfillment_H_ +#define _Secp256k1Fulfillment_H_ + + +#include + +/* Including external dependencies */ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Secp256k1Fulfillment */ +typedef struct Secp256k1Fulfillment { + OCTET_STRING_t publicKey; + OCTET_STRING_t signature; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} Secp256k1Fulfillment_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_Secp256k1Fulfillment; + +#ifdef __cplusplus +} +#endif + +#endif /* _Secp256k1Fulfillment_H_ */ +#include diff --git a/src/cryptoconditions/src/asn/SimpleSha256Condition.c b/src/cryptoconditions/src/asn/SimpleSha256Condition.c new file mode 100644 index 000000000..17c45a5fb --- /dev/null +++ b/src/cryptoconditions/src/asn/SimpleSha256Condition.c @@ -0,0 +1,225 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#include "SimpleSha256Condition.h" + +static int +cost_3_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + + if(!sptr) { + ASN__CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + + /* Constraint check succeeded */ + return 0; +} + +/* + * This type is implemented using NativeInteger, + * so here we adjust the DEF accordingly. + */ +static void +cost_3_inherit_TYPE_descriptor(asn_TYPE_descriptor_t *td) { + td->free_struct = asn_DEF_NativeInteger.free_struct; + td->print_struct = asn_DEF_NativeInteger.print_struct; + td->check_constraints = asn_DEF_NativeInteger.check_constraints; + td->ber_decoder = asn_DEF_NativeInteger.ber_decoder; + td->der_encoder = asn_DEF_NativeInteger.der_encoder; + td->xer_decoder = asn_DEF_NativeInteger.xer_decoder; + td->xer_encoder = asn_DEF_NativeInteger.xer_encoder; + td->uper_decoder = asn_DEF_NativeInteger.uper_decoder; + td->uper_encoder = asn_DEF_NativeInteger.uper_encoder; + if(!td->per_constraints) + td->per_constraints = asn_DEF_NativeInteger.per_constraints; + td->elements = asn_DEF_NativeInteger.elements; + td->elements_count = asn_DEF_NativeInteger.elements_count; + /* td->specifics = asn_DEF_NativeInteger.specifics; // Defined explicitly */ +} + +static void +cost_3_free(asn_TYPE_descriptor_t *td, + void *struct_ptr, int contents_only) { + cost_3_inherit_TYPE_descriptor(td); + td->free_struct(td, struct_ptr, contents_only); +} + +static int +cost_3_print(asn_TYPE_descriptor_t *td, const void *struct_ptr, + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + cost_3_inherit_TYPE_descriptor(td); + return td->print_struct(td, struct_ptr, ilevel, cb, app_key); +} + +static asn_dec_rval_t +cost_3_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const void *bufptr, size_t size, int tag_mode) { + cost_3_inherit_TYPE_descriptor(td); + return td->ber_decoder(opt_codec_ctx, td, structure, bufptr, size, tag_mode); +} + +static asn_enc_rval_t +cost_3_encode_der(asn_TYPE_descriptor_t *td, + void *structure, int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + cost_3_inherit_TYPE_descriptor(td); + return td->der_encoder(td, structure, tag_mode, tag, cb, app_key); +} + +static asn_dec_rval_t +cost_3_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **structure, const char *opt_mname, const void *bufptr, size_t size) { + cost_3_inherit_TYPE_descriptor(td); + return td->xer_decoder(opt_codec_ctx, td, structure, opt_mname, bufptr, size); +} + +static asn_enc_rval_t +cost_3_encode_xer(asn_TYPE_descriptor_t *td, void *structure, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + cost_3_inherit_TYPE_descriptor(td); + return td->xer_encoder(td, structure, ilevel, flags, cb, app_key); +} + +static int +memb_fingerprint_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; + size_t size; + + if(!sptr) { + ASN__CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + size = st->size; + + if((size == 32)) { + /* Constraint check succeeded */ + return 0; + } else { + ASN__CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } +} + +static int +memb_cost_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + + if(!sptr) { + ASN__CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + + /* Constraint check succeeded */ + return 0; +} + +static const asn_INTEGER_specifics_t asn_SPC_cost_specs_3 = { + 0, 0, 0, 0, 0, + 0, /* Native long size */ + 1 /* Unsigned representation */ +}; +static const ber_tlv_tag_t asn_DEF_cost_tags_3[] = { + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)) +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_cost_3 = { + "cost", + "cost", + cost_3_free, + cost_3_print, + cost_3_constraint, + cost_3_decode_ber, + cost_3_encode_der, + cost_3_decode_xer, + cost_3_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_cost_tags_3, + sizeof(asn_DEF_cost_tags_3) + /sizeof(asn_DEF_cost_tags_3[0]) - 1, /* 1 */ + asn_DEF_cost_tags_3, /* Same as above */ + sizeof(asn_DEF_cost_tags_3) + /sizeof(asn_DEF_cost_tags_3[0]), /* 2 */ + 0, /* No PER visible constraints */ + 0, 0, /* No members */ + &asn_SPC_cost_specs_3 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_SimpleSha256Condition_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct SimpleSha256Condition, fingerprint), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_OCTET_STRING, + memb_fingerprint_constraint_1, + 0, /* PER is not compiled, use -gen-PER */ + 0, + "fingerprint" + }, + { ATF_NOFLAGS, 0, offsetof(struct SimpleSha256Condition, cost), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_cost_3, + memb_cost_constraint_1, + 0, /* PER is not compiled, use -gen-PER */ + 0, + "cost" + }, +}; +static const ber_tlv_tag_t asn_DEF_SimpleSha256Condition_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static const asn_TYPE_tag2member_t asn_MAP_SimpleSha256Condition_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* fingerprint */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* cost */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_SimpleSha256Condition_specs_1 = { + sizeof(struct SimpleSha256Condition), + offsetof(struct SimpleSha256Condition, _asn_ctx), + asn_MAP_SimpleSha256Condition_tag2el_1, + 2, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_SimpleSha256Condition = { + "SimpleSha256Condition", + "SimpleSha256Condition", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_SimpleSha256Condition_tags_1, + sizeof(asn_DEF_SimpleSha256Condition_tags_1) + /sizeof(asn_DEF_SimpleSha256Condition_tags_1[0]), /* 1 */ + asn_DEF_SimpleSha256Condition_tags_1, /* Same as above */ + sizeof(asn_DEF_SimpleSha256Condition_tags_1) + /sizeof(asn_DEF_SimpleSha256Condition_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_SimpleSha256Condition_1, + 2, /* Elements count */ + &asn_SPC_SimpleSha256Condition_specs_1 /* Additional specs */ +}; + diff --git a/src/cryptoconditions/src/asn/SimpleSha256Condition.h b/src/cryptoconditions/src/asn/SimpleSha256Condition.h new file mode 100644 index 000000000..4ca08877b --- /dev/null +++ b/src/cryptoconditions/src/asn/SimpleSha256Condition.h @@ -0,0 +1,40 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#ifndef _SimpleSha256Condition_H_ +#define _SimpleSha256Condition_H_ + + +#include + +/* Including external dependencies */ +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* SimpleSha256Condition */ +typedef struct SimpleSha256Condition { + OCTET_STRING_t fingerprint; + unsigned long cost; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} SimpleSha256Condition_t; + +/* Implementation */ +/* extern asn_TYPE_descriptor_t asn_DEF_cost_3; // (Use -fall-defs-global to expose) */ +extern asn_TYPE_descriptor_t asn_DEF_SimpleSha256Condition; + +#ifdef __cplusplus +} +#endif + +#endif /* _SimpleSha256Condition_H_ */ +#include diff --git a/src/cryptoconditions/src/asn/ThresholdFingerprintContents.c b/src/cryptoconditions/src/asn/ThresholdFingerprintContents.c new file mode 100644 index 000000000..b4e05ac67 --- /dev/null +++ b/src/cryptoconditions/src/asn/ThresholdFingerprintContents.c @@ -0,0 +1,138 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#include "ThresholdFingerprintContents.h" + +static int +memb_threshold_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + long value; + + if(!sptr) { + ASN__CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + value = *(const long *)sptr; + + if((value >= 1 && value <= 65535)) { + /* Constraint check succeeded */ + return 0; + } else { + ASN__CTFAIL(app_key, td, sptr, + "%s: constraint failed (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } +} + +static asn_TYPE_member_t asn_MBR_subconditions2_3[] = { + { ATF_POINTER, 0, 0, + -1 /* Ambiguous tag (CHOICE?) */, + 0, + &asn_DEF_Condition, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "" + }, +}; +static const ber_tlv_tag_t asn_DEF_subconditions2_tags_3[] = { + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + (ASN_TAG_CLASS_UNIVERSAL | (17 << 2)) +}; +static asn_SET_OF_specifics_t asn_SPC_subconditions2_specs_3 = { + sizeof(struct subconditions2), + offsetof(struct subconditions2, _asn_ctx), + 2, /* XER encoding is XMLValueList */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_subconditions2_3 = { + "subconditions2", + "subconditions2", + SET_OF_free, + SET_OF_print, + SET_OF_constraint, + SET_OF_decode_ber, + SET_OF_encode_der, + SET_OF_decode_xer, + SET_OF_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_subconditions2_tags_3, + sizeof(asn_DEF_subconditions2_tags_3) + /sizeof(asn_DEF_subconditions2_tags_3[0]) - 1, /* 1 */ + asn_DEF_subconditions2_tags_3, /* Same as above */ + sizeof(asn_DEF_subconditions2_tags_3) + /sizeof(asn_DEF_subconditions2_tags_3[0]), /* 2 */ + 0, /* No PER visible constraints */ + asn_MBR_subconditions2_3, + 1, /* Single element */ + &asn_SPC_subconditions2_specs_3 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_ThresholdFingerprintContents_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct ThresholdFingerprintContents, threshold), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + -1, /* IMPLICIT tag at current level */ + &asn_DEF_NativeInteger, + memb_threshold_constraint_1, + 0, /* PER is not compiled, use -gen-PER */ + 0, + "threshold" + }, + { ATF_NOFLAGS, 0, offsetof(struct ThresholdFingerprintContents, subconditions2), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + 0, + &asn_DEF_subconditions2_3, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "subconditions2" + }, +}; +static const ber_tlv_tag_t asn_DEF_ThresholdFingerprintContents_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static const asn_TYPE_tag2member_t asn_MAP_ThresholdFingerprintContents_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* threshold */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* subconditions2 */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_ThresholdFingerprintContents_specs_1 = { + sizeof(struct ThresholdFingerprintContents), + offsetof(struct ThresholdFingerprintContents, _asn_ctx), + asn_MAP_ThresholdFingerprintContents_tag2el_1, + 2, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_ThresholdFingerprintContents = { + "ThresholdFingerprintContents", + "ThresholdFingerprintContents", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_ThresholdFingerprintContents_tags_1, + sizeof(asn_DEF_ThresholdFingerprintContents_tags_1) + /sizeof(asn_DEF_ThresholdFingerprintContents_tags_1[0]), /* 1 */ + asn_DEF_ThresholdFingerprintContents_tags_1, /* Same as above */ + sizeof(asn_DEF_ThresholdFingerprintContents_tags_1) + /sizeof(asn_DEF_ThresholdFingerprintContents_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_ThresholdFingerprintContents_1, + 2, /* Elements count */ + &asn_SPC_ThresholdFingerprintContents_specs_1 /* Additional specs */ +}; + diff --git a/src/cryptoconditions/src/asn/ThresholdFingerprintContents.h b/src/cryptoconditions/src/asn/ThresholdFingerprintContents.h new file mode 100644 index 000000000..4d1c4f491 --- /dev/null +++ b/src/cryptoconditions/src/asn/ThresholdFingerprintContents.h @@ -0,0 +1,51 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#ifndef _ThresholdFingerprintContents_H_ +#define _ThresholdFingerprintContents_H_ + + +#include + +/* Including external dependencies */ +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward declarations */ +struct Condition; + +/* ThresholdFingerprintContents */ +typedef struct ThresholdFingerprintContents { + long threshold; + struct subconditions2 { + A_SET_OF(struct Condition) list; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } subconditions2; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} ThresholdFingerprintContents_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_ThresholdFingerprintContents; + +#ifdef __cplusplus +} +#endif + +/* Referred external types */ +#include "Condition.h" + +#endif /* _ThresholdFingerprintContents_H_ */ +#include diff --git a/src/cryptoconditions/src/asn/ThresholdFulfillment.c b/src/cryptoconditions/src/asn/ThresholdFulfillment.c new file mode 100644 index 000000000..28c5e36a8 --- /dev/null +++ b/src/cryptoconditions/src/asn/ThresholdFulfillment.c @@ -0,0 +1,158 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#include "ThresholdFulfillment.h" + +static asn_TYPE_member_t asn_MBR_subfulfillments_2[] = { + { ATF_POINTER, 0, 0, + -1 /* Ambiguous tag (CHOICE?) */, + 0, + &asn_DEF_Fulfillment, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "" + }, +}; +static const ber_tlv_tag_t asn_DEF_subfulfillments_tags_2[] = { + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + (ASN_TAG_CLASS_UNIVERSAL | (17 << 2)) +}; +static asn_SET_OF_specifics_t asn_SPC_subfulfillments_specs_2 = { + sizeof(struct subfulfillments), + offsetof(struct subfulfillments, _asn_ctx), + 2, /* XER encoding is XMLValueList */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_subfulfillments_2 = { + "subfulfillments", + "subfulfillments", + SET_OF_free, + SET_OF_print, + SET_OF_constraint, + SET_OF_decode_ber, + SET_OF_encode_der, + SET_OF_decode_xer, + SET_OF_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_subfulfillments_tags_2, + sizeof(asn_DEF_subfulfillments_tags_2) + /sizeof(asn_DEF_subfulfillments_tags_2[0]) - 1, /* 1 */ + asn_DEF_subfulfillments_tags_2, /* Same as above */ + sizeof(asn_DEF_subfulfillments_tags_2) + /sizeof(asn_DEF_subfulfillments_tags_2[0]), /* 2 */ + 0, /* No PER visible constraints */ + asn_MBR_subfulfillments_2, + 1, /* Single element */ + &asn_SPC_subfulfillments_specs_2 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_subconditions_4[] = { + { ATF_POINTER, 0, 0, + -1 /* Ambiguous tag (CHOICE?) */, + 0, + &asn_DEF_Condition, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "" + }, +}; +static const ber_tlv_tag_t asn_DEF_subconditions_tags_4[] = { + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + (ASN_TAG_CLASS_UNIVERSAL | (17 << 2)) +}; +static asn_SET_OF_specifics_t asn_SPC_subconditions_specs_4 = { + sizeof(struct subconditions), + offsetof(struct subconditions, _asn_ctx), + 2, /* XER encoding is XMLValueList */ +}; +static /* Use -fall-defs-global to expose */ +asn_TYPE_descriptor_t asn_DEF_subconditions_4 = { + "subconditions", + "subconditions", + SET_OF_free, + SET_OF_print, + SET_OF_constraint, + SET_OF_decode_ber, + SET_OF_encode_der, + SET_OF_decode_xer, + SET_OF_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_subconditions_tags_4, + sizeof(asn_DEF_subconditions_tags_4) + /sizeof(asn_DEF_subconditions_tags_4[0]) - 1, /* 1 */ + asn_DEF_subconditions_tags_4, /* Same as above */ + sizeof(asn_DEF_subconditions_tags_4) + /sizeof(asn_DEF_subconditions_tags_4[0]), /* 2 */ + 0, /* No PER visible constraints */ + asn_MBR_subconditions_4, + 1, /* Single element */ + &asn_SPC_subconditions_specs_4 /* Additional specs */ +}; + +static asn_TYPE_member_t asn_MBR_ThresholdFulfillment_1[] = { + { ATF_NOFLAGS, 0, offsetof(struct ThresholdFulfillment, subfulfillments), + (ASN_TAG_CLASS_CONTEXT | (0 << 2)), + 0, + &asn_DEF_subfulfillments_2, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "subfulfillments" + }, + { ATF_NOFLAGS, 0, offsetof(struct ThresholdFulfillment, subconditions), + (ASN_TAG_CLASS_CONTEXT | (1 << 2)), + 0, + &asn_DEF_subconditions_4, + 0, /* Defer constraints checking to the member type */ + 0, /* PER is not compiled, use -gen-PER */ + 0, + "subconditions" + }, +}; +static const ber_tlv_tag_t asn_DEF_ThresholdFulfillment_tags_1[] = { + (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) +}; +static const asn_TYPE_tag2member_t asn_MAP_ThresholdFulfillment_tag2el_1[] = { + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* subfulfillments */ + { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* subconditions */ +}; +static asn_SEQUENCE_specifics_t asn_SPC_ThresholdFulfillment_specs_1 = { + sizeof(struct ThresholdFulfillment), + offsetof(struct ThresholdFulfillment, _asn_ctx), + asn_MAP_ThresholdFulfillment_tag2el_1, + 2, /* Count of tags in the map */ + 0, 0, 0, /* Optional elements (not needed) */ + -1, /* Start extensions */ + -1 /* Stop extensions */ +}; +asn_TYPE_descriptor_t asn_DEF_ThresholdFulfillment = { + "ThresholdFulfillment", + "ThresholdFulfillment", + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_constraint, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + SEQUENCE_decode_xer, + SEQUENCE_encode_xer, + 0, 0, /* No PER support, use "-gen-PER" to enable */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_ThresholdFulfillment_tags_1, + sizeof(asn_DEF_ThresholdFulfillment_tags_1) + /sizeof(asn_DEF_ThresholdFulfillment_tags_1[0]), /* 1 */ + asn_DEF_ThresholdFulfillment_tags_1, /* Same as above */ + sizeof(asn_DEF_ThresholdFulfillment_tags_1) + /sizeof(asn_DEF_ThresholdFulfillment_tags_1[0]), /* 1 */ + 0, /* No PER visible constraints */ + asn_MBR_ThresholdFulfillment_1, + 2, /* Elements count */ + &asn_SPC_ThresholdFulfillment_specs_1 /* Additional specs */ +}; + diff --git a/src/cryptoconditions/src/asn/ThresholdFulfillment.h b/src/cryptoconditions/src/asn/ThresholdFulfillment.h new file mode 100644 index 000000000..e00ae5f2b --- /dev/null +++ b/src/cryptoconditions/src/asn/ThresholdFulfillment.h @@ -0,0 +1,57 @@ +/* + * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) + * From ASN.1 module "Crypto-Conditions" + * found in "CryptoConditions.asn" + */ + +#ifndef _ThresholdFulfillment_H_ +#define _ThresholdFulfillment_H_ + + +#include + +/* Including external dependencies */ +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward declarations */ +struct Fulfillment; +struct Condition; + +/* ThresholdFulfillment */ +typedef struct ThresholdFulfillment { + struct subfulfillments { + A_SET_OF(struct Fulfillment) list; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } subfulfillments; + struct subconditions { + A_SET_OF(struct Condition) list; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; + } subconditions; + + /* Context for parsing across buffer boundaries */ + asn_struct_ctx_t _asn_ctx; +} ThresholdFulfillment_t; + +/* Implementation */ +extern asn_TYPE_descriptor_t asn_DEF_ThresholdFulfillment; + +#ifdef __cplusplus +} +#endif + +/* Referred external types */ +#include "Fulfillment.h" +#include "Condition.h" + +#endif /* _ThresholdFulfillment_H_ */ +#include diff --git a/src/cryptoconditions/src/asn/asn_SET_OF.c b/src/cryptoconditions/src/asn/asn_SET_OF.c new file mode 100644 index 000000000..944f2cb8a --- /dev/null +++ b/src/cryptoconditions/src/asn/asn_SET_OF.c @@ -0,0 +1,88 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +/* + * Add another element into the set. + */ +int +asn_set_add(void *asn_set_of_x, void *ptr) { + asn_anonymous_set_ *as = _A_SET_FROM_VOID(asn_set_of_x); + + if(as == 0 || ptr == 0) { + errno = EINVAL; /* Invalid arguments */ + return -1; + } + + /* + * Make sure there's enough space to insert an element. + */ + if(as->count == as->size) { + int _newsize = as->size ? (as->size << 1) : 4; + void *_new_arr; + _new_arr = REALLOC(as->array, _newsize * sizeof(as->array[0])); + if(_new_arr) { + as->array = (void **)_new_arr; + as->size = _newsize; + } else { + /* ENOMEM */ + return -1; + } + } + + as->array[as->count++] = ptr; + + return 0; +} + +void +asn_set_del(void *asn_set_of_x, int number, int _do_free) { + asn_anonymous_set_ *as = _A_SET_FROM_VOID(asn_set_of_x); + + if(as) { + void *ptr; + if(number < 0 || number >= as->count) + return; + + if(_do_free && as->free) { + ptr = as->array[number]; + } else { + ptr = 0; + } + + as->array[number] = as->array[--as->count]; + + /* + * Invoke the third-party function only when the state + * of the parent structure is consistent. + */ + if(ptr) as->free(ptr); + } +} + +/* + * Free the contents of the set, do not free the set itself. + */ +void +asn_set_empty(void *asn_set_of_x) { + asn_anonymous_set_ *as = _A_SET_FROM_VOID(asn_set_of_x); + + if(as) { + if(as->array) { + if(as->free) { + while(as->count--) + as->free(as->array[as->count]); + } + FREEMEM(as->array); + as->array = 0; + } + as->count = 0; + as->size = 0; + } + +} + diff --git a/src/cryptoconditions/src/asn/asn_SET_OF.h b/src/cryptoconditions/src/asn/asn_SET_OF.h new file mode 100644 index 000000000..7edf14b51 --- /dev/null +++ b/src/cryptoconditions/src/asn/asn_SET_OF.h @@ -0,0 +1,62 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef ASN_SET_OF_H +#define ASN_SET_OF_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define A_SET_OF(type) \ + struct { \ + type **array; \ + int count; /* Meaningful size */ \ + int size; /* Allocated size */ \ + void (*free)(type *); \ + } + +#define ASN_SET_ADD(headptr, ptr) \ + asn_set_add((headptr), (ptr)) + +/******************************************* + * Implementation of the SET OF structure. + */ + +/* + * Add another structure into the set by its pointer. + * RETURN VALUES: + * 0 for success and -1/errno for failure. + */ +int asn_set_add(void *asn_set_of_x, void *ptr); + +/* + * Delete the element from the set by its number (base 0). + * This is a constant-time operation. The order of elements before the + * deleted ones is guaranteed, the order of elements after the deleted + * one is NOT guaranteed. + * If _do_free is given AND the (*free) is initialized, the element + * will be freed using the custom (*free) function as well. + */ +void asn_set_del(void *asn_set_of_x, int number, int _do_free); + +/* + * Empty the contents of the set. Will free the elements, if (*free) is given. + * Will NOT free the set itself. + */ +void asn_set_empty(void *asn_set_of_x); + +/* + * Cope with different conversions requirements to/from void in C and C++. + * This is mostly useful for support library. + */ +typedef A_SET_OF(void) asn_anonymous_set_; +#define _A_SET_FROM_VOID(ptr) ((asn_anonymous_set_ *)(ptr)) +#define _A_CSET_FROM_VOID(ptr) ((const asn_anonymous_set_ *)(ptr)) + +#ifdef __cplusplus +} +#endif + +#endif /* ASN_SET_OF_H */ diff --git a/src/cryptoconditions/src/asn/asn_application.h b/src/cryptoconditions/src/asn/asn_application.h new file mode 100644 index 000000000..71e9ba61b --- /dev/null +++ b/src/cryptoconditions/src/asn/asn_application.h @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 2004, 2006 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +/* + * Application-level ASN.1 callbacks. + */ +#ifndef ASN_APPLICATION_H +#define ASN_APPLICATION_H + +#include "asn_system.h" /* for platform-dependent types */ +#include "asn_codecs.h" /* for ASN.1 codecs specifics */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Generic type of an application-defined callback to return various + * types of data to the application. + * EXPECTED RETURN VALUES: + * -1: Failed to consume bytes. Abort the mission. + * Non-negative return values indicate success, and ignored. + */ +typedef int (asn_app_consume_bytes_f)(const void *buffer, size_t size, + void *application_specific_key); + +/* + * A callback of this type is called whenever constraint validation fails + * on some ASN.1 type. See "constraints.h" for more details on constraint + * validation. + * This callback specifies a descriptor of the ASN.1 type which failed + * the constraint check, as well as human readable message on what + * particular constraint has failed. + */ +typedef void (asn_app_constraint_failed_f)(void *application_specific_key, + struct asn_TYPE_descriptor_s *type_descriptor_which_failed, + const void *structure_which_failed_ptr, + const char *error_message_format, ...) GCC_PRINTFLIKE(4, 5); + +#ifdef __cplusplus +} +#endif + +#include "constr_TYPE.h" /* for asn_TYPE_descriptor_t */ + +#endif /* ASN_APPLICATION_H */ diff --git a/src/cryptoconditions/src/asn/asn_codecs.h b/src/cryptoconditions/src/asn/asn_codecs.h new file mode 100644 index 000000000..4b2a29429 --- /dev/null +++ b/src/cryptoconditions/src/asn/asn_codecs.h @@ -0,0 +1,109 @@ +/*- + * Copyright (c) 2003, 2004, 2005 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef ASN_CODECS_H +#define ASN_CODECS_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ + +/* + * This structure defines a set of parameters that may be passed + * to every ASN.1 encoder or decoder function. + * WARNING: if max_stack_size member is set, and you are calling the + * function pointers of the asn_TYPE_descriptor_t directly, + * this structure must be ALLOCATED ON THE STACK! + * If you can't always satisfy this requirement, use ber_decode(), + * xer_decode() and uper_decode() functions instead. + */ +typedef struct asn_codec_ctx_s { + /* + * Limit the decoder routines to use no (much) more stack than a given + * number of bytes. Most of decoders are stack-based, and this + * would protect against stack overflows if the number of nested + * encodings is high. + * The OCTET STRING, BIT STRING and ANY BER decoders are heap-based, + * and are safe from this kind of overflow. + * A value from getrlimit(RLIMIT_STACK) may be used to initialize + * this variable. Be careful in multithreaded environments, as the + * stack size is rather limited. + */ + size_t max_stack_size; /* 0 disables stack bounds checking */ +} asn_codec_ctx_t; + +/* + * Type of the return value of the encoding functions (der_encode, xer_encode). + */ +typedef struct asn_enc_rval_s { + /* + * Number of bytes encoded. + * -1 indicates failure to encode the structure. + * In this case, the members below this one are meaningful. + */ + ssize_t encoded; + + /* + * Members meaningful when (encoded == -1), for post mortem analysis. + */ + + /* Type which cannot be encoded */ + struct asn_TYPE_descriptor_s *failed_type; + + /* Pointer to the structure of that type */ + void *structure_ptr; +} asn_enc_rval_t; +#define ASN__ENCODE_FAILED do { \ + asn_enc_rval_t tmp_error; \ + tmp_error.encoded = -1; \ + tmp_error.failed_type = td; \ + tmp_error.structure_ptr = sptr; \ + ASN_DEBUG("Failed to encode element %s", td ? td->name : ""); \ + return tmp_error; \ +} while(0) +#define ASN__ENCODED_OK(rval) do { \ + rval.structure_ptr = 0; \ + rval.failed_type = 0; \ + return rval; \ +} while(0) + +/* + * Type of the return value of the decoding functions (ber_decode, xer_decode) + * + * Please note that the number of consumed bytes is ALWAYS meaningful, + * even if code==RC_FAIL. This is to indicate the number of successfully + * decoded bytes, hence providing a possibility to fail with more diagnostics + * (i.e., print the offending remainder of the buffer). + */ +enum asn_dec_rval_code_e { + RC_OK, /* Decoded successfully */ + RC_WMORE, /* More data expected, call again */ + RC_FAIL /* Failure to decode data */ +}; +typedef struct asn_dec_rval_s { + enum asn_dec_rval_code_e code; /* Result code */ + size_t consumed; /* Number of bytes consumed */ +} asn_dec_rval_t; +#define ASN__DECODE_FAILED do { \ + asn_dec_rval_t tmp_error; \ + tmp_error.code = RC_FAIL; \ + tmp_error.consumed = 0; \ + ASN_DEBUG("Failed to decode element %s", td ? td->name : ""); \ + return tmp_error; \ +} while(0) +#define ASN__DECODE_STARVED do { \ + asn_dec_rval_t tmp_error; \ + tmp_error.code = RC_WMORE; \ + tmp_error.consumed = 0; \ + return tmp_error; \ +} while(0) + +#ifdef __cplusplus +} +#endif + +#endif /* ASN_CODECS_H */ diff --git a/src/cryptoconditions/src/asn/asn_codecs_prim.c b/src/cryptoconditions/src/asn/asn_codecs_prim.c new file mode 100644 index 000000000..426339c94 --- /dev/null +++ b/src/cryptoconditions/src/asn/asn_codecs_prim.c @@ -0,0 +1,312 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +/* + * Decode an always-primitive type. + */ +asn_dec_rval_t +ber_decode_primitive(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, + void **sptr, const void *buf_ptr, size_t size, int tag_mode) { + ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)*sptr; + asn_dec_rval_t rval; + ber_tlv_len_t length = 0; /* =0 to avoid [incorrect] warning. */ + + /* + * If the structure is not there, allocate it. + */ + if(st == NULL) { + st = (ASN__PRIMITIVE_TYPE_t *)CALLOC(1, sizeof(*st)); + if(st == NULL) ASN__DECODE_FAILED; + *sptr = (void *)st; + } + + ASN_DEBUG("Decoding %s as plain primitive (tm=%d)", + td->name, tag_mode); + + /* + * Check tags and extract value length. + */ + rval = ber_check_tags(opt_codec_ctx, td, 0, buf_ptr, size, + tag_mode, 0, &length, 0); + if(rval.code != RC_OK) + return rval; + + ASN_DEBUG("%s length is %d bytes", td->name, (int)length); + + /* + * Make sure we have this length. + */ + buf_ptr = ((const char *)buf_ptr) + rval.consumed; + size -= rval.consumed; + if(length > (ber_tlv_len_t)size) { + rval.code = RC_WMORE; + rval.consumed = 0; + return rval; + } + + st->size = (int)length; + /* The following better be optimized away. */ + if(sizeof(st->size) != sizeof(length) + && (ber_tlv_len_t)st->size != length) { + st->size = 0; + ASN__DECODE_FAILED; + } + + st->buf = (uint8_t *)MALLOC(length + 1); + if(!st->buf) { + st->size = 0; + ASN__DECODE_FAILED; + } + + memcpy(st->buf, buf_ptr, length); + st->buf[length] = '\0'; /* Just in case */ + + rval.code = RC_OK; + rval.consumed += length; + + ASN_DEBUG("Took %ld/%ld bytes to encode %s", + (long)rval.consumed, + (long)length, td->name); + + return rval; +} + +/* + * Encode an always-primitive type using DER. + */ +asn_enc_rval_t +der_encode_primitive(asn_TYPE_descriptor_t *td, void *sptr, + int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_enc_rval_t erval; + ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)sptr; + + ASN_DEBUG("%s %s as a primitive type (tm=%d)", + cb?"Encoding":"Estimating", td->name, tag_mode); + + erval.encoded = der_write_tags(td, st->size, tag_mode, 0, tag, + cb, app_key); + ASN_DEBUG("%s wrote tags %d", td->name, (int)erval.encoded); + if(erval.encoded == -1) { + erval.failed_type = td; + erval.structure_ptr = sptr; + return erval; + } + + if(cb && st->buf) { + if(cb(st->buf, st->size, app_key) < 0) { + erval.encoded = -1; + erval.failed_type = td; + erval.structure_ptr = sptr; + return erval; + } + } else { + assert(st->buf || st->size == 0); + } + + erval.encoded += st->size; + ASN__ENCODED_OK(erval); +} + +void +ASN__PRIMITIVE_TYPE_free(asn_TYPE_descriptor_t *td, void *sptr, + int contents_only) { + ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)sptr; + + if(!td || !sptr) + return; + + ASN_DEBUG("Freeing %s as a primitive type", td->name); + + if(st->buf) + FREEMEM(st->buf); + + if(!contents_only) + FREEMEM(st); +} + + +/* + * Local internal type passed around as an argument. + */ +struct xdp_arg_s { + asn_TYPE_descriptor_t *type_descriptor; + void *struct_key; + xer_primitive_body_decoder_f *prim_body_decoder; + int decoded_something; + int want_more; +}; + +/* + * Since some kinds of primitive values can be encoded using value-specific + * tags (, , etc), the primitive decoder must + * be supplied with such tags to parse them as needed. + */ +static int +xer_decode__unexpected_tag(void *key, const void *chunk_buf, size_t chunk_size) { + struct xdp_arg_s *arg = (struct xdp_arg_s *)key; + enum xer_pbd_rval bret; + + /* + * The chunk_buf is guaranteed to start at '<'. + */ + assert(chunk_size && ((const char *)chunk_buf)[0] == 0x3c); + + /* + * Decoding was performed once already. Prohibit doing it again. + */ + if(arg->decoded_something) + return -1; + + bret = arg->prim_body_decoder(arg->type_descriptor, + arg->struct_key, chunk_buf, chunk_size); + switch(bret) { + case XPBD_SYSTEM_FAILURE: + case XPBD_DECODER_LIMIT: + case XPBD_BROKEN_ENCODING: + break; + case XPBD_BODY_CONSUMED: + /* Tag decoded successfully */ + arg->decoded_something = 1; + /* Fall through */ + case XPBD_NOT_BODY_IGNORE: /* Safe to proceed further */ + return 0; + } + + return -1; +} + +static ssize_t +xer_decode__primitive_body(void *key, const void *chunk_buf, size_t chunk_size, int have_more) { + struct xdp_arg_s *arg = (struct xdp_arg_s *)key; + enum xer_pbd_rval bret; + size_t lead_wsp_size; + + if(arg->decoded_something) { + if(xer_whitespace_span(chunk_buf, chunk_size) == chunk_size) { + /* + * Example: + * "123 " + * ^- chunk_buf position. + */ + return chunk_size; + } + /* + * Decoding was done once already. Prohibit doing it again. + */ + return -1; + } + + if(!have_more) { + /* + * If we've received something like "1", we can't really + * tell whether it is really `1` or `123`, until we know + * that there is no more data coming. + * The have_more argument will be set to 1 once something + * like this is available to the caller of this callback: + * "1want_more = 1; + return -1; + } + + lead_wsp_size = xer_whitespace_span(chunk_buf, chunk_size); + chunk_buf = (const char *)chunk_buf + lead_wsp_size; + chunk_size -= lead_wsp_size; + + bret = arg->prim_body_decoder(arg->type_descriptor, + arg->struct_key, chunk_buf, chunk_size); + switch(bret) { + case XPBD_SYSTEM_FAILURE: + case XPBD_DECODER_LIMIT: + case XPBD_BROKEN_ENCODING: + break; + case XPBD_BODY_CONSUMED: + /* Tag decoded successfully */ + arg->decoded_something = 1; + /* Fall through */ + case XPBD_NOT_BODY_IGNORE: /* Safe to proceed further */ + return lead_wsp_size + chunk_size; + } + + return -1; +} + + +asn_dec_rval_t +xer_decode_primitive(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, + void **sptr, + size_t struct_size, + const char *opt_mname, + const void *buf_ptr, size_t size, + xer_primitive_body_decoder_f *prim_body_decoder +) { + const char *xml_tag = opt_mname ? opt_mname : td->xml_tag; + asn_struct_ctx_t s_ctx; + struct xdp_arg_s s_arg; + asn_dec_rval_t rc; + + /* + * Create the structure if does not exist. + */ + if(!*sptr) { + *sptr = CALLOC(1, struct_size); + if(!*sptr) ASN__DECODE_FAILED; + } + + memset(&s_ctx, 0, sizeof(s_ctx)); + s_arg.type_descriptor = td; + s_arg.struct_key = *sptr; + s_arg.prim_body_decoder = prim_body_decoder; + s_arg.decoded_something = 0; + s_arg.want_more = 0; + + rc = xer_decode_general(opt_codec_ctx, &s_ctx, &s_arg, + xml_tag, buf_ptr, size, + xer_decode__unexpected_tag, xer_decode__primitive_body); + switch(rc.code) { + case RC_OK: + if(!s_arg.decoded_something) { + char ch; + ASN_DEBUG("Primitive body is not recognized, " + "supplying empty one"); + /* + * Decoding opportunity has come and gone. + * Where's the result? + * Try to feed with empty body, see if it eats it. + */ + if(prim_body_decoder(s_arg.type_descriptor, + s_arg.struct_key, &ch, 0) + != XPBD_BODY_CONSUMED) { + /* + * This decoder does not like empty stuff. + */ + ASN__DECODE_FAILED; + } + } + break; + case RC_WMORE: + /* + * Redo the whole thing later. + * We don't have a context to save intermediate parsing state. + */ + rc.consumed = 0; + break; + case RC_FAIL: + rc.consumed = 0; + if(s_arg.want_more) + rc.code = RC_WMORE; + else + ASN__DECODE_FAILED; + break; + } + return rc; +} + diff --git a/src/cryptoconditions/src/asn/asn_codecs_prim.h b/src/cryptoconditions/src/asn/asn_codecs_prim.h new file mode 100644 index 000000000..0f683fdd0 --- /dev/null +++ b/src/cryptoconditions/src/asn/asn_codecs_prim.h @@ -0,0 +1,53 @@ +/*- + * Copyright (c) 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef ASN_CODECS_PRIM_H +#define ASN_CODECS_PRIM_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ASN__PRIMITIVE_TYPE_s { + uint8_t *buf; /* Buffer with consecutive primitive encoding bytes */ + int size; /* Size of the buffer */ +} ASN__PRIMITIVE_TYPE_t; /* Do not use this type directly! */ + +asn_struct_free_f ASN__PRIMITIVE_TYPE_free; +ber_type_decoder_f ber_decode_primitive; +der_type_encoder_f der_encode_primitive; + +/* + * A callback specification for the xer_decode_primitive() function below. + */ +enum xer_pbd_rval { + XPBD_SYSTEM_FAILURE, /* System failure (memory shortage, etc) */ + XPBD_DECODER_LIMIT, /* Hit some decoder limitation or deficiency */ + XPBD_BROKEN_ENCODING, /* Encoding of a primitive body is broken */ + XPBD_NOT_BODY_IGNORE, /* Not a body format, but safe to ignore */ + XPBD_BODY_CONSUMED /* Body is recognized and consumed */ +}; +typedef enum xer_pbd_rval (xer_primitive_body_decoder_f) + (asn_TYPE_descriptor_t *td, void *struct_ptr, + const void *chunk_buf, size_t chunk_size); + +/* + * Specific function to decode simple primitive types. + * Also see xer_decode_general() in xer_decoder.h + */ +asn_dec_rval_t xer_decode_primitive(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *type_descriptor, + void **struct_ptr, size_t struct_size, + const char *opt_mname, + const void *buf_ptr, size_t size, + xer_primitive_body_decoder_f *prim_body_decoder +); + +#ifdef __cplusplus +} +#endif + +#endif /* ASN_CODECS_PRIM_H */ diff --git a/src/cryptoconditions/src/asn/asn_internal.h b/src/cryptoconditions/src/asn/asn_internal.h new file mode 100644 index 000000000..9c94ca6c3 --- /dev/null +++ b/src/cryptoconditions/src/asn/asn_internal.h @@ -0,0 +1,128 @@ +/*- + * Copyright (c) 2003, 2004, 2005, 2007 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +/* + * Declarations internally useful for the ASN.1 support code. + */ +#ifndef ASN_INTERNAL_H +#define ASN_INTERNAL_H + +#include "asn_application.h" /* Application-visible API */ + +#ifndef __NO_ASSERT_H__ /* Include assert.h only for internal use. */ +#include /* for assert() macro */ +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Environment version might be used to avoid running with the old library */ +#define ASN1C_ENVIRONMENT_VERSION 923 /* Compile-time version */ +int get_asn1c_environment_version(void); /* Run-time version */ + +#define CALLOC(nmemb, size) calloc(nmemb, size) +#define MALLOC(size) malloc(size) +#define REALLOC(oldptr, size) realloc(oldptr, size) +#define FREEMEM(ptr) free(ptr) + +#define asn_debug_indent 0 +#define ASN_DEBUG_INDENT_ADD(i) do{}while(0) + +/* + * A macro for debugging the ASN.1 internals. + * You may enable or override it. + */ +#ifndef ASN_DEBUG /* If debugging code is not defined elsewhere... */ +#if EMIT_ASN_DEBUG == 1 /* And it was asked to emit this code... */ +#ifdef __GNUC__ +#ifdef ASN_THREAD_SAFE +/* Thread safety requires sacrifice in output indentation: + * Retain empty definition of ASN_DEBUG_INDENT_ADD. */ +#else /* !ASN_THREAD_SAFE */ +#undef ASN_DEBUG_INDENT_ADD +#undef asn_debug_indent +int asn_debug_indent; +#define ASN_DEBUG_INDENT_ADD(i) do { asn_debug_indent += i; } while(0) +#endif /* ASN_THREAD_SAFE */ +#define ASN_DEBUG(fmt, args...) do { \ + int adi = asn_debug_indent; \ + while(adi--) fprintf(stderr, " "); \ + fprintf(stderr, fmt, ##args); \ + fprintf(stderr, " (%s:%d)\n", \ + __FILE__, __LINE__); \ + } while(0) +#else /* !__GNUC__ */ +void ASN_DEBUG_f(const char *fmt, ...); +#define ASN_DEBUG ASN_DEBUG_f +#endif /* __GNUC__ */ +#else /* EMIT_ASN_DEBUG != 1 */ +static void ASN_DEBUG(const char *fmt, ...) { (void)fmt; } +#endif /* EMIT_ASN_DEBUG */ +#endif /* ASN_DEBUG */ + +/* + * Invoke the application-supplied callback and fail, if something is wrong. + */ +#define ASN__E_cbc(buf, size) (cb((buf), (size), app_key) < 0) +#define ASN__E_CALLBACK(foo) do { \ + if(foo) goto cb_failed; \ + } while(0) +#define ASN__CALLBACK(buf, size) \ + ASN__E_CALLBACK(ASN__E_cbc(buf, size)) +#define ASN__CALLBACK2(buf1, size1, buf2, size2) \ + ASN__E_CALLBACK(ASN__E_cbc(buf1, size1) || ASN__E_cbc(buf2, size2)) +#define ASN__CALLBACK3(buf1, size1, buf2, size2, buf3, size3) \ + ASN__E_CALLBACK(ASN__E_cbc(buf1, size1) \ + || ASN__E_cbc(buf2, size2) \ + || ASN__E_cbc(buf3, size3)) + +#define ASN__TEXT_INDENT(nl, level) do { \ + int tmp_level = (level); \ + int tmp_nl = ((nl) != 0); \ + int tmp_i; \ + if(tmp_nl) ASN__CALLBACK("\n", 1); \ + if(tmp_level < 0) tmp_level = 0; \ + for(tmp_i = 0; tmp_i < tmp_level; tmp_i++) \ + ASN__CALLBACK(" ", 4); \ + er.encoded += tmp_nl + 4 * tmp_level; \ + } while(0) + +#define _i_INDENT(nl) do { \ + int tmp_i; \ + if((nl) && cb("\n", 1, app_key) < 0) \ + return -1; \ + for(tmp_i = 0; tmp_i < ilevel; tmp_i++) \ + if(cb(" ", 4, app_key) < 0) \ + return -1; \ + } while(0) + +/* + * Check stack against overflow, if limit is set. + */ +#define ASN__DEFAULT_STACK_MAX (30000) +static int __attribute__((unused)) +ASN__STACK_OVERFLOW_CHECK(asn_codec_ctx_t *ctx) { + if(ctx && ctx->max_stack_size) { + + /* ctx MUST be allocated on the stack */ + ptrdiff_t usedstack = ((char *)ctx - (char *)&ctx); + if(usedstack > 0) usedstack = -usedstack; /* grows up! */ + + /* double negative required to avoid int wrap-around */ + if(usedstack < -(ptrdiff_t)ctx->max_stack_size) { + ASN_DEBUG("Stack limit %ld reached", + (long)ctx->max_stack_size); + return -1; + } + } + return 0; +} + +#ifdef __cplusplus +} +#endif + +#endif /* ASN_INTERNAL_H */ diff --git a/src/cryptoconditions/src/asn/asn_system.h b/src/cryptoconditions/src/asn/asn_system.h new file mode 100644 index 000000000..71596fc34 --- /dev/null +++ b/src/cryptoconditions/src/asn/asn_system.h @@ -0,0 +1,138 @@ +/*- + * Copyright (c) 2003, 2004, 2007 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +/* + * Miscellaneous system-dependent types. + */ +#ifndef ASN_SYSTEM_H +#define ASN_SYSTEM_H + +#ifdef CRYPTOCONDITIONS_HAVE_CONFIG_H +#include "cryptoconditions-config.h" +#endif + +#ifndef _BSD_SOURCE +#define _BSD_SOURCE /* for snprintf() on some linux systems */ +#endif + +#include /* For snprintf(3) */ +#include /* For *alloc(3) */ +#include /* For memcpy(3) */ +#include /* For size_t */ +#include /* For LONG_MAX */ +#include /* For va_start */ +#include /* for offsetof and ptrdiff_t */ + +#ifdef HAVE_ALLOCA_H +#include /* For alloca(3) */ +#endif + +#ifdef _WIN32 + +#include +#define snprintf _snprintf +#define vsnprintf _vsnprintf + +/* To avoid linking with ws2_32.lib, here's the definition of ntohl() */ +#define sys_ntohl(l) ((((l) << 24) & 0xff000000) \ + | (((l) << 8) & 0xff0000) \ + | (((l) >> 8) & 0xff00) \ + | ((l >> 24) & 0xff)) + +#ifdef _MSC_VER /* MSVS.Net */ +#ifndef __cplusplus +#define inline __inline +#endif +#ifndef ASSUMESTDTYPES /* Standard types have been defined elsewhere */ +#define ssize_t SSIZE_T +typedef char int8_t; +typedef short int16_t; +typedef int int32_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +#endif /* ASSUMESTDTYPES */ +#define WIN32_LEAN_AND_MEAN +#include +#include +#define isnan _isnan +#define finite _finite +#define copysign _copysign +#define ilogb _logb +#else /* !_MSC_VER */ +#include +#endif /* _MSC_VER */ + +#else /* !_WIN32 */ + +#if defined(__vxworks) +#include +#else /* !defined(__vxworks) */ + +#include /* C99 specifies this file */ +/* + * 1. Earlier FreeBSD version didn't have , + * but was present. + * 2. Sun Solaris requires for alloca(3), + * but does not have . + */ +#if (!defined(__FreeBSD__) || !defined(_SYS_INTTYPES_H_)) +#if defined(sun) +#include /* For alloca(3) */ +#include /* for finite(3) */ +#elif defined(__hpux) +#ifdef __GNUC__ +#include /* For alloca(3) */ +#else /* !__GNUC__ */ +#define inline +#endif /* __GNUC__ */ +#else +#include /* SUSv2+ and C99 specify this file, for uintXX_t */ +#endif /* defined(sun) */ +#endif + +#include /* for ntohl() */ +#define sys_ntohl(foo) ntohl(foo) + +#endif /* defined(__vxworks) */ + +#endif /* _WIN32 */ + +#if __GNUC__ >= 3 +#ifndef GCC_PRINTFLIKE +#define GCC_PRINTFLIKE(fmt,var) __attribute__((format(printf,fmt,var))) +#endif +#ifndef GCC_NOTUSED +#define GCC_NOTUSED __attribute__((unused)) +#endif +#else +#ifndef GCC_PRINTFLIKE +#define GCC_PRINTFLIKE(fmt,var) /* nothing */ +#endif +#ifndef GCC_NOTUSED +#define GCC_NOTUSED +#endif +#endif + +/* Figure out if thread safety is requested */ +#if !defined(ASN_THREAD_SAFE) && (defined(THREAD_SAFE) || defined(_REENTRANT)) +#define ASN_THREAD_SAFE +#endif /* Thread safety */ + +#ifndef offsetof /* If not defined by */ +#define offsetof(s, m) ((ptrdiff_t)&(((s *)0)->m) - (ptrdiff_t)((s *)0)) +#endif /* offsetof */ + + +//#ifndef MIN /* Suitable for comparing primitive types (integers) */ +//#if defined(__GNUC__) +//#define MIN(a,b) ({ __typeof a _a = a; __typeof b _b = b; \ +// ((_a)<(_b)?(_a):(_b)); }) +//#else /* !__GNUC__ */ +//#define MIN(a,b) ((a)<(b)?(a):(b)) /* Unsafe variant */ +//#endif /* __GNUC__ */ +//#endif /* MIN */ + +#endif /* ASN_SYSTEM_H */ diff --git a/src/cryptoconditions/src/asn/ber_decoder.c b/src/cryptoconditions/src/asn/ber_decoder.c new file mode 100644 index 000000000..b3a6329e0 --- /dev/null +++ b/src/cryptoconditions/src/asn/ber_decoder.c @@ -0,0 +1,283 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include + +#undef ADVANCE +#define ADVANCE(num_bytes) do { \ + size_t num = num_bytes; \ + ptr = ((const char *)ptr) + num; \ + size -= num; \ + consumed_myself += num; \ + } while(0) +#undef RETURN +#define RETURN(_code) do { \ + asn_dec_rval_t rval; \ + rval.code = _code; \ + if(opt_ctx) opt_ctx->step = step; /* Save context */ \ + if(_code == RC_OK || opt_ctx) \ + rval.consumed = consumed_myself; \ + else \ + rval.consumed = 0; /* Context-free */ \ + return rval; \ + } while(0) + +/* + * The BER decoder of any type. + */ +asn_dec_rval_t +ber_decode(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *type_descriptor, + void **struct_ptr, const void *ptr, size_t size) { + asn_codec_ctx_t s_codec_ctx; + + /* + * Stack checker requires that the codec context + * must be allocated on the stack. + */ + if(opt_codec_ctx) { + if(opt_codec_ctx->max_stack_size) { + s_codec_ctx = *opt_codec_ctx; + opt_codec_ctx = &s_codec_ctx; + } + } else { + /* If context is not given, be security-conscious anyway */ + memset(&s_codec_ctx, 0, sizeof(s_codec_ctx)); + s_codec_ctx.max_stack_size = ASN__DEFAULT_STACK_MAX; + opt_codec_ctx = &s_codec_ctx; + } + + /* + * Invoke type-specific decoder. + */ + return type_descriptor->ber_decoder(opt_codec_ctx, type_descriptor, + struct_ptr, /* Pointer to the destination structure */ + ptr, size, /* Buffer and its size */ + 0 /* Default tag mode is 0 */ + ); +} + +/* + * Check the set of >> tags matches the definition. + */ +asn_dec_rval_t +ber_check_tags(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, asn_struct_ctx_t *opt_ctx, + const void *ptr, size_t size, int tag_mode, int last_tag_form, + ber_tlv_len_t *last_length, int *opt_tlv_form) { + ssize_t consumed_myself = 0; + ssize_t tag_len; + ssize_t len_len; + ber_tlv_tag_t tlv_tag; + ber_tlv_len_t tlv_len; + ber_tlv_len_t limit_len = -1; + int expect_00_terminators = 0; + int tlv_constr = -1; /* If CHOICE, opt_tlv_form is not given */ + int step = opt_ctx ? opt_ctx->step : 0; /* Where we left previously */ + int tagno; + + /* + * Make sure we didn't exceed the maximum stack size. + */ + if(ASN__STACK_OVERFLOW_CHECK(opt_codec_ctx)) + RETURN(RC_FAIL); + + /* + * So what does all this implicit skip stuff mean? + * Imagine two types, + * A ::= [5] IMPLICIT T + * B ::= [2] EXPLICIT T + * Where T is defined as + * T ::= [4] IMPLICIT SEQUENCE { ... } + * + * Let's say, we are starting to decode type A, given the + * following TLV stream: <5> <0>. What does this mean? + * It means that the type A contains type T which is, + * in turn, empty. + * Remember though, that we are still in A. We cannot + * just pass control to the type T decoder. Why? Because + * the type T decoder expects <4> <0>, not <5> <0>. + * So, we must make sure we are going to receive <5> while + * still in A, then pass control to the T decoder, indicating + * that the tag <4> was implicitly skipped. The decoder of T + * hence will be prepared to treat <4> as valid tag, and decode + * it appropriately. + */ + + tagno = step /* Continuing where left previously */ + + (tag_mode==1?-1:0) + ; + ASN_DEBUG("ber_check_tags(%s, size=%ld, tm=%d, step=%d, tagno=%d)", + td->name, (long)size, tag_mode, step, tagno); + /* assert(td->tags_count >= 1) May not be the case for CHOICE or ANY */ + + if(tag_mode == 0 && tagno == td->tags_count) { + /* + * This must be the _untagged_ ANY type, + * which outermost tag isn't known in advance. + * Fetch the tag and length separately. + */ + tag_len = ber_fetch_tag(ptr, size, &tlv_tag); + switch(tag_len) { + case -1: RETURN(RC_FAIL); + case 0: RETURN(RC_WMORE); + } + tlv_constr = BER_TLV_CONSTRUCTED(ptr); + len_len = ber_fetch_length(tlv_constr, + (const char *)ptr + tag_len, size - tag_len, &tlv_len); + switch(len_len) { + case -1: RETURN(RC_FAIL); + case 0: RETURN(RC_WMORE); + } + ASN_DEBUG("Advancing %ld in ANY case", + (long)(tag_len + len_len)); + ADVANCE(tag_len + len_len); + } else { + assert(tagno < td->tags_count); /* At least one loop */ + } + for((void)tagno; tagno < td->tags_count; tagno++, step++) { + + /* + * Fetch and process T from TLV. + */ + tag_len = ber_fetch_tag(ptr, size, &tlv_tag); + ASN_DEBUG("Fetching tag from {%p,%ld}: " + "len %ld, step %d, tagno %d got %s", + ptr, (long)size, + (long)tag_len, step, tagno, + ber_tlv_tag_string(tlv_tag)); + switch(tag_len) { + case -1: RETURN(RC_FAIL); + case 0: RETURN(RC_WMORE); + } + + tlv_constr = BER_TLV_CONSTRUCTED(ptr); + + /* + * If {I}, don't check anything. + * If {I,B,C}, check B and C unless we're at I. + */ + if(tag_mode != 0 && step == 0) { + /* + * We don't expect tag to match here. + * It's just because we don't know how the tag + * is supposed to look like. + */ + } else { + assert(tagno >= 0); /* Guaranteed by the code above */ + if(tlv_tag != td->tags[tagno]) { + /* + * Unexpected tag. Too bad. + */ + ASN_DEBUG("Expected: %s, " + "expectation failed (tn=%d, tm=%d)", + ber_tlv_tag_string(td->tags[tagno]), + tagno, tag_mode + ); + RETURN(RC_FAIL); + } + } + + /* + * Attention: if there are more tags expected, + * ensure that the current tag is presented + * in constructed form (it contains other tags!). + * If this one is the last one, check that the tag form + * matches the one given in descriptor. + */ + if(tagno < (td->tags_count - 1)) { + if(tlv_constr == 0) { + ASN_DEBUG("tlv_constr = %d, expfail", + tlv_constr); + RETURN(RC_FAIL); + } + } else { + if(last_tag_form != tlv_constr + && last_tag_form != -1) { + ASN_DEBUG("last_tag_form %d != %d", + last_tag_form, tlv_constr); + RETURN(RC_FAIL); + } + } + + /* + * Fetch and process L from TLV. + */ + len_len = ber_fetch_length(tlv_constr, + (const char *)ptr + tag_len, size - tag_len, &tlv_len); + ASN_DEBUG("Fetching len = %ld", (long)len_len); + switch(len_len) { + case -1: RETURN(RC_FAIL); + case 0: RETURN(RC_WMORE); + } + + /* + * FIXME + * As of today, the chain of tags + * must either contain several indefinite length TLVs, + * or several definite length ones. + * No mixing is allowed. + */ + if(tlv_len == -1) { + /* + * Indefinite length. + */ + if(limit_len == -1) { + expect_00_terminators++; + } else { + ASN_DEBUG("Unexpected indefinite length " + "in a chain of definite lengths"); + RETURN(RC_FAIL); + } + ADVANCE(tag_len + len_len); + continue; + } else { + if(expect_00_terminators) { + ASN_DEBUG("Unexpected definite length " + "in a chain of indefinite lengths"); + RETURN(RC_FAIL); + } + } + + /* + * Check that multiple TLVs specify ever decreasing length, + * which is consistent. + */ + if(limit_len == -1) { + limit_len = tlv_len + tag_len + len_len; + if(limit_len < 0) { + /* Too great tlv_len value? */ + RETURN(RC_FAIL); + } + } else if(limit_len != tlv_len + tag_len + len_len) { + /* + * Inner TLV specifies length which is inconsistent + * with the outer TLV's length value. + */ + ASN_DEBUG("Outer TLV is %ld and inner is %ld", + (long)limit_len, (long)tlv_len); + RETURN(RC_FAIL); + } + + ADVANCE(tag_len + len_len); + + limit_len -= (tag_len + len_len); + if((ssize_t)size > limit_len) { + /* + * Make sure that we won't consume more bytes + * from the parent frame than the inferred limit. + */ + size = limit_len; + } + } + + if(opt_tlv_form) + *opt_tlv_form = tlv_constr; + if(expect_00_terminators) + *last_length = -expect_00_terminators; + else + *last_length = tlv_len; + + RETURN(RC_OK); +} diff --git a/src/cryptoconditions/src/asn/ber_decoder.h b/src/cryptoconditions/src/asn/ber_decoder.h new file mode 100644 index 000000000..9fe2e895d --- /dev/null +++ b/src/cryptoconditions/src/asn/ber_decoder.h @@ -0,0 +1,64 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _BER_DECODER_H_ +#define _BER_DECODER_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ +struct asn_codec_ctx_s; /* Forward declaration */ + +/* + * The BER decoder of any type. + * This function may be invoked directly from the application. + * The der_encode() function (der_encoder.h) is an opposite to ber_decode(). + */ +asn_dec_rval_t ber_decode(struct asn_codec_ctx_s *opt_codec_ctx, + struct asn_TYPE_descriptor_s *type_descriptor, + void **struct_ptr, /* Pointer to a target structure's pointer */ + const void *buffer, /* Data to be decoded */ + size_t size /* Size of that buffer */ + ); + +/* + * Type of generic function which decodes the byte stream into the structure. + */ +typedef asn_dec_rval_t (ber_type_decoder_f)( + struct asn_codec_ctx_s *opt_codec_ctx, + struct asn_TYPE_descriptor_s *type_descriptor, + void **struct_ptr, const void *buf_ptr, size_t size, + int tag_mode); + +/******************************* + * INTERNALLY USEFUL FUNCTIONS * + *******************************/ + +/* + * Check that all tags correspond to the type definition (as given in head). + * On return, last_length would contain either a non-negative length of the + * value part of the last TLV, or the negative number of expected + * "end of content" sequences. The number may only be negative if the + * head->last_tag_form is non-zero. + */ +asn_dec_rval_t ber_check_tags( + struct asn_codec_ctx_s *opt_codec_ctx, /* codec options */ + struct asn_TYPE_descriptor_s *type_descriptor, + asn_struct_ctx_t *opt_ctx, /* saved decoding context */ + const void *ptr, size_t size, + int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ + int last_tag_form, /* {-1,0:1}: any, primitive, constr */ + ber_tlv_len_t *last_length, + int *opt_tlv_form /* optional tag form */ + ); + +#ifdef __cplusplus +} +#endif + +#endif /* _BER_DECODER_H_ */ diff --git a/src/cryptoconditions/src/asn/ber_tlv_length.c b/src/cryptoconditions/src/asn/ber_tlv_length.c new file mode 100644 index 000000000..4c2f1e5fd --- /dev/null +++ b/src/cryptoconditions/src/asn/ber_tlv_length.c @@ -0,0 +1,178 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +ssize_t +ber_fetch_length(int _is_constructed, const void *bufptr, size_t size, + ber_tlv_len_t *len_r) { + const uint8_t *buf = (const uint8_t *)bufptr; + unsigned oct; + + if(size == 0) + return 0; /* Want more */ + + oct = *(const uint8_t *)buf; + if((oct & 0x80) == 0) { + /* + * Short definite length. + */ + *len_r = oct; /* & 0x7F */ + return 1; + } else { + ber_tlv_len_t len; + size_t skipped; + + if(_is_constructed && oct == 0x80) { + *len_r = -1; /* Indefinite length */ + return 1; + } + + if(oct == 0xff) { + /* Reserved in standard for future use. */ + return -1; + } + + oct &= 0x7F; /* Leave only the 7 LS bits */ + for(len = 0, buf++, skipped = 1; + oct && (++skipped <= size); buf++, oct--) { + + len = (len << 8) | *buf; + if(len < 0 + || (len >> ((8 * sizeof(len)) - 8) && oct > 1)) { + /* + * Too large length value. + */ + return -1; + } + } + + if(oct == 0) { + ber_tlv_len_t lenplusepsilon = (size_t)len + 1024; + /* + * Here length may be very close or equal to 2G. + * However, the arithmetics used in some decoders + * may add some (small) quantities to the length, + * to check the resulting value against some limits. + * This may result in integer wrap-around, which + * we try to avoid by checking it earlier here. + */ + if(lenplusepsilon < 0) { + /* Too large length value */ + return -1; + } + + *len_r = len; + return skipped; + } + + return 0; /* Want more */ + } + +} + +ssize_t +ber_skip_length(asn_codec_ctx_t *opt_codec_ctx, + int _is_constructed, const void *ptr, size_t size) { + ber_tlv_len_t vlen; /* Length of V in TLV */ + ssize_t tl; /* Length of L in TLV */ + ssize_t ll; /* Length of L in TLV */ + size_t skip; + + /* + * Make sure we didn't exceed the maximum stack size. + */ + if(ASN__STACK_OVERFLOW_CHECK(opt_codec_ctx)) + return -1; + + /* + * Determine the size of L in TLV. + */ + ll = ber_fetch_length(_is_constructed, ptr, size, &vlen); + if(ll <= 0) return ll; + + /* + * Definite length. + */ + if(vlen >= 0) { + skip = ll + vlen; + if(skip > size) + return 0; /* Want more */ + return skip; + } + + /* + * Indefinite length! + */ + ASN_DEBUG("Skipping indefinite length"); + for(skip = ll, ptr = ((const char *)ptr) + ll, size -= ll;;) { + ber_tlv_tag_t tag; + + /* Fetch the tag */ + tl = ber_fetch_tag(ptr, size, &tag); + if(tl <= 0) return tl; + + ll = ber_skip_length(opt_codec_ctx, + BER_TLV_CONSTRUCTED(ptr), + ((const char *)ptr) + tl, size - tl); + if(ll <= 0) return ll; + + skip += tl + ll; + + /* + * This may be the end of the indefinite length structure, + * two consecutive 0 octets. + * Check if it is true. + */ + if(((const uint8_t *)ptr)[0] == 0 + && ((const uint8_t *)ptr)[1] == 0) + return skip; + + ptr = ((const char *)ptr) + tl + ll; + size -= tl + ll; + } + + /* UNREACHABLE */ +} + +size_t +der_tlv_length_serialize(ber_tlv_len_t len, void *bufp, size_t size) { + size_t required_size; /* Size of len encoding */ + uint8_t *buf = (uint8_t *)bufp; + uint8_t *end; + size_t i; + + if(len <= 127) { + /* Encoded in 1 octet */ + if(size) *buf = (uint8_t)len; + return 1; + } + + /* + * Compute the size of the subsequent bytes. + */ + for(required_size = 1, i = 8; i < 8 * sizeof(len); i += 8) { + if(len >> i) + required_size++; + else + break; + } + + if(size <= required_size) + return required_size + 1; + + *buf++ = (uint8_t)(0x80 | required_size); /* Length of the encoding */ + + /* + * Produce the len encoding, space permitting. + */ + end = buf + required_size; + for(i -= 8; buf < end; i -= 8, buf++) + *buf = (uint8_t)(len >> i); + + return required_size + 1; +} + diff --git a/src/cryptoconditions/src/asn/ber_tlv_length.h b/src/cryptoconditions/src/asn/ber_tlv_length.h new file mode 100644 index 000000000..349680224 --- /dev/null +++ b/src/cryptoconditions/src/asn/ber_tlv_length.h @@ -0,0 +1,50 @@ +/*- + * Copyright (c) 2003 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _BER_TLV_LENGTH_H_ +#define _BER_TLV_LENGTH_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef ssize_t ber_tlv_len_t; + +/* + * This function tries to fetch the length of the BER TLV value and place it + * in *len_r. + * RETURN VALUES: + * 0: More data expected than bufptr contains. + * -1: Fatal error deciphering length. + * >0: Number of bytes used from bufptr. + * On return with >0, len_r is constrained as -1..MAX, where -1 mean + * that the value is of indefinite length. + */ +ssize_t ber_fetch_length(int _is_constructed, const void *bufptr, size_t size, + ber_tlv_len_t *len_r); + +/* + * This function expects bufptr to be positioned over L in TLV. + * It returns number of bytes occupied by L and V together, suitable + * for skipping. The function properly handles indefinite length. + * RETURN VALUES: + * Standard {-1,0,>0} convention. + */ +ssize_t ber_skip_length( + struct asn_codec_ctx_s *opt_codec_ctx, /* optional context */ + int _is_constructed, const void *bufptr, size_t size); + +/* + * This function serializes the length (L from TLV) in DER format. + * It always returns number of bytes necessary to represent the length, + * it is a caller's responsibility to check the return value + * against the supplied buffer's size. + */ +size_t der_tlv_length_serialize(ber_tlv_len_t len, void *bufptr, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif /* _BER_TLV_LENGTH_H_ */ diff --git a/src/cryptoconditions/src/asn/ber_tlv_tag.c b/src/cryptoconditions/src/asn/ber_tlv_tag.c new file mode 100644 index 000000000..42708760e --- /dev/null +++ b/src/cryptoconditions/src/asn/ber_tlv_tag.c @@ -0,0 +1,144 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +ssize_t +ber_fetch_tag(const void *ptr, size_t size, ber_tlv_tag_t *tag_r) { + ber_tlv_tag_t val; + ber_tlv_tag_t tclass; + size_t skipped; + + if(size == 0) + return 0; + + val = *(const uint8_t *)ptr; + tclass = (val >> 6); + if((val &= 0x1F) != 0x1F) { + /* + * Simple form: everything encoded in a single octet. + * Tag Class is encoded using two least significant bits. + */ + *tag_r = (val << 2) | tclass; + return 1; + } + + /* + * Each octet contains 7 bits of useful information. + * The MSB is 0 if it is the last octet of the tag. + */ + for(val = 0, ptr = ((const char *)ptr) + 1, skipped = 2; + skipped <= size; + ptr = ((const char *)ptr) + 1, skipped++) { + unsigned int oct = *(const uint8_t *)ptr; + if(oct & 0x80) { + val = (val << 7) | (oct & 0x7F); + /* + * Make sure there are at least 9 bits spare + * at the MS side of a value. + */ + if(val >> ((8 * sizeof(val)) - 9)) { + /* + * We would not be able to accomodate + * any more tag bits. + */ + return -1; + } + } else { + val = (val << 7) | oct; + *tag_r = (val << 2) | tclass; + return skipped; + } + } + + return 0; /* Want more */ +} + + +ssize_t +ber_tlv_tag_fwrite(ber_tlv_tag_t tag, FILE *f) { + char buf[sizeof("[APPLICATION ]") + 32]; + ssize_t ret; + + ret = ber_tlv_tag_snprint(tag, buf, sizeof(buf)); + if(ret >= (ssize_t)sizeof(buf) || ret < 2) { + errno = EPERM; + return -1; + } + + return fwrite(buf, 1, ret, f); +} + +ssize_t +ber_tlv_tag_snprint(ber_tlv_tag_t tag, char *buf, size_t size) { + char *type = 0; + int ret; + + switch(tag & 0x3) { + case ASN_TAG_CLASS_UNIVERSAL: type = "UNIVERSAL "; break; + case ASN_TAG_CLASS_APPLICATION: type = "APPLICATION "; break; + case ASN_TAG_CLASS_CONTEXT: type = ""; break; + case ASN_TAG_CLASS_PRIVATE: type = "PRIVATE "; break; + } + + ret = snprintf(buf, size, "[%s%u]", type, ((unsigned)tag) >> 2); + if(ret <= 0 && size) buf[0] = '\0'; /* against broken libc's */ + + return ret; +} + +char * +ber_tlv_tag_string(ber_tlv_tag_t tag) { + static char buf[sizeof("[APPLICATION ]") + 32]; + + (void)ber_tlv_tag_snprint(tag, buf, sizeof(buf)); + + return buf; +} + + +size_t +ber_tlv_tag_serialize(ber_tlv_tag_t tag, void *bufp, size_t size) { + int tclass = BER_TAG_CLASS(tag); + ber_tlv_tag_t tval = BER_TAG_VALUE(tag); + uint8_t *buf = (uint8_t *)bufp; + uint8_t *end; + size_t required_size; + size_t i; + + if(tval <= 30) { + /* Encoded in 1 octet */ + if(size) buf[0] = (tclass << 6) | tval; + return 1; + } else if(size) { + *buf++ = (tclass << 6) | 0x1F; + size--; + } + + /* + * Compute the size of the subsequent bytes. + */ + for(required_size = 1, i = 7; i < 8 * sizeof(tval); i += 7) { + if(tval >> i) + required_size++; + else + break; + } + + if(size < required_size) + return required_size + 1; + + /* + * Fill in the buffer, space permitting. + */ + end = buf + required_size - 1; + for(i -= 7; buf < end; i -= 7, buf++) + *buf = 0x80 | ((tval >> i) & 0x7F); + *buf = (tval & 0x7F); /* Last octet without high bit */ + + return required_size + 1; +} + diff --git a/src/cryptoconditions/src/asn/ber_tlv_tag.h b/src/cryptoconditions/src/asn/ber_tlv_tag.h new file mode 100644 index 000000000..60e866861 --- /dev/null +++ b/src/cryptoconditions/src/asn/ber_tlv_tag.h @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _BER_TLV_TAG_H_ +#define _BER_TLV_TAG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +enum asn_tag_class { + ASN_TAG_CLASS_UNIVERSAL = 0, /* 0b00 */ + ASN_TAG_CLASS_APPLICATION = 1, /* 0b01 */ + ASN_TAG_CLASS_CONTEXT = 2, /* 0b10 */ + ASN_TAG_CLASS_PRIVATE = 3 /* 0b11 */ +}; +typedef unsigned ber_tlv_tag_t; /* BER TAG from Tag-Length-Value */ + +/* + * Tag class is encoded together with tag value for optimization purposes. + */ +#define BER_TAG_CLASS(tag) ((tag) & 0x3) +#define BER_TAG_VALUE(tag) ((tag) >> 2) +#define BER_TLV_CONSTRUCTED(tagptr) (((*(const uint8_t *)tagptr)&0x20)?1:0) + +#define BER_TAGS_EQUAL(tag1, tag2) ((tag1) == (tag2)) + +/* + * Several functions for printing the TAG in the canonical form + * (i.e. "[PRIVATE 0]"). + * Return values correspond to their libc counterparts (if any). + */ +ssize_t ber_tlv_tag_snprint(ber_tlv_tag_t tag, char *buf, size_t buflen); +ssize_t ber_tlv_tag_fwrite(ber_tlv_tag_t tag, FILE *); +char *ber_tlv_tag_string(ber_tlv_tag_t tag); + + +/* + * This function tries to fetch the tag from the input stream. + * RETURN VALUES: + * 0: More data expected than bufptr contains. + * -1: Fatal error deciphering tag. + * >0: Number of bytes used from bufptr. tag_r will contain the tag. + */ +ssize_t ber_fetch_tag(const void *bufptr, size_t size, ber_tlv_tag_t *tag_r); + +/* + * This function serializes the tag (T from TLV) in BER format. + * It always returns number of bytes necessary to represent the tag, + * it is a caller's responsibility to check the return value + * against the supplied buffer's size. + */ +size_t ber_tlv_tag_serialize(ber_tlv_tag_t tag, void *bufptr, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif /* _BER_TLV_TAG_H_ */ diff --git a/src/cryptoconditions/src/asn/constr_CHOICE.c b/src/cryptoconditions/src/asn/constr_CHOICE.c new file mode 100644 index 000000000..6116e6a6b --- /dev/null +++ b/src/cryptoconditions/src/asn/constr_CHOICE.c @@ -0,0 +1,1114 @@ +/* + * Copyright (c) 2003, 2004, 2005, 2006, 2007 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +/* + * Number of bytes left for this structure. + * (ctx->left) indicates the number of bytes _transferred_ for the structure. + * (size) contains the number of bytes in the buffer passed. + */ +#define LEFT ((size<(size_t)ctx->left)?size:(size_t)ctx->left) + +/* + * If the subprocessor function returns with an indication that it wants + * more data, it may well be a fatal decoding problem, because the + * size is constrained by the 's L, even if the buffer size allows + * reading more data. + * For example, consider the buffer containing the following TLVs: + * ... + * The TLV length clearly indicates that one byte is expected in V, but + * if the V processor returns with "want more data" even if the buffer + * contains way more data than the V processor have seen. + */ +#define SIZE_VIOLATION (ctx->left >= 0 && (size_t)ctx->left <= size) + +/* + * This macro "eats" the part of the buffer which is definitely "consumed", + * i.e. was correctly converted into local representation or rightfully skipped. + */ +#undef ADVANCE +#define ADVANCE(num_bytes) do { \ + size_t num = num_bytes; \ + ptr = ((const char *)ptr) + num;\ + size -= num; \ + if(ctx->left >= 0) \ + ctx->left -= num; \ + consumed_myself += num; \ + } while(0) + +/* + * Switch to the next phase of parsing. + */ +#undef NEXT_PHASE +#define NEXT_PHASE(ctx) do { \ + ctx->phase++; \ + ctx->step = 0; \ + } while(0) + +/* + * Return a standardized complex structure. + */ +#undef RETURN +#define RETURN(_code) do { \ + rval.code = _code; \ + rval.consumed = consumed_myself;\ + return rval; \ + } while(0) + +/* + * See the definitions. + */ +static int _fetch_present_idx(const void *struct_ptr, int off, int size); +static void _set_present_idx(void *sptr, int offset, int size, int pres); + +/* + * Tags are canonically sorted in the tag to member table. + */ +static int +_search4tag(const void *ap, const void *bp) { + const asn_TYPE_tag2member_t *a = (const asn_TYPE_tag2member_t *)ap; + const asn_TYPE_tag2member_t *b = (const asn_TYPE_tag2member_t *)bp; + + int a_class = BER_TAG_CLASS(a->el_tag); + int b_class = BER_TAG_CLASS(b->el_tag); + + if(a_class == b_class) { + ber_tlv_tag_t a_value = BER_TAG_VALUE(a->el_tag); + ber_tlv_tag_t b_value = BER_TAG_VALUE(b->el_tag); + + if(a_value == b_value) + return 0; + else if(a_value < b_value) + return -1; + else + return 1; + } else if(a_class < b_class) { + return -1; + } else { + return 1; + } +} + +/* + * The decoder of the CHOICE type. + */ +asn_dec_rval_t +CHOICE_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **struct_ptr, const void *ptr, size_t size, int tag_mode) { + /* + * Bring closer parts of structure description. + */ + asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; + asn_TYPE_member_t *elements = td->elements; + + /* + * Parts of the structure being constructed. + */ + void *st = *struct_ptr; /* Target structure. */ + asn_struct_ctx_t *ctx; /* Decoder context */ + + ber_tlv_tag_t tlv_tag; /* T from TLV */ + ssize_t tag_len; /* Length of TLV's T */ + asn_dec_rval_t rval; /* Return code from subparsers */ + + ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ + + ASN_DEBUG("Decoding %s as CHOICE", td->name); + + /* + * Create the target structure if it is not present already. + */ + if(st == 0) { + st = *struct_ptr = CALLOC(1, specs->struct_size); + if(st == 0) { + RETURN(RC_FAIL); + } + } + + /* + * Restore parsing context. + */ + ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); + + /* + * Start to parse where left previously + */ + switch(ctx->phase) { + case 0: + /* + * PHASE 0. + * Check that the set of tags associated with given structure + * perfectly fits our expectations. + */ + + if(tag_mode || td->tags_count) { + rval = ber_check_tags(opt_codec_ctx, td, ctx, ptr, size, + tag_mode, -1, &ctx->left, 0); + if(rval.code != RC_OK) { + ASN_DEBUG("%s tagging check failed: %d", + td->name, rval.code); + return rval; + } + + if(ctx->left >= 0) { + /* ?Substracted below! */ + ctx->left += rval.consumed; + } + ADVANCE(rval.consumed); + } else { + ctx->left = -1; + } + + NEXT_PHASE(ctx); + + ASN_DEBUG("Structure consumes %ld bytes, buffer %ld", + (long)ctx->left, (long)size); + + /* Fall through */ + case 1: + /* + * Fetch the T from TLV. + */ + tag_len = ber_fetch_tag(ptr, LEFT, &tlv_tag); + ASN_DEBUG("In %s CHOICE tag length %d", td->name, (int)tag_len); + switch(tag_len) { + case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); + /* Fall through */ + case -1: RETURN(RC_FAIL); + } + + do { + const asn_TYPE_tag2member_t *t2m; + asn_TYPE_tag2member_t key; + + key.el_tag = tlv_tag; + t2m = (const asn_TYPE_tag2member_t *)bsearch(&key, + specs->tag2el, specs->tag2el_count, + sizeof(specs->tag2el[0]), _search4tag); + if(t2m) { + /* + * Found the element corresponding to the tag. + */ + NEXT_PHASE(ctx); + ctx->step = t2m->el_no; + break; + } else if(specs->ext_start == -1) { + ASN_DEBUG("Unexpected tag %s " + "in non-extensible CHOICE %s", + ber_tlv_tag_string(tlv_tag), td->name); + RETURN(RC_FAIL); + } else { + /* Skip this tag */ + ssize_t skip; + + ASN_DEBUG("Skipping unknown tag %s", + ber_tlv_tag_string(tlv_tag)); + + skip = ber_skip_length(opt_codec_ctx, + BER_TLV_CONSTRUCTED(ptr), + (const char *)ptr + tag_len, + LEFT - tag_len); + + switch(skip) { + case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); + /* Fall through */ + case -1: RETURN(RC_FAIL); + } + + ADVANCE(skip + tag_len); + RETURN(RC_OK); + } + } while(0); + + case 2: + /* + * PHASE 2. + * Read in the element. + */ + do { + asn_TYPE_member_t *elm;/* CHOICE's element */ + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + + elm = &elements[ctx->step]; + + /* + * Compute the position of the member inside a structure, + * and also a type of containment (it may be contained + * as pointer or using inline inclusion). + */ + if(elm->flags & ATF_POINTER) { + /* Member is a pointer to another structure */ + memb_ptr2 = (void **)((char *)st + elm->memb_offset); + } else { + /* + * A pointer to a pointer + * holding the start of the structure + */ + memb_ptr = (char *)st + elm->memb_offset; + memb_ptr2 = &memb_ptr; + } + /* Set presence to be able to free it properly at any time */ + _set_present_idx(st, specs->pres_offset, + specs->pres_size, ctx->step + 1); + /* + * Invoke the member fetch routine according to member's type + */ + rval = elm->type->ber_decoder(opt_codec_ctx, elm->type, + memb_ptr2, ptr, LEFT, elm->tag_mode); + switch(rval.code) { + case RC_OK: + break; + case RC_WMORE: /* More data expected */ + if(!SIZE_VIOLATION) { + ADVANCE(rval.consumed); + RETURN(RC_WMORE); + } + RETURN(RC_FAIL); + case RC_FAIL: /* Fatal error */ + RETURN(rval.code); + } /* switch(rval) */ + + ADVANCE(rval.consumed); + } while(0); + + NEXT_PHASE(ctx); + + /* Fall through */ + case 3: + ASN_DEBUG("CHOICE %s Leftover: %ld, size = %ld, tm=%d, tc=%d", + td->name, (long)ctx->left, (long)size, + tag_mode, td->tags_count); + + if(ctx->left > 0) { + /* + * The type must be fully decoded + * by the CHOICE member-specific decoder. + */ + RETURN(RC_FAIL); + } + + if(ctx->left == -1 + && !(tag_mode || td->tags_count)) { + /* + * This is an untagged CHOICE. + * It doesn't contain nothing + * except for the member itself, including all its tags. + * The decoding is completed. + */ + NEXT_PHASE(ctx); + break; + } + + /* + * Read in the "end of data chunks"'s. + */ + while(ctx->left < 0) { + ssize_t tl; + + tl = ber_fetch_tag(ptr, LEFT, &tlv_tag); + switch(tl) { + case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); + /* Fall through */ + case -1: RETURN(RC_FAIL); + } + + /* + * Expected <0><0>... + */ + if(((const uint8_t *)ptr)[0] == 0) { + if(LEFT < 2) { + if(SIZE_VIOLATION) + RETURN(RC_FAIL); + else + RETURN(RC_WMORE); + } else if(((const uint8_t *)ptr)[1] == 0) { + /* + * Correctly finished with <0><0>. + */ + ADVANCE(2); + ctx->left++; + continue; + } + } else { + ASN_DEBUG("Unexpected continuation in %s", + td->name); + RETURN(RC_FAIL); + } + + /* UNREACHABLE */ + } + + NEXT_PHASE(ctx); + case 4: + /* No meaningful work here */ + break; + } + + RETURN(RC_OK); +} + +asn_enc_rval_t +CHOICE_encode_der(asn_TYPE_descriptor_t *td, void *sptr, + int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; + asn_TYPE_member_t *elm; /* CHOICE element */ + asn_enc_rval_t erval; + void *memb_ptr; + size_t computed_size = 0; + int present; + + if(!sptr) ASN__ENCODE_FAILED; + + ASN_DEBUG("%s %s as CHOICE", + cb?"Encoding":"Estimating", td->name); + + present = _fetch_present_idx(sptr, + specs->pres_offset, specs->pres_size); + + /* + * If the structure was not initialized, it cannot be encoded: + * can't deduce what to encode in the choice type. + */ + if(present <= 0 || present > td->elements_count) { + if(present == 0 && td->elements_count == 0) { + /* The CHOICE is empty?! */ + erval.encoded = 0; + ASN__ENCODED_OK(erval); + } + ASN__ENCODE_FAILED; + } + + /* + * Seek over the present member of the structure. + */ + elm = &td->elements[present-1]; + if(elm->flags & ATF_POINTER) { + memb_ptr = *(void **)((char *)sptr + elm->memb_offset); + if(memb_ptr == 0) { + if(elm->optional) { + erval.encoded = 0; + ASN__ENCODED_OK(erval); + } + /* Mandatory element absent */ + ASN__ENCODE_FAILED; + } + } else { + memb_ptr = (void *)((char *)sptr + elm->memb_offset); + } + + /* + * If the CHOICE itself is tagged EXPLICIT: + * T ::= [2] EXPLICIT CHOICE { ... } + * Then emit the appropriate tags. + */ + if(tag_mode == 1 || td->tags_count) { + /* + * For this, we need to pre-compute the member. + */ + ssize_t ret; + + /* Encode member with its tag */ + erval = elm->type->der_encoder(elm->type, memb_ptr, + elm->tag_mode, elm->tag, 0, 0); + if(erval.encoded == -1) + return erval; + + /* Encode CHOICE with parent or my own tag */ + ret = der_write_tags(td, erval.encoded, tag_mode, 1, tag, + cb, app_key); + if(ret == -1) + ASN__ENCODE_FAILED; + computed_size += ret; + } + + /* + * Encode the single underlying member. + */ + erval = elm->type->der_encoder(elm->type, memb_ptr, + elm->tag_mode, elm->tag, cb, app_key); + if(erval.encoded == -1) + return erval; + + ASN_DEBUG("Encoded CHOICE member in %ld bytes (+%ld)", + (long)erval.encoded, (long)computed_size); + + erval.encoded += computed_size; + + return erval; +} + +ber_tlv_tag_t +CHOICE_outmost_tag(const asn_TYPE_descriptor_t *td, const void *ptr, int tag_mode, ber_tlv_tag_t tag) { + asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; + int present; + + assert(tag_mode == 0); (void)tag_mode; + assert(tag == 0); (void)tag; + + /* + * Figure out which CHOICE element is encoded. + */ + present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size); + + if(present > 0 || present <= td->elements_count) { + const asn_TYPE_member_t *elm = &td->elements[present-1]; + const void *memb_ptr; + + if(elm->flags & ATF_POINTER) { + memb_ptr = *(const void * const *) + ((const char *)ptr + elm->memb_offset); + } else { + memb_ptr = (const void *) + ((const char *)ptr + elm->memb_offset); + } + + return asn_TYPE_outmost_tag(elm->type, memb_ptr, + elm->tag_mode, elm->tag); + } else { + return (ber_tlv_tag_t)-1; + } +} + +int +CHOICE_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; + int present; + + if(!sptr) { + ASN__CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + /* + * Figure out which CHOICE element is encoded. + */ + present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size); + if(present > 0 && present <= td->elements_count) { + asn_TYPE_member_t *elm = &td->elements[present-1]; + const void *memb_ptr; + + if(elm->flags & ATF_POINTER) { + memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset); + if(!memb_ptr) { + if(elm->optional) + return 0; + ASN__CTFAIL(app_key, td, sptr, + "%s: mandatory CHOICE element %s absent (%s:%d)", + td->name, elm->name, __FILE__, __LINE__); + return -1; + } + } else { + memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); + } + + if(elm->memb_constraints) { + return elm->memb_constraints(elm->type, memb_ptr, + ctfailcb, app_key); + } else { + int ret = elm->type->check_constraints(elm->type, + memb_ptr, ctfailcb, app_key); + /* + * Cannot inherit it eralier: + * need to make sure we get the updated version. + */ + elm->memb_constraints = elm->type->check_constraints; + return ret; + } + } else { + ASN__CTFAIL(app_key, td, sptr, + "%s: no CHOICE element given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } +} + +#undef XER_ADVANCE +#define XER_ADVANCE(num_bytes) do { \ + size_t num = num_bytes; \ + buf_ptr = (const void *)(((const char *)buf_ptr) + num); \ + size -= num; \ + consumed_myself += num; \ + } while(0) + +/* + * Decode the XER (XML) data. + */ +asn_dec_rval_t +CHOICE_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **struct_ptr, const char *opt_mname, + const void *buf_ptr, size_t size) { + /* + * Bring closer parts of structure description. + */ + asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; + const char *xml_tag = opt_mname ? opt_mname : td->xml_tag; + + /* + * Parts of the structure being constructed. + */ + void *st = *struct_ptr; /* Target structure. */ + asn_struct_ctx_t *ctx; /* Decoder context */ + + asn_dec_rval_t rval; /* Return value of a decoder */ + ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ + int edx; /* Element index */ + + /* + * Create the target structure if it is not present already. + */ + if(st == 0) { + st = *struct_ptr = CALLOC(1, specs->struct_size); + if(st == 0) RETURN(RC_FAIL); + } + + /* + * Restore parsing context. + */ + ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); + if(ctx->phase == 0 && !*xml_tag) + ctx->phase = 1; /* Skip the outer tag checking phase */ + + /* + * Phases of XER/XML processing: + * Phase 0: Check that the opening tag matches our expectations. + * Phase 1: Processing body and reacting on closing tag. + * Phase 2: Processing inner type. + * Phase 3: Only waiting for closing tag. + * Phase 4: Skipping unknown extensions. + * Phase 5: PHASED OUT + */ + for(edx = ctx->step; ctx->phase <= 4;) { + pxer_chunk_type_e ch_type; /* XER chunk type */ + ssize_t ch_size; /* Chunk size */ + xer_check_tag_e tcv; /* Tag check value */ + asn_TYPE_member_t *elm; + + /* + * Go inside the member. + */ + if(ctx->phase == 2) { + asn_dec_rval_t tmprval; + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + + elm = &td->elements[edx]; + + if(elm->flags & ATF_POINTER) { + /* Member is a pointer to another structure */ + memb_ptr2 = (void **)((char *)st + + elm->memb_offset); + } else { + memb_ptr = (char *)st + elm->memb_offset; + memb_ptr2 = &memb_ptr; + } + + /* Start/Continue decoding the inner member */ + tmprval = elm->type->xer_decoder(opt_codec_ctx, + elm->type, memb_ptr2, elm->name, + buf_ptr, size); + XER_ADVANCE(tmprval.consumed); + ASN_DEBUG("XER/CHOICE: itdf: [%s] code=%d", + elm->type->name, tmprval.code); + if(tmprval.code != RC_OK) + RETURN(tmprval.code); + assert(_fetch_present_idx(st, + specs->pres_offset, specs->pres_size) == 0); + /* Record what we've got */ + _set_present_idx(st, + specs->pres_offset, specs->pres_size, edx + 1); + ctx->phase = 3; + /* Fall through */ + } + + /* No need to wait for closing tag; special mode. */ + if(ctx->phase == 3 && !*xml_tag) { + ctx->phase = 5; /* Phase out */ + RETURN(RC_OK); + } + + /* + * Get the next part of the XML stream. + */ + ch_size = xer_next_token(&ctx->context, buf_ptr, size, &ch_type); + if(ch_size == -1) { + RETURN(RC_FAIL); + } else { + switch(ch_type) { + case PXER_WMORE: + RETURN(RC_WMORE); + case PXER_COMMENT: /* Got XML comment */ + case PXER_TEXT: /* Ignore free-standing text */ + XER_ADVANCE(ch_size); /* Skip silently */ + continue; + case PXER_TAG: + break; /* Check the rest down there */ + } + } + + tcv = xer_check_tag(buf_ptr, ch_size, xml_tag); + ASN_DEBUG("XER/CHOICE checked [%c%c%c%c] vs [%s], tcv=%d", + ch_size>0?((const uint8_t *)buf_ptr)[0]:'?', + ch_size>1?((const uint8_t *)buf_ptr)[1]:'?', + ch_size>2?((const uint8_t *)buf_ptr)[2]:'?', + ch_size>3?((const uint8_t *)buf_ptr)[3]:'?', + xml_tag, tcv); + + /* Skip the extensions section */ + if(ctx->phase == 4) { + ASN_DEBUG("skip_unknown(%d, %ld)", + tcv, (long)ctx->left); + switch(xer_skip_unknown(tcv, &ctx->left)) { + case -1: + ctx->phase = 5; + RETURN(RC_FAIL); + continue; + case 1: + ctx->phase = 3; + /* Fall through */ + case 0: + XER_ADVANCE(ch_size); + continue; + case 2: + ctx->phase = 3; + break; + } + } + + switch(tcv) { + case XCT_BOTH: + break; /* No CHOICE? */ + case XCT_CLOSING: + if(ctx->phase != 3) + break; + XER_ADVANCE(ch_size); + ctx->phase = 5; /* Phase out */ + RETURN(RC_OK); + case XCT_OPENING: + if(ctx->phase == 0) { + XER_ADVANCE(ch_size); + ctx->phase = 1; /* Processing body phase */ + continue; + } + /* Fall through */ + case XCT_UNKNOWN_OP: + case XCT_UNKNOWN_BO: + + if(ctx->phase != 1) + break; /* Really unexpected */ + + /* + * Search which inner member corresponds to this tag. + */ + for(edx = 0; edx < td->elements_count; edx++) { + elm = &td->elements[edx]; + tcv = xer_check_tag(buf_ptr,ch_size,elm->name); + switch(tcv) { + case XCT_BOTH: + case XCT_OPENING: + /* + * Process this member. + */ + ctx->step = edx; + ctx->phase = 2; + break; + case XCT_UNKNOWN_OP: + case XCT_UNKNOWN_BO: + continue; + default: + edx = td->elements_count; + break; /* Phase out */ + } + break; + } + if(edx != td->elements_count) + continue; + + /* It is expected extension */ + if(specs->ext_start != -1) { + ASN_DEBUG("Got anticipated extension"); + /* + * Check for (XCT_BOTH or XCT_UNKNOWN_BO) + * By using a mask. Only record a pure + * tags. + */ + if(tcv & XCT_CLOSING) { + /* Found without body */ + ctx->phase = 3; /* Terminating */ + } else { + ctx->left = 1; + ctx->phase = 4; /* Skip ...'s */ + } + XER_ADVANCE(ch_size); + continue; + } + + /* Fall through */ + default: + break; + } + + ASN_DEBUG("Unexpected XML tag [%c%c%c%c] in CHOICE [%s]" + " (ph=%d, tag=%s)", + ch_size>0?((const uint8_t *)buf_ptr)[0]:'?', + ch_size>1?((const uint8_t *)buf_ptr)[1]:'?', + ch_size>2?((const uint8_t *)buf_ptr)[2]:'?', + ch_size>3?((const uint8_t *)buf_ptr)[3]:'?', + td->name, ctx->phase, xml_tag); + break; + } + + ctx->phase = 5; /* Phase out, just in case */ + RETURN(RC_FAIL); +} + + +asn_enc_rval_t +CHOICE_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_CHOICE_specifics_t *specs=(asn_CHOICE_specifics_t *)td->specifics; + asn_enc_rval_t er; + int present; + + if(!sptr) + ASN__ENCODE_FAILED; + + /* + * Figure out which CHOICE element is encoded. + */ + present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size); + + if(present <= 0 || present > td->elements_count) { + ASN__ENCODE_FAILED; + } else { + asn_enc_rval_t tmper; + asn_TYPE_member_t *elm = &td->elements[present-1]; + void *memb_ptr; + const char *mname = elm->name; + unsigned int mlen = strlen(mname); + + if(elm->flags & ATF_POINTER) { + memb_ptr = *(void **)((char *)sptr + elm->memb_offset); + if(!memb_ptr) ASN__ENCODE_FAILED; + } else { + memb_ptr = (void *)((char *)sptr + elm->memb_offset); + } + + er.encoded = 0; + + if(!(flags & XER_F_CANONICAL)) ASN__TEXT_INDENT(1, ilevel); + ASN__CALLBACK3("<", 1, mname, mlen, ">", 1); + + tmper = elm->type->xer_encoder(elm->type, memb_ptr, + ilevel + 1, flags, cb, app_key); + if(tmper.encoded == -1) return tmper; + + ASN__CALLBACK3("", 1); + + er.encoded += 5 + (2 * mlen) + tmper.encoded; + } + + if(!(flags & XER_F_CANONICAL)) ASN__TEXT_INDENT(1, ilevel - 1); + + ASN__ENCODED_OK(er); +cb_failed: + ASN__ENCODE_FAILED; +} + +asn_dec_rval_t +CHOICE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { + asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; + asn_dec_rval_t rv; + asn_per_constraint_t *ct; + asn_TYPE_member_t *elm; /* CHOICE's element */ + void *memb_ptr; + void **memb_ptr2; + void *st = *sptr; + int value; + + if(ASN__STACK_OVERFLOW_CHECK(opt_codec_ctx)) + ASN__DECODE_FAILED; + + /* + * Create the target structure if it is not present already. + */ + if(!st) { + st = *sptr = CALLOC(1, specs->struct_size); + if(!st) ASN__DECODE_FAILED; + } + + if(constraints) ct = &constraints->value; + else if(td->per_constraints) ct = &td->per_constraints->value; + else ct = 0; + + if(ct && ct->flags & APC_EXTENSIBLE) { + value = per_get_few_bits(pd, 1); + if(value < 0) ASN__DECODE_STARVED; + if(value) ct = 0; /* Not restricted */ + } + + if(ct && ct->range_bits >= 0) { + value = per_get_few_bits(pd, ct->range_bits); + if(value < 0) ASN__DECODE_STARVED; + ASN_DEBUG("CHOICE %s got index %d in range %d", + td->name, value, ct->range_bits); + if(value > ct->upper_bound) + ASN__DECODE_FAILED; + } else { + if(specs->ext_start == -1) + ASN__DECODE_FAILED; + value = uper_get_nsnnwn(pd); + if(value < 0) ASN__DECODE_STARVED; + value += specs->ext_start; + if(value >= td->elements_count) + ASN__DECODE_FAILED; + } + + /* Adjust if canonical order is different from natural order */ + if(specs->canonical_order) + value = specs->canonical_order[value]; + + /* Set presence to be able to free it later */ + _set_present_idx(st, specs->pres_offset, specs->pres_size, value + 1); + + elm = &td->elements[value]; + if(elm->flags & ATF_POINTER) { + /* Member is a pointer to another structure */ + memb_ptr2 = (void **)((char *)st + elm->memb_offset); + } else { + memb_ptr = (char *)st + elm->memb_offset; + memb_ptr2 = &memb_ptr; + } + ASN_DEBUG("Discovered CHOICE %s encodes %s", td->name, elm->name); + + if(ct && ct->range_bits >= 0) { + rv = elm->type->uper_decoder(opt_codec_ctx, elm->type, + elm->per_constraints, memb_ptr2, pd); + } else { + rv = uper_open_type_get(opt_codec_ctx, elm->type, + elm->per_constraints, memb_ptr2, pd); + } + + if(rv.code != RC_OK) + ASN_DEBUG("Failed to decode %s in %s (CHOICE) %d", + elm->name, td->name, rv.code); + return rv; +} + +asn_enc_rval_t +CHOICE_encode_uper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; + asn_TYPE_member_t *elm; /* CHOICE's element */ + asn_per_constraint_t *ct; + void *memb_ptr; + int present; + int present_enc; + + if(!sptr) ASN__ENCODE_FAILED; + + ASN_DEBUG("Encoding %s as CHOICE", td->name); + + if(constraints) ct = &constraints->value; + else if(td->per_constraints) ct = &td->per_constraints->value; + else ct = 0; + + present = _fetch_present_idx(sptr, + specs->pres_offset, specs->pres_size); + + /* + * If the structure was not initialized properly, it cannot be encoded: + * can't deduce what to encode in the choice type. + */ + if(present <= 0 || present > td->elements_count) + ASN__ENCODE_FAILED; + else + present--; + + ASN_DEBUG("Encoding %s CHOICE element %d", td->name, present); + + /* Adjust if canonical order is different from natural order */ + if(specs->canonical_order) + present_enc = specs->canonical_order[present]; + else + present_enc = present; + + if(ct && ct->range_bits >= 0) { + if(present_enc < ct->lower_bound + || present_enc > ct->upper_bound) { + if(ct->flags & APC_EXTENSIBLE) { + if(per_put_few_bits(po, 1, 1)) + ASN__ENCODE_FAILED; + } else { + ASN__ENCODE_FAILED; + } + ct = 0; + } + } + if(ct && ct->flags & APC_EXTENSIBLE) + if(per_put_few_bits(po, 0, 1)) + ASN__ENCODE_FAILED; + + elm = &td->elements[present]; + if(elm->flags & ATF_POINTER) { + /* Member is a pointer to another structure */ + memb_ptr = *(void **)((char *)sptr + elm->memb_offset); + if(!memb_ptr) ASN__ENCODE_FAILED; + } else { + memb_ptr = (char *)sptr + elm->memb_offset; + } + + if(ct && ct->range_bits >= 0) { + if(per_put_few_bits(po, present_enc, ct->range_bits)) + ASN__ENCODE_FAILED; + + return elm->type->uper_encoder(elm->type, elm->per_constraints, + memb_ptr, po); + } else { + asn_enc_rval_t rval; + if(specs->ext_start == -1) + ASN__ENCODE_FAILED; + if(uper_put_nsnnwn(po, present_enc - specs->ext_start)) + ASN__ENCODE_FAILED; + if(uper_open_type_put(elm->type, elm->per_constraints, + memb_ptr, po)) + ASN__ENCODE_FAILED; + rval.encoded = 0; + ASN__ENCODED_OK(rval); + } +} + + +int +CHOICE_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; + int present; + + if(!sptr) return (cb("", 8, app_key) < 0) ? -1 : 0; + + /* + * Figure out which CHOICE element is encoded. + */ + present = _fetch_present_idx(sptr, specs->pres_offset,specs->pres_size); + + /* + * Print that element. + */ + if(present > 0 && present <= td->elements_count) { + asn_TYPE_member_t *elm = &td->elements[present-1]; + const void *memb_ptr; + + if(elm->flags & ATF_POINTER) { + memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset); + if(!memb_ptr) return (cb("", 8, app_key) < 0) ? -1 : 0; + } else { + memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); + } + + /* Print member's name and stuff */ + if(0) { + if(cb(elm->name, strlen(elm->name), app_key) < 0 + || cb(": ", 2, app_key) < 0) + return -1; + } + + return elm->type->print_struct(elm->type, memb_ptr, ilevel, + cb, app_key); + } else { + return (cb("", 8, app_key) < 0) ? -1 : 0; + } +} + +void +CHOICE_free(asn_TYPE_descriptor_t *td, void *ptr, int contents_only) { + asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; + int present; + + if(!td || !ptr) + return; + + ASN_DEBUG("Freeing %s as CHOICE", td->name); + + /* + * Figure out which CHOICE element is encoded. + */ + present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size); + + /* + * Free that element. + */ + if(present > 0 && present <= td->elements_count) { + asn_TYPE_member_t *elm = &td->elements[present-1]; + void *memb_ptr; + + if(elm->flags & ATF_POINTER) { + memb_ptr = *(void **)((char *)ptr + elm->memb_offset); + if(memb_ptr) + ASN_STRUCT_FREE(*elm->type, memb_ptr); + } else { + memb_ptr = (void *)((char *)ptr + elm->memb_offset); + ASN_STRUCT_FREE_CONTENTS_ONLY(*elm->type, memb_ptr); + } + } + + if(!contents_only) { + FREEMEM(ptr); + } +} + + +/* + * The following functions functions offer protection against -fshort-enums, + * compatible with little- and big-endian machines. + * If assertion is triggered, either disable -fshort-enums, or add an entry + * here with the ->pres_size of your target stracture. + * Unless the target structure is packed, the ".present" member + * is guaranteed to be aligned properly. ASN.1 compiler itself does not + * produce packed code. + */ +static int +_fetch_present_idx(const void *struct_ptr, int pres_offset, int pres_size) { + const void *present_ptr; + int present; + + present_ptr = ((const char *)struct_ptr) + pres_offset; + + switch(pres_size) { + case sizeof(int): present = *(const int *)present_ptr; break; + case sizeof(short): present = *(const short *)present_ptr; break; + case sizeof(char): present = *(const char *)present_ptr; break; + default: + /* ANSI C mandates enum to be equivalent to integer */ + assert(pres_size != sizeof(int)); + return 0; /* If not aborted, pass back safe value */ + } + + return present; +} + +static void +_set_present_idx(void *struct_ptr, int pres_offset, int pres_size, int present) { + void *present_ptr; + present_ptr = ((char *)struct_ptr) + pres_offset; + + switch(pres_size) { + case sizeof(int): *(int *)present_ptr = present; break; + case sizeof(short): *(short *)present_ptr = present; break; + case sizeof(char): *(char *)present_ptr = present; break; + default: + /* ANSI C mandates enum to be equivalent to integer */ + assert(pres_size != sizeof(int)); + } +} diff --git a/src/cryptoconditions/src/asn/constr_CHOICE.h b/src/cryptoconditions/src/asn/constr_CHOICE.h new file mode 100644 index 000000000..e824a2206 --- /dev/null +++ b/src/cryptoconditions/src/asn/constr_CHOICE.h @@ -0,0 +1,57 @@ +/*- + * Copyright (c) 2003, 2004, 2005 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _CONSTR_CHOICE_H_ +#define _CONSTR_CHOICE_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef const struct asn_CHOICE_specifics_s { + /* + * Target structure description. + */ + int struct_size; /* Size of the target structure. */ + int ctx_offset; /* Offset of the asn_codec_ctx_t member */ + int pres_offset; /* Identifier of the present member */ + int pres_size; /* Size of the identifier (enum) */ + + /* + * Tags to members mapping table. + */ + const asn_TYPE_tag2member_t *tag2el; + int tag2el_count; + + /* Canonical ordering of CHOICE elements, for PER */ + int *canonical_order; + + /* + * Extensions-related stuff. + */ + int ext_start; /* First member of extensions, or -1 */ +} asn_CHOICE_specifics_t; + +/* + * A set specialized functions dealing with the CHOICE type. + */ +asn_struct_free_f CHOICE_free; +asn_struct_print_f CHOICE_print; +asn_constr_check_f CHOICE_constraint; +ber_type_decoder_f CHOICE_decode_ber; +der_type_encoder_f CHOICE_encode_der; +xer_type_decoder_f CHOICE_decode_xer; +xer_type_encoder_f CHOICE_encode_xer; +per_type_decoder_f CHOICE_decode_uper; +per_type_encoder_f CHOICE_encode_uper; +asn_outmost_tag_f CHOICE_outmost_tag; + +#ifdef __cplusplus +} +#endif + +#endif /* _CONSTR_CHOICE_H_ */ diff --git a/src/cryptoconditions/src/asn/constr_SEQUENCE.c b/src/cryptoconditions/src/asn/constr_SEQUENCE.c new file mode 100644 index 000000000..5923023de --- /dev/null +++ b/src/cryptoconditions/src/asn/constr_SEQUENCE.c @@ -0,0 +1,1425 @@ +/*- + * Copyright (c) 2003, 2004, 2005, 2006, 2007 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +/* + * Number of bytes left for this structure. + * (ctx->left) indicates the number of bytes _transferred_ for the structure. + * (size) contains the number of bytes in the buffer passed. + */ +#define LEFT ((size<(size_t)ctx->left)?size:(size_t)ctx->left) + +/* + * If the subprocessor function returns with an indication that it wants + * more data, it may well be a fatal decoding problem, because the + * size is constrained by the 's L, even if the buffer size allows + * reading more data. + * For example, consider the buffer containing the following TLVs: + * ... + * The TLV length clearly indicates that one byte is expected in V, but + * if the V processor returns with "want more data" even if the buffer + * contains way more data than the V processor have seen. + */ +#define SIZE_VIOLATION (ctx->left >= 0 && (size_t)ctx->left <= size) + +/* + * This macro "eats" the part of the buffer which is definitely "consumed", + * i.e. was correctly converted into local representation or rightfully skipped. + */ +#undef ADVANCE +#define ADVANCE(num_bytes) do { \ + size_t num = num_bytes; \ + ptr = ((const char *)ptr) + num; \ + size -= num; \ + if(ctx->left >= 0) \ + ctx->left -= num; \ + consumed_myself += num; \ + } while(0) + +/* + * Switch to the next phase of parsing. + */ +#undef NEXT_PHASE +#undef PHASE_OUT +#define NEXT_PHASE(ctx) do { \ + ctx->phase++; \ + ctx->step = 0; \ + } while(0) +#define PHASE_OUT(ctx) do { ctx->phase = 10; } while(0) + +/* + * Return a standardized complex structure. + */ +#undef RETURN +#define RETURN(_code) do { \ + rval.code = _code; \ + rval.consumed = consumed_myself;\ + return rval; \ + } while(0) + +/* + * Check whether we are inside the extensions group. + */ +#define IN_EXTENSION_GROUP(specs, memb_idx) \ + ( ((memb_idx) > (specs)->ext_after) \ + &&((memb_idx) < (specs)->ext_before)) + + +/* + * Tags are canonically sorted in the tag2element map. + */ +static int +_t2e_cmp(const void *ap, const void *bp) { + const asn_TYPE_tag2member_t *a = (const asn_TYPE_tag2member_t *)ap; + const asn_TYPE_tag2member_t *b = (const asn_TYPE_tag2member_t *)bp; + + int a_class = BER_TAG_CLASS(a->el_tag); + int b_class = BER_TAG_CLASS(b->el_tag); + + if(a_class == b_class) { + ber_tlv_tag_t a_value = BER_TAG_VALUE(a->el_tag); + ber_tlv_tag_t b_value = BER_TAG_VALUE(b->el_tag); + + if(a_value == b_value) { + if(a->el_no > b->el_no) + return 1; + /* + * Important: we do not check + * for a->el_no <= b->el_no! + */ + return 0; + } else if(a_value < b_value) + return -1; + else + return 1; + } else if(a_class < b_class) { + return -1; + } else { + return 1; + } +} + + +/* + * The decoder of the SEQUENCE type. + */ +asn_dec_rval_t +SEQUENCE_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **struct_ptr, const void *ptr, size_t size, int tag_mode) { + /* + * Bring closer parts of structure description. + */ + asn_SEQUENCE_specifics_t *specs = (asn_SEQUENCE_specifics_t *)td->specifics; + asn_TYPE_member_t *elements = td->elements; + + /* + * Parts of the structure being constructed. + */ + void *st = *struct_ptr; /* Target structure. */ + asn_struct_ctx_t *ctx; /* Decoder context */ + + ber_tlv_tag_t tlv_tag; /* T from TLV */ + asn_dec_rval_t rval; /* Return code from subparsers */ + + ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ + int edx; /* SEQUENCE element's index */ + + ASN_DEBUG("Decoding %s as SEQUENCE", td->name); + + /* + * Create the target structure if it is not present already. + */ + if(st == 0) { + st = *struct_ptr = CALLOC(1, specs->struct_size); + if(st == 0) { + RETURN(RC_FAIL); + } + } + + /* + * Restore parsing context. + */ + ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); + + /* + * Start to parse where left previously + */ + switch(ctx->phase) { + case 0: + /* + * PHASE 0. + * Check that the set of tags associated with given structure + * perfectly fits our expectations. + */ + + rval = ber_check_tags(opt_codec_ctx, td, ctx, ptr, size, + tag_mode, 1, &ctx->left, 0); + if(rval.code != RC_OK) { + ASN_DEBUG("%s tagging check failed: %d", + td->name, rval.code); + return rval; + } + + if(ctx->left >= 0) + ctx->left += rval.consumed; /* ?Substracted below! */ + ADVANCE(rval.consumed); + + NEXT_PHASE(ctx); + + ASN_DEBUG("Structure consumes %ld bytes, buffer %ld", + (long)ctx->left, (long)size); + + /* Fall through */ + case 1: + /* + * PHASE 1. + * From the place where we've left it previously, + * try to decode the next member from the list of + * this structure's elements. + * (ctx->step) stores the member being processed + * between invocations and the microphase {0,1} of parsing + * that member: + * step = ( * 2 + ). + */ + for(edx = (ctx->step >> 1); edx < td->elements_count; + edx++, ctx->step = (ctx->step & ~1) + 2) { + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + ssize_t tag_len; /* Length of TLV's T */ + int opt_edx_end; /* Next non-optional element */ + int use_bsearch; + int n; + + if(ctx->step & 1) + goto microphase2; + + /* + * MICROPHASE 1: Synchronize decoding. + */ + ASN_DEBUG("In %s SEQUENCE left %d, edx=%d flags=%d" + " opt=%d ec=%d", + td->name, (int)ctx->left, edx, + elements[edx].flags, elements[edx].optional, + td->elements_count); + + if(ctx->left == 0 /* No more stuff is expected */ + && ( + /* Explicit OPTIONAL specification reaches the end */ + (edx + elements[edx].optional + == td->elements_count) + || + /* All extensions are optional */ + (IN_EXTENSION_GROUP(specs, edx) + && specs->ext_before > td->elements_count) + ) + ) { + ASN_DEBUG("End of SEQUENCE %s", td->name); + /* + * Found the legitimate end of the structure. + */ + PHASE_OUT(ctx); + RETURN(RC_OK); + } + + /* + * Fetch the T from TLV. + */ + tag_len = ber_fetch_tag(ptr, LEFT, &tlv_tag); + ASN_DEBUG("Current tag in %s SEQUENCE for element %d " + "(%s) is %s encoded in %d bytes, of frame %ld", + td->name, edx, elements[edx].name, + ber_tlv_tag_string(tlv_tag), (int)tag_len, (long)LEFT); + switch(tag_len) { + case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); + /* Fall through */ + case -1: RETURN(RC_FAIL); + } + + if(ctx->left < 0 && ((const uint8_t *)ptr)[0] == 0) { + if(LEFT < 2) { + if(SIZE_VIOLATION) + RETURN(RC_FAIL); + else + RETURN(RC_WMORE); + } else if(((const uint8_t *)ptr)[1] == 0) { + ASN_DEBUG("edx = %d, opt = %d, ec=%d", + edx, elements[edx].optional, + td->elements_count); + if((edx + elements[edx].optional + == td->elements_count) + || (IN_EXTENSION_GROUP(specs, edx) + && specs->ext_before + > td->elements_count)) { + /* + * Yeah, baby! Found the terminator + * of the indefinite length structure. + */ + /* + * Proceed to the canonical + * finalization function. + * No advancing is necessary. + */ + goto phase3; + } + } + } + + /* + * Find the next available type with this tag. + */ + use_bsearch = 0; + opt_edx_end = edx + elements[edx].optional + 1; + if(opt_edx_end > td->elements_count) + opt_edx_end = td->elements_count; /* Cap */ + else if(opt_edx_end - edx > 8) { + /* Limit the scope of linear search... */ + opt_edx_end = edx + 8; + use_bsearch = 1; + /* ... and resort to bsearch() */ + } + for(n = edx; n < opt_edx_end; n++) { + if(BER_TAGS_EQUAL(tlv_tag, elements[n].tag)) { + /* + * Found element corresponding to the tag + * being looked at. + * Reposition over the right element. + */ + edx = n; + ctx->step = 1 + 2 * edx; /* Remember! */ + goto microphase2; + } else if(elements[n].flags & ATF_OPEN_TYPE) { + /* + * This is the ANY type, which may bear + * any flag whatsoever. + */ + edx = n; + ctx->step = 1 + 2 * edx; /* Remember! */ + goto microphase2; + } else if(elements[n].tag == (ber_tlv_tag_t)-1) { + use_bsearch = 1; + break; + } + } + if(use_bsearch) { + /* + * Resort to a binary search over + * sorted array of tags. + */ + const asn_TYPE_tag2member_t *t2m; + asn_TYPE_tag2member_t key; + key.el_tag = tlv_tag; + key.el_no = edx; + t2m = (const asn_TYPE_tag2member_t *)bsearch(&key, + specs->tag2el, specs->tag2el_count, + sizeof(specs->tag2el[0]), _t2e_cmp); + if(t2m) { + const asn_TYPE_tag2member_t *best = 0; + const asn_TYPE_tag2member_t *t2m_f, *t2m_l; + int edx_max = edx + elements[edx].optional; + /* + * Rewind to the first element with that tag, + * `cause bsearch() does not guarantee order. + */ + t2m_f = t2m + t2m->toff_first; + t2m_l = t2m + t2m->toff_last; + for(t2m = t2m_f; t2m <= t2m_l; t2m++) { + if(t2m->el_no > edx_max) break; + if(t2m->el_no < edx) continue; + best = t2m; + } + if(best) { + edx = best->el_no; + ctx->step = 1 + 2 * edx; + goto microphase2; + } + } + n = opt_edx_end; + } + if(n == opt_edx_end) { + /* + * If tag is unknown, it may be either + * an unknown (thus, incorrect) tag, + * or an extension (...), + * or an end of the indefinite-length structure. + */ + if(!IN_EXTENSION_GROUP(specs, + edx + elements[edx].optional)) { + ASN_DEBUG("Unexpected tag %s (at %d)", + ber_tlv_tag_string(tlv_tag), edx); + ASN_DEBUG("Expected tag %s (%s)%s", + ber_tlv_tag_string(elements[edx].tag), + elements[edx].name, + elements[edx].optional + ?" or alternatives":""); + RETURN(RC_FAIL); + } else { + /* Skip this tag */ + ssize_t skip; + edx += elements[edx].optional; + + ASN_DEBUG("Skipping unexpected %s (at %d)", + ber_tlv_tag_string(tlv_tag), edx); + skip = ber_skip_length(opt_codec_ctx, + BER_TLV_CONSTRUCTED(ptr), + (const char *)ptr + tag_len, + LEFT - tag_len); + ASN_DEBUG("Skip length %d in %s", + (int)skip, td->name); + switch(skip) { + case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); + /* Fall through */ + case -1: RETURN(RC_FAIL); + } + + ADVANCE(skip + tag_len); + ctx->step -= 2; + edx--; + continue; /* Try again with the next tag */ + } + } + + /* + * MICROPHASE 2: Invoke the member-specific decoder. + */ + ctx->step |= 1; /* Confirm entering next microphase */ + microphase2: + ASN_DEBUG("Inside SEQUENCE %s MF2", td->name); + + /* + * Compute the position of the member inside a structure, + * and also a type of containment (it may be contained + * as pointer or using inline inclusion). + */ + if(elements[edx].flags & ATF_POINTER) { + /* Member is a pointer to another structure */ + memb_ptr2 = (void **)((char *)st + elements[edx].memb_offset); + } else { + /* + * A pointer to a pointer + * holding the start of the structure + */ + memb_ptr = (char *)st + elements[edx].memb_offset; + memb_ptr2 = &memb_ptr; + } + /* + * Invoke the member fetch routine according to member's type + */ + rval = elements[edx].type->ber_decoder(opt_codec_ctx, + elements[edx].type, + memb_ptr2, ptr, LEFT, + elements[edx].tag_mode); + ASN_DEBUG("In %s SEQUENCE decoded %d %s of %d " + "in %d bytes rval.code %d, size=%d", + td->name, edx, elements[edx].type->name, + (int)LEFT, (int)rval.consumed, rval.code, (int)size); + switch(rval.code) { + case RC_OK: + break; + case RC_WMORE: /* More data expected */ + if(!SIZE_VIOLATION) { + ADVANCE(rval.consumed); + RETURN(RC_WMORE); + } + ASN_DEBUG("Size violation (c->l=%ld <= s=%ld)", + (long)ctx->left, (long)size); + /* Fall through */ + case RC_FAIL: /* Fatal error */ + RETURN(RC_FAIL); + } /* switch(rval) */ + + ADVANCE(rval.consumed); + } /* for(all structure members) */ + + phase3: + ctx->phase = 3; + case 3: /* 00 and other tags expected */ + case 4: /* only 00's expected */ + + ASN_DEBUG("SEQUENCE %s Leftover: %ld, size = %ld", + td->name, (long)ctx->left, (long)size); + + /* + * Skip everything until the end of the SEQUENCE. + */ + while(ctx->left) { + ssize_t tl, ll; + + tl = ber_fetch_tag(ptr, LEFT, &tlv_tag); + switch(tl) { + case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); + /* Fall through */ + case -1: RETURN(RC_FAIL); + } + + /* + * If expected <0><0>... + */ + if(ctx->left < 0 + && ((const uint8_t *)ptr)[0] == 0) { + if(LEFT < 2) { + if(SIZE_VIOLATION) + RETURN(RC_FAIL); + else + RETURN(RC_WMORE); + } else if(((const uint8_t *)ptr)[1] == 0) { + /* + * Correctly finished with <0><0>. + */ + ADVANCE(2); + ctx->left++; + ctx->phase = 4; + continue; + } + } + + if(!IN_EXTENSION_GROUP(specs, td->elements_count) + || ctx->phase == 4) { + ASN_DEBUG("Unexpected continuation " + "of a non-extensible type " + "%s (SEQUENCE): %s", + td->name, + ber_tlv_tag_string(tlv_tag)); + RETURN(RC_FAIL); + } + + ll = ber_skip_length(opt_codec_ctx, + BER_TLV_CONSTRUCTED(ptr), + (const char *)ptr + tl, LEFT - tl); + switch(ll) { + case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); + /* Fall through */ + case -1: RETURN(RC_FAIL); + } + + ADVANCE(tl + ll); + } + + PHASE_OUT(ctx); + } + + RETURN(RC_OK); +} + + +/* + * The DER encoder of the SEQUENCE type. + */ +asn_enc_rval_t +SEQUENCE_encode_der(asn_TYPE_descriptor_t *td, + void *sptr, int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + size_t computed_size = 0; + asn_enc_rval_t erval; + ssize_t ret; + int edx; + + ASN_DEBUG("%s %s as SEQUENCE", + cb?"Encoding":"Estimating", td->name); + + /* + * Gather the length of the underlying members sequence. + */ + for(edx = 0; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + void *memb_ptr; + if(elm->flags & ATF_POINTER) { + memb_ptr = *(void **)((char *)sptr + elm->memb_offset); + if(!memb_ptr) { + if(elm->optional) continue; + /* Mandatory element is missing */ + ASN__ENCODE_FAILED; + } + } else { + memb_ptr = (void *)((char *)sptr + elm->memb_offset); + } + erval = elm->type->der_encoder(elm->type, memb_ptr, + elm->tag_mode, elm->tag, + 0, 0); + if(erval.encoded == -1) + return erval; + computed_size += erval.encoded; + ASN_DEBUG("Member %d %s estimated %ld bytes", + edx, elm->name, (long)erval.encoded); + } + + /* + * Encode the TLV for the sequence itself. + */ + ret = der_write_tags(td, computed_size, tag_mode, 1, tag, cb, app_key); + ASN_DEBUG("Wrote tags: %ld (+%ld)", (long)ret, (long)computed_size); + if(ret == -1) + ASN__ENCODE_FAILED; + erval.encoded = computed_size + ret; + + if(!cb) ASN__ENCODED_OK(erval); + + /* + * Encode all members. + */ + for(edx = 0; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + asn_enc_rval_t tmperval; + void *memb_ptr; + + if(elm->flags & ATF_POINTER) { + memb_ptr = *(void **)((char *)sptr + elm->memb_offset); + if(!memb_ptr) continue; + } else { + memb_ptr = (void *)((char *)sptr + elm->memb_offset); + } + tmperval = elm->type->der_encoder(elm->type, memb_ptr, + elm->tag_mode, elm->tag, + cb, app_key); + if(tmperval.encoded == -1) + return tmperval; + computed_size -= tmperval.encoded; + ASN_DEBUG("Member %d %s of SEQUENCE %s encoded in %ld bytes", + edx, elm->name, td->name, (long)tmperval.encoded); + } + + if(computed_size != 0) + /* + * Encoded size is not equal to the computed size. + */ + ASN__ENCODE_FAILED; + + ASN__ENCODED_OK(erval); +} + + +#undef XER_ADVANCE +#define XER_ADVANCE(num_bytes) do { \ + size_t num = num_bytes; \ + buf_ptr = ((const char *)buf_ptr) + num;\ + size -= num; \ + consumed_myself += num; \ + } while(0) + +/* + * Decode the XER (XML) data. + */ +asn_dec_rval_t +SEQUENCE_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **struct_ptr, const char *opt_mname, + const void *buf_ptr, size_t size) { + /* + * Bring closer parts of structure description. + */ + asn_SEQUENCE_specifics_t *specs + = (asn_SEQUENCE_specifics_t *)td->specifics; + asn_TYPE_member_t *elements = td->elements; + const char *xml_tag = opt_mname ? opt_mname : td->xml_tag; + + /* + * ... and parts of the structure being constructed. + */ + void *st = *struct_ptr; /* Target structure. */ + asn_struct_ctx_t *ctx; /* Decoder context */ + + asn_dec_rval_t rval; /* Return value from a decoder */ + ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ + int edx; /* Element index */ + int edx_end; + + /* + * Create the target structure if it is not present already. + */ + if(st == 0) { + st = *struct_ptr = CALLOC(1, specs->struct_size); + if(st == 0) RETURN(RC_FAIL); + } + + /* + * Restore parsing context. + */ + ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); + + + /* + * Phases of XER/XML processing: + * Phase 0: Check that the opening tag matches our expectations. + * Phase 1: Processing body and reacting on closing tag. + * Phase 2: Processing inner type. + * Phase 3: Skipping unknown extensions. + * Phase 4: PHASED OUT + */ + for(edx = ctx->step; ctx->phase <= 3;) { + pxer_chunk_type_e ch_type; /* XER chunk type */ + ssize_t ch_size; /* Chunk size */ + xer_check_tag_e tcv; /* Tag check value */ + asn_TYPE_member_t *elm; + int n; + + /* + * Go inside the inner member of a sequence. + */ + if(ctx->phase == 2) { + asn_dec_rval_t tmprval; + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + + elm = &td->elements[edx]; + + if(elm->flags & ATF_POINTER) { + /* Member is a pointer to another structure */ + memb_ptr2 = (void **)((char *)st + elm->memb_offset); + } else { + memb_ptr = (char *)st + elm->memb_offset; + memb_ptr2 = &memb_ptr; + } + + /* Invoke the inner type decoder, m.b. multiple times */ + tmprval = elm->type->xer_decoder(opt_codec_ctx, + elm->type, memb_ptr2, elm->name, + buf_ptr, size); + XER_ADVANCE(tmprval.consumed); + if(tmprval.code != RC_OK) + RETURN(tmprval.code); + ctx->phase = 1; /* Back to body processing */ + ctx->step = ++edx; + ASN_DEBUG("XER/SEQUENCE phase => %d, step => %d", + ctx->phase, ctx->step); + /* Fall through */ + } + + /* + * Get the next part of the XML stream. + */ + ch_size = xer_next_token(&ctx->context, buf_ptr, size, + &ch_type); + if(ch_size == -1) { + RETURN(RC_FAIL); + } else { + switch(ch_type) { + case PXER_WMORE: + RETURN(RC_WMORE); + case PXER_COMMENT: /* Got XML comment */ + case PXER_TEXT: /* Ignore free-standing text */ + XER_ADVANCE(ch_size); /* Skip silently */ + continue; + case PXER_TAG: + break; /* Check the rest down there */ + } + } + + tcv = xer_check_tag(buf_ptr, ch_size, xml_tag); + ASN_DEBUG("XER/SEQUENCE: tcv = %d, ph=%d [%s]", + tcv, ctx->phase, xml_tag); + + /* Skip the extensions section */ + if(ctx->phase == 3) { + switch(xer_skip_unknown(tcv, &ctx->left)) { + case -1: + ctx->phase = 4; + RETURN(RC_FAIL); + case 0: + XER_ADVANCE(ch_size); + continue; + case 1: + XER_ADVANCE(ch_size); + ctx->phase = 1; + continue; + case 2: + ctx->phase = 1; + break; + } + } + + switch(tcv) { + case XCT_CLOSING: + if(ctx->phase == 0) break; + ctx->phase = 0; + /* Fall through */ + case XCT_BOTH: + if(ctx->phase == 0) { + if(edx >= td->elements_count + || + /* Explicit OPTIONAL specs reaches the end */ + (edx + elements[edx].optional + == td->elements_count) + || + /* All extensions are optional */ + (IN_EXTENSION_GROUP(specs, edx) + && specs->ext_before + > td->elements_count) + ) { + XER_ADVANCE(ch_size); + ctx->phase = 4; /* Phase out */ + RETURN(RC_OK); + } else { + ASN_DEBUG("Premature end of XER SEQUENCE"); + RETURN(RC_FAIL); + } + } + /* Fall through */ + case XCT_OPENING: + if(ctx->phase == 0) { + XER_ADVANCE(ch_size); + ctx->phase = 1; /* Processing body phase */ + continue; + } + /* Fall through */ + case XCT_UNKNOWN_OP: + case XCT_UNKNOWN_BO: + + ASN_DEBUG("XER/SEQUENCE: tcv=%d, ph=%d, edx=%d", + tcv, ctx->phase, edx); + if(ctx->phase != 1) { + break; /* Really unexpected */ + } + + if(edx < td->elements_count) { + /* + * Search which member corresponds to this tag. + */ + edx_end = edx + elements[edx].optional + 1; + if(edx_end > td->elements_count) + edx_end = td->elements_count; + for(n = edx; n < edx_end; n++) { + elm = &td->elements[n]; + tcv = xer_check_tag(buf_ptr, + ch_size, elm->name); + switch(tcv) { + case XCT_BOTH: + case XCT_OPENING: + /* + * Process this member. + */ + ctx->step = edx = n; + ctx->phase = 2; + break; + case XCT_UNKNOWN_OP: + case XCT_UNKNOWN_BO: + continue; + default: + n = edx_end; + break; /* Phase out */ + } + break; + } + if(n != edx_end) + continue; + } else { + ASN_DEBUG("Out of defined members: %d/%d", + edx, td->elements_count); + } + + /* It is expected extension */ + if(IN_EXTENSION_GROUP(specs, + edx + (edx < td->elements_count + ? elements[edx].optional : 0))) { + ASN_DEBUG("Got anticipated extension at %d", + edx); + /* + * Check for (XCT_BOTH or XCT_UNKNOWN_BO) + * By using a mask. Only record a pure + * tags. + */ + if(tcv & XCT_CLOSING) { + /* Found without body */ + } else { + ctx->left = 1; + ctx->phase = 3; /* Skip ...'s */ + } + XER_ADVANCE(ch_size); + continue; + } + + /* Fall through */ + default: + break; + } + + ASN_DEBUG("Unexpected XML tag in SEQUENCE [%c%c%c%c%c%c]", + size>0?((const char *)buf_ptr)[0]:'.', + size>1?((const char *)buf_ptr)[1]:'.', + size>2?((const char *)buf_ptr)[2]:'.', + size>3?((const char *)buf_ptr)[3]:'.', + size>4?((const char *)buf_ptr)[4]:'.', + size>5?((const char *)buf_ptr)[5]:'.'); + break; + } + + ctx->phase = 4; /* "Phase out" on hard failure */ + RETURN(RC_FAIL); +} + +asn_enc_rval_t +SEQUENCE_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_enc_rval_t er; + int xcan = (flags & XER_F_CANONICAL); + int edx; + + if(!sptr) + ASN__ENCODE_FAILED; + + er.encoded = 0; + + for(edx = 0; edx < td->elements_count; edx++) { + asn_enc_rval_t tmper; + asn_TYPE_member_t *elm = &td->elements[edx]; + void *memb_ptr; + const char *mname = elm->name; + unsigned int mlen = strlen(mname); + + if(elm->flags & ATF_POINTER) { + memb_ptr = *(void **)((char *)sptr + elm->memb_offset); + if(!memb_ptr) { + if(elm->optional) + continue; + /* Mandatory element is missing */ + ASN__ENCODE_FAILED; + } + } else { + memb_ptr = (void *)((char *)sptr + elm->memb_offset); + } + + if(!xcan) ASN__TEXT_INDENT(1, ilevel); + ASN__CALLBACK3("<", 1, mname, mlen, ">", 1); + + /* Print the member itself */ + tmper = elm->type->xer_encoder(elm->type, memb_ptr, + ilevel + 1, flags, cb, app_key); + if(tmper.encoded == -1) return tmper; + + ASN__CALLBACK3("", 1); + er.encoded += 5 + (2 * mlen) + tmper.encoded; + } + + if(!xcan) ASN__TEXT_INDENT(1, ilevel - 1); + + ASN__ENCODED_OK(er); +cb_failed: + ASN__ENCODE_FAILED; +} + +int +SEQUENCE_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, + asn_app_consume_bytes_f *cb, void *app_key) { + int edx; + int ret; + + if(!sptr) return (cb("", 8, app_key) < 0) ? -1 : 0; + + /* Dump preamble */ + if(cb(td->name, strlen(td->name), app_key) < 0 + || cb(" ::= {", 6, app_key) < 0) + return -1; + + for(edx = 0; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + const void *memb_ptr; + + if(elm->flags & ATF_POINTER) { + memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset); + if(!memb_ptr) { + if(elm->optional) continue; + /* Print line */ + /* Fall through */ + } + } else { + memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); + } + + /* Indentation */ + _i_INDENT(1); + + /* Print the member's name and stuff */ + if(cb(elm->name, strlen(elm->name), app_key) < 0 + || cb(": ", 2, app_key) < 0) + return -1; + + /* Print the member itself */ + ret = elm->type->print_struct(elm->type, memb_ptr, ilevel + 1, + cb, app_key); + if(ret) return ret; + } + + ilevel--; + _i_INDENT(1); + + return (cb("}", 1, app_key) < 0) ? -1 : 0; +} + +void +SEQUENCE_free(asn_TYPE_descriptor_t *td, void *sptr, int contents_only) { + int edx; + + if(!td || !sptr) + return; + + ASN_DEBUG("Freeing %s as SEQUENCE", td->name); + + for(edx = 0; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + void *memb_ptr; + if(elm->flags & ATF_POINTER) { + memb_ptr = *(void **)((char *)sptr + elm->memb_offset); + if(memb_ptr) + ASN_STRUCT_FREE(*elm->type, memb_ptr); + } else { + memb_ptr = (void *)((char *)sptr + elm->memb_offset); + ASN_STRUCT_FREE_CONTENTS_ONLY(*elm->type, memb_ptr); + } + } + + if(!contents_only) { + FREEMEM(sptr); + } +} + +int +SEQUENCE_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + int edx; + + if(!sptr) { + ASN__CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + /* + * Iterate over structure members and check their validity. + */ + for(edx = 0; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + const void *memb_ptr; + + if(elm->flags & ATF_POINTER) { + memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset); + if(!memb_ptr) { + if(elm->optional) + continue; + ASN__CTFAIL(app_key, td, sptr, + "%s: mandatory element %s absent (%s:%d)", + td->name, elm->name, __FILE__, __LINE__); + return -1; + } + } else { + memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); + } + + if(elm->memb_constraints) { + int ret = elm->memb_constraints(elm->type, memb_ptr, + ctfailcb, app_key); + if(ret) return ret; + } else { + int ret = elm->type->check_constraints(elm->type, + memb_ptr, ctfailcb, app_key); + if(ret) return ret; + /* + * Cannot inherit it earlier: + * need to make sure we get the updated version. + */ + elm->memb_constraints = elm->type->check_constraints; + } + } + + return 0; +} + +asn_dec_rval_t +SEQUENCE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { + asn_SEQUENCE_specifics_t *specs = (asn_SEQUENCE_specifics_t *)td->specifics; + void *st = *sptr; /* Target structure. */ + int extpresent; /* Extension additions are present */ + uint8_t *opres; /* Presence of optional root members */ + asn_per_data_t opmd; + asn_dec_rval_t rv; + int edx; + + (void)constraints; + + if(ASN__STACK_OVERFLOW_CHECK(opt_codec_ctx)) + ASN__DECODE_FAILED; + + if(!st) { + st = *sptr = CALLOC(1, specs->struct_size); + if(!st) ASN__DECODE_FAILED; + } + + ASN_DEBUG("Decoding %s as SEQUENCE (UPER)", td->name); + + /* Handle extensions */ + if(specs->ext_before >= 0) { + extpresent = per_get_few_bits(pd, 1); + if(extpresent < 0) ASN__DECODE_STARVED; + } else { + extpresent = 0; + } + + /* Prepare a place and read-in the presence bitmap */ + memset(&opmd, 0, sizeof(opmd)); + if(specs->roms_count) { + opres = (uint8_t *)MALLOC(((specs->roms_count + 7) >> 3) + 1); + if(!opres) ASN__DECODE_FAILED; + /* Get the presence map */ + if(per_get_many_bits(pd, opres, 0, specs->roms_count)) { + FREEMEM(opres); + ASN__DECODE_STARVED; + } + opmd.buffer = opres; + opmd.nbits = specs->roms_count; + ASN_DEBUG("Read in presence bitmap for %s of %d bits (%x..)", + td->name, specs->roms_count, *opres); + } else { + opres = 0; + } + + /* + * Get the sequence ROOT elements. + */ + for(edx = 0; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + + if(IN_EXTENSION_GROUP(specs, edx)) + continue; + + /* Fetch the pointer to this member */ + if(elm->flags & ATF_POINTER) { + memb_ptr2 = (void **)((char *)st + elm->memb_offset); + } else { + memb_ptr = (char *)st + elm->memb_offset; + memb_ptr2 = &memb_ptr; + } + + /* Deal with optionality */ + if(elm->optional) { + int present = per_get_few_bits(&opmd, 1); + ASN_DEBUG("Member %s->%s is optional, p=%d (%d->%d)", + td->name, elm->name, present, + (int)opmd.nboff, (int)opmd.nbits); + if(present == 0) { + /* This element is not present */ + if(elm->default_value) { + /* Fill-in DEFAULT */ + if(elm->default_value(1, memb_ptr2)) { + FREEMEM(opres); + ASN__DECODE_FAILED; + } + ASN_DEBUG("Filled-in default"); + } + /* The member is just not present */ + continue; + } + /* Fall through */ + } + + /* Fetch the member from the stream */ + ASN_DEBUG("Decoding member %s in %s", elm->name, td->name); + rv = elm->type->uper_decoder(opt_codec_ctx, elm->type, + elm->per_constraints, memb_ptr2, pd); + if(rv.code != RC_OK) { + ASN_DEBUG("Failed decode %s in %s", + elm->name, td->name); + FREEMEM(opres); + return rv; + } + } + + /* Optionality map is not needed anymore */ + FREEMEM(opres); + + /* + * Deal with extensions. + */ + if(extpresent) { + ssize_t bmlength; + uint8_t *epres; /* Presence of extension members */ + asn_per_data_t epmd; + + bmlength = uper_get_nslength(pd); + if(bmlength < 0) ASN__DECODE_STARVED; + + ASN_DEBUG("Extensions %ld present in %s", (long)bmlength, td->name); + + epres = (uint8_t *)MALLOC((bmlength + 15) >> 3); + if(!epres) ASN__DECODE_STARVED; + + /* Get the extensions map */ + if(per_get_many_bits(pd, epres, 0, bmlength)) { + FREEMEM(epres); + ASN__DECODE_STARVED; + } + + memset(&epmd, 0, sizeof(epmd)); + epmd.buffer = epres; + epmd.nbits = bmlength; + ASN_DEBUG("Read in extensions bitmap for %s of %ld bits (%x..)", + td->name, (long)bmlength, *epres); + + /* Go over extensions and read them in */ + for(edx = specs->ext_after + 1; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + int present; + + if(!IN_EXTENSION_GROUP(specs, edx)) { + ASN_DEBUG("%d is not extension", edx); + continue; + } + + /* Fetch the pointer to this member */ + if(elm->flags & ATF_POINTER) { + memb_ptr2 = (void **)((char *)st + elm->memb_offset); + } else { + memb_ptr = (void *)((char *)st + elm->memb_offset); + memb_ptr2 = &memb_ptr; + } + + present = per_get_few_bits(&epmd, 1); + if(present <= 0) { + if(present < 0) break; /* No more extensions */ + continue; + } + + ASN_DEBUG("Decoding member %s in %s %p", elm->name, td->name, *memb_ptr2); + rv = uper_open_type_get(opt_codec_ctx, elm->type, + elm->per_constraints, memb_ptr2, pd); + if(rv.code != RC_OK) { + FREEMEM(epres); + return rv; + } + } + + /* Skip over overflow extensions which aren't present + * in this system's version of the protocol */ + for(;;) { + ASN_DEBUG("Getting overflow extensions"); + switch(per_get_few_bits(&epmd, 1)) { + case -1: break; + case 0: continue; + default: + if(uper_open_type_skip(opt_codec_ctx, pd)) { + FREEMEM(epres); + ASN__DECODE_STARVED; + } + } + break; + } + + FREEMEM(epres); + } + + /* Fill DEFAULT members in extensions */ + for(edx = specs->roms_count; edx < specs->roms_count + + specs->aoms_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + void **memb_ptr2; /* Pointer to member pointer */ + + if(!elm->default_value) continue; + + /* Fetch the pointer to this member */ + if(elm->flags & ATF_POINTER) { + memb_ptr2 = (void **)((char *)st + + elm->memb_offset); + if(*memb_ptr2) continue; + } else { + continue; /* Extensions are all optionals */ + } + + /* Set default value */ + if(elm->default_value(1, memb_ptr2)) { + ASN__DECODE_FAILED; + } + } + + rv.consumed = 0; + rv.code = RC_OK; + return rv; +} + +static int +SEQUENCE_handle_extensions(asn_TYPE_descriptor_t *td, void *sptr, + asn_per_outp_t *po1, asn_per_outp_t *po2) { + asn_SEQUENCE_specifics_t *specs + = (asn_SEQUENCE_specifics_t *)td->specifics; + int exts_present = 0; + int exts_count = 0; + int edx; + + if(specs->ext_before < 0) + return 0; + + /* Find out which extensions are present */ + for(edx = specs->ext_after + 1; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + int present; + + if(!IN_EXTENSION_GROUP(specs, edx)) { + ASN_DEBUG("%s (@%d) is not extension", elm->type->name, edx); + continue; + } + + /* Fetch the pointer to this member */ + if(elm->flags & ATF_POINTER) { + memb_ptr2 = (void **)((char *)sptr + elm->memb_offset); + present = (*memb_ptr2 != 0); + } else { + memb_ptr = (void *)((char *)sptr + elm->memb_offset); + memb_ptr2 = &memb_ptr; + present = 1; + } + + ASN_DEBUG("checking %s (@%d) present => %d", + elm->type->name, edx, present); + exts_count++; + exts_present += present; + + /* Encode as presence marker */ + if(po1 && per_put_few_bits(po1, present, 1)) + return -1; + /* Encode as open type field */ + if(po2 && present && uper_open_type_put(elm->type, + elm->per_constraints, *memb_ptr2, po2)) + return -1; + + } + + return exts_present ? exts_count : 0; +} + +asn_enc_rval_t +SEQUENCE_encode_uper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + asn_SEQUENCE_specifics_t *specs + = (asn_SEQUENCE_specifics_t *)td->specifics; + asn_enc_rval_t er; + int n_extensions; + int edx; + int i; + + (void)constraints; + + if(!sptr) + ASN__ENCODE_FAILED; + + er.encoded = 0; + + ASN_DEBUG("Encoding %s as SEQUENCE (UPER)", td->name); + + + /* + * X.691#18.1 Whether structure is extensible + * and whether to encode extensions + */ + if(specs->ext_before >= 0) { + n_extensions = SEQUENCE_handle_extensions(td, sptr, 0, 0); + per_put_few_bits(po, n_extensions ? 1 : 0, 1); + } else { + n_extensions = 0; /* There are no extensions to encode */ + } + + /* Encode a presence bitmap */ + for(i = 0; i < specs->roms_count; i++) { + asn_TYPE_member_t *elm; + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + int present; + + edx = specs->oms[i]; + elm = &td->elements[edx]; + + /* Fetch the pointer to this member */ + if(elm->flags & ATF_POINTER) { + memb_ptr2 = (void **)((char *)sptr + elm->memb_offset); + present = (*memb_ptr2 != 0); + } else { + memb_ptr = (void *)((char *)sptr + elm->memb_offset); + memb_ptr2 = &memb_ptr; + present = 1; + } + + /* Eliminate default values */ + if(present && elm->default_value + && elm->default_value(0, memb_ptr2) == 1) + present = 0; + + ASN_DEBUG("Element %s %s %s->%s is %s", + elm->flags & ATF_POINTER ? "ptr" : "inline", + elm->default_value ? "def" : "wtv", + td->name, elm->name, present ? "present" : "absent"); + if(per_put_few_bits(po, present, 1)) + ASN__ENCODE_FAILED; + } + + /* + * Encode the sequence ROOT elements. + */ + ASN_DEBUG("ext_after = %d, ec = %d, eb = %d", specs->ext_after, td->elements_count, specs->ext_before); + for(edx = 0; edx < ((specs->ext_after < 0) + ? td->elements_count : specs->ext_before - 1); edx++) { + + asn_TYPE_member_t *elm = &td->elements[edx]; + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + + if(IN_EXTENSION_GROUP(specs, edx)) + continue; + + ASN_DEBUG("About to encode %s", elm->type->name); + + /* Fetch the pointer to this member */ + if(elm->flags & ATF_POINTER) { + memb_ptr2 = (void **)((char *)sptr + elm->memb_offset); + if(!*memb_ptr2) { + ASN_DEBUG("Element %s %d not present", + elm->name, edx); + if(elm->optional) + continue; + /* Mandatory element is missing */ + ASN__ENCODE_FAILED; + } + } else { + memb_ptr = (void *)((char *)sptr + elm->memb_offset); + memb_ptr2 = &memb_ptr; + } + + /* Eliminate default values */ + if(elm->default_value && elm->default_value(0, memb_ptr2) == 1) + continue; + + ASN_DEBUG("Encoding %s->%s", td->name, elm->name); + er = elm->type->uper_encoder(elm->type, elm->per_constraints, + *memb_ptr2, po); + if(er.encoded == -1) + return er; + } + + /* No extensions to encode */ + if(!n_extensions) ASN__ENCODED_OK(er); + + ASN_DEBUG("Length of %d bit-map", n_extensions); + /* #18.8. Write down the presence bit-map length. */ + if(uper_put_nslength(po, n_extensions)) + ASN__ENCODE_FAILED; + + ASN_DEBUG("Bit-map of %d elements", n_extensions); + /* #18.7. Encoding the extensions presence bit-map. */ + /* TODO: act upon NOTE in #18.7 for canonical PER */ + if(SEQUENCE_handle_extensions(td, sptr, po, 0) != n_extensions) + ASN__ENCODE_FAILED; + + ASN_DEBUG("Writing %d extensions", n_extensions); + /* #18.9. Encode extensions as open type fields. */ + if(SEQUENCE_handle_extensions(td, sptr, 0, po) != n_extensions) + ASN__ENCODE_FAILED; + + ASN__ENCODED_OK(er); +} + diff --git a/src/cryptoconditions/src/asn/constr_SEQUENCE.h b/src/cryptoconditions/src/asn/constr_SEQUENCE.h new file mode 100644 index 000000000..c2aeb6676 --- /dev/null +++ b/src/cryptoconditions/src/asn/constr_SEQUENCE.h @@ -0,0 +1,60 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _CONSTR_SEQUENCE_H_ +#define _CONSTR_SEQUENCE_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef const struct asn_SEQUENCE_specifics_s { + /* + * Target structure description. + */ + int struct_size; /* Size of the target structure. */ + int ctx_offset; /* Offset of the asn_struct_ctx_t member */ + + /* + * Tags to members mapping table (sorted). + */ + const asn_TYPE_tag2member_t *tag2el; + int tag2el_count; + + /* + * Optional members of the extensions root (roms) or additions (aoms). + * Meaningful for PER. + */ + const int *oms; /* Optional MemberS */ + int roms_count; /* Root optional members count */ + int aoms_count; /* Additions optional members count */ + + /* + * Description of an extensions group. + */ + int ext_after; /* Extensions start after this member */ + int ext_before; /* Extensions stop before this member */ +} asn_SEQUENCE_specifics_t; + + +/* + * A set specialized functions dealing with the SEQUENCE type. + */ +asn_struct_free_f SEQUENCE_free; +asn_struct_print_f SEQUENCE_print; +asn_constr_check_f SEQUENCE_constraint; +ber_type_decoder_f SEQUENCE_decode_ber; +der_type_encoder_f SEQUENCE_encode_der; +xer_type_decoder_f SEQUENCE_decode_xer; +xer_type_encoder_f SEQUENCE_encode_xer; +per_type_decoder_f SEQUENCE_decode_uper; +per_type_encoder_f SEQUENCE_encode_uper; + +#ifdef __cplusplus +} +#endif + +#endif /* _CONSTR_SEQUENCE_H_ */ diff --git a/src/cryptoconditions/src/asn/constr_SET_OF.c b/src/cryptoconditions/src/asn/constr_SET_OF.c new file mode 100644 index 000000000..2dbc6e518 --- /dev/null +++ b/src/cryptoconditions/src/asn/constr_SET_OF.c @@ -0,0 +1,954 @@ +/*- + * Copyright (c) 2003, 2004, 2005 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +/* + * Number of bytes left for this structure. + * (ctx->left) indicates the number of bytes _transferred_ for the structure. + * (size) contains the number of bytes in the buffer passed. + */ +#define LEFT ((size<(size_t)ctx->left)?size:(size_t)ctx->left) + +/* + * If the subprocessor function returns with an indication that it wants + * more data, it may well be a fatal decoding problem, because the + * size is constrained by the 's L, even if the buffer size allows + * reading more data. + * For example, consider the buffer containing the following TLVs: + * ... + * The TLV length clearly indicates that one byte is expected in V, but + * if the V processor returns with "want more data" even if the buffer + * contains way more data than the V processor have seen. + */ +#define SIZE_VIOLATION (ctx->left >= 0 && (size_t)ctx->left <= size) + +/* + * This macro "eats" the part of the buffer which is definitely "consumed", + * i.e. was correctly converted into local representation or rightfully skipped. + */ +#undef ADVANCE +#define ADVANCE(num_bytes) do { \ + size_t num = num_bytes; \ + ptr = ((const char *)ptr) + num;\ + size -= num; \ + if(ctx->left >= 0) \ + ctx->left -= num; \ + consumed_myself += num; \ + } while(0) + +/* + * Switch to the next phase of parsing. + */ +#undef NEXT_PHASE +#undef PHASE_OUT +#define NEXT_PHASE(ctx) do { \ + ctx->phase++; \ + ctx->step = 0; \ + } while(0) +#define PHASE_OUT(ctx) do { ctx->phase = 10; } while(0) + +/* + * Return a standardized complex structure. + */ +#undef RETURN +#define RETURN(_code) do { \ + rval.code = _code; \ + rval.consumed = consumed_myself;\ + return rval; \ + } while(0) + +/* + * The decoder of the SET OF type. + */ +asn_dec_rval_t +SET_OF_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **struct_ptr, const void *ptr, size_t size, int tag_mode) { + /* + * Bring closer parts of structure description. + */ + asn_SET_OF_specifics_t *specs = (asn_SET_OF_specifics_t *)td->specifics; + asn_TYPE_member_t *elm = td->elements; /* Single one */ + + /* + * Parts of the structure being constructed. + */ + void *st = *struct_ptr; /* Target structure. */ + asn_struct_ctx_t *ctx; /* Decoder context */ + + ber_tlv_tag_t tlv_tag; /* T from TLV */ + asn_dec_rval_t rval; /* Return code from subparsers */ + + ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ + + ASN_DEBUG("Decoding %s as SET OF", td->name); + + /* + * Create the target structure if it is not present already. + */ + if(st == 0) { + st = *struct_ptr = CALLOC(1, specs->struct_size); + if(st == 0) { + RETURN(RC_FAIL); + } + } + + /* + * Restore parsing context. + */ + ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); + + /* + * Start to parse where left previously + */ + switch(ctx->phase) { + case 0: + /* + * PHASE 0. + * Check that the set of tags associated with given structure + * perfectly fits our expectations. + */ + + rval = ber_check_tags(opt_codec_ctx, td, ctx, ptr, size, + tag_mode, 1, &ctx->left, 0); + if(rval.code != RC_OK) { + ASN_DEBUG("%s tagging check failed: %d", + td->name, rval.code); + return rval; + } + + if(ctx->left >= 0) + ctx->left += rval.consumed; /* ?Substracted below! */ + ADVANCE(rval.consumed); + + ASN_DEBUG("Structure consumes %ld bytes, " + "buffer %ld", (long)ctx->left, (long)size); + + NEXT_PHASE(ctx); + /* Fall through */ + case 1: + /* + * PHASE 1. + * From the place where we've left it previously, + * try to decode the next item. + */ + for(;; ctx->step = 0) { + ssize_t tag_len; /* Length of TLV's T */ + + if(ctx->step & 1) + goto microphase2; + + /* + * MICROPHASE 1: Synchronize decoding. + */ + + if(ctx->left == 0) { + ASN_DEBUG("End of SET OF %s", td->name); + /* + * No more things to decode. + * Exit out of here. + */ + PHASE_OUT(ctx); + RETURN(RC_OK); + } + + /* + * Fetch the T from TLV. + */ + tag_len = ber_fetch_tag(ptr, LEFT, &tlv_tag); + switch(tag_len) { + case 0: if(!SIZE_VIOLATION) RETURN(RC_WMORE); + /* Fall through */ + case -1: RETURN(RC_FAIL); + } + + if(ctx->left < 0 && ((const uint8_t *)ptr)[0] == 0) { + if(LEFT < 2) { + if(SIZE_VIOLATION) + RETURN(RC_FAIL); + else + RETURN(RC_WMORE); + } else if(((const uint8_t *)ptr)[1] == 0) { + /* + * Found the terminator of the + * indefinite length structure. + */ + break; + } + } + + /* Outmost tag may be unknown and cannot be fetched/compared */ + if(elm->tag != (ber_tlv_tag_t)-1) { + if(BER_TAGS_EQUAL(tlv_tag, elm->tag)) { + /* + * The new list member of expected type has arrived. + */ + } else { + ASN_DEBUG("Unexpected tag %s fixed SET OF %s", + ber_tlv_tag_string(tlv_tag), td->name); + ASN_DEBUG("%s SET OF has tag %s", + td->name, ber_tlv_tag_string(elm->tag)); + RETURN(RC_FAIL); + } + } + + /* + * MICROPHASE 2: Invoke the member-specific decoder. + */ + ctx->step |= 1; /* Confirm entering next microphase */ + microphase2: + + /* + * Invoke the member fetch routine according to member's type + */ + rval = elm->type->ber_decoder(opt_codec_ctx, + elm->type, &ctx->ptr, ptr, LEFT, 0); + ASN_DEBUG("In %s SET OF %s code %d consumed %d", + td->name, elm->type->name, + rval.code, (int)rval.consumed); + switch(rval.code) { + case RC_OK: + { + asn_anonymous_set_ *list = _A_SET_FROM_VOID(st); + if(ASN_SET_ADD(list, ctx->ptr) != 0) + RETURN(RC_FAIL); + else + ctx->ptr = 0; + } + break; + case RC_WMORE: /* More data expected */ + if(!SIZE_VIOLATION) { + ADVANCE(rval.consumed); + RETURN(RC_WMORE); + } + /* Fall through */ + case RC_FAIL: /* Fatal error */ + ASN_STRUCT_FREE(*elm->type, ctx->ptr); + ctx->ptr = 0; + RETURN(RC_FAIL); + } /* switch(rval) */ + + ADVANCE(rval.consumed); + } /* for(all list members) */ + + NEXT_PHASE(ctx); + case 2: + /* + * Read in all "end of content" TLVs. + */ + while(ctx->left < 0) { + if(LEFT < 2) { + if(LEFT > 0 && ((const char *)ptr)[0] != 0) { + /* Unexpected tag */ + RETURN(RC_FAIL); + } else { + RETURN(RC_WMORE); + } + } + if(((const char *)ptr)[0] == 0 + && ((const char *)ptr)[1] == 0) { + ADVANCE(2); + ctx->left++; + } else { + RETURN(RC_FAIL); + } + } + + PHASE_OUT(ctx); + } + + RETURN(RC_OK); +} + +/* + * Internally visible buffer holding a single encoded element. + */ +struct _el_buffer { + uint8_t *buf; + size_t length; + size_t size; +}; +/* Append bytes to the above structure */ +static int _el_addbytes(const void *buffer, size_t size, void *el_buf_ptr) { + struct _el_buffer *el_buf = (struct _el_buffer *)el_buf_ptr; + + if(el_buf->length + size > el_buf->size) + return -1; + + memcpy(el_buf->buf + el_buf->length, buffer, size); + + el_buf->length += size; + return 0; +} +static int _el_buf_cmp(const void *ap, const void *bp) { + const struct _el_buffer *a = (const struct _el_buffer *)ap; + const struct _el_buffer *b = (const struct _el_buffer *)bp; + int ret; + size_t common_len; + + if(a->length < b->length) + common_len = a->length; + else + common_len = b->length; + + ret = memcmp(a->buf, b->buf, common_len); + if(ret == 0) { + if(a->length < b->length) + ret = -1; + else if(a->length > b->length) + ret = 1; + } + + return ret; +} + +/* + * The DER encoder of the SET OF type. + */ +asn_enc_rval_t +SET_OF_encode_der(asn_TYPE_descriptor_t *td, void *ptr, + int tag_mode, ber_tlv_tag_t tag, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_TYPE_member_t *elm = td->elements; + asn_TYPE_descriptor_t *elm_type = elm->type; + der_type_encoder_f *der_encoder = elm_type->der_encoder; + asn_anonymous_set_ *list = _A_SET_FROM_VOID(ptr); + size_t computed_size = 0; + ssize_t encoding_size = 0; + struct _el_buffer *encoded_els; + ssize_t eels_count = 0; + size_t max_encoded_len = 1; + asn_enc_rval_t erval; + int ret; + int edx; + + ASN_DEBUG("Estimating size for SET OF %s", td->name); + + /* + * Gather the length of the underlying members sequence. + */ + for(edx = 0; edx < list->count; edx++) { + void *memb_ptr = list->array[edx]; + if(!memb_ptr) continue; + erval = der_encoder(elm_type, memb_ptr, 0, elm->tag, 0, 0); + if(erval.encoded == -1) + return erval; + computed_size += erval.encoded; + + /* Compute maximum encoding's size */ + if(max_encoded_len < (size_t)erval.encoded) + max_encoded_len = erval.encoded; + } + + /* + * Encode the TLV for the sequence itself. + */ + encoding_size = der_write_tags(td, computed_size, tag_mode, 1, tag, + cb, app_key); + if(encoding_size == -1) { + erval.encoded = -1; + erval.failed_type = td; + erval.structure_ptr = ptr; + return erval; + } + computed_size += encoding_size; + + if(!cb || list->count == 0) { + erval.encoded = computed_size; + ASN__ENCODED_OK(erval); + } + + /* + * DER mandates dynamic sorting of the SET OF elements + * according to their encodings. Build an array of the + * encoded elements. + */ + encoded_els = (struct _el_buffer *)MALLOC( + list->count * sizeof(encoded_els[0])); + if(encoded_els == NULL) { + erval.encoded = -1; + erval.failed_type = td; + erval.structure_ptr = ptr; + return erval; + } + + ASN_DEBUG("Encoding members of %s SET OF", td->name); + + /* + * Encode all members. + */ + for(edx = 0; edx < list->count; edx++) { + void *memb_ptr = list->array[edx]; + struct _el_buffer *encoded_el = &encoded_els[eels_count]; + + if(!memb_ptr) continue; + + /* + * Prepare space for encoding. + */ + encoded_el->buf = (uint8_t *)MALLOC(max_encoded_len); + if(encoded_el->buf) { + encoded_el->length = 0; + encoded_el->size = max_encoded_len; + } else { + for(edx--; edx >= 0; edx--) + FREEMEM(encoded_els[edx].buf); + FREEMEM(encoded_els); + erval.encoded = -1; + erval.failed_type = td; + erval.structure_ptr = ptr; + return erval; + } + + /* + * Encode the member into the prepared space. + */ + erval = der_encoder(elm_type, memb_ptr, 0, elm->tag, + _el_addbytes, encoded_el); + if(erval.encoded == -1) { + for(; edx >= 0; edx--) + FREEMEM(encoded_els[edx].buf); + FREEMEM(encoded_els); + return erval; + } + encoding_size += erval.encoded; + eels_count++; + } + + /* + * Sort the encoded elements according to their encoding. + */ + qsort(encoded_els, eels_count, sizeof(encoded_els[0]), _el_buf_cmp); + + /* + * Report encoded elements to the application. + * Dispose of temporary sorted members table. + */ + ret = 0; + for(edx = 0; edx < eels_count; edx++) { + struct _el_buffer *encoded_el = &encoded_els[edx]; + /* Report encoded chunks to the application */ + if(ret == 0 + && cb(encoded_el->buf, encoded_el->length, app_key) < 0) + ret = -1; + FREEMEM(encoded_el->buf); + } + FREEMEM(encoded_els); + + if(ret || computed_size != (size_t)encoding_size) { + /* + * Standard callback failed, or + * encoded size is not equal to the computed size. + */ + erval.encoded = -1; + erval.failed_type = td; + erval.structure_ptr = ptr; + } else { + erval.encoded = computed_size; + } + + ASN__ENCODED_OK(erval); +} + +#undef XER_ADVANCE +#define XER_ADVANCE(num_bytes) do { \ + size_t num = num_bytes; \ + buf_ptr = ((const char *)buf_ptr) + num;\ + size -= num; \ + consumed_myself += num; \ + } while(0) + +/* + * Decode the XER (XML) data. + */ +asn_dec_rval_t +SET_OF_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **struct_ptr, const char *opt_mname, + const void *buf_ptr, size_t size) { + /* + * Bring closer parts of structure description. + */ + asn_SET_OF_specifics_t *specs = (asn_SET_OF_specifics_t *)td->specifics; + asn_TYPE_member_t *element = td->elements; + const char *elm_tag; + const char *xml_tag = opt_mname ? opt_mname : td->xml_tag; + + /* + * ... and parts of the structure being constructed. + */ + void *st = *struct_ptr; /* Target structure. */ + asn_struct_ctx_t *ctx; /* Decoder context */ + + asn_dec_rval_t rval; /* Return value from a decoder */ + ssize_t consumed_myself = 0; /* Consumed bytes from ptr */ + + /* + * Create the target structure if it is not present already. + */ + if(st == 0) { + st = *struct_ptr = CALLOC(1, specs->struct_size); + if(st == 0) RETURN(RC_FAIL); + } + + /* Which tag is expected for the downstream */ + if(specs->as_XMLValueList) { + elm_tag = (specs->as_XMLValueList == 1) ? 0 : ""; + } else { + elm_tag = (*element->name) + ? element->name : element->type->xml_tag; + } + + /* + * Restore parsing context. + */ + ctx = (asn_struct_ctx_t *)((char *)st + specs->ctx_offset); + + /* + * Phases of XER/XML processing: + * Phase 0: Check that the opening tag matches our expectations. + * Phase 1: Processing body and reacting on closing tag. + * Phase 2: Processing inner type. + */ + for(; ctx->phase <= 2;) { + pxer_chunk_type_e ch_type; /* XER chunk type */ + ssize_t ch_size; /* Chunk size */ + xer_check_tag_e tcv; /* Tag check value */ + + /* + * Go inside the inner member of a set. + */ + if(ctx->phase == 2) { + asn_dec_rval_t tmprval; + + /* Invoke the inner type decoder, m.b. multiple times */ + ASN_DEBUG("XER/SET OF element [%s]", elm_tag); + tmprval = element->type->xer_decoder(opt_codec_ctx, + element->type, &ctx->ptr, elm_tag, + buf_ptr, size); + if(tmprval.code == RC_OK) { + asn_anonymous_set_ *list = _A_SET_FROM_VOID(st); + if(ASN_SET_ADD(list, ctx->ptr) != 0) + RETURN(RC_FAIL); + ctx->ptr = 0; + XER_ADVANCE(tmprval.consumed); + } else { + XER_ADVANCE(tmprval.consumed); + RETURN(tmprval.code); + } + ctx->phase = 1; /* Back to body processing */ + ASN_DEBUG("XER/SET OF phase => %d", ctx->phase); + /* Fall through */ + } + + /* + * Get the next part of the XML stream. + */ + ch_size = xer_next_token(&ctx->context, + buf_ptr, size, &ch_type); + if(ch_size == -1) { + RETURN(RC_FAIL); + } else { + switch(ch_type) { + case PXER_WMORE: + RETURN(RC_WMORE); + case PXER_COMMENT: /* Got XML comment */ + case PXER_TEXT: /* Ignore free-standing text */ + XER_ADVANCE(ch_size); /* Skip silently */ + continue; + case PXER_TAG: + break; /* Check the rest down there */ + } + } + + tcv = xer_check_tag(buf_ptr, ch_size, xml_tag); + ASN_DEBUG("XER/SET OF: tcv = %d, ph=%d t=%s", + tcv, ctx->phase, xml_tag); + switch(tcv) { + case XCT_CLOSING: + if(ctx->phase == 0) break; + ctx->phase = 0; + /* Fall through */ + case XCT_BOTH: + if(ctx->phase == 0) { + /* No more things to decode */ + XER_ADVANCE(ch_size); + ctx->phase = 3; /* Phase out */ + RETURN(RC_OK); + } + /* Fall through */ + case XCT_OPENING: + if(ctx->phase == 0) { + XER_ADVANCE(ch_size); + ctx->phase = 1; /* Processing body phase */ + continue; + } + /* Fall through */ + case XCT_UNKNOWN_OP: + case XCT_UNKNOWN_BO: + + ASN_DEBUG("XER/SET OF: tcv=%d, ph=%d", tcv, ctx->phase); + if(ctx->phase == 1) { + /* + * Process a single possible member. + */ + ctx->phase = 2; + continue; + } + /* Fall through */ + default: + break; + } + + ASN_DEBUG("Unexpected XML tag in SET OF"); + break; + } + + ctx->phase = 3; /* "Phase out" on hard failure */ + RETURN(RC_FAIL); +} + + + +typedef struct xer_tmp_enc_s { + void *buffer; + size_t offset; + size_t size; +} xer_tmp_enc_t; +static int +SET_OF_encode_xer_callback(const void *buffer, size_t size, void *key) { + xer_tmp_enc_t *t = (xer_tmp_enc_t *)key; + if(t->offset + size >= t->size) { + size_t newsize = (t->size << 2) + size; + void *p = REALLOC(t->buffer, newsize); + if(!p) return -1; + t->buffer = p; + t->size = newsize; + } + memcpy((char *)t->buffer + t->offset, buffer, size); + t->offset += size; + return 0; +} +static int +SET_OF_xer_order(const void *aptr, const void *bptr) { + const xer_tmp_enc_t *a = (const xer_tmp_enc_t *)aptr; + const xer_tmp_enc_t *b = (const xer_tmp_enc_t *)bptr; + size_t minlen = a->offset; + int ret; + if(b->offset < minlen) minlen = b->offset; + /* Well-formed UTF-8 has this nice lexicographical property... */ + ret = memcmp(a->buffer, b->buffer, minlen); + if(ret != 0) return ret; + if(a->offset == b->offset) + return 0; + if(a->offset == minlen) + return -1; + return 1; +} + + +asn_enc_rval_t +SET_OF_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, + int ilevel, enum xer_encoder_flags_e flags, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_enc_rval_t er; + asn_SET_OF_specifics_t *specs = (asn_SET_OF_specifics_t *)td->specifics; + asn_TYPE_member_t *elm = td->elements; + asn_anonymous_set_ *list = _A_SET_FROM_VOID(sptr); + const char *mname = specs->as_XMLValueList + ? 0 : ((*elm->name) ? elm->name : elm->type->xml_tag); + size_t mlen = mname ? strlen(mname) : 0; + int xcan = (flags & XER_F_CANONICAL); + xer_tmp_enc_t *encs = 0; + size_t encs_count = 0; + void *original_app_key = app_key; + asn_app_consume_bytes_f *original_cb = cb; + int i; + + if(!sptr) ASN__ENCODE_FAILED; + + if(xcan) { + encs = (xer_tmp_enc_t *)MALLOC(list->count * sizeof(encs[0])); + if(!encs) ASN__ENCODE_FAILED; + cb = SET_OF_encode_xer_callback; + } + + er.encoded = 0; + + for(i = 0; i < list->count; i++) { + asn_enc_rval_t tmper; + + void *memb_ptr = list->array[i]; + if(!memb_ptr) continue; + + if(encs) { + memset(&encs[encs_count], 0, sizeof(encs[0])); + app_key = &encs[encs_count]; + encs_count++; + } + + if(mname) { + if(!xcan) ASN__TEXT_INDENT(1, ilevel); + ASN__CALLBACK3("<", 1, mname, mlen, ">", 1); + } + + if(!xcan && specs->as_XMLValueList == 1) + ASN__TEXT_INDENT(1, ilevel + 1); + tmper = elm->type->xer_encoder(elm->type, memb_ptr, + ilevel + (specs->as_XMLValueList != 2), + flags, cb, app_key); + if(tmper.encoded == -1) { + td = tmper.failed_type; + sptr = tmper.structure_ptr; + goto cb_failed; + } + if(tmper.encoded == 0 && specs->as_XMLValueList) { + const char *name = elm->type->xml_tag; + size_t len = strlen(name); + ASN__CALLBACK3("<", 1, name, len, "/>", 2); + } + + if(mname) { + ASN__CALLBACK3("", 1); + er.encoded += 5; + } + + er.encoded += (2 * mlen) + tmper.encoded; + } + + if(!xcan) ASN__TEXT_INDENT(1, ilevel - 1); + + if(encs) { + xer_tmp_enc_t *enc = encs; + xer_tmp_enc_t *end = encs + encs_count; + ssize_t control_size = 0; + + cb = original_cb; + app_key = original_app_key; + qsort(encs, encs_count, sizeof(encs[0]), SET_OF_xer_order); + + for(; enc < end; enc++) { + ASN__CALLBACK(enc->buffer, enc->offset); + FREEMEM(enc->buffer); + enc->buffer = 0; + control_size += enc->offset; + } + assert(control_size == er.encoded); + } + + goto cleanup; +cb_failed: + er.encoded = -1; + er.failed_type = td; + er.structure_ptr = sptr; +cleanup: + if(encs) { + while(encs_count-- > 0) { + if(encs[encs_count].buffer) + FREEMEM(encs[encs_count].buffer); + } + FREEMEM(encs); + } + ASN__ENCODED_OK(er); +} + +int +SET_OF_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_TYPE_member_t *elm = td->elements; + const asn_anonymous_set_ *list = _A_CSET_FROM_VOID(sptr); + int ret; + int i; + + if(!sptr) return (cb("", 8, app_key) < 0) ? -1 : 0; + + /* Dump preamble */ + if(cb(td->name, strlen(td->name), app_key) < 0 + || cb(" ::= {", 6, app_key) < 0) + return -1; + + for(i = 0; i < list->count; i++) { + const void *memb_ptr = list->array[i]; + if(!memb_ptr) continue; + + _i_INDENT(1); + + ret = elm->type->print_struct(elm->type, memb_ptr, + ilevel + 1, cb, app_key); + if(ret) return ret; + } + + ilevel--; + _i_INDENT(1); + + return (cb("}", 1, app_key) < 0) ? -1 : 0; +} + +void +SET_OF_free(asn_TYPE_descriptor_t *td, void *ptr, int contents_only) { + if(td && ptr) { + asn_SET_OF_specifics_t *specs; + asn_TYPE_member_t *elm = td->elements; + asn_anonymous_set_ *list = _A_SET_FROM_VOID(ptr); + asn_struct_ctx_t *ctx; /* Decoder context */ + int i; + + /* + * Could not use set_of_empty() because of (*free) + * incompatibility. + */ + for(i = 0; i < list->count; i++) { + void *memb_ptr = list->array[i]; + if(memb_ptr) + ASN_STRUCT_FREE(*elm->type, memb_ptr); + } + list->count = 0; /* No meaningful elements left */ + + asn_set_empty(list); /* Remove (list->array) */ + + specs = (asn_SET_OF_specifics_t *)td->specifics; + ctx = (asn_struct_ctx_t *)((char *)ptr + specs->ctx_offset); + if(ctx->ptr) { + ASN_STRUCT_FREE(*elm->type, ctx->ptr); + ctx->ptr = 0; + } + + if(!contents_only) { + FREEMEM(ptr); + } + } +} + +int +SET_OF_constraint(asn_TYPE_descriptor_t *td, const void *sptr, + asn_app_constraint_failed_f *ctfailcb, void *app_key) { + asn_TYPE_member_t *elm = td->elements; + asn_constr_check_f *constr; + const asn_anonymous_set_ *list = _A_CSET_FROM_VOID(sptr); + int i; + + if(!sptr) { + ASN__CTFAIL(app_key, td, sptr, + "%s: value not given (%s:%d)", + td->name, __FILE__, __LINE__); + return -1; + } + + constr = elm->memb_constraints; + if(!constr) constr = elm->type->check_constraints; + + /* + * Iterate over the members of an array. + * Validate each in turn, until one fails. + */ + for(i = 0; i < list->count; i++) { + const void *memb_ptr = list->array[i]; + int ret; + + if(!memb_ptr) continue; + + ret = constr(elm->type, memb_ptr, ctfailcb, app_key); + if(ret) return ret; + } + + /* + * Cannot inherit it eralier: + * need to make sure we get the updated version. + */ + if(!elm->memb_constraints) + elm->memb_constraints = elm->type->check_constraints; + + return 0; +} + +asn_dec_rval_t +SET_OF_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { + asn_dec_rval_t rv; + asn_SET_OF_specifics_t *specs = (asn_SET_OF_specifics_t *)td->specifics; + asn_TYPE_member_t *elm = td->elements; /* Single one */ + void *st = *sptr; + asn_anonymous_set_ *list; + asn_per_constraint_t *ct; + int repeat = 0; + ssize_t nelems; + + if(ASN__STACK_OVERFLOW_CHECK(opt_codec_ctx)) + ASN__DECODE_FAILED; + + /* + * Create the target structure if it is not present already. + */ + if(!st) { + st = *sptr = CALLOC(1, specs->struct_size); + if(!st) ASN__DECODE_FAILED; + } + list = _A_SET_FROM_VOID(st); + + /* Figure out which constraints to use */ + if(constraints) ct = &constraints->size; + else if(td->per_constraints) ct = &td->per_constraints->size; + else ct = 0; + + if(ct && ct->flags & APC_EXTENSIBLE) { + int value = per_get_few_bits(pd, 1); + if(value < 0) ASN__DECODE_STARVED; + if(value) ct = 0; /* Not restricted! */ + } + + if(ct && ct->effective_bits >= 0) { + /* X.691, #19.5: No length determinant */ + nelems = per_get_few_bits(pd, ct->effective_bits); + ASN_DEBUG("Preparing to fetch %ld+%ld elements from %s", + (long)nelems, ct->lower_bound, td->name); + if(nelems < 0) ASN__DECODE_STARVED; + nelems += ct->lower_bound; + } else { + nelems = -1; + } + + do { + int i; + if(nelems < 0) { + nelems = uper_get_length(pd, + ct ? ct->effective_bits : -1, &repeat); + ASN_DEBUG("Got to decode %d elements (eff %d)", + (int)nelems, (int)(ct ? ct->effective_bits : -1)); + if(nelems < 0) ASN__DECODE_STARVED; + } + + for(i = 0; i < nelems; i++) { + void *ptr = 0; + ASN_DEBUG("SET OF %s decoding", elm->type->name); + rv = elm->type->uper_decoder(opt_codec_ctx, elm->type, + elm->per_constraints, &ptr, pd); + ASN_DEBUG("%s SET OF %s decoded %d, %p", + td->name, elm->type->name, rv.code, ptr); + if(rv.code == RC_OK) { + if(ASN_SET_ADD(list, ptr) == 0) + continue; + ASN_DEBUG("Failed to add element into %s", + td->name); + /* Fall through */ + rv.code = RC_FAIL; + } else { + ASN_DEBUG("Failed decoding %s of %s (SET OF)", + elm->type->name, td->name); + } + if(ptr) ASN_STRUCT_FREE(*elm->type, ptr); + return rv; + } + + nelems = -1; /* Allow uper_get_length() */ + } while(repeat); + + ASN_DEBUG("Decoded %s as SET OF", td->name); + + rv.code = RC_OK; + rv.consumed = 0; + return rv; +} + diff --git a/src/cryptoconditions/src/asn/constr_SET_OF.h b/src/cryptoconditions/src/asn/constr_SET_OF.h new file mode 100644 index 000000000..75e18cfa0 --- /dev/null +++ b/src/cryptoconditions/src/asn/constr_SET_OF.h @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 2003 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _CONSTR_SET_OF_H_ +#define _CONSTR_SET_OF_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef const struct asn_SET_OF_specifics_s { + /* + * Target structure description. + */ + int struct_size; /* Size of the target structure. */ + int ctx_offset; /* Offset of the asn_struct_ctx_t member */ + + /* XER-specific stuff */ + int as_XMLValueList; /* The member type must be encoded like this */ +} asn_SET_OF_specifics_t; + +/* + * A set specialized functions dealing with the SET OF type. + */ +asn_struct_free_f SET_OF_free; +asn_struct_print_f SET_OF_print; +asn_constr_check_f SET_OF_constraint; +ber_type_decoder_f SET_OF_decode_ber; +der_type_encoder_f SET_OF_encode_der; +xer_type_decoder_f SET_OF_decode_xer; +xer_type_encoder_f SET_OF_encode_xer; +per_type_decoder_f SET_OF_decode_uper; +per_type_encoder_f SET_OF_encode_uper; + +#ifdef __cplusplus +} +#endif + +#endif /* _CONSTR_SET_OF_H_ */ diff --git a/src/cryptoconditions/src/asn/constr_TYPE.c b/src/cryptoconditions/src/asn/constr_TYPE.c new file mode 100644 index 000000000..322f68c86 --- /dev/null +++ b/src/cryptoconditions/src/asn/constr_TYPE.c @@ -0,0 +1,77 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +/* + * Version of the ASN.1 infrastructure shipped with compiler. + */ +int get_asn1c_environment_version() { return ASN1C_ENVIRONMENT_VERSION; } + +static asn_app_consume_bytes_f _print2fp; + +/* + * Return the outmost tag of the type. + */ +ber_tlv_tag_t +asn_TYPE_outmost_tag(const asn_TYPE_descriptor_t *type_descriptor, + const void *struct_ptr, int tag_mode, ber_tlv_tag_t tag) { + + if(tag_mode) + return tag; + + if(type_descriptor->tags_count) + return type_descriptor->tags[0]; + + return type_descriptor->outmost_tag(type_descriptor, struct_ptr, 0, 0); +} + +/* + * Print the target language's structure in human readable form. + */ +int +asn_fprint(FILE *stream, asn_TYPE_descriptor_t *td, const void *struct_ptr) { + if(!stream) stream = stdout; + if(!td || !struct_ptr) { + errno = EINVAL; + return -1; + } + + /* Invoke type-specific printer */ + if(td->print_struct(td, struct_ptr, 1, _print2fp, stream)) + return -1; + + /* Terminate the output */ + if(_print2fp("\n", 1, stream)) + return -1; + + return fflush(stream); +} + +/* Dump the data into the specified stdio stream */ +static int +_print2fp(const void *buffer, size_t size, void *app_key) { + FILE *stream = (FILE *)app_key; + + if(fwrite(buffer, 1, size, stream) != size) + return -1; + + return 0; +} + + +/* + * Some compilers do not support variable args macros. + * This function is a replacement of ASN_DEBUG() macro. + */ +void ASN_DEBUG_f(const char *fmt, ...); +void ASN_DEBUG_f(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); +} diff --git a/src/cryptoconditions/src/asn/constr_TYPE.h b/src/cryptoconditions/src/asn/constr_TYPE.h new file mode 100644 index 000000000..a9cd86dc3 --- /dev/null +++ b/src/cryptoconditions/src/asn/constr_TYPE.h @@ -0,0 +1,180 @@ +/*- + * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +/* + * This file contains the declaration structure called "ASN.1 Type Definition", + * which holds all information necessary for encoding and decoding routines. + * This structure even contains pointer to these encoding and decoding routines + * for each defined ASN.1 type. + */ +#ifndef _CONSTR_TYPE_H_ +#define _CONSTR_TYPE_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ +struct asn_TYPE_member_s; /* Forward declaration */ + +/* + * This type provides the context information for various ASN.1 routines, + * primarily ones doing decoding. A member _asn_ctx of this type must be + * included into certain target language's structures, such as compound types. + */ +typedef struct asn_struct_ctx_s { + short phase; /* Decoding phase */ + short step; /* Elementary step of a phase */ + int context; /* Other context information */ + void *ptr; /* Decoder-specific stuff (stack elements) */ + ber_tlv_len_t left; /* Number of bytes left, -1 for indefinite */ +} asn_struct_ctx_t; + +#include /* Basic Encoding Rules decoder */ +#include /* Distinguished Encoding Rules encoder */ +#include /* Decoder of XER (XML, text) */ +#include /* Encoder into XER (XML, text) */ +#include /* Packet Encoding Rules decoder */ +#include /* Packet Encoding Rules encoder */ +#include /* Subtype constraints support */ + +/* + * Free the structure according to its specification. + * If (free_contents_only) is set, the wrapper structure itself (struct_ptr) + * will not be freed. (It may be useful in case the structure is allocated + * statically or arranged on the stack, yet its elements are allocated + * dynamically.) + */ +typedef void (asn_struct_free_f)( + struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, int free_contents_only); +#define ASN_STRUCT_FREE(asn_DEF, ptr) (asn_DEF).free_struct(&(asn_DEF),ptr,0) +#define ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF, ptr) \ + (asn_DEF).free_struct(&(asn_DEF),ptr,1) + +/* + * Print the structure according to its specification. + */ +typedef int (asn_struct_print_f)( + struct asn_TYPE_descriptor_s *type_descriptor, + const void *struct_ptr, + int level, /* Indentation level */ + asn_app_consume_bytes_f *callback, void *app_key); + +/* + * Return the outmost tag of the type. + * If the type is untagged CHOICE, the dynamic operation is performed. + * NOTE: This function pointer type is only useful internally. + * Do not use it in your application. + */ +typedef ber_tlv_tag_t (asn_outmost_tag_f)( + const struct asn_TYPE_descriptor_s *type_descriptor, + const void *struct_ptr, int tag_mode, ber_tlv_tag_t tag); +/* The instance of the above function type; used internally. */ +asn_outmost_tag_f asn_TYPE_outmost_tag; + + +/* + * The definitive description of the destination language's structure. + */ +typedef struct asn_TYPE_descriptor_s { + const char *name; /* A name of the ASN.1 type. "" in some cases. */ + const char *xml_tag; /* Name used in XML tag */ + + /* + * Generalized functions for dealing with the specific type. + * May be directly invoked by applications. + */ + asn_struct_free_f *free_struct; /* Free the structure */ + asn_struct_print_f *print_struct; /* Human readable output */ + asn_constr_check_f *check_constraints; /* Constraints validator */ + ber_type_decoder_f *ber_decoder; /* Generic BER decoder */ + der_type_encoder_f *der_encoder; /* Canonical DER encoder */ + xer_type_decoder_f *xer_decoder; /* Generic XER decoder */ + xer_type_encoder_f *xer_encoder; /* [Canonical] XER encoder */ + per_type_decoder_f *uper_decoder; /* Unaligned PER decoder */ + per_type_encoder_f *uper_encoder; /* Unaligned PER encoder */ + + /*********************************************************************** + * Internally useful members. Not to be used by applications directly. * + **********************************************************************/ + + /* + * Tags that are expected to occur. + */ + asn_outmost_tag_f *outmost_tag; /* */ + const ber_tlv_tag_t *tags; /* Effective tags sequence for this type */ + int tags_count; /* Number of tags which are expected */ + const ber_tlv_tag_t *all_tags; /* Every tag for BER/containment */ + int all_tags_count; /* Number of tags */ + + asn_per_constraints_t *per_constraints; /* PER compiled constraints */ + + /* + * An ASN.1 production type members (members of SEQUENCE, SET, CHOICE). + */ + struct asn_TYPE_member_s *elements; + int elements_count; + + /* + * Additional information describing the type, used by appropriate + * functions above. + */ + const void *specifics; +} asn_TYPE_descriptor_t; + +/* + * This type describes an element of the constructed type, + * i.e. SEQUENCE, SET, CHOICE, etc. + */ + enum asn_TYPE_flags_e { + ATF_NOFLAGS, + ATF_POINTER = 0x01, /* Represented by the pointer */ + ATF_OPEN_TYPE = 0x02 /* ANY type, without meaningful tag */ + }; +typedef struct asn_TYPE_member_s { + enum asn_TYPE_flags_e flags; /* Element's presentation flags */ + int optional; /* Following optional members, including current */ + int memb_offset; /* Offset of the element */ + ber_tlv_tag_t tag; /* Outmost (most immediate) tag */ + int tag_mode; /* IMPLICIT/no/EXPLICIT tag at current level */ + asn_TYPE_descriptor_t *type; /* Member type descriptor */ + asn_constr_check_f *memb_constraints; /* Constraints validator */ + asn_per_constraints_t *per_constraints; /* PER compiled constraints */ + int (*default_value)(int setval, void **sptr); /* DEFAULT */ + const char *name; /* ASN.1 identifier of the element */ +} asn_TYPE_member_t; + +/* + * BER tag to element number mapping. + */ +typedef struct asn_TYPE_tag2member_s { + ber_tlv_tag_t el_tag; /* Outmost tag of the member */ + int el_no; /* Index of the associated member, base 0 */ + int toff_first; /* First occurence of the el_tag, relative */ + int toff_last; /* Last occurence of the el_tag, relatvie */ +} asn_TYPE_tag2member_t; + +/* + * This function is a wrapper around (td)->print_struct, which prints out + * the contents of the target language's structure (struct_ptr) into the + * file pointer (stream) in human readable form. + * RETURN VALUES: + * 0: The structure is printed. + * -1: Problem dumping the structure. + * (See also xer_fprint() in xer_encoder.h) + */ +int asn_fprint(FILE *stream, /* Destination stream descriptor */ + asn_TYPE_descriptor_t *td, /* ASN.1 type descriptor */ + const void *struct_ptr); /* Structure to be printed */ + +#ifdef __cplusplus +} +#endif + +#endif /* _CONSTR_TYPE_H_ */ diff --git a/src/cryptoconditions/src/asn/constraints.c b/src/cryptoconditions/src/asn/constraints.c new file mode 100644 index 000000000..1bdda73e5 --- /dev/null +++ b/src/cryptoconditions/src/asn/constraints.c @@ -0,0 +1,93 @@ +#include "asn_internal.h" +#include "constraints.h" + +int +asn_generic_no_constraint(asn_TYPE_descriptor_t *type_descriptor, + const void *struct_ptr, asn_app_constraint_failed_f *cb, void *key) { + + (void)type_descriptor; /* Unused argument */ + (void)struct_ptr; /* Unused argument */ + (void)cb; /* Unused argument */ + (void)key; /* Unused argument */ + + /* Nothing to check */ + return 0; +} + +int +asn_generic_unknown_constraint(asn_TYPE_descriptor_t *type_descriptor, + const void *struct_ptr, asn_app_constraint_failed_f *cb, void *key) { + + (void)type_descriptor; /* Unused argument */ + (void)struct_ptr; /* Unused argument */ + (void)cb; /* Unused argument */ + (void)key; /* Unused argument */ + + /* Unknown how to check */ + return 0; +} + +struct errbufDesc { + asn_TYPE_descriptor_t *failed_type; + const void *failed_struct_ptr; + char *errbuf; + size_t errlen; +}; + +static void +_asn_i_ctfailcb(void *key, asn_TYPE_descriptor_t *td, const void *sptr, const char *fmt, ...) { + struct errbufDesc *arg = key; + va_list ap; + ssize_t vlen; + ssize_t maxlen; + + arg->failed_type = td; + arg->failed_struct_ptr = sptr; + + maxlen = arg->errlen; + if(maxlen <= 0) + return; + + va_start(ap, fmt); + vlen = vsnprintf(arg->errbuf, maxlen, fmt, ap); + va_end(ap); + if(vlen >= maxlen) { + arg->errbuf[maxlen-1] = '\0'; /* Ensuring libc correctness */ + arg->errlen = maxlen - 1; /* Not counting termination */ + return; + } else if(vlen >= 0) { + arg->errbuf[vlen] = '\0'; /* Ensuring libc correctness */ + arg->errlen = vlen; /* Not counting termination */ + } else { + /* + * The libc on this system is broken. + */ + vlen = sizeof("") - 1; + maxlen--; + arg->errlen = vlen < maxlen ? vlen : maxlen; + memcpy(arg->errbuf, "", arg->errlen); + arg->errbuf[arg->errlen] = 0; + } + + return; +} + +int +asn_check_constraints(asn_TYPE_descriptor_t *type_descriptor, + const void *struct_ptr, char *errbuf, size_t *errlen) { + struct errbufDesc arg; + int ret; + + arg.failed_type = 0; + arg.failed_struct_ptr = 0; + arg.errbuf = errbuf; + arg.errlen = errlen ? *errlen : 0; + + ret = type_descriptor->check_constraints(type_descriptor, + struct_ptr, _asn_i_ctfailcb, &arg); + if(ret == -1 && errlen) + *errlen = arg.errlen; + + return ret; +} + diff --git a/src/cryptoconditions/src/asn/constraints.h b/src/cryptoconditions/src/asn/constraints.h new file mode 100644 index 000000000..48d49e246 --- /dev/null +++ b/src/cryptoconditions/src/asn/constraints.h @@ -0,0 +1,63 @@ +/*- + * Copyright (c) 2004, 2006 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef ASN1_CONSTRAINTS_VALIDATOR_H +#define ASN1_CONSTRAINTS_VALIDATOR_H + +#include /* Platform-dependent types */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ + +/* + * Validate the structure according to the ASN.1 constraints. + * If errbuf and errlen are given, they shall be pointing to the appropriate + * buffer space and its length before calling this function. Alternatively, + * they could be passed as NULL's. If constraints validation fails, + * errlen will contain the actual number of bytes taken from the errbuf + * to encode an error message (properly 0-terminated). + * + * RETURN VALUES: + * This function returns 0 in case all ASN.1 constraints are met + * and -1 if one or more constraints were failed. + */ +int +asn_check_constraints(struct asn_TYPE_descriptor_s *type_descriptor, + const void *struct_ptr, /* Target language's structure */ + char *errbuf, /* Returned error description */ + size_t *errlen /* Length of the error description */ + ); + + +/* + * Generic type for constraint checking callback, + * associated with every type descriptor. + */ +typedef int (asn_constr_check_f)( + struct asn_TYPE_descriptor_s *type_descriptor, + const void *struct_ptr, + asn_app_constraint_failed_f *optional_callback, /* Log the error */ + void *optional_app_key /* Opaque key passed to a callback */ + ); + +/******************************* + * INTERNALLY USEFUL FUNCTIONS * + *******************************/ + +asn_constr_check_f asn_generic_no_constraint; /* No constraint whatsoever */ +asn_constr_check_f asn_generic_unknown_constraint; /* Not fully supported */ + +/* + * Invoke the callback with a complete error message. + */ +#define ASN__CTFAIL if(ctfailcb) ctfailcb + +#ifdef __cplusplus +} +#endif + +#endif /* ASN1_CONSTRAINTS_VALIDATOR_H */ diff --git a/src/cryptoconditions/src/asn/der_encoder.c b/src/cryptoconditions/src/asn/der_encoder.c new file mode 100644 index 000000000..1c014802a --- /dev/null +++ b/src/cryptoconditions/src/asn/der_encoder.c @@ -0,0 +1,201 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include + +static ssize_t der_write_TL(ber_tlv_tag_t tag, ber_tlv_len_t len, + asn_app_consume_bytes_f *cb, void *app_key, int constructed); + +/* + * The DER encoder of any type. + */ +asn_enc_rval_t +der_encode(asn_TYPE_descriptor_t *type_descriptor, void *struct_ptr, + asn_app_consume_bytes_f *consume_bytes, void *app_key) { + + ASN_DEBUG("DER encoder invoked for %s", + type_descriptor->name); + + /* + * Invoke type-specific encoder. + */ + return type_descriptor->der_encoder(type_descriptor, + struct_ptr, /* Pointer to the destination structure */ + 0, 0, + consume_bytes, app_key); +} + +/* + * Argument type and callback necessary for der_encode_to_buffer(). + */ +typedef struct enc_to_buf_arg { + void *buffer; + size_t left; +} enc_to_buf_arg; +static int encode_to_buffer_cb(const void *buffer, size_t size, void *key) { + enc_to_buf_arg *arg = (enc_to_buf_arg *)key; + + if(arg->left < size) + return -1; /* Data exceeds the available buffer size */ + + memcpy(arg->buffer, buffer, size); + arg->buffer = ((char *)arg->buffer) + size; + arg->left -= size; + + return 0; +} + +/* + * A variant of the der_encode() which encodes the data into the provided buffer + */ +asn_enc_rval_t +der_encode_to_buffer(asn_TYPE_descriptor_t *type_descriptor, void *struct_ptr, + void *buffer, size_t buffer_size) { + enc_to_buf_arg arg; + asn_enc_rval_t ec; + + arg.buffer = buffer; + arg.left = buffer_size; + + ec = type_descriptor->der_encoder(type_descriptor, + struct_ptr, /* Pointer to the destination structure */ + 0, 0, encode_to_buffer_cb, &arg); + if(ec.encoded != -1) { + assert(ec.encoded == (ssize_t)(buffer_size - arg.left)); + /* Return the encoded contents size */ + } + return ec; +} + + +/* + * Write out leading TL[v] sequence according to the type definition. + */ +ssize_t +der_write_tags(asn_TYPE_descriptor_t *sd, + size_t struct_length, + int tag_mode, int last_tag_form, + ber_tlv_tag_t tag, /* EXPLICIT or IMPLICIT tag */ + asn_app_consume_bytes_f *cb, + void *app_key) { + const ber_tlv_tag_t *tags; /* Copy of tags stream */ + int tags_count; /* Number of tags */ + size_t overall_length; + ssize_t *lens; + int i; + + ASN_DEBUG("Writing tags (%s, tm=%d, tc=%d, tag=%s, mtc=%d)", + sd->name, tag_mode, sd->tags_count, + ber_tlv_tag_string(tag), + tag_mode + ?(sd->tags_count+1 + -((tag_mode == -1) && sd->tags_count)) + :sd->tags_count + ); + + if(tag_mode) { + /* + * Instead of doing shaman dance like we do in ber_check_tags(), + * allocate a small array on the stack + * and initialize it appropriately. + */ + int stag_offset; + ber_tlv_tag_t *tags_buf; + tags_buf = (ber_tlv_tag_t *)alloca((sd->tags_count + 1) * sizeof(ber_tlv_tag_t)); + if(!tags_buf) { /* Can fail on !x86 */ + errno = ENOMEM; + return -1; + } + tags_count = sd->tags_count + + 1 /* EXPLICIT or IMPLICIT tag is given */ + - ((tag_mode == -1) && sd->tags_count); + /* Copy tags over */ + tags_buf[0] = tag; + stag_offset = -1 + ((tag_mode == -1) && sd->tags_count); + for(i = 1; i < tags_count; i++) + tags_buf[i] = sd->tags[i + stag_offset]; + tags = tags_buf; + } else { + tags = sd->tags; + tags_count = sd->tags_count; + } + + /* No tags to write */ + if(tags_count == 0) + return 0; + + lens = (ssize_t *)alloca(tags_count * sizeof(lens[0])); + if(!lens) { + errno = ENOMEM; + return -1; + } + + /* + * Array of tags is initialized. + * Now, compute the size of the TLV pairs, from right to left. + */ + overall_length = struct_length; + for(i = tags_count - 1; i >= 0; --i) { + lens[i] = der_write_TL(tags[i], overall_length, 0, 0, 0); + if(lens[i] == -1) return -1; + overall_length += lens[i]; + lens[i] = overall_length - lens[i]; + } + + if(!cb) return overall_length - struct_length; + + ASN_DEBUG("%s %s TL sequence (%d elements)", + cb?"Encoding":"Estimating", sd->name, tags_count); + + /* + * Encode the TL sequence for real. + */ + for(i = 0; i < tags_count; i++) { + ssize_t len; + int _constr; + + /* Check if this tag happens to be constructed */ + _constr = (last_tag_form || i < (tags_count - 1)); + + len = der_write_TL(tags[i], lens[i], cb, app_key, _constr); + if(len == -1) return -1; + } + + return overall_length - struct_length; +} + +static ssize_t +der_write_TL(ber_tlv_tag_t tag, ber_tlv_len_t len, + asn_app_consume_bytes_f *cb, void *app_key, + int constructed) { + uint8_t buf[32]; + size_t size = 0; + int buf_size = cb?sizeof(buf):0; + ssize_t tmp; + + /* Serialize tag (T from TLV) into possibly zero-length buffer */ + tmp = ber_tlv_tag_serialize(tag, buf, buf_size); + if(tmp == -1 || tmp > (ssize_t)sizeof(buf)) return -1; + size += tmp; + + /* Serialize length (L from TLV) into possibly zero-length buffer */ + tmp = der_tlv_length_serialize(len, buf+size, buf_size?buf_size-size:0); + if(tmp == -1) return -1; + size += tmp; + + if(size > sizeof(buf)) + return -1; + + /* + * If callback is specified, invoke it, and check its return value. + */ + if(cb) { + if(constructed) *buf |= 0x20; + if(cb(buf, size, app_key) < 0) + return -1; + } + + return size; +} diff --git a/src/cryptoconditions/src/asn/der_encoder.h b/src/cryptoconditions/src/asn/der_encoder.h new file mode 100644 index 000000000..61431c6db --- /dev/null +++ b/src/cryptoconditions/src/asn/der_encoder.h @@ -0,0 +1,68 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _DER_ENCODER_H_ +#define _DER_ENCODER_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ + +/* + * The DER encoder of any type. May be invoked by the application. + * The ber_decode() function (ber_decoder.h) is an opposite of der_encode(). + */ +asn_enc_rval_t der_encode(struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + asn_app_consume_bytes_f *consume_bytes_cb, + void *app_key /* Arbitrary callback argument */ + ); + +/* A variant of der_encode() which encodes data into the pre-allocated buffer */ +asn_enc_rval_t der_encode_to_buffer( + struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + void *buffer, /* Pre-allocated buffer */ + size_t buffer_size /* Initial buffer size (maximum) */ + ); + +/* + * Type of the generic DER encoder. + */ +typedef asn_enc_rval_t (der_type_encoder_f)( + struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ + ber_tlv_tag_t tag, + asn_app_consume_bytes_f *consume_bytes_cb, /* Callback */ + void *app_key /* Arbitrary callback argument */ + ); + + +/******************************* + * INTERNALLY USEFUL FUNCTIONS * + *******************************/ + +/* + * Write out leading TL[v] sequence according to the type definition. + */ +ssize_t der_write_tags( + struct asn_TYPE_descriptor_s *type_descriptor, + size_t struct_length, + int tag_mode, /* {-1,0,1}: IMPLICIT, no, EXPLICIT */ + int last_tag_form, /* {0,!0}: prim, constructed */ + ber_tlv_tag_t tag, + asn_app_consume_bytes_f *consume_bytes_cb, + void *app_key + ); + +#ifdef __cplusplus +} +#endif + +#endif /* _DER_ENCODER_H_ */ diff --git a/src/cryptoconditions/src/asn/per_decoder.c b/src/cryptoconditions/src/asn/per_decoder.c new file mode 100644 index 000000000..461b7262f --- /dev/null +++ b/src/cryptoconditions/src/asn/per_decoder.c @@ -0,0 +1,93 @@ +#include +#include +#include + +/* + * Decode a "Production of a complete encoding", X.691#10.1. + * The complete encoding contains at least one byte, and is an integral + * multiple of 8 bytes. + */ +asn_dec_rval_t +uper_decode_complete(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **sptr, const void *buffer, size_t size) { + asn_dec_rval_t rval; + + rval = uper_decode(opt_codec_ctx, td, sptr, buffer, size, 0, 0); + if(rval.consumed) { + /* + * We've always given 8-aligned data, + * so convert bits to integral bytes. + */ + rval.consumed += 7; + rval.consumed >>= 3; + } else if(rval.code == RC_OK) { + if(size) { + if(((const uint8_t *)buffer)[0] == 0) { + rval.consumed = 1; /* 1 byte */ + } else { + ASN_DEBUG("Expecting single zeroed byte"); + rval.code = RC_FAIL; + } + } else { + /* Must contain at least 8 bits. */ + rval.code = RC_WMORE; + } + } + + return rval; +} + +asn_dec_rval_t +uper_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **sptr, const void *buffer, size_t size, int skip_bits, int unused_bits) { + asn_codec_ctx_t s_codec_ctx; + asn_dec_rval_t rval; + asn_per_data_t pd; + + if(skip_bits < 0 || skip_bits > 7 + || unused_bits < 0 || unused_bits > 7 + || (unused_bits > 0 && !size)) + ASN__DECODE_FAILED; + + /* + * Stack checker requires that the codec context + * must be allocated on the stack. + */ + if(opt_codec_ctx) { + if(opt_codec_ctx->max_stack_size) { + s_codec_ctx = *opt_codec_ctx; + opt_codec_ctx = &s_codec_ctx; + } + } else { + /* If context is not given, be security-conscious anyway */ + memset(&s_codec_ctx, 0, sizeof(s_codec_ctx)); + s_codec_ctx.max_stack_size = ASN__DEFAULT_STACK_MAX; + opt_codec_ctx = &s_codec_ctx; + } + + /* Fill in the position indicator */ + memset(&pd, 0, sizeof(pd)); + pd.buffer = (const uint8_t *)buffer; + pd.nboff = skip_bits; + pd.nbits = 8 * size - unused_bits; /* 8 is CHAR_BIT from */ + if(pd.nboff > pd.nbits) + ASN__DECODE_FAILED; + + /* + * Invoke type-specific decoder. + */ + if(!td->uper_decoder) + ASN__DECODE_FAILED; /* PER is not compiled in */ + rval = td->uper_decoder(opt_codec_ctx, td, 0, sptr, &pd); + if(rval.code == RC_OK) { + /* Return the number of consumed bits */ + rval.consumed = ((pd.buffer - (const uint8_t *)buffer) << 3) + + pd.nboff - skip_bits; + ASN_DEBUG("PER decoding consumed %ld, counted %ld", + (long)rval.consumed, (long)pd.moved); + assert(rval.consumed == pd.moved); + } else { + /* PER codec is not a restartable */ + rval.consumed = 0; + } + return rval; +} + diff --git a/src/cryptoconditions/src/asn/per_decoder.h b/src/cryptoconditions/src/asn/per_decoder.h new file mode 100644 index 000000000..8397a545f --- /dev/null +++ b/src/cryptoconditions/src/asn/per_decoder.h @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 2005, 2007 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _PER_DECODER_H_ +#define _PER_DECODER_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ + +/* + * Unaligned PER decoder of a "complete encoding" as per X.691#10.1. + * On success, this call always returns (.consumed >= 1), as per X.691#10.1.3. + */ +asn_dec_rval_t uper_decode_complete(struct asn_codec_ctx_s *opt_codec_ctx, + struct asn_TYPE_descriptor_s *type_descriptor, /* Type to decode */ + void **struct_ptr, /* Pointer to a target structure's pointer */ + const void *buffer, /* Data to be decoded */ + size_t size /* Size of data buffer */ + ); + +/* + * Unaligned PER decoder of any ASN.1 type. May be invoked by the application. + * WARNING: This call returns the number of BITS read from the stream. Beware. + */ +asn_dec_rval_t uper_decode(struct asn_codec_ctx_s *opt_codec_ctx, + struct asn_TYPE_descriptor_s *type_descriptor, /* Type to decode */ + void **struct_ptr, /* Pointer to a target structure's pointer */ + const void *buffer, /* Data to be decoded */ + size_t size, /* Size of data buffer */ + int skip_bits, /* Number of unused leading bits, 0..7 */ + int unused_bits /* Number of unused tailing bits, 0..7 */ + ); + + +/* + * Type of the type-specific PER decoder function. + */ +typedef asn_dec_rval_t (per_type_decoder_f)(asn_codec_ctx_t *opt_codec_ctx, + struct asn_TYPE_descriptor_s *type_descriptor, + asn_per_constraints_t *constraints, + void **struct_ptr, + asn_per_data_t *per_data + ); + +#ifdef __cplusplus +} +#endif + +#endif /* _PER_DECODER_H_ */ diff --git a/src/cryptoconditions/src/asn/per_encoder.c b/src/cryptoconditions/src/asn/per_encoder.c new file mode 100644 index 000000000..47f3c916d --- /dev/null +++ b/src/cryptoconditions/src/asn/per_encoder.c @@ -0,0 +1,151 @@ +#include +#include +#include + +static asn_enc_rval_t uper_encode_internal(asn_TYPE_descriptor_t *td, asn_per_constraints_t *, void *sptr, asn_app_consume_bytes_f *cb, void *app_key); + +asn_enc_rval_t +uper_encode(asn_TYPE_descriptor_t *td, void *sptr, asn_app_consume_bytes_f *cb, void *app_key) { + return uper_encode_internal(td, 0, sptr, cb, app_key); +} + +/* + * Argument type and callback necessary for uper_encode_to_buffer(). + */ +typedef struct enc_to_buf_arg { + void *buffer; + size_t left; +} enc_to_buf_arg; +static int encode_to_buffer_cb(const void *buffer, size_t size, void *key) { + enc_to_buf_arg *arg = (enc_to_buf_arg *)key; + + if(arg->left < size) + return -1; /* Data exceeds the available buffer size */ + + memcpy(arg->buffer, buffer, size); + arg->buffer = ((char *)arg->buffer) + size; + arg->left -= size; + + return 0; +} + +asn_enc_rval_t +uper_encode_to_buffer(asn_TYPE_descriptor_t *td, void *sptr, void *buffer, size_t buffer_size) { + enc_to_buf_arg key; + + key.buffer = buffer; + key.left = buffer_size; + + if(td) ASN_DEBUG("Encoding \"%s\" using UNALIGNED PER", td->name); + + return uper_encode_internal(td, 0, sptr, encode_to_buffer_cb, &key); +} + +typedef struct enc_dyn_arg { + void *buffer; + size_t length; + size_t allocated; +} enc_dyn_arg; +static int +encode_dyn_cb(const void *buffer, size_t size, void *key) { + enc_dyn_arg *arg = key; + if(arg->length + size >= arg->allocated) { + void *p; + arg->allocated = arg->allocated ? (arg->allocated << 2) : size; + p = REALLOC(arg->buffer, arg->allocated); + if(!p) { + FREEMEM(arg->buffer); + memset(arg, 0, sizeof(*arg)); + return -1; + } + arg->buffer = p; + } + memcpy(((char *)arg->buffer) + arg->length, buffer, size); + arg->length += size; + return 0; +} +ssize_t +uper_encode_to_new_buffer(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, void **buffer_r) { + asn_enc_rval_t er; + enc_dyn_arg key; + + memset(&key, 0, sizeof(key)); + + er = uper_encode_internal(td, constraints, sptr, encode_dyn_cb, &key); + switch(er.encoded) { + case -1: + FREEMEM(key.buffer); + return -1; + case 0: + FREEMEM(key.buffer); + key.buffer = MALLOC(1); + if(key.buffer) { + *(char *)key.buffer = '\0'; + *buffer_r = key.buffer; + return 1; + } else { + return -1; + } + default: + *buffer_r = key.buffer; + ASN_DEBUG("Complete encoded in %ld bits", (long)er.encoded); + return ((er.encoded + 7) >> 3); + } +} + +/* + * Internally useful functions. + */ + +/* Flush partially filled buffer */ +static int +_uper_encode_flush_outp(asn_per_outp_t *po) { + uint8_t *buf; + + if(po->nboff == 0 && po->buffer == po->tmpspace) + return 0; + + buf = po->buffer + (po->nboff >> 3); + /* Make sure we account for the last, partially filled */ + if(po->nboff & 0x07) { + buf[0] &= 0xff << (8 - (po->nboff & 0x07)); + buf++; + } + + return po->outper(po->tmpspace, buf - po->tmpspace, po->op_key); +} + +static asn_enc_rval_t +uper_encode_internal(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_app_consume_bytes_f *cb, void *app_key) { + asn_per_outp_t po; + asn_enc_rval_t er; + + /* + * Invoke type-specific encoder. + */ + if(!td || !td->uper_encoder) + ASN__ENCODE_FAILED; /* PER is not compiled in */ + + po.buffer = po.tmpspace; + po.nboff = 0; + po.nbits = 8 * sizeof(po.tmpspace); + po.outper = cb; + po.op_key = app_key; + po.flushed_bytes = 0; + + er = td->uper_encoder(td, constraints, sptr, &po); + if(er.encoded != -1) { + size_t bits_to_flush; + + bits_to_flush = ((po.buffer - po.tmpspace) << 3) + po.nboff; + + /* Set number of bits encoded to a firm value */ + er.encoded = (po.flushed_bytes << 3) + bits_to_flush; + + if(_uper_encode_flush_outp(&po)) + ASN__ENCODE_FAILED; + } + + return er; +} + diff --git a/src/cryptoconditions/src/asn/per_encoder.h b/src/cryptoconditions/src/asn/per_encoder.h new file mode 100644 index 000000000..95a6506e4 --- /dev/null +++ b/src/cryptoconditions/src/asn/per_encoder.h @@ -0,0 +1,69 @@ +/*- + * Copyright (c) 2006, 2007 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _PER_ENCODER_H_ +#define _PER_ENCODER_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ + +/* + * Unaligned PER encoder of any ASN.1 type. May be invoked by the application. + * WARNING: This function returns the number of encoded bits in the .encoded + * field of the return value. Use the following formula to convert to bytes: + * bytes = ((.encoded + 7) / 8) + */ +asn_enc_rval_t uper_encode(struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + asn_app_consume_bytes_f *consume_bytes_cb, /* Data collector */ + void *app_key /* Arbitrary callback argument */ +); + +/* + * A variant of uper_encode() which encodes data into the existing buffer + * WARNING: This function returns the number of encoded bits in the .encoded + * field of the return value. + */ +asn_enc_rval_t uper_encode_to_buffer( + struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + void *buffer, /* Pre-allocated buffer */ + size_t buffer_size /* Initial buffer size (max) */ +); + +/* + * A variant of uper_encode_to_buffer() which allocates buffer itself. + * Returns the number of bytes in the buffer or -1 in case of failure. + * WARNING: This function produces a "Production of the complete encoding", + * with length of at least one octet. Contrast this to precise bit-packing + * encoding of uper_encode() and uper_encode_to_buffer(). + */ +ssize_t uper_encode_to_new_buffer( + struct asn_TYPE_descriptor_s *type_descriptor, + asn_per_constraints_t *constraints, + void *struct_ptr, /* Structure to be encoded */ + void **buffer_r /* Buffer allocated and returned */ +); + +/* + * Type of the generic PER encoder function. + */ +typedef asn_enc_rval_t (per_type_encoder_f)( + struct asn_TYPE_descriptor_s *type_descriptor, + asn_per_constraints_t *constraints, + void *struct_ptr, + asn_per_outp_t *per_output +); + +#ifdef __cplusplus +} +#endif + +#endif /* _PER_ENCODER_H_ */ diff --git a/src/cryptoconditions/src/asn/per_opentype.c b/src/cryptoconditions/src/asn/per_opentype.c new file mode 100644 index 000000000..404aa7264 --- /dev/null +++ b/src/cryptoconditions/src/asn/per_opentype.c @@ -0,0 +1,378 @@ +/* + * Copyright (c) 2007 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include +#include + +typedef struct uper_ugot_key { + asn_per_data_t oldpd; /* Old per data source */ + size_t unclaimed; + size_t ot_moved; /* Number of bits moved by OT processing */ + int repeat; +} uper_ugot_key; + +static int uper_ugot_refill(asn_per_data_t *pd); +static int per_skip_bits(asn_per_data_t *pd, int skip_nbits); +static asn_dec_rval_t uper_sot_suck(asn_codec_ctx_t *, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd); + +/* + * Encode an "open type field". + * #10.1, #10.2 + */ +int +uper_open_type_put(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + void *buf; + void *bptr; + ssize_t size; + size_t toGo; + + ASN_DEBUG("Open type put %s ...", td->name); + + size = uper_encode_to_new_buffer(td, constraints, sptr, &buf); + if(size <= 0) return -1; + + for(bptr = buf, toGo = size; toGo;) { + ssize_t maySave = uper_put_length(po, toGo); + ASN_DEBUG("Prepending length %d to %s and allowing to save %d", + (int)size, td->name, (int)maySave); + if(maySave < 0) break; + if(per_put_many_bits(po, bptr, maySave * 8)) break; + bptr = (char *)bptr + maySave; + toGo -= maySave; + } + + FREEMEM(buf); + if(toGo) return -1; + + ASN_DEBUG("Open type put %s of length %ld + overhead (1byte?)", + td->name, (long)size); + + return 0; +} + +static asn_dec_rval_t +uper_open_type_get_simple(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { + asn_dec_rval_t rv; + ssize_t chunk_bytes; + int repeat; + uint8_t *buf = 0; + size_t bufLen = 0; + size_t bufSize = 0; + asn_per_data_t spd; + size_t padding; + + ASN__STACK_OVERFLOW_CHECK(ctx); + + ASN_DEBUG("Getting open type %s...", td->name); + + do { + chunk_bytes = uper_get_length(pd, -1, &repeat); + if(chunk_bytes < 0) { + FREEMEM(buf); + ASN__DECODE_STARVED; + } + if(bufLen + chunk_bytes > bufSize) { + void *ptr; + bufSize = chunk_bytes + (bufSize << 2); + ptr = REALLOC(buf, bufSize); + if(!ptr) { + FREEMEM(buf); + ASN__DECODE_FAILED; + } + buf = ptr; + } + if(per_get_many_bits(pd, buf + bufLen, 0, chunk_bytes << 3)) { + FREEMEM(buf); + ASN__DECODE_STARVED; + } + bufLen += chunk_bytes; + } while(repeat); + + ASN_DEBUG("Getting open type %s encoded in %ld bytes", td->name, + (long)bufLen); + + memset(&spd, 0, sizeof(spd)); + spd.buffer = buf; + spd.nbits = bufLen << 3; + + ASN_DEBUG_INDENT_ADD(+4); + rv = td->uper_decoder(ctx, td, constraints, sptr, &spd); + ASN_DEBUG_INDENT_ADD(-4); + + if(rv.code == RC_OK) { + /* Check padding validity */ + padding = spd.nbits - spd.nboff; + if ((padding < 8 || + /* X.691#10.1.3 */ + (spd.nboff == 0 && spd.nbits == 8 && spd.buffer == buf)) && + per_get_few_bits(&spd, padding) == 0) { + /* Everything is cool */ + FREEMEM(buf); + return rv; + } + FREEMEM(buf); + if(padding >= 8) { + ASN_DEBUG("Too large padding %d in open type", (int)padding); + ASN__DECODE_FAILED; + } else { + ASN_DEBUG("Non-zero padding"); + ASN__DECODE_FAILED; + } + } else { + FREEMEM(buf); + /* rv.code could be RC_WMORE, nonsense in this context */ + rv.code = RC_FAIL; /* Noone would give us more */ + } + + return rv; +} + +static asn_dec_rval_t GCC_NOTUSED +uper_open_type_get_complex(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { + uper_ugot_key arg; + asn_dec_rval_t rv; + ssize_t padding; + + ASN__STACK_OVERFLOW_CHECK(ctx); + + ASN_DEBUG("Getting open type %s from %s", td->name, + per_data_string(pd)); + arg.oldpd = *pd; + arg.unclaimed = 0; + arg.ot_moved = 0; + arg.repeat = 1; + pd->refill = uper_ugot_refill; + pd->refill_key = &arg; + pd->nbits = pd->nboff; /* 0 good bits at this point, will refill */ + pd->moved = 0; /* This now counts the open type size in bits */ + + ASN_DEBUG_INDENT_ADD(+4); + rv = td->uper_decoder(ctx, td, constraints, sptr, pd); + ASN_DEBUG_INDENT_ADD(-4); + +#define UPDRESTOREPD do { \ + /* buffer and nboff are valid, preserve them. */ \ + pd->nbits = arg.oldpd.nbits - (pd->moved - arg.ot_moved); \ + pd->moved = arg.oldpd.moved + (pd->moved - arg.ot_moved); \ + pd->refill = arg.oldpd.refill; \ + pd->refill_key = arg.oldpd.refill_key; \ + } while(0) + + if(rv.code != RC_OK) { + UPDRESTOREPD; + return rv; + } + + ASN_DEBUG("OpenType %s pd%s old%s unclaimed=%d, repeat=%d", td->name, + per_data_string(pd), + per_data_string(&arg.oldpd), + (int)arg.unclaimed, (int)arg.repeat); + + padding = pd->moved % 8; + if(padding) { + int32_t pvalue; + if(padding > 7) { + ASN_DEBUG("Too large padding %d in open type", + (int)padding); + rv.code = RC_FAIL; + UPDRESTOREPD; + return rv; + } + padding = 8 - padding; + ASN_DEBUG("Getting padding of %d bits", (int)padding); + pvalue = per_get_few_bits(pd, padding); + switch(pvalue) { + case -1: + ASN_DEBUG("Padding skip failed"); + UPDRESTOREPD; + ASN__DECODE_STARVED; + case 0: break; + default: + ASN_DEBUG("Non-blank padding (%d bits 0x%02x)", + (int)padding, (int)pvalue); + UPDRESTOREPD; + ASN__DECODE_FAILED; + } + } + if(pd->nboff != pd->nbits) { + ASN_DEBUG("Open type %s overhead pd%s old%s", td->name, + per_data_string(pd), per_data_string(&arg.oldpd)); + if(1) { + UPDRESTOREPD; + ASN__DECODE_FAILED; + } else { + arg.unclaimed += pd->nbits - pd->nboff; + } + } + + /* Adjust pd back so it points to original data */ + UPDRESTOREPD; + + /* Skip data not consumed by the decoder */ + if(arg.unclaimed) { + ASN_DEBUG("Getting unclaimed %d", (int)arg.unclaimed); + switch(per_skip_bits(pd, arg.unclaimed)) { + case -1: + ASN_DEBUG("Claim of %d failed", (int)arg.unclaimed); + ASN__DECODE_STARVED; + case 0: + ASN_DEBUG("Got claim of %d", (int)arg.unclaimed); + break; + default: + /* Padding must be blank */ + ASN_DEBUG("Non-blank unconsumed padding"); + ASN__DECODE_FAILED; + } + arg.unclaimed = 0; + } + + if(arg.repeat) { + ASN_DEBUG("Not consumed the whole thing"); + rv.code = RC_FAIL; + return rv; + } + + return rv; +} + + +asn_dec_rval_t +uper_open_type_get(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { + + return uper_open_type_get_simple(ctx, td, constraints, sptr, pd); +} + +int +uper_open_type_skip(asn_codec_ctx_t *ctx, asn_per_data_t *pd) { + asn_TYPE_descriptor_t s_td; + asn_dec_rval_t rv; + + s_td.name = ""; + s_td.uper_decoder = uper_sot_suck; + + rv = uper_open_type_get(ctx, &s_td, 0, 0, pd); + if(rv.code != RC_OK) + return -1; + else + return 0; +} + +/* + * Internal functions. + */ + +static asn_dec_rval_t +uper_sot_suck(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { + asn_dec_rval_t rv; + + (void)ctx; + (void)td; + (void)constraints; + (void)sptr; + + while(per_get_few_bits(pd, 24) >= 0); + + rv.code = RC_OK; + rv.consumed = pd->moved; + + return rv; +} + +static int +uper_ugot_refill(asn_per_data_t *pd) { + uper_ugot_key *arg = pd->refill_key; + ssize_t next_chunk_bytes, next_chunk_bits; + ssize_t avail; + + asn_per_data_t *oldpd = &arg->oldpd; + + ASN_DEBUG("REFILLING pd->moved=%ld, oldpd->moved=%ld", + (long)pd->moved, (long)oldpd->moved); + + /* Advance our position to where pd is */ + oldpd->buffer = pd->buffer; + oldpd->nboff = pd->nboff; + oldpd->nbits -= pd->moved - arg->ot_moved; + oldpd->moved += pd->moved - arg->ot_moved; + arg->ot_moved = pd->moved; + + if(arg->unclaimed) { + /* Refill the container */ + if(per_get_few_bits(oldpd, 1)) + return -1; + if(oldpd->nboff == 0) { + assert(0); + return -1; + } + pd->buffer = oldpd->buffer; + pd->nboff = oldpd->nboff - 1; + pd->nbits = oldpd->nbits; + ASN_DEBUG("UNCLAIMED <- return from (pd->moved=%ld)", + (long)pd->moved); + return 0; + } + + if(!arg->repeat) { + ASN_DEBUG("Want more but refill doesn't have it"); + return -1; + } + + next_chunk_bytes = uper_get_length(oldpd, -1, &arg->repeat); + ASN_DEBUG("Open type LENGTH %ld bytes at off %ld, repeat %ld", + (long)next_chunk_bytes, (long)oldpd->moved, (long)arg->repeat); + if(next_chunk_bytes < 0) return -1; + if(next_chunk_bytes == 0) { + pd->refill = 0; /* No more refills, naturally */ + assert(!arg->repeat); /* Implementation guarantee */ + } + next_chunk_bits = next_chunk_bytes << 3; + avail = oldpd->nbits - oldpd->nboff; + if(avail >= next_chunk_bits) { + pd->nbits = oldpd->nboff + next_chunk_bits; + arg->unclaimed = 0; + ASN_DEBUG("!+Parent frame %ld bits, alloting %ld [%ld..%ld] (%ld)", + (long)next_chunk_bits, (long)oldpd->moved, + (long)oldpd->nboff, (long)oldpd->nbits, + (long)(oldpd->nbits - oldpd->nboff)); + } else { + pd->nbits = oldpd->nbits; + arg->unclaimed = next_chunk_bits - avail; + ASN_DEBUG("!-Parent frame %ld, require %ld, will claim %ld", + (long)avail, (long)next_chunk_bits, + (long)arg->unclaimed); + } + pd->buffer = oldpd->buffer; + pd->nboff = oldpd->nboff; + ASN_DEBUG("Refilled pd%s old%s", + per_data_string(pd), per_data_string(oldpd)); + return 0; +} + +static int +per_skip_bits(asn_per_data_t *pd, int skip_nbits) { + int hasNonZeroBits = 0; + while(skip_nbits > 0) { + int skip; + + /* per_get_few_bits() is more efficient when nbits <= 24 */ + if(skip_nbits < 24) + skip = skip_nbits; + else + skip = 24; + skip_nbits -= skip; + + switch(per_get_few_bits(pd, skip)) { + case -1: return -1; /* Starving */ + case 0: continue; /* Skipped empty space */ + default: hasNonZeroBits = 1; continue; + } + } + return hasNonZeroBits; +} diff --git a/src/cryptoconditions/src/asn/per_opentype.h b/src/cryptoconditions/src/asn/per_opentype.h new file mode 100644 index 000000000..facfaa637 --- /dev/null +++ b/src/cryptoconditions/src/asn/per_opentype.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2007 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _PER_OPENTYPE_H_ +#define _PER_OPENTYPE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +asn_dec_rval_t uper_open_type_get(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd); + +int uper_open_type_skip(asn_codec_ctx_t *opt_codec_ctx, asn_per_data_t *pd); + +int uper_open_type_put(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po); + +#ifdef __cplusplus +} +#endif + +#endif /* _PER_OPENTYPE_H_ */ diff --git a/src/cryptoconditions/src/asn/per_support.c b/src/cryptoconditions/src/asn/per_support.c new file mode 100644 index 000000000..14b4c4c76 --- /dev/null +++ b/src/cryptoconditions/src/asn/per_support.c @@ -0,0 +1,483 @@ +/* + * Copyright (c) 2005-2014 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +char * +per_data_string(asn_per_data_t *pd) { + static char buf[2][32]; + static int n; + n = (n+1) % 2; + snprintf(buf[n], sizeof(buf[n]), + "{m=%ld span %+ld[%d..%d] (%d)}", + (long)pd->moved, + (((long)pd->buffer) & 0xf), + (int)pd->nboff, (int)pd->nbits, + (int)(pd->nbits - pd->nboff)); + return buf[n]; +} + +void +per_get_undo(asn_per_data_t *pd, int nbits) { + if((ssize_t)pd->nboff < nbits) { + assert((ssize_t)pd->nboff < nbits); + } else { + pd->nboff -= nbits; + pd->moved -= nbits; + } +} + +/* + * Extract a small number of bits (<= 31) from the specified PER data pointer. + */ +int32_t +per_get_few_bits(asn_per_data_t *pd, int nbits) { + size_t off; /* Next after last bit offset */ + ssize_t nleft; /* Number of bits left in this stream */ + uint32_t accum; + const uint8_t *buf; + + if(nbits < 0) + return -1; + + nleft = pd->nbits - pd->nboff; + if(nbits > nleft) { + int32_t tailv, vhead; + if(!pd->refill || nbits > 31) return -1; + /* Accumulate unused bytes before refill */ + ASN_DEBUG("Obtain the rest %d bits (want %d)", + (int)nleft, (int)nbits); + tailv = per_get_few_bits(pd, nleft); + if(tailv < 0) return -1; + /* Refill (replace pd contents with new data) */ + if(pd->refill(pd)) + return -1; + nbits -= nleft; + vhead = per_get_few_bits(pd, nbits); + /* Combine the rest of previous pd with the head of new one */ + tailv = (tailv << nbits) | vhead; /* Could == -1 */ + return tailv; + } + + /* + * Normalize position indicator. + */ + if(pd->nboff >= 8) { + pd->buffer += (pd->nboff >> 3); + pd->nbits -= (pd->nboff & ~0x07); + pd->nboff &= 0x07; + } + pd->moved += nbits; + pd->nboff += nbits; + off = pd->nboff; + buf = pd->buffer; + + /* + * Extract specified number of bits. + */ + if(off <= 8) + accum = nbits ? (buf[0]) >> (8 - off) : 0; + else if(off <= 16) + accum = ((buf[0] << 8) + buf[1]) >> (16 - off); + else if(off <= 24) + accum = ((buf[0] << 16) + (buf[1] << 8) + buf[2]) >> (24 - off); + else if(off <= 31) + accum = ((buf[0] << 24) + (buf[1] << 16) + + (buf[2] << 8) + (buf[3])) >> (32 - off); + else if(nbits <= 31) { + asn_per_data_t tpd = *pd; + /* Here are we with our 31-bits limit plus 1..7 bits offset. */ + per_get_undo(&tpd, nbits); + /* The number of available bits in the stream allow + * for the following operations to take place without + * invoking the ->refill() function */ + accum = per_get_few_bits(&tpd, nbits - 24) << 24; + accum |= per_get_few_bits(&tpd, 24); + } else { + per_get_undo(pd, nbits); + return -1; + } + + accum &= (((uint32_t)1 << nbits) - 1); + + ASN_DEBUG(" [PER got %2d<=%2d bits => span %d %+ld[%d..%d]:%02x (%d) => 0x%x]", + (int)nbits, (int)nleft, + (int)pd->moved, + (((long)pd->buffer) & 0xf), + (int)pd->nboff, (int)pd->nbits, + ((pd->buffer != NULL)?pd->buffer[0]:0), + (int)(pd->nbits - pd->nboff), + (int)accum); + + return accum; +} + +/* + * Extract a large number of bits from the specified PER data pointer. + */ +int +per_get_many_bits(asn_per_data_t *pd, uint8_t *dst, int alright, int nbits) { + int32_t value; + + if(alright && (nbits & 7)) { + /* Perform right alignment of a first few bits */ + value = per_get_few_bits(pd, nbits & 0x07); + if(value < 0) return -1; + *dst++ = value; /* value is already right-aligned */ + nbits &= ~7; + } + + while(nbits) { + if(nbits >= 24) { + value = per_get_few_bits(pd, 24); + if(value < 0) return -1; + *(dst++) = value >> 16; + *(dst++) = value >> 8; + *(dst++) = value; + nbits -= 24; + } else { + value = per_get_few_bits(pd, nbits); + if(value < 0) return -1; + if(nbits & 7) { /* implies left alignment */ + value <<= 8 - (nbits & 7), + nbits += 8 - (nbits & 7); + if(nbits > 24) + *dst++ = value >> 24; + } + if(nbits > 16) + *dst++ = value >> 16; + if(nbits > 8) + *dst++ = value >> 8; + *dst++ = value; + break; + } + } + + return 0; +} + +/* + * Get the length "n" from the stream. + */ +ssize_t +uper_get_length(asn_per_data_t *pd, int ebits, int *repeat) { + ssize_t value; + + *repeat = 0; + + if(ebits >= 0) return per_get_few_bits(pd, ebits); + + value = per_get_few_bits(pd, 8); + if(value < 0) return -1; + if((value & 128) == 0) /* #10.9.3.6 */ + return (value & 0x7F); + if((value & 64) == 0) { /* #10.9.3.7 */ + value = ((value & 63) << 8) | per_get_few_bits(pd, 8); + if(value < 0) return -1; + return value; + } + value &= 63; /* this is "m" from X.691, #10.9.3.8 */ + if(value < 1 || value > 4) + return -1; + *repeat = 1; + return (16384 * value); +} + +/* + * Get the normally small length "n". + * This procedure used to decode length of extensions bit-maps + * for SET and SEQUENCE types. + */ +ssize_t +uper_get_nslength(asn_per_data_t *pd) { + ssize_t length; + + ASN_DEBUG("Getting normally small length"); + + if(per_get_few_bits(pd, 1) == 0) { + length = per_get_few_bits(pd, 6) + 1; + if(length <= 0) return -1; + ASN_DEBUG("l=%d", (int)length); + return length; + } else { + int repeat; + length = uper_get_length(pd, -1, &repeat); + if(length >= 0 && !repeat) return length; + return -1; /* Error, or do not support >16K extensions */ + } +} + +/* + * Get the normally small non-negative whole number. + * X.691, #10.6 + */ +ssize_t +uper_get_nsnnwn(asn_per_data_t *pd) { + ssize_t value; + + value = per_get_few_bits(pd, 7); + if(value & 64) { /* implicit (value < 0) */ + value &= 63; + value <<= 2; + value |= per_get_few_bits(pd, 2); + if(value & 128) /* implicit (value < 0) */ + return -1; + if(value == 0) + return 0; + if(value >= 3) + return -1; + value = per_get_few_bits(pd, 8 * value); + return value; + } + + return value; +} + +/* + * X.691-11/2008, #11.6 + * Encoding of a normally small non-negative whole number + */ +int +uper_put_nsnnwn(asn_per_outp_t *po, int n) { + int bytes; + + if(n <= 63) { + if(n < 0) return -1; + return per_put_few_bits(po, n, 7); + } + if(n < 256) + bytes = 1; + else if(n < 65536) + bytes = 2; + else if(n < 256 * 65536) + bytes = 3; + else + return -1; /* This is not a "normally small" value */ + if(per_put_few_bits(po, bytes, 8)) + return -1; + + return per_put_few_bits(po, n, 8 * bytes); +} + + +/* X.691-2008/11, #11.5.6 -> #11.3 */ +int uper_get_constrained_whole_number(asn_per_data_t *pd, unsigned long *out_value, int nbits) { + unsigned long lhalf; /* Lower half of the number*/ + long half; + + if(nbits <= 31) { + half = per_get_few_bits(pd, nbits); + if(half < 0) return -1; + *out_value = half; + return 0; + } + + if((size_t)nbits > 8 * sizeof(*out_value)) + return -1; /* RANGE */ + + half = per_get_few_bits(pd, 31); + if(half < 0) return -1; + + if(uper_get_constrained_whole_number(pd, &lhalf, nbits - 31)) + return -1; + + *out_value = ((unsigned long)half << (nbits - 31)) | lhalf; + return 0; +} + + +/* X.691-2008/11, #11.5.6 -> #11.3 */ +int uper_put_constrained_whole_number_s(asn_per_outp_t *po, long v, int nbits) { + /* + * Assume signed number can be safely coerced into + * unsigned of the same range. + * The following testing code will likely be optimized out + * by compiler if it is true. + */ + unsigned long uvalue1 = ULONG_MAX; + long svalue = uvalue1; + unsigned long uvalue2 = svalue; + assert(uvalue1 == uvalue2); + return uper_put_constrained_whole_number_u(po, v, nbits); +} + +int uper_put_constrained_whole_number_u(asn_per_outp_t *po, unsigned long v, int nbits) { + if(nbits <= 31) { + return per_put_few_bits(po, v, nbits); + } else { + /* Put higher portion first, followed by lower 31-bit */ + if(uper_put_constrained_whole_number_u(po, v >> 31, nbits - 31)) + return -1; + return per_put_few_bits(po, v, 31); + } +} + +/* + * Put a small number of bits (<= 31). + */ +int +per_put_few_bits(asn_per_outp_t *po, uint32_t bits, int obits) { + size_t off; /* Next after last bit offset */ + size_t omsk; /* Existing last byte meaningful bits mask */ + uint8_t *buf; + + if(obits <= 0 || obits >= 32) return obits ? -1 : 0; + + ASN_DEBUG("[PER put %d bits %x to %p+%d bits]", + obits, (int)bits, po->buffer, (int)po->nboff); + + /* + * Normalize position indicator. + */ + if(po->nboff >= 8) { + po->buffer += (po->nboff >> 3); + po->nbits -= (po->nboff & ~0x07); + po->nboff &= 0x07; + } + + /* + * Flush whole-bytes output, if necessary. + */ + if(po->nboff + obits > po->nbits) { + int complete_bytes = (po->buffer - po->tmpspace); + ASN_DEBUG("[PER output %ld complete + %ld]", + (long)complete_bytes, (long)po->flushed_bytes); + if(po->outper(po->tmpspace, complete_bytes, po->op_key) < 0) + return -1; + if(po->nboff) + po->tmpspace[0] = po->buffer[0]; + po->buffer = po->tmpspace; + po->nbits = 8 * sizeof(po->tmpspace); + po->flushed_bytes += complete_bytes; + } + + /* + * Now, due to sizeof(tmpspace), we are guaranteed large enough space. + */ + buf = po->buffer; + omsk = ~((1 << (8 - po->nboff)) - 1); + off = (po->nboff + obits); + + /* Clear data of debris before meaningful bits */ + bits &= (((uint32_t)1 << obits) - 1); + + ASN_DEBUG("[PER out %d %u/%x (t=%d,o=%d) %x&%x=%x]", obits, + (int)bits, (int)bits, + (int)po->nboff, (int)off, + buf[0], (int)(omsk&0xff), + (int)(buf[0] & omsk)); + + if(off <= 8) /* Completely within 1 byte */ + po->nboff = off, + bits <<= (8 - off), + buf[0] = (buf[0] & omsk) | bits; + else if(off <= 16) + po->nboff = off, + bits <<= (16 - off), + buf[0] = (buf[0] & omsk) | (bits >> 8), + buf[1] = bits; + else if(off <= 24) + po->nboff = off, + bits <<= (24 - off), + buf[0] = (buf[0] & omsk) | (bits >> 16), + buf[1] = bits >> 8, + buf[2] = bits; + else if(off <= 31) + po->nboff = off, + bits <<= (32 - off), + buf[0] = (buf[0] & omsk) | (bits >> 24), + buf[1] = bits >> 16, + buf[2] = bits >> 8, + buf[3] = bits; + else { + per_put_few_bits(po, bits >> (obits - 24), 24); + per_put_few_bits(po, bits, obits - 24); + } + + ASN_DEBUG("[PER out %u/%x => %02x buf+%ld]", + (int)bits, (int)bits, buf[0], + (long)(po->buffer - po->tmpspace)); + + return 0; +} + + +/* + * Output a large number of bits. + */ +int +per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int nbits) { + + while(nbits) { + uint32_t value; + + if(nbits >= 24) { + value = (src[0] << 16) | (src[1] << 8) | src[2]; + src += 3; + nbits -= 24; + if(per_put_few_bits(po, value, 24)) + return -1; + } else { + value = src[0]; + if(nbits > 8) + value = (value << 8) | src[1]; + if(nbits > 16) + value = (value << 8) | src[2]; + if(nbits & 0x07) + value >>= (8 - (nbits & 0x07)); + if(per_put_few_bits(po, value, nbits)) + return -1; + break; + } + } + + return 0; +} + +/* + * Put the length "n" (or part of it) into the stream. + */ +ssize_t +uper_put_length(asn_per_outp_t *po, size_t length) { + + if(length <= 127) /* #10.9.3.6 */ + return per_put_few_bits(po, length, 8) + ? -1 : (ssize_t)length; + else if(length < 16384) /* #10.9.3.7 */ + return per_put_few_bits(po, length|0x8000, 16) + ? -1 : (ssize_t)length; + + length >>= 14; + if(length > 4) length = 4; + + return per_put_few_bits(po, 0xC0 | length, 8) + ? -1 : (ssize_t)(length << 14); +} + + +/* + * Put the normally small length "n" into the stream. + * This procedure used to encode length of extensions bit-maps + * for SET and SEQUENCE types. + */ +int +uper_put_nslength(asn_per_outp_t *po, size_t length) { + + if(length <= 64) { + /* #10.9.3.4 */ + if(length == 0) return -1; + return per_put_few_bits(po, length-1, 7) ? -1 : 0; + } else { + if(uper_put_length(po, length) != (ssize_t)length) { + /* This might happen in case of >16K extensions */ + return -1; + } + } + + return 0; +} + diff --git a/src/cryptoconditions/src/asn/per_support.h b/src/cryptoconditions/src/asn/per_support.h new file mode 100644 index 000000000..a75ac94fc --- /dev/null +++ b/src/cryptoconditions/src/asn/per_support.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2005-2014 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _PER_SUPPORT_H_ +#define _PER_SUPPORT_H_ + +#include /* Platform-specific types */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Pre-computed PER constraints. + */ +typedef const struct asn_per_constraint_s { + enum asn_per_constraint_flags { + APC_UNCONSTRAINED = 0x0, /* No PER visible constraints */ + APC_SEMI_CONSTRAINED = 0x1, /* Constrained at "lb" */ + APC_CONSTRAINED = 0x2, /* Fully constrained */ + APC_EXTENSIBLE = 0x4 /* May have extension */ + } flags; + int range_bits; /* Full number of bits in the range */ + int effective_bits; /* Effective bits */ + long lower_bound; /* "lb" value */ + long upper_bound; /* "ub" value */ +} asn_per_constraint_t; +typedef const struct asn_per_constraints_s { + struct asn_per_constraint_s value; + struct asn_per_constraint_s size; + int (*value2code)(unsigned int value); + int (*code2value)(unsigned int code); +} asn_per_constraints_t; + +/* + * This structure describes a position inside an incoming PER bit stream. + */ +typedef struct asn_per_data_s { + const uint8_t *buffer; /* Pointer to the octet stream */ + size_t nboff; /* Bit offset to the meaningful bit */ + size_t nbits; /* Number of bits in the stream */ + size_t moved; /* Number of bits moved through this bit stream */ + int (*refill)(struct asn_per_data_s *); + void *refill_key; +} asn_per_data_t; + +/* + * Extract a small number of bits (<= 31) from the specified PER data pointer. + * This function returns -1 if the specified number of bits could not be + * extracted due to EOD or other conditions. + */ +int32_t per_get_few_bits(asn_per_data_t *per_data, int get_nbits); + +/* Undo the immediately preceeding "get_few_bits" operation */ +void per_get_undo(asn_per_data_t *per_data, int get_nbits); + +/* + * Extract a large number of bits from the specified PER data pointer. + * This function returns -1 if the specified number of bits could not be + * extracted due to EOD or other conditions. + */ +int per_get_many_bits(asn_per_data_t *pd, uint8_t *dst, int right_align, + int get_nbits); + +/* + * Get the length "n" from the Unaligned PER stream. + */ +ssize_t uper_get_length(asn_per_data_t *pd, + int effective_bound_bits, + int *repeat); + +/* + * Get the normally small length "n". + */ +ssize_t uper_get_nslength(asn_per_data_t *pd); + +/* + * Get the normally small non-negative whole number. + */ +ssize_t uper_get_nsnnwn(asn_per_data_t *pd); + +/* X.691-2008/11, #11.5.6 */ +int uper_get_constrained_whole_number(asn_per_data_t *pd, unsigned long *v, int nbits); + +/* Non-thread-safe debugging function, don't use it */ +char *per_data_string(asn_per_data_t *pd); + +/* + * This structure supports forming PER output. + */ +typedef struct asn_per_outp_s { + uint8_t *buffer; /* Pointer into the (tmpspace) */ + size_t nboff; /* Bit offset to the meaningful bit */ + size_t nbits; /* Number of bits left in (tmpspace) */ + uint8_t tmpspace[32]; /* Preliminary storage to hold data */ + int (*outper)(const void *data, size_t size, void *op_key); + void *op_key; /* Key for (outper) data callback */ + size_t flushed_bytes; /* Bytes already flushed through (outper) */ +} asn_per_outp_t; + +/* Output a small number of bits (<= 31) */ +int per_put_few_bits(asn_per_outp_t *per_data, uint32_t bits, int obits); + +/* Output a large number of bits */ +int per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int put_nbits); + +/* X.691-2008/11, #11.5 */ +int uper_put_constrained_whole_number_s(asn_per_outp_t *po, long v, int nbits); +int uper_put_constrained_whole_number_u(asn_per_outp_t *po, unsigned long v, int nbits); + +/* + * Put the length "n" to the Unaligned PER stream. + * This function returns the number of units which may be flushed + * in the next units saving iteration. + */ +ssize_t uper_put_length(asn_per_outp_t *po, size_t whole_length); + +/* + * Put the normally small length "n" to the Unaligned PER stream. + * Returns 0 or -1. + */ +int uper_put_nslength(asn_per_outp_t *po, size_t length); + +/* + * Put the normally small non-negative whole number. + */ +int uper_put_nsnnwn(asn_per_outp_t *po, int n); + +#ifdef __cplusplus +} +#endif + +#endif /* _PER_SUPPORT_H_ */ diff --git a/src/cryptoconditions/src/asn/xer_decoder.c b/src/cryptoconditions/src/asn/xer_decoder.c new file mode 100644 index 000000000..299a7c1ee --- /dev/null +++ b/src/cryptoconditions/src/asn/xer_decoder.c @@ -0,0 +1,368 @@ +/* + * Copyright (c) 2004, 2005 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include /* XER/XML parsing support */ + + +/* + * Decode the XER encoding of a given type. + */ +asn_dec_rval_t +xer_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, + void **struct_ptr, const void *buffer, size_t size) { + asn_codec_ctx_t s_codec_ctx; + + /* + * Stack checker requires that the codec context + * must be allocated on the stack. + */ + if(opt_codec_ctx) { + if(opt_codec_ctx->max_stack_size) { + s_codec_ctx = *opt_codec_ctx; + opt_codec_ctx = &s_codec_ctx; + } + } else { + /* If context is not given, be security-conscious anyway */ + memset(&s_codec_ctx, 0, sizeof(s_codec_ctx)); + s_codec_ctx.max_stack_size = ASN__DEFAULT_STACK_MAX; + opt_codec_ctx = &s_codec_ctx; + } + + /* + * Invoke type-specific decoder. + */ + return td->xer_decoder(opt_codec_ctx, td, struct_ptr, 0, buffer, size); +} + + + +struct xer__cb_arg { + pxml_chunk_type_e chunk_type; + size_t chunk_size; + const void *chunk_buf; + int callback_not_invoked; +}; + +static int +xer__token_cb(pxml_chunk_type_e type, const void *_chunk_data, size_t _chunk_size, void *key) { + struct xer__cb_arg *arg = (struct xer__cb_arg *)key; + arg->chunk_type = type; + arg->chunk_size = _chunk_size; + arg->chunk_buf = _chunk_data; + arg->callback_not_invoked = 0; + return -1; /* Terminate the XML parsing */ +} + +/* + * Fetch the next token from the XER/XML stream. + */ +ssize_t +xer_next_token(int *stateContext, const void *buffer, size_t size, pxer_chunk_type_e *ch_type) { + struct xer__cb_arg arg; + int new_stateContext = *stateContext; + ssize_t ret; + + arg.callback_not_invoked = 1; + ret = pxml_parse(&new_stateContext, buffer, size, xer__token_cb, &arg); + if(ret < 0) return -1; + if(arg.callback_not_invoked) { + assert(ret == 0); /* No data was consumed */ + *ch_type = PXER_WMORE; + return 0; /* Try again with more data */ + } else { + assert(arg.chunk_size); + assert(arg.chunk_buf == buffer); + } + + /* + * Translate the XML chunk types into more convenient ones. + */ + switch(arg.chunk_type) { + case PXML_TEXT: + *ch_type = PXER_TEXT; + break; + case PXML_TAG: + *ch_type = PXER_WMORE; + return 0; /* Want more */ + case PXML_TAG_END: + *ch_type = PXER_TAG; + break; + case PXML_COMMENT: + case PXML_COMMENT_END: + *ch_type = PXER_COMMENT; + break; + } + + *stateContext = new_stateContext; + return arg.chunk_size; +} + +#define CSLASH 0x2f /* '/' */ +#define LANGLE 0x3c /* '<' */ +#define RANGLE 0x3e /* '>' */ + +xer_check_tag_e +xer_check_tag(const void *buf_ptr, int size, const char *need_tag) { + const char *buf = (const char *)buf_ptr; + const char *end; + xer_check_tag_e ct = XCT_OPENING; + + if(size < 2 || buf[0] != LANGLE || buf[size-1] != RANGLE) { + if(size >= 2) + ASN_DEBUG("Broken XML tag: \"%c...%c\"", + buf[0], buf[size - 1]); + return XCT_BROKEN; + } + + /* + * Determine the tag class. + */ + if(buf[1] == CSLASH) { + buf += 2; /* advance past "" */ + ct = XCT_CLOSING; + if(size > 0 && buf[size-1] == CSLASH) + return XCT_BROKEN; /* */ + } else { + buf++; /* advance past "<" */ + size -= 2; /* strip "<" and ">" */ + if(size > 0 && buf[size-1] == CSLASH) { + ct = XCT_BOTH; + size--; /* One more, for "/" */ + } + } + + /* Sometimes we don't care about the tag */ + if(!need_tag || !*need_tag) + return (xer_check_tag_e)(XCT__UNK__MASK | ct); + + /* + * Determine the tag name. + */ + for(end = buf + size; buf < end; buf++, need_tag++) { + int b = *buf, n = *need_tag; + if(b != n) { + if(n == 0) { + switch(b) { + case 0x09: case 0x0a: case 0x0c: case 0x0d: + case 0x20: + /* "": whitespace is normal */ + return ct; + } + } + return (xer_check_tag_e)(XCT__UNK__MASK | ct); + } + if(b == 0) + return XCT_BROKEN; /* Embedded 0 in buf?! */ + } + if(*need_tag) + return (xer_check_tag_e)(XCT__UNK__MASK | ct); + + return ct; +} + + +#undef ADVANCE +#define ADVANCE(num_bytes) do { \ + size_t num = (num_bytes); \ + buf_ptr = ((const char *)buf_ptr) + num; \ + size -= num; \ + consumed_myself += num; \ + } while(0) + +#undef RETURN +#define RETURN(_code) do { \ + rval.code = _code; \ + rval.consumed = consumed_myself; \ + if(rval.code != RC_OK) \ + ASN_DEBUG("Failed with %d", rval.code); \ + return rval; \ + } while(0) + +#define XER_GOT_BODY(chunk_buf, chunk_size, size) do { \ + ssize_t converted_size = body_receiver \ + (struct_key, chunk_buf, chunk_size, \ + (size_t)chunk_size < size); \ + if(converted_size == -1) RETURN(RC_FAIL); \ + if(converted_size == 0 \ + && size == (size_t)chunk_size) \ + RETURN(RC_WMORE); \ + chunk_size = converted_size; \ + } while(0) +#define XER_GOT_EMPTY() do { \ + if(body_receiver(struct_key, 0, 0, size > 0) == -1) \ + RETURN(RC_FAIL); \ + } while(0) + +/* + * Generalized function for decoding the primitive values. + */ +asn_dec_rval_t +xer_decode_general(asn_codec_ctx_t *opt_codec_ctx, + asn_struct_ctx_t *ctx, /* Type decoder context */ + void *struct_key, + const char *xml_tag, /* Expected XML tag */ + const void *buf_ptr, size_t size, + int (*opt_unexpected_tag_decoder) + (void *struct_key, const void *chunk_buf, size_t chunk_size), + ssize_t (*body_receiver) + (void *struct_key, const void *chunk_buf, size_t chunk_size, + int have_more) + ) { + + asn_dec_rval_t rval; + ssize_t consumed_myself = 0; + + (void)opt_codec_ctx; + + /* + * Phases of XER/XML processing: + * Phase 0: Check that the opening tag matches our expectations. + * Phase 1: Processing body and reacting on closing tag. + */ + if(ctx->phase > 1) RETURN(RC_FAIL); + for(;;) { + pxer_chunk_type_e ch_type; /* XER chunk type */ + ssize_t ch_size; /* Chunk size */ + xer_check_tag_e tcv; /* Tag check value */ + + /* + * Get the next part of the XML stream. + */ + ch_size = xer_next_token(&ctx->context, buf_ptr, size, + &ch_type); + if(ch_size == -1) { + RETURN(RC_FAIL); + } else { + switch(ch_type) { + case PXER_WMORE: + RETURN(RC_WMORE); + case PXER_COMMENT: /* Got XML comment */ + ADVANCE(ch_size); /* Skip silently */ + continue; + case PXER_TEXT: + if(ctx->phase == 0) { + /* + * We have to ignore whitespace here, + * but in order to be forward compatible + * with EXTENDED-XER (EMBED-VALUES, #25) + * any text is just ignored here. + */ + } else { + XER_GOT_BODY(buf_ptr, ch_size, size); + } + ADVANCE(ch_size); + continue; + case PXER_TAG: + break; /* Check the rest down there */ + } + } + + assert(ch_type == PXER_TAG && size); + + tcv = xer_check_tag(buf_ptr, ch_size, xml_tag); + /* + * Phase 0: + * Expecting the opening tag + * for the type being processed. + * Phase 1: + * Waiting for the closing XML tag. + */ + switch(tcv) { + case XCT_BOTH: + if(ctx->phase) break; + /* Finished decoding of an empty element */ + XER_GOT_EMPTY(); + ADVANCE(ch_size); + ctx->phase = 2; /* Phase out */ + RETURN(RC_OK); + case XCT_OPENING: + if(ctx->phase) break; + ADVANCE(ch_size); + ctx->phase = 1; /* Processing body phase */ + continue; + case XCT_CLOSING: + if(!ctx->phase) break; + ADVANCE(ch_size); + ctx->phase = 2; /* Phase out */ + RETURN(RC_OK); + case XCT_UNKNOWN_BO: + /* + * Certain tags in the body may be expected. + */ + if(opt_unexpected_tag_decoder + && opt_unexpected_tag_decoder(struct_key, + buf_ptr, ch_size) >= 0) { + /* Tag's processed fine */ + ADVANCE(ch_size); + if(!ctx->phase) { + /* We are not expecting + * the closing tag anymore. */ + ctx->phase = 2; /* Phase out */ + RETURN(RC_OK); + } + continue; + } + /* Fall through */ + default: + break; /* Unexpected tag */ + } + + ASN_DEBUG("Unexpected XML tag (expected \"%s\")", xml_tag); + break; /* Dark and mysterious things have just happened */ + } + + RETURN(RC_FAIL); +} + + +size_t +xer_whitespace_span(const void *chunk_buf, size_t chunk_size) { + const char *p = (const char *)chunk_buf; + const char *pend = p + chunk_size; + + for(; p < pend; p++) { + switch(*p) { + /* X.693, #8.1.4 + * HORISONTAL TAB (9) + * LINE FEED (10) + * CARRIAGE RETURN (13) + * SPACE (32) + */ + case 0x09: case 0x0a: case 0x0d: case 0x20: + continue; + default: + break; + } + break; + } + return (p - (const char *)chunk_buf); +} + +/* + * This is a vastly simplified, non-validating XML tree skipper. + */ +int +xer_skip_unknown(xer_check_tag_e tcv, ber_tlv_len_t *depth) { + assert(*depth > 0); + switch(tcv) { + case XCT_BOTH: + case XCT_UNKNOWN_BO: + /* These negate each other. */ + return 0; + case XCT_OPENING: + case XCT_UNKNOWN_OP: + ++(*depth); + return 0; + case XCT_CLOSING: + case XCT_UNKNOWN_CL: + if(--(*depth) == 0) + return (tcv == XCT_CLOSING) ? 2 : 1; + return 0; + default: + return -1; + } +} diff --git a/src/cryptoconditions/src/asn/xer_decoder.h b/src/cryptoconditions/src/asn/xer_decoder.h new file mode 100644 index 000000000..301b613cf --- /dev/null +++ b/src/cryptoconditions/src/asn/xer_decoder.h @@ -0,0 +1,106 @@ +/*- + * Copyright (c) 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _XER_DECODER_H_ +#define _XER_DECODER_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ + +/* + * The XER decoder of any ASN.1 type. May be invoked by the application. + */ +asn_dec_rval_t xer_decode(struct asn_codec_ctx_s *opt_codec_ctx, + struct asn_TYPE_descriptor_s *type_descriptor, + void **struct_ptr, /* Pointer to a target structure's pointer */ + const void *buffer, /* Data to be decoded */ + size_t size /* Size of data buffer */ + ); + +/* + * Type of the type-specific XER decoder function. + */ +typedef asn_dec_rval_t (xer_type_decoder_f)(asn_codec_ctx_t *opt_codec_ctx, + struct asn_TYPE_descriptor_s *type_descriptor, + void **struct_ptr, + const char *opt_mname, /* Member name */ + const void *buf_ptr, size_t size + ); + +/******************************* + * INTERNALLY USEFUL FUNCTIONS * + *******************************/ + +/* + * Generalized function for decoding the primitive values. + * Used by more specialized functions, such as OCTET_STRING_decode_xer_utf8 + * and others. This function should not be used by applications, as its API + * is subject to changes. + */ +asn_dec_rval_t xer_decode_general(asn_codec_ctx_t *opt_codec_ctx, + asn_struct_ctx_t *ctx, /* Type decoder context */ + void *struct_key, /* Treated as opaque pointer */ + const char *xml_tag, /* Expected XML tag name */ + const void *buf_ptr, size_t size, + int (*opt_unexpected_tag_decoder) + (void *struct_key, const void *chunk_buf, size_t chunk_size), + ssize_t (*body_receiver) + (void *struct_key, const void *chunk_buf, size_t chunk_size, + int have_more) + ); + + +/* + * Fetch the next XER (XML) token from the stream. + * The function returns the number of bytes occupied by the chunk type, + * returned in the _ch_type. The _ch_type is only set (and valid) when + * the return value is >= 0. + */ + typedef enum pxer_chunk_type { + PXER_WMORE, /* Chunk type is not clear, more data expected. */ + PXER_TAG, /* Complete XER tag */ + PXER_TEXT, /* Plain text between XER tags */ + PXER_COMMENT /* A comment, may be part of */ + } pxer_chunk_type_e; +ssize_t xer_next_token(int *stateContext, + const void *buffer, size_t size, pxer_chunk_type_e *_ch_type); + +/* + * This function checks the buffer against the tag name is expected to occur. + */ + typedef enum xer_check_tag { + XCT_BROKEN = 0, /* The tag is broken */ + XCT_OPENING = 1, /* This is the tag */ + XCT_CLOSING = 2, /* This is the tag */ + XCT_BOTH = 3, /* This is the tag */ + XCT__UNK__MASK = 4, /* Mask of everything unexpected */ + XCT_UNKNOWN_OP = 5, /* Unexpected tag */ + XCT_UNKNOWN_CL = 6, /* Unexpected tag */ + XCT_UNKNOWN_BO = 7 /* Unexpected tag */ + } xer_check_tag_e; +xer_check_tag_e xer_check_tag(const void *buf_ptr, int size, + const char *need_tag); + +/* + * Get the number of bytes consisting entirely of XER whitespace characters. + * RETURN VALUES: + * >=0: Number of whitespace characters in the string. + */ +size_t xer_whitespace_span(const void *chunk_buf, size_t chunk_size); + +/* + * Skip the series of anticipated extensions. + */ +int xer_skip_unknown(xer_check_tag_e tcv, ber_tlv_len_t *depth); + +#ifdef __cplusplus +} +#endif + +#endif /* _XER_DECODER_H_ */ diff --git a/src/cryptoconditions/src/asn/xer_encoder.c b/src/cryptoconditions/src/asn/xer_encoder.c new file mode 100644 index 000000000..460657580 --- /dev/null +++ b/src/cryptoconditions/src/asn/xer_encoder.c @@ -0,0 +1,67 @@ +/*- + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include + +/* + * The XER encoder of any type. May be invoked by the application. + */ +asn_enc_rval_t +xer_encode(asn_TYPE_descriptor_t *td, void *sptr, + enum xer_encoder_flags_e xer_flags, + asn_app_consume_bytes_f *cb, void *app_key) { + asn_enc_rval_t er, tmper; + const char *mname; + size_t mlen; + int xcan = (xer_flags & XER_F_CANONICAL) ? 1 : 2; + + if(!td || !sptr) goto cb_failed; + + mname = td->xml_tag; + mlen = strlen(mname); + + ASN__CALLBACK3("<", 1, mname, mlen, ">", 1); + + tmper = td->xer_encoder(td, sptr, 1, xer_flags, cb, app_key); + if(tmper.encoded == -1) return tmper; + + ASN__CALLBACK3("\n", xcan); + + er.encoded = 4 + xcan + (2 * mlen) + tmper.encoded; + + ASN__ENCODED_OK(er); +cb_failed: + ASN__ENCODE_FAILED; +} + +/* + * This is a helper function for xer_fprint, which directs all incoming data + * into the provided file descriptor. + */ +static int +xer__print2fp(const void *buffer, size_t size, void *app_key) { + FILE *stream = (FILE *)app_key; + + if(fwrite(buffer, 1, size, stream) != size) + return -1; + + return 0; +} + +int +xer_fprint(FILE *stream, asn_TYPE_descriptor_t *td, void *sptr) { + asn_enc_rval_t er; + + if(!stream) stream = stdout; + if(!td || !sptr) + return -1; + + er = xer_encode(td, sptr, XER_F_BASIC, xer__print2fp, stream); + if(er.encoded == -1) + return -1; + + return fflush(stream); +} diff --git a/src/cryptoconditions/src/asn/xer_encoder.h b/src/cryptoconditions/src/asn/xer_encoder.h new file mode 100644 index 000000000..055e73c0c --- /dev/null +++ b/src/cryptoconditions/src/asn/xer_encoder.h @@ -0,0 +1,59 @@ +/*- + * Copyright (c) 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _XER_ENCODER_H_ +#define _XER_ENCODER_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ + +/* Flags used by the xer_encode() and (*xer_type_encoder_f), defined below */ +enum xer_encoder_flags_e { + /* Mode of encoding */ + XER_F_BASIC = 0x01, /* BASIC-XER (pretty-printing) */ + XER_F_CANONICAL = 0x02 /* Canonical XER (strict rules) */ +}; + +/* + * The XER encoder of any type. May be invoked by the application. + */ +asn_enc_rval_t xer_encode(struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + enum xer_encoder_flags_e xer_flags, + asn_app_consume_bytes_f *consume_bytes_cb, + void *app_key /* Arbitrary callback argument */ + ); + +/* + * The variant of the above function which dumps the BASIC-XER (XER_F_BASIC) + * output into the chosen file pointer. + * RETURN VALUES: + * 0: The structure is printed. + * -1: Problem printing the structure. + * WARNING: No sensible errno value is returned. + */ +int xer_fprint(FILE *stream, struct asn_TYPE_descriptor_s *td, void *sptr); + +/* + * Type of the generic XER encoder. + */ +typedef asn_enc_rval_t (xer_type_encoder_f)( + struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + int ilevel, /* Level of indentation */ + enum xer_encoder_flags_e xer_flags, + asn_app_consume_bytes_f *consume_bytes_cb, /* Callback */ + void *app_key /* Arbitrary callback argument */ + ); + +#ifdef __cplusplus +} +#endif + +#endif /* _XER_ENCODER_H_ */ diff --git a/src/cryptoconditions/src/asn/xer_support.c b/src/cryptoconditions/src/asn/xer_support.c new file mode 100644 index 000000000..36b4bfbfc --- /dev/null +++ b/src/cryptoconditions/src/asn/xer_support.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2003, 2004 X/IO Labs, xiolabs.com. + * Copyright (c) 2003, 2004, 2005 Lev Walkin . + * All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include + +/* Parser states */ +typedef enum { + ST_TEXT, + ST_TAG_START, + ST_TAG_BODY, + ST_TAG_QUOTE_WAIT, + ST_TAG_QUOTED_STRING, + ST_TAG_UNQUOTED_STRING, + ST_COMMENT_WAIT_DASH1, /* ""[0] */ + ST_COMMENT_CLO_RT /* "-->"[1] */ +} pstate_e; + +static const int +_charclass[256] = { + 0,0,0,0,0,0,0,0, 0,1,1,0,1,1,0,0, + 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + 1,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, + 2,2,2,2,2,2,2,2, 2,2,0,0,0,0,0,0, /* 01234567 89 */ + 0,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3, /* ABCDEFG HIJKLMNO */ + 3,3,3,3,3,3,3,3, 3,3,3,0,0,0,0,0, /* PQRSTUVW XYZ */ + 0,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3, /* abcdefg hijklmno */ + 3,3,3,3,3,3,3,3, 3,3,3,0,0,0,0,0 /* pqrstuvw xyz */ +}; +#define WHITESPACE(c) (_charclass[(unsigned char)(c)] == 1) +#define ALNUM(c) (_charclass[(unsigned char)(c)] >= 2) +#define ALPHA(c) (_charclass[(unsigned char)(c)] == 3) + +/* Aliases for characters, ASCII/UTF-8 */ +#define EXCLAM 0x21 /* '!' */ +#define CQUOTE 0x22 /* '"' */ +#define CDASH 0x2d /* '-' */ +#define CSLASH 0x2f /* '/' */ +#define LANGLE 0x3c /* '<' */ +#define CEQUAL 0x3d /* '=' */ +#define RANGLE 0x3e /* '>' */ +#define CQUEST 0x3f /* '?' */ + +/* Invoke token callback */ +#define TOKEN_CB_CALL(type, _ns, _current_too, _final) do { \ + int _ret; \ + pstate_e ns = _ns; \ + ssize_t _sz = (p - chunk_start) + _current_too; \ + if (!_sz) { \ + /* Shortcut */ \ + state = _ns; \ + break; \ + } \ + _ret = cb(type, chunk_start, _sz, key); \ + if(_ret < _sz) { \ + if(_current_too && _ret == -1) \ + state = ns; \ + goto finish; \ + } \ + chunk_start = p + _current_too; \ + state = ns; \ + } while(0) + +#define TOKEN_CB(_type, _ns, _current_too) \ + TOKEN_CB_CALL(_type, _ns, _current_too, 0) + +#define PXML_TAG_FINAL_CHUNK_TYPE PXML_TAG_END +#define PXML_COMMENT_FINAL_CHUNK_TYPE PXML_COMMENT_END + +#define TOKEN_CB_FINAL(_type, _ns, _current_too) \ + TOKEN_CB_CALL( _type ## _FINAL_CHUNK_TYPE , _ns, _current_too, 1) + +/* + * Parser itself + */ +ssize_t pxml_parse(int *stateContext, const void *xmlbuf, size_t size, pxml_callback_f *cb, void *key) { + pstate_e state = (pstate_e)*stateContext; + const char *chunk_start = (const char *)xmlbuf; + const char *p = chunk_start; + const char *end = p + size; + + for(; p < end; p++) { + int C = *(const unsigned char *)p; + switch(state) { + case ST_TEXT: + /* + * Initial state: we're in the middle of some text, + * or just have started. + */ + if (C == LANGLE) + /* We're now in the tag, probably */ + TOKEN_CB(PXML_TEXT, ST_TAG_START, 0); + break; + case ST_TAG_START: + if (ALPHA(C) || (C == CSLASH)) + state = ST_TAG_BODY; + else if (C == EXCLAM) + state = ST_COMMENT_WAIT_DASH1; + else + /* + * Not characters and not whitespace. + * Must be something like "3 < 4". + */ + TOKEN_CB(PXML_TEXT, ST_TEXT, 1);/* Flush as data */ + break; + case ST_TAG_BODY: + switch(C) { + case RANGLE: + /* End of the tag */ + TOKEN_CB_FINAL(PXML_TAG, ST_TEXT, 1); + break; + case LANGLE: + /* + * The previous tag wasn't completed, but still + * recognized as valid. (Mozilla-compatible) + */ + TOKEN_CB_FINAL(PXML_TAG, ST_TAG_START, 0); + break; + case CEQUAL: + state = ST_TAG_QUOTE_WAIT; + break; + } + break; + case ST_TAG_QUOTE_WAIT: + /* + * State after the equal sign ("=") in the tag. + */ + switch(C) { + case CQUOTE: + state = ST_TAG_QUOTED_STRING; + break; + case RANGLE: + /* End of the tag */ + TOKEN_CB_FINAL(PXML_TAG, ST_TEXT, 1); + break; + default: + if(!WHITESPACE(C)) + /* Unquoted string value */ + state = ST_TAG_UNQUOTED_STRING; + } + break; + case ST_TAG_QUOTED_STRING: + /* + * Tag attribute's string value in quotes. + */ + if(C == CQUOTE) { + /* Return back to the tag state */ + state = ST_TAG_BODY; + } + break; + case ST_TAG_UNQUOTED_STRING: + if(C == RANGLE) { + /* End of the tag */ + TOKEN_CB_FINAL(PXML_TAG, ST_TEXT, 1); + } else if(WHITESPACE(C)) { + /* Return back to the tag state */ + state = ST_TAG_BODY; + } + break; + case ST_COMMENT_WAIT_DASH1: + if(C == CDASH) { + state = ST_COMMENT_WAIT_DASH2; + } else { + /* Some ordinary tag. */ + state = ST_TAG_BODY; + } + break; + case ST_COMMENT_WAIT_DASH2: + if(C == CDASH) { + /* Seen "<--" */ + state = ST_COMMENT; + } else { + /* Some ordinary tag */ + state = ST_TAG_BODY; + } + break; + case ST_COMMENT: + if(C == CDASH) { + state = ST_COMMENT_CLO_DASH2; + } + break; + case ST_COMMENT_CLO_DASH2: + if(C == CDASH) { + state = ST_COMMENT_CLO_RT; + } else { + /* This is not an end of a comment */ + state = ST_COMMENT; + } + break; + case ST_COMMENT_CLO_RT: + if(C == RANGLE) { + TOKEN_CB_FINAL(PXML_COMMENT, ST_TEXT, 1); + } else if(C == CDASH) { + /* Maintain current state, still waiting for '>' */ + } else { + state = ST_COMMENT; + } + break; + } /* switch(*ptr) */ + } /* for() */ + + /* + * Flush the partially processed chunk, state permitting. + */ + if(p - chunk_start) { + switch (state) { + case ST_COMMENT: + TOKEN_CB(PXML_COMMENT, state, 0); + break; + case ST_TEXT: + TOKEN_CB(PXML_TEXT, state, 0); + break; + default: break; /* a no-op */ + } + } + +finish: + *stateContext = (int)state; + return chunk_start - (const char *)xmlbuf; +} + diff --git a/src/cryptoconditions/src/asn/xer_support.h b/src/cryptoconditions/src/asn/xer_support.h new file mode 100644 index 000000000..8b01944ab --- /dev/null +++ b/src/cryptoconditions/src/asn/xer_support.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2003, 2004 X/IO Labs, xiolabs.com. + * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _XER_SUPPORT_H_ +#define _XER_SUPPORT_H_ + +#include /* Platform-specific types */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Types of data transferred to the application. + */ +typedef enum { + PXML_TEXT, /* Plain text between XML tags. */ + PXML_TAG, /* A tag, starting with '<'. */ + PXML_COMMENT, /* An XML comment, including "". */ + /* + * The following chunk types are reported if the chunk + * terminates the specified XML element. + */ + PXML_TAG_END, /* Tag ended */ + PXML_COMMENT_END /* Comment ended */ +} pxml_chunk_type_e; + +/* + * Callback function that is called by the parser when parsed data is + * available. The _opaque is the pointer to a field containing opaque user + * data specified in pxml_create() call. The chunk type is _type and the text + * data is the piece of buffer identified by _bufid (as supplied to + * pxml_feed() call) starting at offset _offset and of _size bytes size. + * The chunk is NOT '\0'-terminated. + */ +typedef int (pxml_callback_f)(pxml_chunk_type_e _type, + const void *_chunk_data, size_t _chunk_size, void *_key); + +/* + * Parse the given buffer as it were a chunk of XML data. + * Invoke the specified callback each time the meaninful data is found. + * This function returns number of bytes consumed from the bufer. + * It will always be lesser than or equal to the specified _size. + * The next invocation of this function must account the difference. + */ +ssize_t pxml_parse(int *_stateContext, const void *_buf, size_t _size, + pxml_callback_f *cb, void *_key); + +#ifdef __cplusplus +} +#endif + +#endif /* _XER_SUPPORT_H_ */ diff --git a/src/cryptoconditions/src/cryptoconditions-config.h.in b/src/cryptoconditions/src/cryptoconditions-config.h.in new file mode 100644 index 000000000..72f0d216b --- /dev/null +++ b/src/cryptoconditions/src/cryptoconditions-config.h.in @@ -0,0 +1,176 @@ +/* src/cryptoconditions-config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP + systems. This function is required for `alloca.c' support on those systems. + */ +#undef CRAY_STACKSEG_END + +/* Define to 1 if using `alloca.c'. */ +#undef C_ALLOCA + +/* Define to 1 if you have `alloca', as a function or macro. */ +#undef HAVE_ALLOCA + +/* Define to 1 if you have and it should be used (not on Ultrix). + */ +#undef HAVE_ALLOCA_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ARPA_INET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FLOAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define to 1 if you have the `localeconv' function. */ +#undef HAVE_LOCALECONV + +/* Define to 1 if you have the header file. */ +#undef HAVE_LOCALE_H + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#undef HAVE_MALLOC + +/* Define to 1 if you have the header file. */ +#undef HAVE_MALLOC_H + +/* Define to 1 if you have the `memchr' function. */ +#undef HAVE_MEMCHR + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `memset' function. */ +#undef HAVE_MEMSET + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN_H + +/* Define to 1 if the system has the type `ptrdiff_t'. */ +#undef HAVE_PTRDIFF_T + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDDEF_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if the system has the type `_Bool'. */ +#undef HAVE__BOOL + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#undef LT_OBJDIR + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at runtime. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +#undef STACK_DIRECTION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION + +/* Define for Solaris 2.5.1 so the uint32_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +#undef _UINT32_T + +/* Define for Solaris 2.5.1 so the uint64_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +#undef _UINT64_T + +/* Define for Solaris 2.5.1 so the uint8_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +#undef _UINT8_T + +/* Define to the type of a signed integer type of width exactly 16 bits if + such a type exists and the standard includes do not define it. */ +#undef int16_t + +/* Define to the type of a signed integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +#undef int32_t + +/* Define to the type of a signed integer type of width exactly 8 bits if such + a type exists and the standard includes do not define it. */ +#undef int8_t + +/* Define to rpl_malloc if the replacement function should be used. */ +#undef malloc + +/* Define to `unsigned int' if does not define. */ +#undef size_t + +/* Define to `int' if does not define. */ +#undef ssize_t + +/* Define to the type of an unsigned integer type of width exactly 16 bits if + such a type exists and the standard includes do not define it. */ +#undef uint16_t + +/* Define to the type of an unsigned integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +#undef uint32_t + +/* Define to the type of an unsigned integer type of width exactly 64 bits if + such a type exists and the standard includes do not define it. */ +#undef uint64_t + +/* Define to the type of an unsigned integer type of width exactly 8 bits if + such a type exists and the standard includes do not define it. */ +#undef uint8_t diff --git a/src/cryptoconditions/src/cryptoconditions.c b/src/cryptoconditions/src/cryptoconditions.c new file mode 100644 index 000000000..147cbb334 --- /dev/null +++ b/src/cryptoconditions/src/cryptoconditions.c @@ -0,0 +1,267 @@ +#include "strings.h" +#include "asn/Condition.h" +#include "asn/Fulfillment.h" +#include "asn/OCTET_STRING.h" +#include "cryptoconditions.h" +#include "src/internal.h" +#include "src/threshold.c" +#include "src/prefix.c" +#include "src/preimage.c" +#include "src/ed25519.c" +#include "src/secp256k1.c" +#include "src/anon.c" +#include "src/eval.c" +#include "src/json_rpc.c" +#include "src/utils.c" +#include +#include + + +static struct CCType *typeRegistry[] = { + &cc_preimageType, + &cc_prefixType, + &cc_thresholdType, + NULL, /* &cc_rsaType */ + &cc_ed25519Type, + &cc_secp256k1Type, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 6-14 unused */ + &cc_evalType +}; + + +static int typeRegistryLength = sizeof(typeRegistry) / sizeof(typeRegistry[0]); + + +void appendUriSubtypes(uint32_t mask, unsigned char *buf) { + int append = 0; + for (int i=0; i<32; i++) { + if (mask & 1 << i) { + if (append) { + strcat(buf, ","); + strcat(buf, typeRegistry[i]->name); + } else { + strcat(buf, "&subtypes="); + strcat(buf, typeRegistry[i]->name); + } + append = 1; + } + } +} + + +unsigned char *cc_conditionUri(const CC *cond) { + unsigned char *fp = cond->type->fingerprint(cond); + if (!fp) return NULL; + + unsigned char *encoded = base64_encode(fp, 32); + + unsigned char *out = calloc(1, 1000); + sprintf(out, "ni:///sha-256;%s?fpt=%s&cost=%lu", + encoded, cond->type->name, cc_getCost(cond)); + + if (cond->type->hasSubtypes) { + appendUriSubtypes(cond->type->getSubtypes(cond), out); + } + + free(fp); + free(encoded); + + return out; +} + + +static uint32_t getSubtypes(CC *cond) { + uint32_t mask = 1 << cond->type->typeId; + if (cond->type->hasSubtypes) { + mask |= cond->type->getSubtypes(cond); + } + return mask; +} + + +static ConditionTypes_t asnSubtypes(uint32_t mask) { + ConditionTypes_t types; + uint8_t buf[4] = {0,0,0,0}; + int maxId = 0; + + for (int i=0; i<32; i++) { + if (mask & (1<> 3] |= 1 << (7 - i % 8); + } + } + + types.size = 1 + (maxId >> 3); + types.buf = calloc(1, types.size); + memcpy(types.buf, &buf, types.size); + types.bits_unused = 7 - maxId % 8; + return types; +} + + +static uint32_t fromAsnSubtypes(const ConditionTypes_t types) { + uint32_t mask = 0; + for (int i=0; i> 3] & (1 << (7 - i % 8))) { + mask |= 1 << i; + } + } + return mask; +} + + +size_t cc_conditionBinary(const CC *cond, unsigned char *buf) { + Condition_t *asn = calloc(1, sizeof(Condition_t)); + asnCondition(cond, asn); + asn_enc_rval_t rc = der_encode_to_buffer(&asn_DEF_Condition, asn, buf, 1000); + if (rc.encoded == -1) { + printf("CONDITION NOT ENCODED\n"); + return 0; + } + ASN_STRUCT_FREE(asn_DEF_Condition, asn); + return rc.encoded; +} + + +size_t cc_fulfillmentBinary(const CC *cond, unsigned char *buf, size_t length) { + Fulfillment_t *ffill = asnFulfillmentNew(cond); + asn_enc_rval_t rc = der_encode_to_buffer(&asn_DEF_Fulfillment, ffill, buf, length); + if (rc.encoded == -1) { + printf("FULFILLMENT NOT ENCODED\n"); + return 0; + } + ASN_STRUCT_FREE(asn_DEF_Fulfillment, ffill); + return rc.encoded; +} + + +static void asnCondition(const CC *cond, Condition_t *asn) { + asn->present = cond->type->asnType; + + // 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->subtypes = asnSubtypes(cond->type->getSubtypes(cond)); +} + + +static Condition_t *asnConditionNew(const CC *cond) { + Condition_t *asn = calloc(1, sizeof(Condition_t)); + asnCondition(cond, asn); + return asn; +} + + +static Fulfillment_t *asnFulfillmentNew(const CC *cond) { + return cond->type->toFulfillment(cond); +} + + +unsigned long cc_getCost(const CC *cond) { + return cond->type->getCost(cond); +} + + +CCType *getTypeByAsnEnum(Condition_PR present) { + for (int i=0; iasnType == present) { + return typeRegistry[i]; + } + } + return NULL; +} + + +static CC *fulfillmentToCC(Fulfillment_t *ffill) { + CCType *type = getTypeByAsnEnum(ffill->present); + if (!type) { + fprintf(stderr, "Unknown fulfillment type: %i\n", ffill->present); + return 0; + } + return type->fromFulfillment(ffill); +} + + +CC *cc_readFulfillmentBinary(unsigned char *ffill_bin, size_t ffill_bin_len) { + Fulfillment_t *ffill = 0; + CC *cond = 0; + asn_dec_rval_t rval = ber_decode(0, &asn_DEF_Fulfillment, (void **)&ffill, ffill_bin, ffill_bin_len); + if (rval.code == RC_OK) { + cond = fulfillmentToCC(ffill); + ASN_STRUCT_FREE(asn_DEF_Fulfillment, ffill); + } + return cond; +} + + +int cc_visit(CC *cond, CCVisitor visitor) { + int out = visitor.visit(cond, visitor); + if (out && cond->type->visitChildren) { + out = cond->type->visitChildren(cond, visitor); + } + return out; +} + + +int cc_verify(const struct CC *cond, const unsigned char *msg, size_t msgLength, int doHashMsg, + const unsigned char *condBin, size_t condBinLength, + VerifyEval verifyEval, void *evalContext) { + unsigned char targetBinary[1000]; + const size_t binLength = cc_conditionBinary(cond, targetBinary); + if (0 != memcmp(condBin, targetBinary, binLength)) { + return 0; + } + + if (!cc_ed25519VerifyTree(cond, msg, msgLength)) { + return 0; + } + + unsigned char msgHash[32]; + if (doHashMsg) sha256(msg, msgLength, msgHash); + else memcpy(msgHash, msg, 32); + if (!cc_secp256k1VerifyTreeMsg32(cond, msgHash)) { + return 0; + } + + if (!cc_verifyEval(cond, verifyEval, evalContext)) { + return 0; + } + return 1; +} + + +CC *cc_readConditionBinary(unsigned char *cond_bin, size_t length) { + Condition_t *asnCond = 0; + asn_dec_rval_t rval; + rval = ber_decode(0, &asn_DEF_Condition, (void **)&asnCond, cond_bin, length); + if (rval.code != RC_OK) { + printf("Failed reading condition binary\n"); + return NULL; + } + CC *cond = mkAnon(asnCond); + ASN_STRUCT_FREE(asn_DEF_Condition, asnCond); + return cond; +} + + +enum CCTypeId cc_typeId(const CC *cond) { + return cond->type->typeId; +} + + +int cc_isFulfilled(const CC *cond) { + return cond->type->isFulfilled(cond); +} + + +void cc_free(CC *cond) { + if (cond) + cond->type->free(cond); +} + + diff --git a/src/cryptoconditions/src/ed25519.c b/src/cryptoconditions/src/ed25519.c new file mode 100644 index 000000000..85655c2dc --- /dev/null +++ b/src/cryptoconditions/src/ed25519.c @@ -0,0 +1,170 @@ +#include "asn/Condition.h" +#include "asn/Fulfillment.h" +#include "asn/Ed25519FingerprintContents.h" +#include "asn/OCTET_STRING.h" +#include "include/cJSON.h" +#include "include/ed25519/src/ed25519.h" +#include "cryptoconditions.h" + + +struct CCType cc_ed25519Type; + + +static unsigned char *ed25519Fingerprint(const CC *cond) { + Ed25519FingerprintContents_t *fp = calloc(1, sizeof(Ed25519FingerprintContents_t)); + OCTET_STRING_fromBuf(&fp->publicKey, cond->publicKey, 32); + return hashFingerprintContents(&asn_DEF_Ed25519FingerprintContents, fp); +} + + +int ed25519Verify(CC *cond, CCVisitor visitor) { + if (cond->type->typeId != cc_ed25519Type.typeId) return 1; + // TODO: test failure mode: empty sig / null pointer + return ed25519_verify(cond->signature, visitor.msg, visitor.msgLength, cond->publicKey); +} + + +static int cc_ed25519VerifyTree(const CC *cond, const unsigned char *msg, size_t msgLength) { + CCVisitor visitor = {&ed25519Verify, msg, msgLength, NULL}; + return cc_visit((CC*) cond, visitor); +} + + +/* + * Signing data + */ +typedef struct CCEd25519SigningData { + unsigned char *pk; + unsigned char *skpk; + int nSigned; +} CCEd25519SigningData; + + +/* + * Visitor that signs an ed25519 condition if it has a matching public key + */ +static int ed25519Sign(CC *cond, CCVisitor visitor) { + if (cond->type->typeId != cc_ed25519Type.typeId) return 1; + CCEd25519SigningData *signing = (CCEd25519SigningData*) visitor.context; + if (0 != memcmp(cond->publicKey, signing->pk, 32)) return 1; + if (!cond->signature) cond->signature = malloc(64); + ed25519_sign(cond->signature, visitor.msg, visitor.msgLength, + signing->pk, signing->skpk); + signing->nSigned++; + return 1; +} + + +/* + * Sign ed25519 conditions in a tree + */ +int cc_signTreeEd25519(CC *cond, const unsigned char *privateKey, const unsigned char *msg, size_t msgLength) { + unsigned char pk[32], skpk[64]; + ed25519_create_keypair(pk, skpk, privateKey); + + CCEd25519SigningData signing = {pk, skpk, 0}; + CCVisitor visitor = {&ed25519Sign, (unsigned char*)msg, msgLength, &signing}; + cc_visit(cond, visitor); + return signing.nSigned; +} + + +static unsigned long ed25519Cost(const CC *cond) { + return 131072; +} + + +static CC *ed25519FromJSON(const cJSON *params, unsigned char *err) { + size_t binsz; + + cJSON *pk_item = cJSON_GetObjectItem(params, "publicKey"); + if (!cJSON_IsString(pk_item)) { + strcpy(err, "publicKey must be a string"); + return NULL; + } + unsigned char *pk = base64_decode(pk_item->valuestring, &binsz); + if (32 != binsz) { + strcpy(err, "publicKey has incorrect length"); + free(pk); + return NULL; + } + + cJSON *signature_item = cJSON_GetObjectItem(params, "signature"); + unsigned char *sig = NULL; + if (signature_item && !cJSON_IsNull(signature_item)) { + if (!cJSON_IsString(signature_item)) { + strcpy(err, "signature must be null or a string"); + return NULL; + } + sig = base64_decode(signature_item->valuestring, &binsz); + if (64 != binsz) { + strcpy(err, "signature has incorrect length"); + free(sig); + return NULL; + } + } + + CC *cond = calloc(1, sizeof(CC)); + cond->type = &cc_ed25519Type; + cond->publicKey = pk; + cond->signature = sig; + return cond; +} + + +static void ed25519ToJSON(const CC *cond, cJSON *params) { + unsigned char *b64 = base64_encode(cond->publicKey, 32); + cJSON_AddItemToObject(params, "publicKey", cJSON_CreateString(b64)); + free(b64); + if (cond->signature) { + b64 = base64_encode(cond->signature, 64); + cJSON_AddItemToObject(params, "signature", cJSON_CreateString(b64)); + free(b64); + } +} + + +static CC *ed25519FromFulfillment(const Fulfillment_t *ffill) { + CC *cond = calloc(1, sizeof(CC)); + cond->type = &cc_ed25519Type; + cond->publicKey = malloc(32); + memcpy(cond->publicKey, ffill->choice.ed25519Sha256.publicKey.buf, 32); + cond->signature = malloc(64); + memcpy(cond->signature, ffill->choice.ed25519Sha256.signature.buf, 64); + return cond; +} + + +static Fulfillment_t *ed25519ToFulfillment(const CC *cond) { + if (!cond->signature) { + return NULL; + } + Fulfillment_t *ffill = calloc(1, sizeof(Fulfillment_t)); + ffill->present = Fulfillment_PR_ed25519Sha256; + Ed25519Sha512Fulfillment_t *ed2 = &ffill->choice.ed25519Sha256; + OCTET_STRING_fromBuf(&ed2->publicKey, cond->publicKey, 32); + OCTET_STRING_fromBuf(&ed2->signature, cond->signature, 64); + return ffill; +} + + +int ed25519IsFulfilled(const CC *cond) { + return cond->signature > 0; +} + + +static void ed25519Free(CC *cond) { + free(cond->publicKey); + if (cond->signature) { + free(cond->signature); + } + free(cond); +} + + +static uint32_t ed25519Subtypes(const CC *cond) { + return 0; +} + + +struct CCType cc_ed25519Type = { 4, "ed25519-sha-256", Condition_PR_ed25519Sha256, 0, 0, &ed25519Fingerprint, &ed25519Cost, &ed25519Subtypes, &ed25519FromJSON, &ed25519ToJSON, &ed25519FromFulfillment, &ed25519ToFulfillment, &ed25519IsFulfilled, &ed25519Free }; diff --git a/src/cryptoconditions/src/eval.c b/src/cryptoconditions/src/eval.c new file mode 100644 index 000000000..976af32d7 --- /dev/null +++ b/src/cryptoconditions/src/eval.c @@ -0,0 +1,142 @@ +#include "asn/Condition.h" +#include "asn/Fulfillment.h" +#include "asn/EvalFulfillment.h" +#include "asn/EvalFingerprintContents.h" +#include "asn/OCTET_STRING.h" +#include "cryptoconditions.h" +#include "internal.h" +#include "include/cJSON.h" + + +struct CCType cc_evalType; + + +static unsigned char *evalFingerprint(const CC *cond) { + EvalFingerprintContents_t *fp = calloc(1, sizeof(EvalFingerprintContents_t)); + OCTET_STRING_fromBuf(&fp->method, cond->method, strlen(cond->method)); + OCTET_STRING_fromBuf(&fp->paramsBin, cond->paramsBin, cond->paramsBinLength); + return hashFingerprintContents(&asn_DEF_EvalFingerprintContents, fp); +} + + +static unsigned long evalCost(const CC *cond) { + return 1048576; // Pretty high +} + + +static CC *evalFromJSON(const cJSON *params, unsigned char *err) { + size_t paramsBinLength; + unsigned char *paramsBin = 0; + + cJSON *method_item = cJSON_GetObjectItem(params, "method"); + if (!checkString(method_item, "method", err)) { + return NULL; + } + + if (strlen(method_item->valuestring) > 64) { + strcpy(err, "method must be less than or equal to 64 bytes"); + return NULL; + } + + if (!jsonGetBase64(params, "params", err, ¶msBin, ¶msBinLength)) { + return NULL; + } + + CC *cond = calloc(1, sizeof(CC)); + strcpy(cond->method, method_item->valuestring); + cond->paramsBin = paramsBin; + cond->paramsBinLength = paramsBinLength; + cond->type = &cc_evalType; + return cond; +} + + +static void evalToJSON(const CC *cond, cJSON *params) { + + // add method + cJSON_AddItemToObject(params, "method", cJSON_CreateString(cond->method)); + + // add params + unsigned char *b64 = base64_encode(cond->paramsBin, cond->paramsBinLength); + cJSON_AddItemToObject(params, "params", cJSON_CreateString(b64)); + free(b64); +} + + +static CC *evalFromFulfillment(const Fulfillment_t *ffill) { + CC *cond = calloc(1, sizeof(CC)); + cond->type = &cc_evalType; + + EvalFulfillment_t *eval = &ffill->choice.evalSha256; + + memcpy(cond->method, eval->method.buf, eval->method.size); + cond->method[eval->method.size] = 0; + + OCTET_STRING_t octets = eval->paramsBin; + cond->paramsBinLength = octets.size; + cond->paramsBin = malloc(octets.size); + memcpy(cond->paramsBin, octets.buf, octets.size); + + return cond; +} + + +static Fulfillment_t *evalToFulfillment(const CC *cond) { + Fulfillment_t *ffill = calloc(1, sizeof(Fulfillment_t)); + ffill->present = Fulfillment_PR_evalSha256; + EvalFulfillment_t *eval = &ffill->choice.evalSha256; + OCTET_STRING_fromBuf(&eval->method, cond->method, strlen(cond->method)); + OCTET_STRING_fromBuf(&eval->paramsBin, cond->paramsBin, cond->paramsBinLength); + return ffill; +} + + +int evalIsFulfilled(const CC *cond) { + return 1; +} + + +static void evalFree(CC *cond) { + free(cond->paramsBin); + free(cond); +} + + +static uint32_t evalSubtypes(const CC *cond) { + return 0; +} + + +/* + * The JSON api doesn't contain custom verifiers, so a stub method is provided suitable for testing + */ +int jsonVerifyEval(CC *cond, void *context) { + if (strcmp(cond->method, "testEval") == 0) { + return memcmp(cond->paramsBin, "testEval", cond->paramsBinLength) == 0; + } + fprintf(stderr, "Cannot verify eval; user function unknown\n"); + return 0; +} + + +typedef struct CCEvalVerifyData { + VerifyEval verify; + void *context; +} CCEvalVerifyData; + + +int evalVisit(CC *cond, CCVisitor visitor) { + if (cond->type->typeId != cc_evalType.typeId) return 1; + CCEvalVerifyData *evalData = visitor.context; + return evalData->verify(cond, evalData->context); +} + + +int cc_verifyEval(const CC *cond, VerifyEval verify, void *context) { + CCEvalVerifyData evalData = {verify, context}; + CCVisitor visitor = {&evalVisit, "", 0, &evalData}; + return cc_visit(cond, visitor); +} + + +struct CCType cc_evalType = { 15, "eval-sha-256", Condition_PR_evalSha256, 0, 0, &evalFingerprint, &evalCost, &evalSubtypes, &evalFromJSON, &evalToJSON, &evalFromFulfillment, &evalToFulfillment, &evalIsFulfilled, &evalFree }; diff --git a/src/cryptoconditions/src/include/cJSON.c b/src/cryptoconditions/src/include/cJSON.c new file mode 100644 index 000000000..306bb5b0d --- /dev/null +++ b/src/cryptoconditions/src/include/cJSON.c @@ -0,0 +1,2699 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + 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. +*/ + +/* cJSON */ +/* JSON parser in C. */ + +#ifdef __GNUC__ +#pragma GCC visibility push(default) +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __GNUC__ +#pragma GCC visibility pop +#endif + +#include "cJSON.h" + +/* define our own boolean type */ +#define true ((cJSON_bool)1) +#define false ((cJSON_bool)0) + +typedef struct { + const unsigned char *json; + size_t position; +} error; +static error global_error = { NULL, 0 }; + +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) +{ + return (const char*) (global_error.json + global_error.position); +} + +/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ +#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 5) || (CJSON_VERSION_PATCH != 9) + #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. +#endif + +CJSON_PUBLIC(const char*) cJSON_Version(void) +{ + static char version[15]; + sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); + + return version; +} + +/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ +static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) +{ + if ((string1 == NULL) || (string2 == NULL)) + { + return 1; + } + + if (string1 == string2) + { + return 0; + } + + for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) + { + if (*string1 == '\0') + { + return 0; + } + } + + return tolower(*string1) - tolower(*string2); +} + +typedef struct internal_hooks +{ + void *(*allocate)(size_t size); + void (*deallocate)(void *pointer); + void *(*reallocate)(void *pointer, size_t size); +} internal_hooks; + +static internal_hooks global_hooks = { malloc, free, realloc }; + +static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks) +{ + size_t length = 0; + unsigned char *copy = NULL; + + if (string == NULL) + { + return NULL; + } + + length = strlen((const char*)string) + sizeof(""); + if (!(copy = (unsigned char*)hooks->allocate(length))) + { + return NULL; + } + memcpy(copy, string, length); + + return copy; +} + +CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) +{ + if (hooks == NULL) + { + /* Reset hooks */ + global_hooks.allocate = malloc; + global_hooks.deallocate = free; + global_hooks.reallocate = realloc; + return; + } + + global_hooks.allocate = malloc; + if (hooks->malloc_fn != NULL) + { + global_hooks.allocate = hooks->malloc_fn; + } + + global_hooks.deallocate = free; + if (hooks->free_fn != NULL) + { + global_hooks.deallocate = hooks->free_fn; + } + + /* use realloc only if both free and malloc are used */ + global_hooks.reallocate = NULL; + if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free)) + { + global_hooks.reallocate = realloc; + } +} + +/* Internal constructor. */ +static cJSON *cJSON_New_Item(const internal_hooks * const hooks) +{ + cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON)); + if (node) + { + memset(node, '\0', sizeof(cJSON)); + } + + return node; +} + +/* Delete a cJSON structure. */ +CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) +{ + cJSON *next = NULL; + while (item != NULL) + { + next = item->next; + if (!(item->type & cJSON_IsReference) && (item->child != NULL)) + { + cJSON_Delete(item->child); + } + if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) + { + global_hooks.deallocate(item->valuestring); + } + if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) + { + global_hooks.deallocate(item->string); + } + global_hooks.deallocate(item); + item = next; + } +} + +/* get the decimal point character of the current locale */ +static unsigned char get_decimal_point(void) +{ + struct lconv *lconv = localeconv(); + return (unsigned char) lconv->decimal_point[0]; +} + +typedef struct +{ + const unsigned char *content; + size_t length; + size_t offset; + size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ + internal_hooks hooks; +} parse_buffer; + +/* check if the given size is left to read in a given parse buffer (starting with 1) */ +#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length)) +#define cannot_read(buffer, size) (!can_read(buffer, size)) +/* check if the buffer can be accessed at the given index (starting with 0) */ +#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) +#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) +/* get a pointer to the buffer at the position */ +#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) + +/* Parse the input text to generate a number, and populate the result into item. */ +static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer) +{ + double number = 0; + unsigned char *after_end = NULL; + unsigned char number_c_string[64]; + unsigned char decimal_point = get_decimal_point(); + size_t i = 0; + + if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { + return false; + } + + /* copy the number into a temporary buffer and replace '.' with the decimal point + * of the current locale (for strtod) + * This also takes care of '\0' not necessarily being available for marking the end of the input */ + for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) + { + switch (buffer_at_offset(input_buffer)[i]) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '+': + case '-': + case 'e': + case 'E': + number_c_string[i] = buffer_at_offset(input_buffer)[i]; + break; + + case '.': + number_c_string[i] = decimal_point; + break; + + default: + goto loop_end; + } + } +loop_end: + number_c_string[i] = '\0'; + + number = strtod((const char*)number_c_string, (char**)&after_end); + if (number_c_string == after_end) + { + return false; /* parse_error */ + } + + item->valuedouble = number; + + /* use saturation in case of overflow */ + if (number >= INT_MAX) + { + item->valueint = INT_MAX; + } + else if (number <= INT_MIN) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = (int)number; + } + + item->type = cJSON_Number; + + input_buffer->offset += (size_t)(after_end - number_c_string); + return true; +} + +/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) +{ + if (number >= INT_MAX) + { + object->valueint = INT_MAX; + } + else if (number <= INT_MIN) + { + object->valueint = INT_MIN; + } + else + { + object->valueint = (int)number; + } + + return object->valuedouble = number; +} + +typedef struct +{ + unsigned char *buffer; + size_t length; + size_t offset; + size_t depth; /* current nesting depth (for formatted printing) */ + cJSON_bool noalloc; + cJSON_bool format; /* is this print a formatted print */ + internal_hooks hooks; +} printbuffer; + +/* realloc printbuffer if necessary to have at least "needed" bytes more */ +static unsigned char* ensure(printbuffer * const p, size_t needed) +{ + unsigned char *newbuffer = NULL; + size_t newsize = 0; + + if ((p == NULL) || (p->buffer == NULL)) + { + return NULL; + } + + if ((p->length > 0) && (p->offset >= p->length)) + { + /* make sure that offset is valid */ + return NULL; + } + + if (needed > INT_MAX) + { + /* sizes bigger than INT_MAX are currently not supported */ + return NULL; + } + + needed += p->offset + 1; + if (needed <= p->length) + { + return p->buffer + p->offset; + } + + if (p->noalloc) { + return NULL; + } + + /* calculate new buffer size */ + if (needed > (INT_MAX / 2)) + { + /* overflow of int, use INT_MAX if possible */ + if (needed <= INT_MAX) + { + newsize = INT_MAX; + } + else + { + return NULL; + } + } + else + { + newsize = needed * 2; + } + + if (p->hooks.reallocate != NULL) + { + /* reallocate with realloc if available */ + newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize); + if (newbuffer == NULL) + { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + } + else + { + /* otherwise reallocate manually */ + newbuffer = (unsigned char*)p->hooks.allocate(newsize); + if (!newbuffer) + { + p->hooks.deallocate(p->buffer); + p->length = 0; + p->buffer = NULL; + + return NULL; + } + if (newbuffer) + { + memcpy(newbuffer, p->buffer, p->offset + 1); + } + p->hooks.deallocate(p->buffer); + } + p->length = newsize; + p->buffer = newbuffer; + + return newbuffer + p->offset; +} + +/* calculate the new length of the string in a printbuffer and update the offset */ +static void update_offset(printbuffer * const buffer) +{ + const unsigned char *buffer_pointer = NULL; + if ((buffer == NULL) || (buffer->buffer == NULL)) + { + return; + } + buffer_pointer = buffer->buffer + buffer->offset; + + buffer->offset += strlen((const char*)buffer_pointer); +} + +/* Render the number nicely from the given item into a string. */ +static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + double d = item->valuedouble; + int length = 0; + size_t i = 0; + unsigned char number_buffer[26]; /* temporary buffer to print the number into */ + unsigned char decimal_point = get_decimal_point(); + double test; + + if (output_buffer == NULL) + { + return false; + } + + /* This checks for NaN and Infinity */ + if ((d * 0) != 0) + { + length = sprintf((char*)number_buffer, "null"); + } + else + { + /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ + length = sprintf((char*)number_buffer, "%1.15g", d); + + /* Check whether the original double can be recovered */ + if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || ((double)test != d)) + { + /* If not, print with 17 decimal places of precision */ + length = sprintf((char*)number_buffer, "%1.17g", d); + } + } + + /* sprintf failed or buffer overrun occured */ + if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) + { + return false; + } + + /* reserve appropriate space in the output */ + output_pointer = ensure(output_buffer, (size_t)length); + if (output_pointer == NULL) + { + return false; + } + + /* copy the printed number to the output and replace locale + * dependent decimal point with '.' */ + for (i = 0; i < ((size_t)length); i++) + { + if (number_buffer[i] == decimal_point) + { + output_pointer[i] = '.'; + continue; + } + + output_pointer[i] = number_buffer[i]; + } + output_pointer[i] = '\0'; + + output_buffer->offset += (size_t)length; + + return true; +} + +/* parse 4 digit hexadecimal number */ +static unsigned parse_hex4(const unsigned char * const input) +{ + unsigned int h = 0; + size_t i = 0; + + for (i = 0; i < 4; i++) + { + /* parse digit */ + if ((input[i] >= '0') && (input[i] <= '9')) + { + h += (unsigned int) input[i] - '0'; + } + else if ((input[i] >= 'A') && (input[i] <= 'F')) + { + h += (unsigned int) 10 + input[i] - 'A'; + } + else if ((input[i] >= 'a') && (input[i] <= 'f')) + { + h += (unsigned int) 10 + input[i] - 'a'; + } + else /* invalid */ + { + return 0; + } + + if (i < 3) + { + /* shift left to make place for the next nibble */ + h = h << 4; + } + } + + return h; +} + +/* converts a UTF-16 literal to UTF-8 + * A literal can be one or two sequences of the form \uXXXX */ +static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer) +{ + long unsigned int codepoint = 0; + unsigned int first_code = 0; + const unsigned char *first_sequence = input_pointer; + unsigned char utf8_length = 0; + unsigned char utf8_position = 0; + unsigned char sequence_length = 0; + unsigned char first_byte_mark = 0; + + if ((input_end - first_sequence) < 6) + { + /* input ends unexpectedly */ + goto fail; + } + + /* get the first utf16 sequence */ + first_code = parse_hex4(first_sequence + 2); + + /* check that the code is valid */ + if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) + { + goto fail; + } + + /* UTF16 surrogate pair */ + if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) + { + const unsigned char *second_sequence = first_sequence + 6; + unsigned int second_code = 0; + sequence_length = 12; /* \uXXXX\uXXXX */ + + if ((input_end - second_sequence) < 6) + { + /* input ends unexpectedly */ + goto fail; + } + + if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) + { + /* missing second half of the surrogate pair */ + goto fail; + } + + /* get the second utf16 sequence */ + second_code = parse_hex4(second_sequence + 2); + /* check that the code is valid */ + if ((second_code < 0xDC00) || (second_code > 0xDFFF)) + { + /* invalid second half of the surrogate pair */ + goto fail; + } + + + /* calculate the unicode codepoint from the surrogate pair */ + codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); + } + else + { + sequence_length = 6; /* \uXXXX */ + codepoint = first_code; + } + + /* encode as UTF-8 + * takes at maximum 4 bytes to encode: + * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + if (codepoint < 0x80) + { + /* normal ascii, encoding 0xxxxxxx */ + utf8_length = 1; + } + else if (codepoint < 0x800) + { + /* two bytes, encoding 110xxxxx 10xxxxxx */ + utf8_length = 2; + first_byte_mark = 0xC0; /* 11000000 */ + } + else if (codepoint < 0x10000) + { + /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ + utf8_length = 3; + first_byte_mark = 0xE0; /* 11100000 */ + } + else if (codepoint <= 0x10FFFF) + { + /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ + utf8_length = 4; + first_byte_mark = 0xF0; /* 11110000 */ + } + else + { + /* invalid unicode codepoint */ + goto fail; + } + + /* encode as utf8 */ + for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) + { + /* 10xxxxxx */ + (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); + codepoint >>= 6; + } + /* encode first byte */ + if (utf8_length > 1) + { + (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); + } + else + { + (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); + } + + *output_pointer += utf8_length; + + return sequence_length; + +fail: + return 0; +} + +/* Parse the input text into an unescaped cinput, and populate item. */ +static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer) +{ + const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; + const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; + unsigned char *output_pointer = NULL; + unsigned char *output = NULL; + + /* not a string */ + if (buffer_at_offset(input_buffer)[0] != '\"') + { + goto fail; + } + + { + /* calculate approximate size of the output (overestimate) */ + size_t allocation_length = 0; + size_t skipped_bytes = 0; + while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) + { + /* is escape sequence */ + if (input_end[0] == '\\') + { + if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) + { + /* prevent buffer overflow when last input character is a backslash */ + goto fail; + } + skipped_bytes++; + input_end++; + } + input_end++; + } + if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) + { + goto fail; /* string ended unexpectedly */ + } + + /* This is at most how much we need for the output */ + allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; + output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof("")); + if (output == NULL) + { + goto fail; /* allocation failure */ + } + } + + output_pointer = output; + /* loop through the string literal */ + while (input_pointer < input_end) + { + if (*input_pointer != '\\') + { + *output_pointer++ = *input_pointer++; + } + /* escape sequence */ + else + { + unsigned char sequence_length = 2; + if ((input_end - input_pointer) < 1) + { + goto fail; + } + + switch (input_pointer[1]) + { + case 'b': + *output_pointer++ = '\b'; + break; + case 'f': + *output_pointer++ = '\f'; + break; + case 'n': + *output_pointer++ = '\n'; + break; + case 'r': + *output_pointer++ = '\r'; + break; + case 't': + *output_pointer++ = '\t'; + break; + case '\"': + case '\\': + case '/': + *output_pointer++ = input_pointer[1]; + break; + + /* UTF-16 literal */ + case 'u': + sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); + if (sequence_length == 0) + { + /* failed to convert UTF16-literal to UTF-8 */ + goto fail; + } + break; + + default: + goto fail; + } + input_pointer += sequence_length; + } + } + + /* zero terminate the output */ + *output_pointer = '\0'; + + item->type = cJSON_String; + item->valuestring = (char*)output; + + input_buffer->offset = (size_t) (input_end - input_buffer->content); + input_buffer->offset++; + + return true; + +fail: + if (output != NULL) + { + input_buffer->hooks.deallocate(output); + } + + if (input_pointer != NULL) + { + input_buffer->offset = (size_t)(input_pointer - input_buffer->content); + } + + return false; +} + +/* Render the cstring provided to an escaped version that can be printed. */ +static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) +{ + const unsigned char *input_pointer = NULL; + unsigned char *output = NULL; + unsigned char *output_pointer = NULL; + size_t output_length = 0; + /* numbers of additional characters needed for escaping */ + size_t escape_characters = 0; + + if (output_buffer == NULL) + { + return false; + } + + /* empty string */ + if (input == NULL) + { + output = ensure(output_buffer, sizeof("\"\"")); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "\"\""); + + return true; + } + + /* set "flag" to 1 if something needs to be escaped */ + for (input_pointer = input; *input_pointer; input_pointer++) + { + switch (*input_pointer) + { + case '\"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + /* one character escape sequence */ + escape_characters++; + break; + default: + if (*input_pointer < 32) + { + /* UTF-16 escape sequence uXXXX */ + escape_characters += 5; + } + break; + } + } + output_length = (size_t)(input_pointer - input) + escape_characters; + + output = ensure(output_buffer, output_length + sizeof("\"\"")); + if (output == NULL) + { + return false; + } + + /* no characters have to be escaped */ + if (escape_characters == 0) + { + output[0] = '\"'; + memcpy(output + 1, input, output_length); + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; + } + + output[0] = '\"'; + output_pointer = output + 1; + /* copy the string */ + for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) + { + if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) + { + /* normal character, copy */ + *output_pointer = *input_pointer; + } + else + { + /* character needs to be escaped */ + *output_pointer++ = '\\'; + switch (*input_pointer) + { + case '\\': + *output_pointer = '\\'; + break; + case '\"': + *output_pointer = '\"'; + break; + case '\b': + *output_pointer = 'b'; + break; + case '\f': + *output_pointer = 'f'; + break; + case '\n': + *output_pointer = 'n'; + break; + case '\r': + *output_pointer = 'r'; + break; + case '\t': + *output_pointer = 't'; + break; + default: + /* escape and print as unicode codepoint */ + sprintf((char*)output_pointer, "u%04x", *input_pointer); + output_pointer += 4; + break; + } + } + } + output[output_length + 1] = '\"'; + output[output_length + 2] = '\0'; + + return true; +} + +/* Invoke print_string_ptr (which is useful) on an item. */ +static cJSON_bool print_string(const cJSON * const item, printbuffer * const p) +{ + return print_string_ptr((unsigned char*)item->valuestring, p); +} + +/* Predeclare these prototypes. */ +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer); +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer); +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer); +static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer); + +/* Utility to jump whitespace and cr/lf */ +static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) +{ + if ((buffer == NULL) || (buffer->content == NULL)) + { + return NULL; + } + + while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) + { + buffer->offset++; + } + + if (buffer->offset == buffer->length) + { + buffer->offset--; + } + + return buffer; +} + +/* Parse an object - create a new root, and populate. */ +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) +{ + parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; + cJSON *item = NULL; + + /* reset error position */ + global_error.json = NULL; + global_error.position = 0; + + if (value == NULL) + { + goto fail; + } + + buffer.content = (const unsigned char*)value; + buffer.length = strlen((const char*)value) + sizeof(""); + buffer.offset = 0; + buffer.hooks = global_hooks; + + item = cJSON_New_Item(&global_hooks); + if (item == NULL) /* memory fail */ + { + goto fail; + } + + if (!parse_value(item, buffer_skip_whitespace(&buffer))) + { + /* parse failure. ep is set. */ + goto fail; + } + + /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ + if (require_null_terminated) + { + buffer_skip_whitespace(&buffer); + if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') + { + goto fail; + } + } + if (return_parse_end) + { + *return_parse_end = (const char*)buffer_at_offset(&buffer); + } + + return item; + +fail: + if (item != NULL) + { + cJSON_Delete(item); + } + + if (value != NULL) + { + error local_error; + local_error.json = (const unsigned char*)value; + local_error.position = 0; + + if (buffer.offset < buffer.length) + { + local_error.position = buffer.offset; + } + else if (buffer.length > 0) + { + local_error.position = buffer.length - 1; + } + + if (return_parse_end != NULL) + { + *return_parse_end = (const char*)local_error.json + local_error.position; + } + + global_error = local_error; + } + + return NULL; +} + +/* Default options for cJSON_Parse */ +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) +{ + return cJSON_ParseWithOpts(value, 0, 0); +} + +#define cjson_min(a, b) ((a < b) ? a : b) + +static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks) +{ + printbuffer buffer[1]; + unsigned char *printed = NULL; + + memset(buffer, 0, sizeof(buffer)); + + /* create buffer */ + buffer->buffer = (unsigned char*) hooks->allocate(256); + buffer->format = format; + buffer->hooks = *hooks; + if (buffer->buffer == NULL) + { + goto fail; + } + + /* print the value */ + if (!print_value(item, buffer)) + { + goto fail; + } + update_offset(buffer); + + /* check if reallocate is available */ + if (hooks->reallocate != NULL) + { + printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->length); + buffer->buffer = NULL; + if (printed == NULL) { + goto fail; + } + } + else /* otherwise copy the JSON over to a new buffer */ + { + printed = (unsigned char*) hooks->allocate(buffer->offset + 1); + if (printed == NULL) + { + goto fail; + } + memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1)); + printed[buffer->offset] = '\0'; /* just to be sure */ + + /* free the buffer */ + hooks->deallocate(buffer->buffer); + } + + return printed; + +fail: + if (buffer->buffer != NULL) + { + hooks->deallocate(buffer->buffer); + } + + if (printed != NULL) + { + hooks->deallocate(printed); + } + + return NULL; +} + +/* Render a cJSON item/entity/structure to text. */ +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) +{ + return (char*)print(item, true, &global_hooks); +} + +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) +{ + return (char*)print(item, false, &global_hooks); +} + +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if (prebuffer < 0) + { + return NULL; + } + + p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer); + if (!p.buffer) + { + return NULL; + } + + p.length = (size_t)prebuffer; + p.offset = 0; + p.noalloc = false; + p.format = fmt; + p.hooks = global_hooks; + + if (!print_value(item, &p)) + { + global_hooks.deallocate(p.buffer); + return NULL; + } + + return (char*)p.buffer; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cJSON_bool fmt) +{ + printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; + + if ((len < 0) || (buf == NULL)) + { + return false; + } + + p.buffer = (unsigned char*)buf; + p.length = (size_t)len; + p.offset = 0; + p.noalloc = true; + p.format = fmt; + p.hooks = global_hooks; + + return print_value(item, &p); +} + +/* Parser core - when encountering text, process appropriately. */ +static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer) +{ + if ((input_buffer == NULL) || (input_buffer->content == NULL)) + { + return false; /* no input */ + } + + /* parse the different types of values */ + /* null */ + if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0)) + { + item->type = cJSON_NULL; + input_buffer->offset += 4; + return true; + } + /* false */ + if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0)) + { + item->type = cJSON_False; + input_buffer->offset += 5; + return true; + } + /* true */ + if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0)) + { + item->type = cJSON_True; + item->valueint = 1; + input_buffer->offset += 4; + return true; + } + /* string */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) + { + return parse_string(item, input_buffer); + } + /* number */ + if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) + { + return parse_number(item, input_buffer); + } + /* array */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) + { + return parse_array(item, input_buffer); + } + /* object */ + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) + { + return parse_object(item, input_buffer); + } + + + return false; +} + +/* Render a value to text. */ +static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output = NULL; + + if ((item == NULL) || (output_buffer == NULL)) + { + return false; + } + + switch ((item->type) & 0xFF) + { + case cJSON_NULL: + output = ensure(output_buffer, 5); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "null"); + return true; + + case cJSON_False: + output = ensure(output_buffer, 6); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "false"); + return true; + + case cJSON_True: + output = ensure(output_buffer, 5); + if (output == NULL) + { + return false; + } + strcpy((char*)output, "true"); + return true; + + case cJSON_Number: + return print_number(item, output_buffer); + + case cJSON_Raw: + { + size_t raw_length = 0; + if (item->valuestring == NULL) + { + if (!output_buffer->noalloc) + { + output_buffer->hooks.deallocate(output_buffer->buffer); + } + return false; + } + + raw_length = strlen(item->valuestring) + sizeof(""); + output = ensure(output_buffer, raw_length); + if (output == NULL) + { + return false; + } + memcpy(output, item->valuestring, raw_length); + return true; + } + + case cJSON_String: + return print_string(item, output_buffer); + + case cJSON_Array: + return print_array(item, output_buffer); + + case cJSON_Object: + return print_object(item, output_buffer); + + default: + return false; + } +} + +/* Build an array from input text. */ +static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer) +{ + cJSON *head = NULL; /* head of the linked list */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= CJSON_NESTING_LIMIT) + { + return false; /* to deeply nested */ + } + input_buffer->depth++; + + if (buffer_at_offset(input_buffer)[0] != '[') + { + /* not an array */ + goto fail; + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) + { + /* empty array */ + goto success; + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) + { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do + { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) + { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) + { + /* start the linked list */ + current_item = head = new_item; + } + else + { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse next value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) + { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } + while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') + { + goto fail; /* expected end of array */ + } + +success: + input_buffer->depth--; + + item->type = cJSON_Array; + item->child = head; + + input_buffer->offset++; + + return true; + +fail: + if (head != NULL) + { + cJSON_Delete(head); + } + + return false; +} + +/* Render an array to text */ +static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_element = item->child; + + if (output_buffer == NULL) + { + return false; + } + + /* Compose the output array. */ + /* opening square bracket */ + output_pointer = ensure(output_buffer, 1); + if (output_pointer == NULL) + { + return false; + } + + *output_pointer = '['; + output_buffer->offset++; + output_buffer->depth++; + + while (current_element != NULL) + { + if (!print_value(current_element, output_buffer)) + { + return false; + } + update_offset(output_buffer); + if (current_element->next) + { + length = (size_t) (output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ','; + if(output_buffer->format) + { + *output_pointer++ = ' '; + } + *output_pointer = '\0'; + output_buffer->offset += length; + } + current_element = current_element->next; + } + + output_pointer = ensure(output_buffer, 2); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ']'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Build an object from the text. */ +static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer) +{ + cJSON *head = NULL; /* linked list head */ + cJSON *current_item = NULL; + + if (input_buffer->depth >= CJSON_NESTING_LIMIT) + { + return false; /* to deeply nested */ + } + input_buffer->depth++; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) + { + goto fail; /* not an object */ + } + + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) + { + goto success; /* empty object */ + } + + /* check if we skipped to the end of the buffer */ + if (cannot_access_at_index(input_buffer, 0)) + { + input_buffer->offset--; + goto fail; + } + + /* step back to character in front of the first element */ + input_buffer->offset--; + /* loop through the comma separated array elements */ + do + { + /* allocate next item */ + cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); + if (new_item == NULL) + { + goto fail; /* allocation failure */ + } + + /* attach next item to list */ + if (head == NULL) + { + /* start the linked list */ + current_item = head = new_item; + } + else + { + /* add to the end and advance */ + current_item->next = new_item; + new_item->prev = current_item; + current_item = new_item; + } + + /* parse the name of the child */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_string(current_item, input_buffer)) + { + goto fail; /* faile to parse name */ + } + buffer_skip_whitespace(input_buffer); + + /* swap valuestring and string, because we parsed the name */ + current_item->string = current_item->valuestring; + current_item->valuestring = NULL; + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) + { + goto fail; /* invalid object */ + } + + /* parse the value */ + input_buffer->offset++; + buffer_skip_whitespace(input_buffer); + if (!parse_value(current_item, input_buffer)) + { + goto fail; /* failed to parse value */ + } + buffer_skip_whitespace(input_buffer); + } + while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) + { + goto fail; /* expected end of object */ + } + +success: + input_buffer->depth--; + + item->type = cJSON_Object; + item->child = head; + + input_buffer->offset++; + return true; + +fail: + if (head != NULL) + { + cJSON_Delete(head); + } + + return false; +} + +/* Render an object to text. */ +static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer) +{ + unsigned char *output_pointer = NULL; + size_t length = 0; + cJSON *current_item = item->child; + + if (output_buffer == NULL) + { + return false; + } + + /* Compose the output: */ + length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */ + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + + *output_pointer++ = '{'; + output_buffer->depth++; + if (output_buffer->format) + { + *output_pointer++ = '\n'; + } + output_buffer->offset += length; + + while (current_item) + { + if (output_buffer->format) + { + size_t i; + output_pointer = ensure(output_buffer, output_buffer->depth); + if (output_pointer == NULL) + { + return false; + } + for (i = 0; i < output_buffer->depth; i++) + { + *output_pointer++ = '\t'; + } + output_buffer->offset += output_buffer->depth; + } + + /* print key */ + if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) + { + return false; + } + update_offset(output_buffer); + + length = (size_t) (output_buffer->format ? 2 : 1); + output_pointer = ensure(output_buffer, length); + if (output_pointer == NULL) + { + return false; + } + *output_pointer++ = ':'; + if (output_buffer->format) + { + *output_pointer++ = '\t'; + } + output_buffer->offset += length; + + /* print value */ + if (!print_value(current_item, output_buffer)) + { + return false; + } + update_offset(output_buffer); + + /* print comma if not last */ + length = (size_t) ((output_buffer->format ? 1 : 0) + (current_item->next ? 1 : 0)); + output_pointer = ensure(output_buffer, length + 1); + if (output_pointer == NULL) + { + return false; + } + if (current_item->next) + { + *output_pointer++ = ','; + } + + if (output_buffer->format) + { + *output_pointer++ = '\n'; + } + *output_pointer = '\0'; + output_buffer->offset += length; + + current_item = current_item->next; + } + + output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); + if (output_pointer == NULL) + { + return false; + } + if (output_buffer->format) + { + size_t i; + for (i = 0; i < (output_buffer->depth - 1); i++) + { + *output_pointer++ = '\t'; + } + } + *output_pointer++ = '}'; + *output_pointer = '\0'; + output_buffer->depth--; + + return true; +} + +/* Get Array size/item / object item. */ +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) +{ + cJSON *child = NULL; + size_t size = 0; + + if (array == NULL) + { + return 0; + } + + child = array->child; + + while(child != NULL) + { + size++; + child = child->next; + } + + /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ + + return (int)size; +} + +static cJSON* get_array_item(const cJSON *array, size_t index) +{ + cJSON *current_child = NULL; + + if (array == NULL) + { + return NULL; + } + + current_child = array->child; + while ((current_child != NULL) && (index > 0)) + { + index--; + current_child = current_child->next; + } + + return current_child; +} + +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) +{ + if (index < 0) + { + return NULL; + } + + return get_array_item(array, (size_t)index); +} + +static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive) +{ + cJSON *current_element = NULL; + + if ((object == NULL) || (name == NULL)) + { + return NULL; + } + + current_element = object->child; + if (case_sensitive) + { + while ((current_element != NULL) && (strcmp(name, current_element->string) != 0)) + { + current_element = current_element->next; + } + } + else + { + while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) + { + current_element = current_element->next; + } + } + + return current_element; +} + +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) +{ + return get_object_item(object, string, false); +} + +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) +{ + return get_object_item(object, string, true); +} + +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) +{ + return cJSON_GetObjectItem(object, string) ? 1 : 0; +} + +/* Utility for array list handling. */ +static void suffix_object(cJSON *prev, cJSON *item) +{ + prev->next = item; + item->prev = prev; +} + +/* Utility for handling references. */ +static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks) +{ + cJSON *reference = NULL; + if (item == NULL) + { + return NULL; + } + + reference = cJSON_New_Item(hooks); + if (reference == NULL) + { + return NULL; + } + + memcpy(reference, item, sizeof(cJSON)); + reference->string = NULL; + reference->type |= cJSON_IsReference; + reference->next = reference->prev = NULL; + return reference; +} + +/* Add item to array/object. */ +CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item) +{ + cJSON *child = NULL; + + if ((item == NULL) || (array == NULL)) + { + return; + } + + child = array->child; + + if (child == NULL) + { + /* list is empty, start new one */ + array->child = item; + } + else + { + /* append to the end */ + while (child->next) + { + child = child->next; + } + suffix_object(child, item); + } +} + +CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) +{ + if (item == NULL) + { + return; + } + + /* call cJSON_AddItemToObjectCS for code reuse */ + cJSON_AddItemToObjectCS(object, (char*)cJSON_strdup((const unsigned char*)string, &global_hooks), item); + /* remove cJSON_StringIsConst flag */ + item->type &= ~cJSON_StringIsConst; +} + +#if defined (__clang__) || ((__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic push +#endif +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif + +/* Add an item to an object with constant string as key */ +CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) +{ + if ((item == NULL) || (string == NULL)) + { + return; + } + if (!(item->type & cJSON_StringIsConst) && item->string) + { + global_hooks.deallocate(item->string); + } + item->string = (char*)string; + item->type |= cJSON_StringIsConst; + cJSON_AddItemToArray(object, item); +} +#if defined (__clang__) || ((__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) + #pragma GCC diagnostic pop +#endif + +CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) +{ + if (array == NULL) + { + return; + } + + cJSON_AddItemToArray(array, create_reference(item, &global_hooks)); +} + +CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) +{ + if ((object == NULL) || (string == NULL)) + { + return; + } + + cJSON_AddItemToObject(object, string, create_reference(item, &global_hooks)); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) +{ + if ((parent == NULL) || (item == NULL)) + { + return NULL; + } + + if (item->prev != NULL) + { + /* not the first element */ + item->prev->next = item->next; + } + if (item->next != NULL) + { + /* not the last element */ + item->next->prev = item->prev; + } + + if (item == parent->child) + { + /* first element */ + parent->child = item->next; + } + /* make sure the detached item doesn't point anywhere anymore */ + item->prev = NULL; + item->next = NULL; + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) +{ + if (which < 0) + { + return NULL; + } + + return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which)); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) +{ + cJSON_Delete(cJSON_DetachItemFromArray(array, which)); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItem(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string); + + return cJSON_DetachItemViaPointer(object, to_detach); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObject(object, string)); +} + +CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) +{ + cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string)); +} + +/* Replace array/object items with new ones. */ +CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) +{ + cJSON *after_inserted = NULL; + + if (which < 0) + { + return; + } + + after_inserted = get_array_item(array, (size_t)which); + if (after_inserted == NULL) + { + cJSON_AddItemToArray(array, newitem); + return; + } + + newitem->next = after_inserted; + newitem->prev = after_inserted->prev; + after_inserted->prev = newitem; + if (after_inserted == array->child) + { + array->child = newitem; + } + else + { + newitem->prev->next = newitem; + } +} + +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) +{ + if ((parent == NULL) || (replacement == NULL) || (item == NULL)) + { + return false; + } + + if (replacement == item) + { + return true; + } + + replacement->next = item->next; + replacement->prev = item->prev; + + if (replacement->next != NULL) + { + replacement->next->prev = replacement; + } + if (replacement->prev != NULL) + { + replacement->prev->next = replacement; + } + if (parent->child == item) + { + parent->child = replacement; + } + + item->next = NULL; + item->prev = NULL; + cJSON_Delete(item); + + return true; +} + +CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) +{ + if (which < 0) + { + return; + } + + cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); +} + +static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive) +{ + if ((replacement == NULL) || (string == NULL)) + { + return false; + } + + /* replace the name in the replacement */ + if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL)) + { + cJSON_free(replacement->string); + } + replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + replacement->type &= ~cJSON_StringIsConst; + + cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); + + return true; +} + +CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) +{ + replace_item_in_object(object, string, newitem, false); +} + +CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) +{ + replace_item_in_object(object, string, newitem, true); +} + +/* Create basic types: */ +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_NULL; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_True; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_False; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool b) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = b ? cJSON_True : cJSON_False; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_Number; + item->valuedouble = num; + + /* use saturation in case of overflow */ + if (num >= INT_MAX) + { + item->valueint = INT_MAX; + } + else if (num <= INT_MIN) + { + item->valueint = INT_MIN; + } + else + { + item->valueint = (int)num; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_String; + item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); + if(!item->valuestring) + { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type = cJSON_Raw; + item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); + if(!item->valuestring) + { + cJSON_Delete(item); + return NULL; + } + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if(item) + { + item->type=cJSON_Array; + } + + return item; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) +{ + cJSON *item = cJSON_New_Item(&global_hooks); + if (item) + { + item->type = cJSON_Object; + } + + return item; +} + +/* Create Arrays: */ +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber(numbers[i]); + if (!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber((double)numbers[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (numbers == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for(i = 0;a && (i < (size_t)count); i++) + { + n = cJSON_CreateNumber(numbers[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p, n); + } + p = n; + } + + return a; +} + +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count) +{ + size_t i = 0; + cJSON *n = NULL; + cJSON *p = NULL; + cJSON *a = NULL; + + if ((count < 0) || (strings == NULL)) + { + return NULL; + } + + a = cJSON_CreateArray(); + + for (i = 0; a && (i < (size_t)count); i++) + { + n = cJSON_CreateString(strings[i]); + if(!n) + { + cJSON_Delete(a); + return NULL; + } + if(!i) + { + a->child = n; + } + else + { + suffix_object(p,n); + } + p = n; + } + + return a; +} + +/* Duplication */ +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) +{ + cJSON *newitem = NULL; + cJSON *child = NULL; + cJSON *next = NULL; + cJSON *newchild = NULL; + + /* Bail on bad ptr */ + if (!item) + { + goto fail; + } + /* Create new item */ + newitem = cJSON_New_Item(&global_hooks); + if (!newitem) + { + goto fail; + } + /* Copy over all vars */ + newitem->type = item->type & (~cJSON_IsReference); + newitem->valueint = item->valueint; + newitem->valuedouble = item->valuedouble; + if (item->valuestring) + { + newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); + if (!newitem->valuestring) + { + goto fail; + } + } + if (item->string) + { + newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); + if (!newitem->string) + { + goto fail; + } + } + /* If non-recursive, then we're done! */ + if (!recurse) + { + return newitem; + } + /* Walk the ->next chain for the child. */ + child = item->child; + while (child != NULL) + { + newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ + if (!newchild) + { + goto fail; + } + if (next != NULL) + { + /* If newitem->child already set, then crosswire ->prev and ->next and move on */ + next->next = newchild; + newchild->prev = next; + next = newchild; + } + else + { + /* Set newitem->child and move to it */ + newitem->child = newchild; + next = newchild; + } + child = child->next; + } + + return newitem; + +fail: + if (newitem != NULL) + { + cJSON_Delete(newitem); + } + + return NULL; +} + +CJSON_PUBLIC(void) cJSON_Minify(char *json) +{ + unsigned char *into = (unsigned char*)json; + + if (json == NULL) + { + return; + } + + while (*json) + { + if (*json == ' ') + { + json++; + } + else if (*json == '\t') + { + /* Whitespace characters. */ + json++; + } + else if (*json == '\r') + { + json++; + } + else if (*json=='\n') + { + json++; + } + else if ((*json == '/') && (json[1] == '/')) + { + /* double-slash comments, to end of line. */ + while (*json && (*json != '\n')) + { + json++; + } + } + else if ((*json == '/') && (json[1] == '*')) + { + /* multiline comments. */ + while (*json && !((*json == '*') && (json[1] == '/'))) + { + json++; + } + json += 2; + } + else if (*json == '\"') + { + /* string literals, which are \" sensitive. */ + *into++ = (unsigned char)*json++; + while (*json && (*json != '\"')) + { + if (*json == '\\') + { + *into++ = (unsigned char)*json++; + } + *into++ = (unsigned char)*json++; + } + *into++ = (unsigned char)*json++; + } + else + { + /* All other characters. */ + *into++ = (unsigned char)*json++; + } + } + + /* and null-terminate. */ + *into = '\0'; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Invalid; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_False; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xff) == cJSON_True; +} + + +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & (cJSON_True | cJSON_False)) != 0; +} +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_NULL; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Number; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_String; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Array; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Object; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) +{ + if (item == NULL) + { + return false; + } + + return (item->type & 0xFF) == cJSON_Raw; +} + +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) +{ + if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) + { + return false; + } + + /* check if type is valid */ + switch (a->type & 0xFF) + { + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + case cJSON_Number: + case cJSON_String: + case cJSON_Raw: + case cJSON_Array: + case cJSON_Object: + break; + + default: + return false; + } + + /* identical objects are equal */ + if (a == b) + { + return true; + } + + switch (a->type & 0xFF) + { + /* in these cases and equal type is enough */ + case cJSON_False: + case cJSON_True: + case cJSON_NULL: + return true; + + case cJSON_Number: + if (a->valuedouble == b->valuedouble) + { + return true; + } + return false; + + case cJSON_String: + case cJSON_Raw: + if ((a->valuestring == NULL) || (b->valuestring == NULL)) + { + return false; + } + if (strcmp(a->valuestring, b->valuestring) == 0) + { + return true; + } + + return false; + + case cJSON_Array: + { + cJSON *a_element = a->child; + cJSON *b_element = b->child; + + for (; (a_element != NULL) && (b_element != NULL);) + { + if (!cJSON_Compare(a_element, b_element, case_sensitive)) + { + return false; + } + + a_element = a_element->next; + b_element = b_element->next; + } + + /* one of the arrays is longer than the other */ + if (a_element != b_element) { + return false; + } + + return true; + } + + case cJSON_Object: + { + cJSON *a_element = NULL; + cJSON *b_element = NULL; + cJSON_ArrayForEach(a_element, a) + { + /* TODO This has O(n^2) runtime, which is horrible! */ + b_element = get_object_item(b, a_element->string, case_sensitive); + if (b_element == NULL) + { + return false; + } + + if (!cJSON_Compare(a_element, b_element, case_sensitive)) + { + return false; + } + } + + /* doing this twice, once on a and b to prevent true comparison if a subset of b + * TODO: Do this the proper way, this is just a fix for now */ + cJSON_ArrayForEach(b_element, b) + { + a_element = get_object_item(a, b_element->string, case_sensitive); + if (a_element == NULL) + { + return false; + } + + if (!cJSON_Compare(b_element, a_element, case_sensitive)) + { + return false; + } + } + + return true; + } + + default: + return false; + } +} + +CJSON_PUBLIC(void *) cJSON_malloc(size_t size) +{ + return global_hooks.allocate(size); +} + +CJSON_PUBLIC(void) cJSON_free(void *object) +{ + global_hooks.deallocate(object); +} diff --git a/src/cryptoconditions/src/include/cJSON.h b/src/cryptoconditions/src/include/cJSON.h new file mode 100644 index 000000000..1e388137e --- /dev/null +++ b/src/cryptoconditions/src/include/cJSON.h @@ -0,0 +1,263 @@ +/* + Copyright (c) 2009-2017 Dave Gamble and cJSON contributors + + 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. +*/ + +#ifndef cJSON__h +#define cJSON__h + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* project version */ +#define CJSON_VERSION_MAJOR 1 +#define CJSON_VERSION_MINOR 5 +#define CJSON_VERSION_PATCH 9 + +#include + +/* cJSON Types: */ +#define cJSON_Invalid (0) +#define cJSON_False (1 << 0) +#define cJSON_True (1 << 1) +#define cJSON_NULL (1 << 2) +#define cJSON_Number (1 << 3) +#define cJSON_String (1 << 4) +#define cJSON_Array (1 << 5) +#define cJSON_Object (1 << 6) +#define cJSON_Raw (1 << 7) /* raw json */ + +#define cJSON_IsReference 256 +#define cJSON_StringIsConst 512 + +/* The cJSON structure: */ +typedef struct cJSON +{ + /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON *next; + struct cJSON *prev; + /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ + struct cJSON *child; + + /* The type of the item, as above. */ + int type; + + /* The item's string, if type==cJSON_String and type == cJSON_Raw */ + char *valuestring; + /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ + int valueint; + /* The item's number, if type==cJSON_Number */ + double valuedouble; + + /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ + char *string; +} cJSON; + +typedef struct cJSON_Hooks +{ + void *(*malloc_fn)(size_t sz); + void (*free_fn)(void *ptr); +} cJSON_Hooks; + +typedef int cJSON_bool; + +#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) +#define __WINDOWS__ +#endif +#ifdef __WINDOWS__ + +/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 2 define options: + +CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols +CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) +CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol + +For *nix builds that support visibility attribute, you can define similar behavior by + +setting default visibility to hidden by adding +-fvisibility=hidden (for gcc) +or +-xldscope=hidden (for sun cc) +to CFLAGS + +then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does + +*/ + +/* export symbols by default, this is necessary for copy pasting the C and header file */ +#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_EXPORT_SYMBOLS +#endif + +#if defined(CJSON_HIDE_SYMBOLS) +#define CJSON_PUBLIC(type) type __stdcall +#elif defined(CJSON_EXPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllexport) type __stdcall +#elif defined(CJSON_IMPORT_SYMBOLS) +#define CJSON_PUBLIC(type) __declspec(dllimport) type __stdcall +#endif +#else /* !WIN32 */ +#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) +#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type +#else +#define CJSON_PUBLIC(type) type +#endif +#endif + +/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. + * This is to prevent stack overflows. */ +#ifndef CJSON_NESTING_LIMIT +#define CJSON_NESTING_LIMIT 1000 +#endif + +/* returns the version of cJSON as a string */ +CJSON_PUBLIC(const char*) cJSON_Version(void); + +/* Supply malloc, realloc and free functions to cJSON */ +CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); + +/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ +/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ +CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); +/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ +/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ +CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); + +/* Render a cJSON entity to text for transfer/storage. */ +CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); +/* Render a cJSON entity to text for transfer/storage without any formatting. */ +CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); +/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ +CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); +/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ +/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ +CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); +/* Delete a cJSON entity and all subentities. */ +CJSON_PUBLIC(void) cJSON_Delete(cJSON *c); + +/* Returns the number of items in an array (or object). */ +CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); +/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ +CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); +/* Get item "string" from object. Case insensitive. */ +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); +CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); +CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); +/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ +CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); + +/* These functions check the type of an item */ +CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); +CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); + +/* These calls create a cJSON item of the appropriate type. */ +CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); +CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); +CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); +/* raw json */ +CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); +CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); +CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); + +/* These utilities create an Array of count items. */ +CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); +CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count); + +/* Append item to the specified array/object. */ +CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); +/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. + * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before + * writing to `item->string` */ +CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); +/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ +CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); +CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); + +/* Remove/Detatch items from Arrays/Objects. */ +CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); +CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); +CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); +CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); +CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); + +/* Update array items. */ +CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ +CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); +CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); +CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); +CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); + +/* Duplicate a cJSON item */ +CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); +/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will +need to be released. With recurse!=0, it will duplicate any children connected to the item. +The item->next and ->prev pointers are always zero on return from Duplicate. */ +/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. + * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ +CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); + + +CJSON_PUBLIC(void) cJSON_Minify(char *json); + +/* Macros for creating things quickly. */ +#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) +#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) +#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) +#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) +#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) +#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) +#define cJSON_AddRawToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateRaw(s)) + +/* When assigning an integer value, it needs to be propagated to valuedouble too. */ +#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) +/* helper for the cJSON_SetNumberValue macro */ +CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); +#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) + +/* Macro for iterating over an array or object */ +#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) + +/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ +CJSON_PUBLIC(void *) cJSON_malloc(size_t size); +CJSON_PUBLIC(void) cJSON_free(void *object); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/cryptoconditions/src/include/ed25519/license.txt b/src/cryptoconditions/src/include/ed25519/license.txt new file mode 100644 index 000000000..c1503f912 --- /dev/null +++ b/src/cryptoconditions/src/include/ed25519/license.txt @@ -0,0 +1,16 @@ +Copyright (c) 2015 Orson Peters + +This software is provided 'as-is', without any express or implied warranty. In no event will the +authors be held liable for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, including commercial +applications, and to alter it and redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not claim that you wrote the + original software. If you use this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be misrepresented as + being the original software. + +3. This notice may not be removed or altered from any source distribution. diff --git a/src/cryptoconditions/src/include/ed25519/readme.md b/src/cryptoconditions/src/include/ed25519/readme.md new file mode 100644 index 000000000..89329bbe4 --- /dev/null +++ b/src/cryptoconditions/src/include/ed25519/readme.md @@ -0,0 +1,166 @@ +Ed25519 +======= + +This is a portable implementation of [Ed25519](http://ed25519.cr.yp.to/) based +on the SUPERCOP "ref10" implementation. Additionally there is key exchanging +and scalar addition included to further aid building a PKI using Ed25519. All +code is licensed under the permissive zlib license. + +All code is pure ANSI C without any dependencies, except for the random seed +generation which uses standard OS cryptography APIs (`CryptGenRandom` on +Windows, `/dev/urandom` on nix). If you wish to be entirely portable define +`ED25519_NO_SEED`. This disables the `ed25519_create_seed` function, so if your +application requires key generation you must supply your own seeding function +(which is simply a 256 bit (32 byte) cryptographic random number generator). + + +Performance +----------- + +On a Windows machine with an Intel Pentium B970 @ 2.3GHz I got the following +speeds (running on only one a single core): + + Seed generation: 64us (15625 per second) + Key generation: 88us (11364 per second) + Message signing (short message): 87us (11494 per second) + Message verifying (short message): 228us (4386 per second) + Scalar addition: 100us (10000 per second) + Key exchange: 220us (4545 per second) + +The speeds on other machines may vary. Sign/verify times will be higher with +longer messages. The implementation significantly benefits from 64 bit +architectures, if possible compile as 64 bit. + + +Usage +----- + +Simply add all .c and .h files in the `src/` folder to your project and include +`ed25519.h` in any file you want to use the API. If you prefer to use a shared +library, only copy `ed25519.h` and define `ED25519_DLL` before importing. A +windows DLL is pre-built. + +There are no defined types for seeds, private keys, public keys, shared secrets +or signatures. Instead simple `unsigned char` buffers are used with the +following sizes: + +```c +unsigned char seed[32]; +unsigned char signature[64]; +unsigned char public_key[32]; +unsigned char private_key[64]; +unsigned char scalar[32]; +unsigned char shared_secret[32]; +``` + +API +--- + +```c +int ed25519_create_seed(unsigned char *seed); +``` + +Creates a 32 byte random seed in `seed` for key generation. `seed` must be a +writable 32 byte buffer. Returns 0 on success, and nonzero on failure. + +```c +void ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key, + const unsigned char *seed); +``` + +Creates a new key pair from the given seed. `public_key` must be a writable 32 +byte buffer, `private_key` must be a writable 64 byte buffer and `seed` must be +a 32 byte buffer. + +```c +void ed25519_sign(unsigned char *signature, + const unsigned char *message, size_t message_len, + const unsigned char *public_key, const unsigned char *private_key); +``` + +Creates a signature of the given message with the given key pair. `signature` +must be a writable 64 byte buffer. `message` must have at least `message_len` +bytes to be read. + +```c +int ed25519_verify(const unsigned char *signature, + const unsigned char *message, size_t message_len, + const unsigned char *public_key); +``` + +Verifies the signature on the given message using `public_key`. `signature` +must be a readable 64 byte buffer. `message` must have at least `message_len` +bytes to be read. Returns 1 if the signature matches, 0 otherwise. + +```c +void ed25519_add_scalar(unsigned char *public_key, unsigned char *private_key, + const unsigned char *scalar); +``` + +Adds `scalar` to the given key pair where scalar is a 32 byte buffer (possibly +generated with `ed25519_create_seed`), generating a new key pair. You can +calculate the public key sum without knowing the private key and vice versa by +passing in `NULL` for the key you don't know. This is useful for enforcing +randomness on a key pair by a third party while only knowing the public key, +among other things. Warning: the last bit of the scalar is ignored - if +comparing scalars make sure to clear it with `scalar[31] &= 127`. + + +```c +void ed25519_key_exchange(unsigned char *shared_secret, + const unsigned char *public_key, const unsigned char *private_key); +``` + +Performs a key exchange on the given public key and private key, producing a +shared secret. It is recommended to hash the shared secret before using it. +`shared_secret` must be a 32 byte writable buffer where the shared secret will +be stored. + +Example +------- + +```c +unsigned char seed[32], public_key[32], private_key[64], signature[64]; +unsigned char other_public_key[32], other_private_key[64], shared_secret[32]; +const unsigned char message[] = "TEST MESSAGE"; + +/* create a random seed, and a key pair out of that seed */ +if (ed25519_create_seed(seed)) { + printf("error while generating seed\n"); + exit(1); +} + +ed25519_create_keypair(public_key, private_key, seed); + +/* create signature on the message with the key pair */ +ed25519_sign(signature, message, strlen(message), public_key, private_key); + +/* verify the signature */ +if (ed25519_verify(signature, message, strlen(message), public_key)) { + printf("valid signature\n"); +} else { + printf("invalid signature\n"); +} + +/* create a dummy keypair to use for a key exchange, normally you'd only have +the public key and receive it through some communication channel */ +if (ed25519_create_seed(seed)) { + printf("error while generating seed\n"); + exit(1); +} + +ed25519_create_keypair(other_public_key, other_private_key, seed); + +/* do a key exchange with other_public_key */ +ed25519_key_exchange(shared_secret, other_public_key, private_key); + +/* + the magic here is that ed25519_key_exchange(shared_secret, public_key, + other_private_key); would result in the same shared_secret +*/ + +``` + +License +------- +All code is released under the zlib license. See license.txt for details. diff --git a/src/cryptoconditions/src/include/ed25519/src/add_scalar.c b/src/cryptoconditions/src/include/ed25519/src/add_scalar.c new file mode 100644 index 000000000..7528a7a4a --- /dev/null +++ b/src/cryptoconditions/src/include/ed25519/src/add_scalar.c @@ -0,0 +1,69 @@ +#include "ed25519.h" +#include "ge.h" +#include "sc.h" +#include "sha512.h" + + +/* see http://crypto.stackexchange.com/a/6215/4697 */ +void ed25519_add_scalar(unsigned char *public_key, unsigned char *private_key, const unsigned char *scalar) { + const unsigned char SC_1[32] = {1}; /* scalar with value 1 */ + + unsigned char n[32]; + ge_p3 nB; + ge_p1p1 A_p1p1; + ge_p3 A; + ge_p3 public_key_unpacked; + ge_cached T; + + sha512_context hash; + unsigned char hashbuf[64]; + + int i; + + /* copy the scalar and clear highest bit */ + for (i = 0; i < 31; ++i) { + n[i] = scalar[i]; + } + n[31] = scalar[31] & 127; + + /* private key: a = n + t */ + if (private_key) { + sc_muladd(private_key, SC_1, n, private_key); + + // https://github.com/orlp/ed25519/issues/3 + sha512_init(&hash); + sha512_update(&hash, private_key + 32, 32); + sha512_update(&hash, scalar, 32); + sha512_final(&hash, hashbuf); + for (i = 0; i < 32; ++i) { + private_key[32 + i] = hashbuf[i]; + } + } + + /* public key: A = nB + T */ + if (public_key) { + /* if we know the private key we don't need a point addition, which is faster */ + /* using a "timing attack" you could find out wether or not we know the private + key, but this information seems rather useless - if this is important pass + public_key and private_key seperately in 2 function calls */ + if (private_key) { + ge_scalarmult_base(&A, private_key); + } else { + /* unpack public key into T */ + ge_frombytes_negate_vartime(&public_key_unpacked, public_key); + fe_neg(public_key_unpacked.X, public_key_unpacked.X); /* undo negate */ + fe_neg(public_key_unpacked.T, public_key_unpacked.T); /* undo negate */ + ge_p3_to_cached(&T, &public_key_unpacked); + + /* calculate n*B */ + ge_scalarmult_base(&nB, n); + + /* A = n*B + T */ + ge_add(&A_p1p1, &nB, &T); + ge_p1p1_to_p3(&A, &A_p1p1); + } + + /* pack public key */ + ge_p3_tobytes(public_key, &A); + } +} diff --git a/src/cryptoconditions/src/include/ed25519/src/ed25519.h b/src/cryptoconditions/src/include/ed25519/src/ed25519.h new file mode 100644 index 000000000..8924659fa --- /dev/null +++ b/src/cryptoconditions/src/include/ed25519/src/ed25519.h @@ -0,0 +1,38 @@ +#ifndef ED25519_H +#define ED25519_H + +#include + +#if defined(_WIN32) + #if defined(ED25519_BUILD_DLL) + #define ED25519_DECLSPEC __declspec(dllexport) + #elif defined(ED25519_DLL) + #define ED25519_DECLSPEC __declspec(dllimport) + #else + #define ED25519_DECLSPEC + #endif +#else + #define ED25519_DECLSPEC +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef ED25519_NO_SEED +int ED25519_DECLSPEC ed25519_create_seed(unsigned char *seed); +#endif + +void ED25519_DECLSPEC ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key, const unsigned char *seed); +void ED25519_DECLSPEC ed25519_sign(unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key, const unsigned char *private_key); +int ED25519_DECLSPEC ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key); +void ED25519_DECLSPEC ed25519_add_scalar(unsigned char *public_key, unsigned char *private_key, const unsigned char *scalar); +void ED25519_DECLSPEC ed25519_key_exchange(unsigned char *shared_secret, const unsigned char *public_key, const unsigned char *private_key); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/cryptoconditions/src/include/ed25519/src/fe.c b/src/cryptoconditions/src/include/ed25519/src/fe.c new file mode 100644 index 000000000..2105eb7b2 --- /dev/null +++ b/src/cryptoconditions/src/include/ed25519/src/fe.c @@ -0,0 +1,1491 @@ +#include "fixedint.h" +#include "fe.h" + + +/* + helper functions +*/ +static uint64_t load_3(const unsigned char *in) { + uint64_t result; + + result = (uint64_t) in[0]; + result |= ((uint64_t) in[1]) << 8; + result |= ((uint64_t) in[2]) << 16; + + return result; +} + +static uint64_t load_4(const unsigned char *in) { + uint64_t result; + + result = (uint64_t) in[0]; + result |= ((uint64_t) in[1]) << 8; + result |= ((uint64_t) in[2]) << 16; + result |= ((uint64_t) in[3]) << 24; + + return result; +} + + + +/* + h = 0 +*/ + +void fe_0(fe h) { + h[0] = 0; + h[1] = 0; + h[2] = 0; + h[3] = 0; + h[4] = 0; + h[5] = 0; + h[6] = 0; + h[7] = 0; + h[8] = 0; + h[9] = 0; +} + + + +/* + h = 1 +*/ + +void fe_1(fe h) { + h[0] = 1; + h[1] = 0; + h[2] = 0; + h[3] = 0; + h[4] = 0; + h[5] = 0; + h[6] = 0; + h[7] = 0; + h[8] = 0; + h[9] = 0; +} + + + +/* + h = f + g + Can overlap h with f or g. + + Preconditions: + |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + + Postconditions: + |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. +*/ + +void fe_add(fe h, const fe f, const fe g) { + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + int32_t g0 = g[0]; + int32_t g1 = g[1]; + int32_t g2 = g[2]; + int32_t g3 = g[3]; + int32_t g4 = g[4]; + int32_t g5 = g[5]; + int32_t g6 = g[6]; + int32_t g7 = g[7]; + int32_t g8 = g[8]; + int32_t g9 = g[9]; + int32_t h0 = f0 + g0; + int32_t h1 = f1 + g1; + int32_t h2 = f2 + g2; + int32_t h3 = f3 + g3; + int32_t h4 = f4 + g4; + int32_t h5 = f5 + g5; + int32_t h6 = f6 + g6; + int32_t h7 = f7 + g7; + int32_t h8 = f8 + g8; + int32_t h9 = f9 + g9; + + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; +} + + + +/* + Replace (f,g) with (g,g) if b == 1; + replace (f,g) with (f,g) if b == 0. + + Preconditions: b in {0,1}. +*/ + +void fe_cmov(fe f, const fe g, unsigned int b) { + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + int32_t g0 = g[0]; + int32_t g1 = g[1]; + int32_t g2 = g[2]; + int32_t g3 = g[3]; + int32_t g4 = g[4]; + int32_t g5 = g[5]; + int32_t g6 = g[6]; + int32_t g7 = g[7]; + int32_t g8 = g[8]; + int32_t g9 = g[9]; + int32_t x0 = f0 ^ g0; + int32_t x1 = f1 ^ g1; + int32_t x2 = f2 ^ g2; + int32_t x3 = f3 ^ g3; + int32_t x4 = f4 ^ g4; + int32_t x5 = f5 ^ g5; + int32_t x6 = f6 ^ g6; + int32_t x7 = f7 ^ g7; + int32_t x8 = f8 ^ g8; + int32_t x9 = f9 ^ g9; + + b = (unsigned int) (- (int) b); /* silence warning */ + x0 &= b; + x1 &= b; + x2 &= b; + x3 &= b; + x4 &= b; + x5 &= b; + x6 &= b; + x7 &= b; + x8 &= b; + x9 &= b; + + f[0] = f0 ^ x0; + f[1] = f1 ^ x1; + f[2] = f2 ^ x2; + f[3] = f3 ^ x3; + f[4] = f4 ^ x4; + f[5] = f5 ^ x5; + f[6] = f6 ^ x6; + f[7] = f7 ^ x7; + f[8] = f8 ^ x8; + f[9] = f9 ^ x9; +} + +/* + Replace (f,g) with (g,f) if b == 1; + replace (f,g) with (f,g) if b == 0. + + Preconditions: b in {0,1}. +*/ + +void fe_cswap(fe f,fe g,unsigned int b) { + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + int32_t g0 = g[0]; + int32_t g1 = g[1]; + int32_t g2 = g[2]; + int32_t g3 = g[3]; + int32_t g4 = g[4]; + int32_t g5 = g[5]; + int32_t g6 = g[6]; + int32_t g7 = g[7]; + int32_t g8 = g[8]; + int32_t g9 = g[9]; + int32_t x0 = f0 ^ g0; + int32_t x1 = f1 ^ g1; + int32_t x2 = f2 ^ g2; + int32_t x3 = f3 ^ g3; + int32_t x4 = f4 ^ g4; + int32_t x5 = f5 ^ g5; + int32_t x6 = f6 ^ g6; + int32_t x7 = f7 ^ g7; + int32_t x8 = f8 ^ g8; + int32_t x9 = f9 ^ g9; + b = (unsigned int) (- (int) b); /* silence warning */ + x0 &= b; + x1 &= b; + x2 &= b; + x3 &= b; + x4 &= b; + x5 &= b; + x6 &= b; + x7 &= b; + x8 &= b; + x9 &= b; + f[0] = f0 ^ x0; + f[1] = f1 ^ x1; + f[2] = f2 ^ x2; + f[3] = f3 ^ x3; + f[4] = f4 ^ x4; + f[5] = f5 ^ x5; + f[6] = f6 ^ x6; + f[7] = f7 ^ x7; + f[8] = f8 ^ x8; + f[9] = f9 ^ x9; + g[0] = g0 ^ x0; + g[1] = g1 ^ x1; + g[2] = g2 ^ x2; + g[3] = g3 ^ x3; + g[4] = g4 ^ x4; + g[5] = g5 ^ x5; + g[6] = g6 ^ x6; + g[7] = g7 ^ x7; + g[8] = g8 ^ x8; + g[9] = g9 ^ x9; +} + + + +/* + h = f +*/ + +void fe_copy(fe h, const fe f) { + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + + h[0] = f0; + h[1] = f1; + h[2] = f2; + h[3] = f3; + h[4] = f4; + h[5] = f5; + h[6] = f6; + h[7] = f7; + h[8] = f8; + h[9] = f9; +} + + + +/* + Ignores top bit of h. +*/ + +void fe_frombytes(fe h, const unsigned char *s) { + int64_t h0 = load_4(s); + int64_t h1 = load_3(s + 4) << 6; + int64_t h2 = load_3(s + 7) << 5; + int64_t h3 = load_3(s + 10) << 3; + int64_t h4 = load_3(s + 13) << 2; + int64_t h5 = load_4(s + 16); + int64_t h6 = load_3(s + 20) << 7; + int64_t h7 = load_3(s + 23) << 5; + int64_t h8 = load_3(s + 26) << 4; + int64_t h9 = (load_3(s + 29) & 8388607) << 2; + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + + carry9 = (h9 + (int64_t) (1 << 24)) >> 25; + h0 += carry9 * 19; + h9 -= carry9 << 25; + carry1 = (h1 + (int64_t) (1 << 24)) >> 25; + h2 += carry1; + h1 -= carry1 << 25; + carry3 = (h3 + (int64_t) (1 << 24)) >> 25; + h4 += carry3; + h3 -= carry3 << 25; + carry5 = (h5 + (int64_t) (1 << 24)) >> 25; + h6 += carry5; + h5 -= carry5 << 25; + carry7 = (h7 + (int64_t) (1 << 24)) >> 25; + h8 += carry7; + h7 -= carry7 << 25; + carry0 = (h0 + (int64_t) (1 << 25)) >> 26; + h1 += carry0; + h0 -= carry0 << 26; + carry2 = (h2 + (int64_t) (1 << 25)) >> 26; + h3 += carry2; + h2 -= carry2 << 26; + carry4 = (h4 + (int64_t) (1 << 25)) >> 26; + h5 += carry4; + h4 -= carry4 << 26; + carry6 = (h6 + (int64_t) (1 << 25)) >> 26; + h7 += carry6; + h6 -= carry6 << 26; + carry8 = (h8 + (int64_t) (1 << 25)) >> 26; + h9 += carry8; + h8 -= carry8 << 26; + + h[0] = (int32_t) h0; + h[1] = (int32_t) h1; + h[2] = (int32_t) h2; + h[3] = (int32_t) h3; + h[4] = (int32_t) h4; + h[5] = (int32_t) h5; + h[6] = (int32_t) h6; + h[7] = (int32_t) h7; + h[8] = (int32_t) h8; + h[9] = (int32_t) h9; +} + + + +void fe_invert(fe out, const fe z) { + fe t0; + fe t1; + fe t2; + fe t3; + int i; + + fe_sq(t0, z); + + for (i = 1; i < 1; ++i) { + fe_sq(t0, t0); + } + + fe_sq(t1, t0); + + for (i = 1; i < 2; ++i) { + fe_sq(t1, t1); + } + + fe_mul(t1, z, t1); + fe_mul(t0, t0, t1); + fe_sq(t2, t0); + + for (i = 1; i < 1; ++i) { + fe_sq(t2, t2); + } + + fe_mul(t1, t1, t2); + fe_sq(t2, t1); + + for (i = 1; i < 5; ++i) { + fe_sq(t2, t2); + } + + fe_mul(t1, t2, t1); + fe_sq(t2, t1); + + for (i = 1; i < 10; ++i) { + fe_sq(t2, t2); + } + + fe_mul(t2, t2, t1); + fe_sq(t3, t2); + + for (i = 1; i < 20; ++i) { + fe_sq(t3, t3); + } + + fe_mul(t2, t3, t2); + fe_sq(t2, t2); + + for (i = 1; i < 10; ++i) { + fe_sq(t2, t2); + } + + fe_mul(t1, t2, t1); + fe_sq(t2, t1); + + for (i = 1; i < 50; ++i) { + fe_sq(t2, t2); + } + + fe_mul(t2, t2, t1); + fe_sq(t3, t2); + + for (i = 1; i < 100; ++i) { + fe_sq(t3, t3); + } + + fe_mul(t2, t3, t2); + fe_sq(t2, t2); + + for (i = 1; i < 50; ++i) { + fe_sq(t2, t2); + } + + fe_mul(t1, t2, t1); + fe_sq(t1, t1); + + for (i = 1; i < 5; ++i) { + fe_sq(t1, t1); + } + + fe_mul(out, t1, t0); +} + + + +/* + return 1 if f is in {1,3,5,...,q-2} + return 0 if f is in {0,2,4,...,q-1} + + Preconditions: + |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. +*/ + +int fe_isnegative(const fe f) { + unsigned char s[32]; + + fe_tobytes(s, f); + + return s[0] & 1; +} + + + +/* + return 1 if f == 0 + return 0 if f != 0 + + Preconditions: + |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. +*/ + +int fe_isnonzero(const fe f) { + unsigned char s[32]; + unsigned char r; + + fe_tobytes(s, f); + + r = s[0]; + #define F(i) r |= s[i] + F(1); + F(2); + F(3); + F(4); + F(5); + F(6); + F(7); + F(8); + F(9); + F(10); + F(11); + F(12); + F(13); + F(14); + F(15); + F(16); + F(17); + F(18); + F(19); + F(20); + F(21); + F(22); + F(23); + F(24); + F(25); + F(26); + F(27); + F(28); + F(29); + F(30); + F(31); + #undef F + + return r != 0; +} + + + +/* + h = f * g + Can overlap h with f or g. + + Preconditions: + |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + |g| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + + Postconditions: + |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. + */ + + /* + Notes on implementation strategy: + + Using schoolbook multiplication. + Karatsuba would save a little in some cost models. + + Most multiplications by 2 and 19 are 32-bit precomputations; + cheaper than 64-bit postcomputations. + + There is one remaining multiplication by 19 in the carry chain; + one *19 precomputation can be merged into this, + but the resulting data flow is considerably less clean. + + There are 12 carries below. + 10 of them are 2-way parallelizable and vectorizable. + Can get away with 11 carries, but then data flow is much deeper. + + With tighter constraints on inputs can squeeze carries into int32. +*/ + +void fe_mul(fe h, const fe f, const fe g) { + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + int32_t g0 = g[0]; + int32_t g1 = g[1]; + int32_t g2 = g[2]; + int32_t g3 = g[3]; + int32_t g4 = g[4]; + int32_t g5 = g[5]; + int32_t g6 = g[6]; + int32_t g7 = g[7]; + int32_t g8 = g[8]; + int32_t g9 = g[9]; + int32_t g1_19 = 19 * g1; /* 1.959375*2^29 */ + int32_t g2_19 = 19 * g2; /* 1.959375*2^30; still ok */ + int32_t g3_19 = 19 * g3; + int32_t g4_19 = 19 * g4; + int32_t g5_19 = 19 * g5; + int32_t g6_19 = 19 * g6; + int32_t g7_19 = 19 * g7; + int32_t g8_19 = 19 * g8; + int32_t g9_19 = 19 * g9; + int32_t f1_2 = 2 * f1; + int32_t f3_2 = 2 * f3; + int32_t f5_2 = 2 * f5; + int32_t f7_2 = 2 * f7; + int32_t f9_2 = 2 * f9; + int64_t f0g0 = f0 * (int64_t) g0; + int64_t f0g1 = f0 * (int64_t) g1; + int64_t f0g2 = f0 * (int64_t) g2; + int64_t f0g3 = f0 * (int64_t) g3; + int64_t f0g4 = f0 * (int64_t) g4; + int64_t f0g5 = f0 * (int64_t) g5; + int64_t f0g6 = f0 * (int64_t) g6; + int64_t f0g7 = f0 * (int64_t) g7; + int64_t f0g8 = f0 * (int64_t) g8; + int64_t f0g9 = f0 * (int64_t) g9; + int64_t f1g0 = f1 * (int64_t) g0; + int64_t f1g1_2 = f1_2 * (int64_t) g1; + int64_t f1g2 = f1 * (int64_t) g2; + int64_t f1g3_2 = f1_2 * (int64_t) g3; + int64_t f1g4 = f1 * (int64_t) g4; + int64_t f1g5_2 = f1_2 * (int64_t) g5; + int64_t f1g6 = f1 * (int64_t) g6; + int64_t f1g7_2 = f1_2 * (int64_t) g7; + int64_t f1g8 = f1 * (int64_t) g8; + int64_t f1g9_38 = f1_2 * (int64_t) g9_19; + int64_t f2g0 = f2 * (int64_t) g0; + int64_t f2g1 = f2 * (int64_t) g1; + int64_t f2g2 = f2 * (int64_t) g2; + int64_t f2g3 = f2 * (int64_t) g3; + int64_t f2g4 = f2 * (int64_t) g4; + int64_t f2g5 = f2 * (int64_t) g5; + int64_t f2g6 = f2 * (int64_t) g6; + int64_t f2g7 = f2 * (int64_t) g7; + int64_t f2g8_19 = f2 * (int64_t) g8_19; + int64_t f2g9_19 = f2 * (int64_t) g9_19; + int64_t f3g0 = f3 * (int64_t) g0; + int64_t f3g1_2 = f3_2 * (int64_t) g1; + int64_t f3g2 = f3 * (int64_t) g2; + int64_t f3g3_2 = f3_2 * (int64_t) g3; + int64_t f3g4 = f3 * (int64_t) g4; + int64_t f3g5_2 = f3_2 * (int64_t) g5; + int64_t f3g6 = f3 * (int64_t) g6; + int64_t f3g7_38 = f3_2 * (int64_t) g7_19; + int64_t f3g8_19 = f3 * (int64_t) g8_19; + int64_t f3g9_38 = f3_2 * (int64_t) g9_19; + int64_t f4g0 = f4 * (int64_t) g0; + int64_t f4g1 = f4 * (int64_t) g1; + int64_t f4g2 = f4 * (int64_t) g2; + int64_t f4g3 = f4 * (int64_t) g3; + int64_t f4g4 = f4 * (int64_t) g4; + int64_t f4g5 = f4 * (int64_t) g5; + int64_t f4g6_19 = f4 * (int64_t) g6_19; + int64_t f4g7_19 = f4 * (int64_t) g7_19; + int64_t f4g8_19 = f4 * (int64_t) g8_19; + int64_t f4g9_19 = f4 * (int64_t) g9_19; + int64_t f5g0 = f5 * (int64_t) g0; + int64_t f5g1_2 = f5_2 * (int64_t) g1; + int64_t f5g2 = f5 * (int64_t) g2; + int64_t f5g3_2 = f5_2 * (int64_t) g3; + int64_t f5g4 = f5 * (int64_t) g4; + int64_t f5g5_38 = f5_2 * (int64_t) g5_19; + int64_t f5g6_19 = f5 * (int64_t) g6_19; + int64_t f5g7_38 = f5_2 * (int64_t) g7_19; + int64_t f5g8_19 = f5 * (int64_t) g8_19; + int64_t f5g9_38 = f5_2 * (int64_t) g9_19; + int64_t f6g0 = f6 * (int64_t) g0; + int64_t f6g1 = f6 * (int64_t) g1; + int64_t f6g2 = f6 * (int64_t) g2; + int64_t f6g3 = f6 * (int64_t) g3; + int64_t f6g4_19 = f6 * (int64_t) g4_19; + int64_t f6g5_19 = f6 * (int64_t) g5_19; + int64_t f6g6_19 = f6 * (int64_t) g6_19; + int64_t f6g7_19 = f6 * (int64_t) g7_19; + int64_t f6g8_19 = f6 * (int64_t) g8_19; + int64_t f6g9_19 = f6 * (int64_t) g9_19; + int64_t f7g0 = f7 * (int64_t) g0; + int64_t f7g1_2 = f7_2 * (int64_t) g1; + int64_t f7g2 = f7 * (int64_t) g2; + int64_t f7g3_38 = f7_2 * (int64_t) g3_19; + int64_t f7g4_19 = f7 * (int64_t) g4_19; + int64_t f7g5_38 = f7_2 * (int64_t) g5_19; + int64_t f7g6_19 = f7 * (int64_t) g6_19; + int64_t f7g7_38 = f7_2 * (int64_t) g7_19; + int64_t f7g8_19 = f7 * (int64_t) g8_19; + int64_t f7g9_38 = f7_2 * (int64_t) g9_19; + int64_t f8g0 = f8 * (int64_t) g0; + int64_t f8g1 = f8 * (int64_t) g1; + int64_t f8g2_19 = f8 * (int64_t) g2_19; + int64_t f8g3_19 = f8 * (int64_t) g3_19; + int64_t f8g4_19 = f8 * (int64_t) g4_19; + int64_t f8g5_19 = f8 * (int64_t) g5_19; + int64_t f8g6_19 = f8 * (int64_t) g6_19; + int64_t f8g7_19 = f8 * (int64_t) g7_19; + int64_t f8g8_19 = f8 * (int64_t) g8_19; + int64_t f8g9_19 = f8 * (int64_t) g9_19; + int64_t f9g0 = f9 * (int64_t) g0; + int64_t f9g1_38 = f9_2 * (int64_t) g1_19; + int64_t f9g2_19 = f9 * (int64_t) g2_19; + int64_t f9g3_38 = f9_2 * (int64_t) g3_19; + int64_t f9g4_19 = f9 * (int64_t) g4_19; + int64_t f9g5_38 = f9_2 * (int64_t) g5_19; + int64_t f9g6_19 = f9 * (int64_t) g6_19; + int64_t f9g7_38 = f9_2 * (int64_t) g7_19; + int64_t f9g8_19 = f9 * (int64_t) g8_19; + int64_t f9g9_38 = f9_2 * (int64_t) g9_19; + int64_t h0 = f0g0 + f1g9_38 + f2g8_19 + f3g7_38 + f4g6_19 + f5g5_38 + f6g4_19 + f7g3_38 + f8g2_19 + f9g1_38; + int64_t h1 = f0g1 + f1g0 + f2g9_19 + f3g8_19 + f4g7_19 + f5g6_19 + f6g5_19 + f7g4_19 + f8g3_19 + f9g2_19; + int64_t h2 = f0g2 + f1g1_2 + f2g0 + f3g9_38 + f4g8_19 + f5g7_38 + f6g6_19 + f7g5_38 + f8g4_19 + f9g3_38; + int64_t h3 = f0g3 + f1g2 + f2g1 + f3g0 + f4g9_19 + f5g8_19 + f6g7_19 + f7g6_19 + f8g5_19 + f9g4_19; + int64_t h4 = f0g4 + f1g3_2 + f2g2 + f3g1_2 + f4g0 + f5g9_38 + f6g8_19 + f7g7_38 + f8g6_19 + f9g5_38; + int64_t h5 = f0g5 + f1g4 + f2g3 + f3g2 + f4g1 + f5g0 + f6g9_19 + f7g8_19 + f8g7_19 + f9g6_19; + int64_t h6 = f0g6 + f1g5_2 + f2g4 + f3g3_2 + f4g2 + f5g1_2 + f6g0 + f7g9_38 + f8g8_19 + f9g7_38; + int64_t h7 = f0g7 + f1g6 + f2g5 + f3g4 + f4g3 + f5g2 + f6g1 + f7g0 + f8g9_19 + f9g8_19; + int64_t h8 = f0g8 + f1g7_2 + f2g6 + f3g5_2 + f4g4 + f5g3_2 + f6g2 + f7g1_2 + f8g0 + f9g9_38; + int64_t h9 = f0g9 + f1g8 + f2g7 + f3g6 + f4g5 + f5g4 + f6g3 + f7g2 + f8g1 + f9g0 ; + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + + carry0 = (h0 + (int64_t) (1 << 25)) >> 26; + h1 += carry0; + h0 -= carry0 << 26; + carry4 = (h4 + (int64_t) (1 << 25)) >> 26; + h5 += carry4; + h4 -= carry4 << 26; + + carry1 = (h1 + (int64_t) (1 << 24)) >> 25; + h2 += carry1; + h1 -= carry1 << 25; + carry5 = (h5 + (int64_t) (1 << 24)) >> 25; + h6 += carry5; + h5 -= carry5 << 25; + + carry2 = (h2 + (int64_t) (1 << 25)) >> 26; + h3 += carry2; + h2 -= carry2 << 26; + carry6 = (h6 + (int64_t) (1 << 25)) >> 26; + h7 += carry6; + h6 -= carry6 << 26; + + carry3 = (h3 + (int64_t) (1 << 24)) >> 25; + h4 += carry3; + h3 -= carry3 << 25; + carry7 = (h7 + (int64_t) (1 << 24)) >> 25; + h8 += carry7; + h7 -= carry7 << 25; + + carry4 = (h4 + (int64_t) (1 << 25)) >> 26; + h5 += carry4; + h4 -= carry4 << 26; + carry8 = (h8 + (int64_t) (1 << 25)) >> 26; + h9 += carry8; + h8 -= carry8 << 26; + + carry9 = (h9 + (int64_t) (1 << 24)) >> 25; + h0 += carry9 * 19; + h9 -= carry9 << 25; + + carry0 = (h0 + (int64_t) (1 << 25)) >> 26; + h1 += carry0; + h0 -= carry0 << 26; + + h[0] = (int32_t) h0; + h[1] = (int32_t) h1; + h[2] = (int32_t) h2; + h[3] = (int32_t) h3; + h[4] = (int32_t) h4; + h[5] = (int32_t) h5; + h[6] = (int32_t) h6; + h[7] = (int32_t) h7; + h[8] = (int32_t) h8; + h[9] = (int32_t) h9; +} + + +/* +h = f * 121666 +Can overlap h with f. + +Preconditions: + |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + +Postconditions: + |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +*/ + +void fe_mul121666(fe h, fe f) { + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + int64_t h0 = f0 * (int64_t) 121666; + int64_t h1 = f1 * (int64_t) 121666; + int64_t h2 = f2 * (int64_t) 121666; + int64_t h3 = f3 * (int64_t) 121666; + int64_t h4 = f4 * (int64_t) 121666; + int64_t h5 = f5 * (int64_t) 121666; + int64_t h6 = f6 * (int64_t) 121666; + int64_t h7 = f7 * (int64_t) 121666; + int64_t h8 = f8 * (int64_t) 121666; + int64_t h9 = f9 * (int64_t) 121666; + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + + carry9 = (h9 + (int64_t) (1<<24)) >> 25; h0 += carry9 * 19; h9 -= carry9 << 25; + carry1 = (h1 + (int64_t) (1<<24)) >> 25; h2 += carry1; h1 -= carry1 << 25; + carry3 = (h3 + (int64_t) (1<<24)) >> 25; h4 += carry3; h3 -= carry3 << 25; + carry5 = (h5 + (int64_t) (1<<24)) >> 25; h6 += carry5; h5 -= carry5 << 25; + carry7 = (h7 + (int64_t) (1<<24)) >> 25; h8 += carry7; h7 -= carry7 << 25; + + carry0 = (h0 + (int64_t) (1<<25)) >> 26; h1 += carry0; h0 -= carry0 << 26; + carry2 = (h2 + (int64_t) (1<<25)) >> 26; h3 += carry2; h2 -= carry2 << 26; + carry4 = (h4 + (int64_t) (1<<25)) >> 26; h5 += carry4; h4 -= carry4 << 26; + carry6 = (h6 + (int64_t) (1<<25)) >> 26; h7 += carry6; h6 -= carry6 << 26; + carry8 = (h8 + (int64_t) (1<<25)) >> 26; h9 += carry8; h8 -= carry8 << 26; + + h[0] = (int32_t) h0; + h[1] = (int32_t) h1; + h[2] = (int32_t) h2; + h[3] = (int32_t) h3; + h[4] = (int32_t) h4; + h[5] = (int32_t) h5; + h[6] = (int32_t) h6; + h[7] = (int32_t) h7; + h[8] = (int32_t) h8; + h[9] = (int32_t) h9; +} + + +/* +h = -f + +Preconditions: + |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + +Postconditions: + |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. +*/ + +void fe_neg(fe h, const fe f) { + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + int32_t h0 = -f0; + int32_t h1 = -f1; + int32_t h2 = -f2; + int32_t h3 = -f3; + int32_t h4 = -f4; + int32_t h5 = -f5; + int32_t h6 = -f6; + int32_t h7 = -f7; + int32_t h8 = -f8; + int32_t h9 = -f9; + + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; +} + + +void fe_pow22523(fe out, const fe z) { + fe t0; + fe t1; + fe t2; + int i; + fe_sq(t0, z); + + for (i = 1; i < 1; ++i) { + fe_sq(t0, t0); + } + + fe_sq(t1, t0); + + for (i = 1; i < 2; ++i) { + fe_sq(t1, t1); + } + + fe_mul(t1, z, t1); + fe_mul(t0, t0, t1); + fe_sq(t0, t0); + + for (i = 1; i < 1; ++i) { + fe_sq(t0, t0); + } + + fe_mul(t0, t1, t0); + fe_sq(t1, t0); + + for (i = 1; i < 5; ++i) { + fe_sq(t1, t1); + } + + fe_mul(t0, t1, t0); + fe_sq(t1, t0); + + for (i = 1; i < 10; ++i) { + fe_sq(t1, t1); + } + + fe_mul(t1, t1, t0); + fe_sq(t2, t1); + + for (i = 1; i < 20; ++i) { + fe_sq(t2, t2); + } + + fe_mul(t1, t2, t1); + fe_sq(t1, t1); + + for (i = 1; i < 10; ++i) { + fe_sq(t1, t1); + } + + fe_mul(t0, t1, t0); + fe_sq(t1, t0); + + for (i = 1; i < 50; ++i) { + fe_sq(t1, t1); + } + + fe_mul(t1, t1, t0); + fe_sq(t2, t1); + + for (i = 1; i < 100; ++i) { + fe_sq(t2, t2); + } + + fe_mul(t1, t2, t1); + fe_sq(t1, t1); + + for (i = 1; i < 50; ++i) { + fe_sq(t1, t1); + } + + fe_mul(t0, t1, t0); + fe_sq(t0, t0); + + for (i = 1; i < 2; ++i) { + fe_sq(t0, t0); + } + + fe_mul(out, t0, z); + return; +} + + +/* +h = f * f +Can overlap h with f. + +Preconditions: + |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + +Postconditions: + |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. +*/ + +/* +See fe_mul.c for discussion of implementation strategy. +*/ + +void fe_sq(fe h, const fe f) { + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + int32_t f0_2 = 2 * f0; + int32_t f1_2 = 2 * f1; + int32_t f2_2 = 2 * f2; + int32_t f3_2 = 2 * f3; + int32_t f4_2 = 2 * f4; + int32_t f5_2 = 2 * f5; + int32_t f6_2 = 2 * f6; + int32_t f7_2 = 2 * f7; + int32_t f5_38 = 38 * f5; /* 1.959375*2^30 */ + int32_t f6_19 = 19 * f6; /* 1.959375*2^30 */ + int32_t f7_38 = 38 * f7; /* 1.959375*2^30 */ + int32_t f8_19 = 19 * f8; /* 1.959375*2^30 */ + int32_t f9_38 = 38 * f9; /* 1.959375*2^30 */ + int64_t f0f0 = f0 * (int64_t) f0; + int64_t f0f1_2 = f0_2 * (int64_t) f1; + int64_t f0f2_2 = f0_2 * (int64_t) f2; + int64_t f0f3_2 = f0_2 * (int64_t) f3; + int64_t f0f4_2 = f0_2 * (int64_t) f4; + int64_t f0f5_2 = f0_2 * (int64_t) f5; + int64_t f0f6_2 = f0_2 * (int64_t) f6; + int64_t f0f7_2 = f0_2 * (int64_t) f7; + int64_t f0f8_2 = f0_2 * (int64_t) f8; + int64_t f0f9_2 = f0_2 * (int64_t) f9; + int64_t f1f1_2 = f1_2 * (int64_t) f1; + int64_t f1f2_2 = f1_2 * (int64_t) f2; + int64_t f1f3_4 = f1_2 * (int64_t) f3_2; + int64_t f1f4_2 = f1_2 * (int64_t) f4; + int64_t f1f5_4 = f1_2 * (int64_t) f5_2; + int64_t f1f6_2 = f1_2 * (int64_t) f6; + int64_t f1f7_4 = f1_2 * (int64_t) f7_2; + int64_t f1f8_2 = f1_2 * (int64_t) f8; + int64_t f1f9_76 = f1_2 * (int64_t) f9_38; + int64_t f2f2 = f2 * (int64_t) f2; + int64_t f2f3_2 = f2_2 * (int64_t) f3; + int64_t f2f4_2 = f2_2 * (int64_t) f4; + int64_t f2f5_2 = f2_2 * (int64_t) f5; + int64_t f2f6_2 = f2_2 * (int64_t) f6; + int64_t f2f7_2 = f2_2 * (int64_t) f7; + int64_t f2f8_38 = f2_2 * (int64_t) f8_19; + int64_t f2f9_38 = f2 * (int64_t) f9_38; + int64_t f3f3_2 = f3_2 * (int64_t) f3; + int64_t f3f4_2 = f3_2 * (int64_t) f4; + int64_t f3f5_4 = f3_2 * (int64_t) f5_2; + int64_t f3f6_2 = f3_2 * (int64_t) f6; + int64_t f3f7_76 = f3_2 * (int64_t) f7_38; + int64_t f3f8_38 = f3_2 * (int64_t) f8_19; + int64_t f3f9_76 = f3_2 * (int64_t) f9_38; + int64_t f4f4 = f4 * (int64_t) f4; + int64_t f4f5_2 = f4_2 * (int64_t) f5; + int64_t f4f6_38 = f4_2 * (int64_t) f6_19; + int64_t f4f7_38 = f4 * (int64_t) f7_38; + int64_t f4f8_38 = f4_2 * (int64_t) f8_19; + int64_t f4f9_38 = f4 * (int64_t) f9_38; + int64_t f5f5_38 = f5 * (int64_t) f5_38; + int64_t f5f6_38 = f5_2 * (int64_t) f6_19; + int64_t f5f7_76 = f5_2 * (int64_t) f7_38; + int64_t f5f8_38 = f5_2 * (int64_t) f8_19; + int64_t f5f9_76 = f5_2 * (int64_t) f9_38; + int64_t f6f6_19 = f6 * (int64_t) f6_19; + int64_t f6f7_38 = f6 * (int64_t) f7_38; + int64_t f6f8_38 = f6_2 * (int64_t) f8_19; + int64_t f6f9_38 = f6 * (int64_t) f9_38; + int64_t f7f7_38 = f7 * (int64_t) f7_38; + int64_t f7f8_38 = f7_2 * (int64_t) f8_19; + int64_t f7f9_76 = f7_2 * (int64_t) f9_38; + int64_t f8f8_19 = f8 * (int64_t) f8_19; + int64_t f8f9_38 = f8 * (int64_t) f9_38; + int64_t f9f9_38 = f9 * (int64_t) f9_38; + int64_t h0 = f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38; + int64_t h1 = f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38; + int64_t h2 = f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19; + int64_t h3 = f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38; + int64_t h4 = f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38; + int64_t h5 = f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38; + int64_t h6 = f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19; + int64_t h7 = f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38; + int64_t h8 = f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38; + int64_t h9 = f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2; + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + carry0 = (h0 + (int64_t) (1 << 25)) >> 26; + h1 += carry0; + h0 -= carry0 << 26; + carry4 = (h4 + (int64_t) (1 << 25)) >> 26; + h5 += carry4; + h4 -= carry4 << 26; + carry1 = (h1 + (int64_t) (1 << 24)) >> 25; + h2 += carry1; + h1 -= carry1 << 25; + carry5 = (h5 + (int64_t) (1 << 24)) >> 25; + h6 += carry5; + h5 -= carry5 << 25; + carry2 = (h2 + (int64_t) (1 << 25)) >> 26; + h3 += carry2; + h2 -= carry2 << 26; + carry6 = (h6 + (int64_t) (1 << 25)) >> 26; + h7 += carry6; + h6 -= carry6 << 26; + carry3 = (h3 + (int64_t) (1 << 24)) >> 25; + h4 += carry3; + h3 -= carry3 << 25; + carry7 = (h7 + (int64_t) (1 << 24)) >> 25; + h8 += carry7; + h7 -= carry7 << 25; + carry4 = (h4 + (int64_t) (1 << 25)) >> 26; + h5 += carry4; + h4 -= carry4 << 26; + carry8 = (h8 + (int64_t) (1 << 25)) >> 26; + h9 += carry8; + h8 -= carry8 << 26; + carry9 = (h9 + (int64_t) (1 << 24)) >> 25; + h0 += carry9 * 19; + h9 -= carry9 << 25; + carry0 = (h0 + (int64_t) (1 << 25)) >> 26; + h1 += carry0; + h0 -= carry0 << 26; + h[0] = (int32_t) h0; + h[1] = (int32_t) h1; + h[2] = (int32_t) h2; + h[3] = (int32_t) h3; + h[4] = (int32_t) h4; + h[5] = (int32_t) h5; + h[6] = (int32_t) h6; + h[7] = (int32_t) h7; + h[8] = (int32_t) h8; + h[9] = (int32_t) h9; +} + + +/* +h = 2 * f * f +Can overlap h with f. + +Preconditions: + |f| bounded by 1.65*2^26,1.65*2^25,1.65*2^26,1.65*2^25,etc. + +Postconditions: + |h| bounded by 1.01*2^25,1.01*2^24,1.01*2^25,1.01*2^24,etc. +*/ + +/* +See fe_mul.c for discussion of implementation strategy. +*/ + +void fe_sq2(fe h, const fe f) { + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + int32_t f0_2 = 2 * f0; + int32_t f1_2 = 2 * f1; + int32_t f2_2 = 2 * f2; + int32_t f3_2 = 2 * f3; + int32_t f4_2 = 2 * f4; + int32_t f5_2 = 2 * f5; + int32_t f6_2 = 2 * f6; + int32_t f7_2 = 2 * f7; + int32_t f5_38 = 38 * f5; /* 1.959375*2^30 */ + int32_t f6_19 = 19 * f6; /* 1.959375*2^30 */ + int32_t f7_38 = 38 * f7; /* 1.959375*2^30 */ + int32_t f8_19 = 19 * f8; /* 1.959375*2^30 */ + int32_t f9_38 = 38 * f9; /* 1.959375*2^30 */ + int64_t f0f0 = f0 * (int64_t) f0; + int64_t f0f1_2 = f0_2 * (int64_t) f1; + int64_t f0f2_2 = f0_2 * (int64_t) f2; + int64_t f0f3_2 = f0_2 * (int64_t) f3; + int64_t f0f4_2 = f0_2 * (int64_t) f4; + int64_t f0f5_2 = f0_2 * (int64_t) f5; + int64_t f0f6_2 = f0_2 * (int64_t) f6; + int64_t f0f7_2 = f0_2 * (int64_t) f7; + int64_t f0f8_2 = f0_2 * (int64_t) f8; + int64_t f0f9_2 = f0_2 * (int64_t) f9; + int64_t f1f1_2 = f1_2 * (int64_t) f1; + int64_t f1f2_2 = f1_2 * (int64_t) f2; + int64_t f1f3_4 = f1_2 * (int64_t) f3_2; + int64_t f1f4_2 = f1_2 * (int64_t) f4; + int64_t f1f5_4 = f1_2 * (int64_t) f5_2; + int64_t f1f6_2 = f1_2 * (int64_t) f6; + int64_t f1f7_4 = f1_2 * (int64_t) f7_2; + int64_t f1f8_2 = f1_2 * (int64_t) f8; + int64_t f1f9_76 = f1_2 * (int64_t) f9_38; + int64_t f2f2 = f2 * (int64_t) f2; + int64_t f2f3_2 = f2_2 * (int64_t) f3; + int64_t f2f4_2 = f2_2 * (int64_t) f4; + int64_t f2f5_2 = f2_2 * (int64_t) f5; + int64_t f2f6_2 = f2_2 * (int64_t) f6; + int64_t f2f7_2 = f2_2 * (int64_t) f7; + int64_t f2f8_38 = f2_2 * (int64_t) f8_19; + int64_t f2f9_38 = f2 * (int64_t) f9_38; + int64_t f3f3_2 = f3_2 * (int64_t) f3; + int64_t f3f4_2 = f3_2 * (int64_t) f4; + int64_t f3f5_4 = f3_2 * (int64_t) f5_2; + int64_t f3f6_2 = f3_2 * (int64_t) f6; + int64_t f3f7_76 = f3_2 * (int64_t) f7_38; + int64_t f3f8_38 = f3_2 * (int64_t) f8_19; + int64_t f3f9_76 = f3_2 * (int64_t) f9_38; + int64_t f4f4 = f4 * (int64_t) f4; + int64_t f4f5_2 = f4_2 * (int64_t) f5; + int64_t f4f6_38 = f4_2 * (int64_t) f6_19; + int64_t f4f7_38 = f4 * (int64_t) f7_38; + int64_t f4f8_38 = f4_2 * (int64_t) f8_19; + int64_t f4f9_38 = f4 * (int64_t) f9_38; + int64_t f5f5_38 = f5 * (int64_t) f5_38; + int64_t f5f6_38 = f5_2 * (int64_t) f6_19; + int64_t f5f7_76 = f5_2 * (int64_t) f7_38; + int64_t f5f8_38 = f5_2 * (int64_t) f8_19; + int64_t f5f9_76 = f5_2 * (int64_t) f9_38; + int64_t f6f6_19 = f6 * (int64_t) f6_19; + int64_t f6f7_38 = f6 * (int64_t) f7_38; + int64_t f6f8_38 = f6_2 * (int64_t) f8_19; + int64_t f6f9_38 = f6 * (int64_t) f9_38; + int64_t f7f7_38 = f7 * (int64_t) f7_38; + int64_t f7f8_38 = f7_2 * (int64_t) f8_19; + int64_t f7f9_76 = f7_2 * (int64_t) f9_38; + int64_t f8f8_19 = f8 * (int64_t) f8_19; + int64_t f8f9_38 = f8 * (int64_t) f9_38; + int64_t f9f9_38 = f9 * (int64_t) f9_38; + int64_t h0 = f0f0 + f1f9_76 + f2f8_38 + f3f7_76 + f4f6_38 + f5f5_38; + int64_t h1 = f0f1_2 + f2f9_38 + f3f8_38 + f4f7_38 + f5f6_38; + int64_t h2 = f0f2_2 + f1f1_2 + f3f9_76 + f4f8_38 + f5f7_76 + f6f6_19; + int64_t h3 = f0f3_2 + f1f2_2 + f4f9_38 + f5f8_38 + f6f7_38; + int64_t h4 = f0f4_2 + f1f3_4 + f2f2 + f5f9_76 + f6f8_38 + f7f7_38; + int64_t h5 = f0f5_2 + f1f4_2 + f2f3_2 + f6f9_38 + f7f8_38; + int64_t h6 = f0f6_2 + f1f5_4 + f2f4_2 + f3f3_2 + f7f9_76 + f8f8_19; + int64_t h7 = f0f7_2 + f1f6_2 + f2f5_2 + f3f4_2 + f8f9_38; + int64_t h8 = f0f8_2 + f1f7_4 + f2f6_2 + f3f5_4 + f4f4 + f9f9_38; + int64_t h9 = f0f9_2 + f1f8_2 + f2f7_2 + f3f6_2 + f4f5_2; + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + h0 += h0; + h1 += h1; + h2 += h2; + h3 += h3; + h4 += h4; + h5 += h5; + h6 += h6; + h7 += h7; + h8 += h8; + h9 += h9; + carry0 = (h0 + (int64_t) (1 << 25)) >> 26; + h1 += carry0; + h0 -= carry0 << 26; + carry4 = (h4 + (int64_t) (1 << 25)) >> 26; + h5 += carry4; + h4 -= carry4 << 26; + carry1 = (h1 + (int64_t) (1 << 24)) >> 25; + h2 += carry1; + h1 -= carry1 << 25; + carry5 = (h5 + (int64_t) (1 << 24)) >> 25; + h6 += carry5; + h5 -= carry5 << 25; + carry2 = (h2 + (int64_t) (1 << 25)) >> 26; + h3 += carry2; + h2 -= carry2 << 26; + carry6 = (h6 + (int64_t) (1 << 25)) >> 26; + h7 += carry6; + h6 -= carry6 << 26; + carry3 = (h3 + (int64_t) (1 << 24)) >> 25; + h4 += carry3; + h3 -= carry3 << 25; + carry7 = (h7 + (int64_t) (1 << 24)) >> 25; + h8 += carry7; + h7 -= carry7 << 25; + carry4 = (h4 + (int64_t) (1 << 25)) >> 26; + h5 += carry4; + h4 -= carry4 << 26; + carry8 = (h8 + (int64_t) (1 << 25)) >> 26; + h9 += carry8; + h8 -= carry8 << 26; + carry9 = (h9 + (int64_t) (1 << 24)) >> 25; + h0 += carry9 * 19; + h9 -= carry9 << 25; + carry0 = (h0 + (int64_t) (1 << 25)) >> 26; + h1 += carry0; + h0 -= carry0 << 26; + h[0] = (int32_t) h0; + h[1] = (int32_t) h1; + h[2] = (int32_t) h2; + h[3] = (int32_t) h3; + h[4] = (int32_t) h4; + h[5] = (int32_t) h5; + h[6] = (int32_t) h6; + h[7] = (int32_t) h7; + h[8] = (int32_t) h8; + h[9] = (int32_t) h9; +} + + +/* +h = f - g +Can overlap h with f or g. + +Preconditions: + |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + +Postconditions: + |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. +*/ + +void fe_sub(fe h, const fe f, const fe g) { + int32_t f0 = f[0]; + int32_t f1 = f[1]; + int32_t f2 = f[2]; + int32_t f3 = f[3]; + int32_t f4 = f[4]; + int32_t f5 = f[5]; + int32_t f6 = f[6]; + int32_t f7 = f[7]; + int32_t f8 = f[8]; + int32_t f9 = f[9]; + int32_t g0 = g[0]; + int32_t g1 = g[1]; + int32_t g2 = g[2]; + int32_t g3 = g[3]; + int32_t g4 = g[4]; + int32_t g5 = g[5]; + int32_t g6 = g[6]; + int32_t g7 = g[7]; + int32_t g8 = g[8]; + int32_t g9 = g[9]; + int32_t h0 = f0 - g0; + int32_t h1 = f1 - g1; + int32_t h2 = f2 - g2; + int32_t h3 = f3 - g3; + int32_t h4 = f4 - g4; + int32_t h5 = f5 - g5; + int32_t h6 = f6 - g6; + int32_t h7 = f7 - g7; + int32_t h8 = f8 - g8; + int32_t h9 = f9 - g9; + + h[0] = h0; + h[1] = h1; + h[2] = h2; + h[3] = h3; + h[4] = h4; + h[5] = h5; + h[6] = h6; + h[7] = h7; + h[8] = h8; + h[9] = h9; +} + + + +/* +Preconditions: + |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + +Write p=2^255-19; q=floor(h/p). +Basic claim: q = floor(2^(-255)(h + 19 2^(-25)h9 + 2^(-1))). + +Proof: + Have |h|<=p so |q|<=1 so |19^2 2^(-255) q|<1/4. + Also have |h-2^230 h9|<2^231 so |19 2^(-255)(h-2^230 h9)|<1/4. + + Write y=2^(-1)-19^2 2^(-255)q-19 2^(-255)(h-2^230 h9). + Then 0> 25; + q = (h0 + q) >> 26; + q = (h1 + q) >> 25; + q = (h2 + q) >> 26; + q = (h3 + q) >> 25; + q = (h4 + q) >> 26; + q = (h5 + q) >> 25; + q = (h6 + q) >> 26; + q = (h7 + q) >> 25; + q = (h8 + q) >> 26; + q = (h9 + q) >> 25; + /* Goal: Output h-(2^255-19)q, which is between 0 and 2^255-20. */ + h0 += 19 * q; + /* Goal: Output h-2^255 q, which is between 0 and 2^255-20. */ + carry0 = h0 >> 26; + h1 += carry0; + h0 -= carry0 << 26; + carry1 = h1 >> 25; + h2 += carry1; + h1 -= carry1 << 25; + carry2 = h2 >> 26; + h3 += carry2; + h2 -= carry2 << 26; + carry3 = h3 >> 25; + h4 += carry3; + h3 -= carry3 << 25; + carry4 = h4 >> 26; + h5 += carry4; + h4 -= carry4 << 26; + carry5 = h5 >> 25; + h6 += carry5; + h5 -= carry5 << 25; + carry6 = h6 >> 26; + h7 += carry6; + h6 -= carry6 << 26; + carry7 = h7 >> 25; + h8 += carry7; + h7 -= carry7 << 25; + carry8 = h8 >> 26; + h9 += carry8; + h8 -= carry8 << 26; + carry9 = h9 >> 25; + h9 -= carry9 << 25; + + /* h10 = carry9 */ + /* + Goal: Output h0+...+2^255 h10-2^255 q, which is between 0 and 2^255-20. + Have h0+...+2^230 h9 between 0 and 2^255-1; + evidently 2^255 h10-2^255 q = 0. + Goal: Output h0+...+2^230 h9. + */ + s[0] = (unsigned char) (h0 >> 0); + s[1] = (unsigned char) (h0 >> 8); + s[2] = (unsigned char) (h0 >> 16); + s[3] = (unsigned char) ((h0 >> 24) | (h1 << 2)); + s[4] = (unsigned char) (h1 >> 6); + s[5] = (unsigned char) (h1 >> 14); + s[6] = (unsigned char) ((h1 >> 22) | (h2 << 3)); + s[7] = (unsigned char) (h2 >> 5); + s[8] = (unsigned char) (h2 >> 13); + s[9] = (unsigned char) ((h2 >> 21) | (h3 << 5)); + s[10] = (unsigned char) (h3 >> 3); + s[11] = (unsigned char) (h3 >> 11); + s[12] = (unsigned char) ((h3 >> 19) | (h4 << 6)); + s[13] = (unsigned char) (h4 >> 2); + s[14] = (unsigned char) (h4 >> 10); + s[15] = (unsigned char) (h4 >> 18); + s[16] = (unsigned char) (h5 >> 0); + s[17] = (unsigned char) (h5 >> 8); + s[18] = (unsigned char) (h5 >> 16); + s[19] = (unsigned char) ((h5 >> 24) | (h6 << 1)); + s[20] = (unsigned char) (h6 >> 7); + s[21] = (unsigned char) (h6 >> 15); + s[22] = (unsigned char) ((h6 >> 23) | (h7 << 3)); + s[23] = (unsigned char) (h7 >> 5); + s[24] = (unsigned char) (h7 >> 13); + s[25] = (unsigned char) ((h7 >> 21) | (h8 << 4)); + s[26] = (unsigned char) (h8 >> 4); + s[27] = (unsigned char) (h8 >> 12); + s[28] = (unsigned char) ((h8 >> 20) | (h9 << 6)); + s[29] = (unsigned char) (h9 >> 2); + s[30] = (unsigned char) (h9 >> 10); + s[31] = (unsigned char) (h9 >> 18); +} diff --git a/src/cryptoconditions/src/include/ed25519/src/fe.h b/src/cryptoconditions/src/include/ed25519/src/fe.h new file mode 100644 index 000000000..b4b62d282 --- /dev/null +++ b/src/cryptoconditions/src/include/ed25519/src/fe.h @@ -0,0 +1,41 @@ +#ifndef FE_H +#define FE_H + +#include "fixedint.h" + + +/* + fe means field element. + Here the field is \Z/(2^255-19). + An element t, entries t[0]...t[9], represents the integer + t[0]+2^26 t[1]+2^51 t[2]+2^77 t[3]+2^102 t[4]+...+2^230 t[9]. + Bounds on each t[i] vary depending on context. +*/ + + +typedef int32_t fe[10]; + + +void fe_0(fe h); +void fe_1(fe h); + +void fe_frombytes(fe h, const unsigned char *s); +void fe_tobytes(unsigned char *s, const fe h); + +void fe_copy(fe h, const fe f); +int fe_isnegative(const fe f); +int fe_isnonzero(const fe f); +void fe_cmov(fe f, const fe g, unsigned int b); +void fe_cswap(fe f, fe g, unsigned int b); + +void fe_neg(fe h, const fe f); +void fe_add(fe h, const fe f, const fe g); +void fe_invert(fe out, const fe z); +void fe_sq(fe h, const fe f); +void fe_sq2(fe h, const fe f); +void fe_mul(fe h, const fe f, const fe g); +void fe_mul121666(fe h, fe f); +void fe_pow22523(fe out, const fe z); +void fe_sub(fe h, const fe f, const fe g); + +#endif diff --git a/src/cryptoconditions/src/include/ed25519/src/fixedint.h b/src/cryptoconditions/src/include/ed25519/src/fixedint.h new file mode 100644 index 000000000..1a8745b1e --- /dev/null +++ b/src/cryptoconditions/src/include/ed25519/src/fixedint.h @@ -0,0 +1,72 @@ +/* + Portable header to provide the 32 and 64 bits type. + + Not a compatible replacement for , do not blindly use it as such. +*/ + +#if ((defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined(__WATCOMC__) && (defined(_STDINT_H_INCLUDED) || __WATCOMC__ >= 1250)) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_) || defined(__UINT_FAST64_TYPE__)) )) && !defined(FIXEDINT_H_INCLUDED) + #include + #define FIXEDINT_H_INCLUDED + + #if defined(__WATCOMC__) && __WATCOMC__ >= 1250 && !defined(UINT64_C) + #include + #define UINT64_C(x) (x + (UINT64_MAX - UINT64_MAX)) + #endif +#endif + + +#ifndef FIXEDINT_H_INCLUDED + #define FIXEDINT_H_INCLUDED + + #include + + /* (u)int32_t */ + #ifndef uint32_t + #if (ULONG_MAX == 0xffffffffUL) + typedef unsigned long uint32_t; + #elif (UINT_MAX == 0xffffffffUL) + typedef unsigned int uint32_t; + #elif (USHRT_MAX == 0xffffffffUL) + typedef unsigned short uint32_t; + #endif + #endif + + + #ifndef int32_t + #if (LONG_MAX == 0x7fffffffL) + typedef signed long int32_t; + #elif (INT_MAX == 0x7fffffffL) + typedef signed int int32_t; + #elif (SHRT_MAX == 0x7fffffffL) + typedef signed short int32_t; + #endif + #endif + + + /* (u)int64_t */ + #if (defined(__STDC__) && defined(__STDC_VERSION__) && __STDC__ && __STDC_VERSION__ >= 199901L) + typedef long long int64_t; + typedef unsigned long long uint64_t; + + #define UINT64_C(v) v ##ULL + #define INT64_C(v) v ##LL + #elif defined(__GNUC__) + __extension__ typedef long long int64_t; + __extension__ typedef unsigned long long uint64_t; + + #define UINT64_C(v) v ##ULL + #define INT64_C(v) v ##LL + #elif defined(__MWERKS__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) || defined(__APPLE_CC__) || defined(_LONG_LONG) || defined(_CRAYC) + typedef long long int64_t; + typedef unsigned long long uint64_t; + + #define UINT64_C(v) v ##ULL + #define INT64_C(v) v ##LL + #elif (defined(__WATCOMC__) && defined(__WATCOM_INT64__)) || (defined(_MSC_VER) && _INTEGRAL_MAX_BITS >= 64) || (defined(__BORLANDC__) && __BORLANDC__ > 0x460) || defined(__alpha) || defined(__DECC) + typedef __int64 int64_t; + typedef unsigned __int64 uint64_t; + + #define UINT64_C(v) v ##UI64 + #define INT64_C(v) v ##I64 + #endif +#endif diff --git a/src/cryptoconditions/src/include/ed25519/src/ge.c b/src/cryptoconditions/src/include/ed25519/src/ge.c new file mode 100644 index 000000000..87c691bff --- /dev/null +++ b/src/cryptoconditions/src/include/ed25519/src/ge.c @@ -0,0 +1,467 @@ +#include "ge.h" +#include "precomp_data.h" + + +/* +r = p + q +*/ + +void ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) { + fe t0; + fe_add(r->X, p->Y, p->X); + fe_sub(r->Y, p->Y, p->X); + fe_mul(r->Z, r->X, q->YplusX); + fe_mul(r->Y, r->Y, q->YminusX); + fe_mul(r->T, q->T2d, p->T); + fe_mul(r->X, p->Z, q->Z); + fe_add(t0, r->X, r->X); + fe_sub(r->X, r->Z, r->Y); + fe_add(r->Y, r->Z, r->Y); + fe_add(r->Z, t0, r->T); + fe_sub(r->T, t0, r->T); +} + + +static void slide(signed char *r, const unsigned char *a) { + int i; + int b; + int k; + + for (i = 0; i < 256; ++i) { + r[i] = 1 & (a[i >> 3] >> (i & 7)); + } + + for (i = 0; i < 256; ++i) + if (r[i]) { + for (b = 1; b <= 6 && i + b < 256; ++b) { + if (r[i + b]) { + if (r[i] + (r[i + b] << b) <= 15) { + r[i] += r[i + b] << b; + r[i + b] = 0; + } else if (r[i] - (r[i + b] << b) >= -15) { + r[i] -= r[i + b] << b; + + for (k = i + b; k < 256; ++k) { + if (!r[k]) { + r[k] = 1; + break; + } + + r[k] = 0; + } + } else { + break; + } + } + } + } +} + +/* +r = a * A + b * B +where a = a[0]+256*a[1]+...+256^31 a[31]. +and b = b[0]+256*b[1]+...+256^31 b[31]. +B is the Ed25519 base point (x,4/5) with x positive. +*/ + +void ge_double_scalarmult_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b) { + signed char aslide[256]; + signed char bslide[256]; + ge_cached Ai[8]; /* A,3A,5A,7A,9A,11A,13A,15A */ + ge_p1p1 t; + ge_p3 u; + ge_p3 A2; + int i; + slide(aslide, a); + slide(bslide, b); + ge_p3_to_cached(&Ai[0], A); + ge_p3_dbl(&t, A); + ge_p1p1_to_p3(&A2, &t); + ge_add(&t, &A2, &Ai[0]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[1], &u); + ge_add(&t, &A2, &Ai[1]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[2], &u); + ge_add(&t, &A2, &Ai[2]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[3], &u); + ge_add(&t, &A2, &Ai[3]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[4], &u); + ge_add(&t, &A2, &Ai[4]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[5], &u); + ge_add(&t, &A2, &Ai[5]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[6], &u); + ge_add(&t, &A2, &Ai[6]); + ge_p1p1_to_p3(&u, &t); + ge_p3_to_cached(&Ai[7], &u); + ge_p2_0(r); + + for (i = 255; i >= 0; --i) { + if (aslide[i] || bslide[i]) { + break; + } + } + + for (; i >= 0; --i) { + ge_p2_dbl(&t, r); + + if (aslide[i] > 0) { + ge_p1p1_to_p3(&u, &t); + ge_add(&t, &u, &Ai[aslide[i] / 2]); + } else if (aslide[i] < 0) { + ge_p1p1_to_p3(&u, &t); + ge_sub(&t, &u, &Ai[(-aslide[i]) / 2]); + } + + if (bslide[i] > 0) { + ge_p1p1_to_p3(&u, &t); + ge_madd(&t, &u, &Bi[bslide[i] / 2]); + } else if (bslide[i] < 0) { + ge_p1p1_to_p3(&u, &t); + ge_msub(&t, &u, &Bi[(-bslide[i]) / 2]); + } + + ge_p1p1_to_p2(r, &t); + } +} + + +static const fe d = { + -10913610, 13857413, -15372611, 6949391, 114729, -8787816, -6275908, -3247719, -18696448, -12055116 +}; + +static const fe sqrtm1 = { + -32595792, -7943725, 9377950, 3500415, 12389472, -272473, -25146209, -2005654, 326686, 11406482 +}; + +int ge_frombytes_negate_vartime(ge_p3 *h, const unsigned char *s) { + fe u; + fe v; + fe v3; + fe vxx; + fe check; + fe_frombytes(h->Y, s); + fe_1(h->Z); + fe_sq(u, h->Y); + fe_mul(v, u, d); + fe_sub(u, u, h->Z); /* u = y^2-1 */ + fe_add(v, v, h->Z); /* v = dy^2+1 */ + fe_sq(v3, v); + fe_mul(v3, v3, v); /* v3 = v^3 */ + fe_sq(h->X, v3); + fe_mul(h->X, h->X, v); + fe_mul(h->X, h->X, u); /* x = uv^7 */ + fe_pow22523(h->X, h->X); /* x = (uv^7)^((q-5)/8) */ + fe_mul(h->X, h->X, v3); + fe_mul(h->X, h->X, u); /* x = uv^3(uv^7)^((q-5)/8) */ + fe_sq(vxx, h->X); + fe_mul(vxx, vxx, v); + fe_sub(check, vxx, u); /* vx^2-u */ + + if (fe_isnonzero(check)) { + fe_add(check, vxx, u); /* vx^2+u */ + + if (fe_isnonzero(check)) { + return -1; + } + + fe_mul(h->X, h->X, sqrtm1); + } + + if (fe_isnegative(h->X) == (s[31] >> 7)) { + fe_neg(h->X, h->X); + } + + fe_mul(h->T, h->X, h->Y); + return 0; +} + + +/* +r = p + q +*/ + +void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) { + fe t0; + fe_add(r->X, p->Y, p->X); + fe_sub(r->Y, p->Y, p->X); + fe_mul(r->Z, r->X, q->yplusx); + fe_mul(r->Y, r->Y, q->yminusx); + fe_mul(r->T, q->xy2d, p->T); + fe_add(t0, p->Z, p->Z); + fe_sub(r->X, r->Z, r->Y); + fe_add(r->Y, r->Z, r->Y); + fe_add(r->Z, t0, r->T); + fe_sub(r->T, t0, r->T); +} + + +/* +r = p - q +*/ + +void ge_msub(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) { + fe t0; + + fe_add(r->X, p->Y, p->X); + fe_sub(r->Y, p->Y, p->X); + fe_mul(r->Z, r->X, q->yminusx); + fe_mul(r->Y, r->Y, q->yplusx); + fe_mul(r->T, q->xy2d, p->T); + fe_add(t0, p->Z, p->Z); + fe_sub(r->X, r->Z, r->Y); + fe_add(r->Y, r->Z, r->Y); + fe_sub(r->Z, t0, r->T); + fe_add(r->T, t0, r->T); +} + + +/* +r = p +*/ + +void ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p) { + fe_mul(r->X, p->X, p->T); + fe_mul(r->Y, p->Y, p->Z); + fe_mul(r->Z, p->Z, p->T); +} + + + +/* +r = p +*/ + +void ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p) { + fe_mul(r->X, p->X, p->T); + fe_mul(r->Y, p->Y, p->Z); + fe_mul(r->Z, p->Z, p->T); + fe_mul(r->T, p->X, p->Y); +} + + +void ge_p2_0(ge_p2 *h) { + fe_0(h->X); + fe_1(h->Y); + fe_1(h->Z); +} + + + +/* +r = 2 * p +*/ + +void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p) { + fe t0; + + fe_sq(r->X, p->X); + fe_sq(r->Z, p->Y); + fe_sq2(r->T, p->Z); + fe_add(r->Y, p->X, p->Y); + fe_sq(t0, r->Y); + fe_add(r->Y, r->Z, r->X); + fe_sub(r->Z, r->Z, r->X); + fe_sub(r->X, t0, r->Y); + fe_sub(r->T, r->T, r->Z); +} + + +void ge_p3_0(ge_p3 *h) { + fe_0(h->X); + fe_1(h->Y); + fe_1(h->Z); + fe_0(h->T); +} + + +/* +r = 2 * p +*/ + +void ge_p3_dbl(ge_p1p1 *r, const ge_p3 *p) { + ge_p2 q; + ge_p3_to_p2(&q, p); + ge_p2_dbl(r, &q); +} + + + +/* +r = p +*/ + +static const fe d2 = { + -21827239, -5839606, -30745221, 13898782, 229458, 15978800, -12551817, -6495438, 29715968, 9444199 +}; + +void ge_p3_to_cached(ge_cached *r, const ge_p3 *p) { + fe_add(r->YplusX, p->Y, p->X); + fe_sub(r->YminusX, p->Y, p->X); + fe_copy(r->Z, p->Z); + fe_mul(r->T2d, p->T, d2); +} + + +/* +r = p +*/ + +void ge_p3_to_p2(ge_p2 *r, const ge_p3 *p) { + fe_copy(r->X, p->X); + fe_copy(r->Y, p->Y); + fe_copy(r->Z, p->Z); +} + + +void ge_p3_tobytes(unsigned char *s, const ge_p3 *h) { + fe recip; + fe x; + fe y; + fe_invert(recip, h->Z); + fe_mul(x, h->X, recip); + fe_mul(y, h->Y, recip); + fe_tobytes(s, y); + s[31] ^= fe_isnegative(x) << 7; +} + + +static unsigned char equal(signed char b, signed char c) { + unsigned char ub = b; + unsigned char uc = c; + unsigned char x = ub ^ uc; /* 0: yes; 1..255: no */ + uint64_t y = x; /* 0: yes; 1..255: no */ + y -= 1; /* large: yes; 0..254: no */ + y >>= 63; /* 1: yes; 0: no */ + return (unsigned char) y; +} + +static unsigned char negative(signed char b) { + uint64_t x = b; /* 18446744073709551361..18446744073709551615: yes; 0..255: no */ + x >>= 63; /* 1: yes; 0: no */ + return (unsigned char) x; +} + +static void cmov(ge_precomp *t, const ge_precomp *u, unsigned char b) { + fe_cmov(t->yplusx, u->yplusx, b); + fe_cmov(t->yminusx, u->yminusx, b); + fe_cmov(t->xy2d, u->xy2d, b); +} + + +static void select(ge_precomp *t, int pos, signed char b) { + ge_precomp minust; + unsigned char bnegative = negative(b); + unsigned char babs = b - (((-bnegative) & b) << 1); + fe_1(t->yplusx); + fe_1(t->yminusx); + fe_0(t->xy2d); + cmov(t, &base[pos][0], equal(babs, 1)); + cmov(t, &base[pos][1], equal(babs, 2)); + cmov(t, &base[pos][2], equal(babs, 3)); + cmov(t, &base[pos][3], equal(babs, 4)); + cmov(t, &base[pos][4], equal(babs, 5)); + cmov(t, &base[pos][5], equal(babs, 6)); + cmov(t, &base[pos][6], equal(babs, 7)); + cmov(t, &base[pos][7], equal(babs, 8)); + fe_copy(minust.yplusx, t->yminusx); + fe_copy(minust.yminusx, t->yplusx); + fe_neg(minust.xy2d, t->xy2d); + cmov(t, &minust, bnegative); +} + +/* +h = a * B +where a = a[0]+256*a[1]+...+256^31 a[31] +B is the Ed25519 base point (x,4/5) with x positive. + +Preconditions: + a[31] <= 127 +*/ + +void ge_scalarmult_base(ge_p3 *h, const unsigned char *a) { + signed char e[64]; + signed char carry; + ge_p1p1 r; + ge_p2 s; + ge_precomp t; + int i; + + for (i = 0; i < 32; ++i) { + e[2 * i + 0] = (a[i] >> 0) & 15; + e[2 * i + 1] = (a[i] >> 4) & 15; + } + + /* each e[i] is between 0 and 15 */ + /* e[63] is between 0 and 7 */ + carry = 0; + + for (i = 0; i < 63; ++i) { + e[i] += carry; + carry = e[i] + 8; + carry >>= 4; + e[i] -= carry << 4; + } + + e[63] += carry; + /* each e[i] is between -8 and 8 */ + ge_p3_0(h); + + for (i = 1; i < 64; i += 2) { + select(&t, i / 2, e[i]); + ge_madd(&r, h, &t); + ge_p1p1_to_p3(h, &r); + } + + ge_p3_dbl(&r, h); + ge_p1p1_to_p2(&s, &r); + ge_p2_dbl(&r, &s); + ge_p1p1_to_p2(&s, &r); + ge_p2_dbl(&r, &s); + ge_p1p1_to_p2(&s, &r); + ge_p2_dbl(&r, &s); + ge_p1p1_to_p3(h, &r); + + for (i = 0; i < 64; i += 2) { + select(&t, i / 2, e[i]); + ge_madd(&r, h, &t); + ge_p1p1_to_p3(h, &r); + } +} + + +/* +r = p - q +*/ + +void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q) { + fe t0; + + fe_add(r->X, p->Y, p->X); + fe_sub(r->Y, p->Y, p->X); + fe_mul(r->Z, r->X, q->YminusX); + fe_mul(r->Y, r->Y, q->YplusX); + fe_mul(r->T, q->T2d, p->T); + fe_mul(r->X, p->Z, q->Z); + fe_add(t0, r->X, r->X); + fe_sub(r->X, r->Z, r->Y); + fe_add(r->Y, r->Z, r->Y); + fe_sub(r->Z, t0, r->T); + fe_add(r->T, t0, r->T); +} + + +void ge_tobytes(unsigned char *s, const ge_p2 *h) { + fe recip; + fe x; + fe y; + fe_invert(recip, h->Z); + fe_mul(x, h->X, recip); + fe_mul(y, h->Y, recip); + fe_tobytes(s, y); + s[31] ^= fe_isnegative(x) << 7; +} diff --git a/src/cryptoconditions/src/include/ed25519/src/ge.h b/src/cryptoconditions/src/include/ed25519/src/ge.h new file mode 100644 index 000000000..17fde2df1 --- /dev/null +++ b/src/cryptoconditions/src/include/ed25519/src/ge.h @@ -0,0 +1,74 @@ +#ifndef GE_H +#define GE_H + +#include "fe.h" + + +/* +ge means group element. + +Here the group is the set of pairs (x,y) of field elements (see fe.h) +satisfying -x^2 + y^2 = 1 + d x^2y^2 +where d = -121665/121666. + +Representations: + ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z + ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT + ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T + ge_precomp (Duif): (y+x,y-x,2dxy) +*/ + +typedef struct { + fe X; + fe Y; + fe Z; +} ge_p2; + +typedef struct { + fe X; + fe Y; + fe Z; + fe T; +} ge_p3; + +typedef struct { + fe X; + fe Y; + fe Z; + fe T; +} ge_p1p1; + +typedef struct { + fe yplusx; + fe yminusx; + fe xy2d; +} ge_precomp; + +typedef struct { + fe YplusX; + fe YminusX; + fe Z; + fe T2d; +} ge_cached; + +void ge_p3_tobytes(unsigned char *s, const ge_p3 *h); +void ge_tobytes(unsigned char *s, const ge_p2 *h); +int ge_frombytes_negate_vartime(ge_p3 *h, const unsigned char *s); + +void ge_add(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q); +void ge_sub(ge_p1p1 *r, const ge_p3 *p, const ge_cached *q); +void ge_double_scalarmult_vartime(ge_p2 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b); +void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q); +void ge_msub(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q); +void ge_scalarmult_base(ge_p3 *h, const unsigned char *a); + +void ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p); +void ge_p1p1_to_p3(ge_p3 *r, const ge_p1p1 *p); +void ge_p2_0(ge_p2 *h); +void ge_p2_dbl(ge_p1p1 *r, const ge_p2 *p); +void ge_p3_0(ge_p3 *h); +void ge_p3_dbl(ge_p1p1 *r, const ge_p3 *p); +void ge_p3_to_cached(ge_cached *r, const ge_p3 *p); +void ge_p3_to_p2(ge_p2 *r, const ge_p3 *p); + +#endif diff --git a/src/cryptoconditions/src/include/ed25519/src/key_exchange.c b/src/cryptoconditions/src/include/ed25519/src/key_exchange.c new file mode 100644 index 000000000..abd75da2c --- /dev/null +++ b/src/cryptoconditions/src/include/ed25519/src/key_exchange.c @@ -0,0 +1,79 @@ +#include "ed25519.h" +#include "fe.h" + +void ed25519_key_exchange(unsigned char *shared_secret, const unsigned char *public_key, const unsigned char *private_key) { + unsigned char e[32]; + unsigned int i; + + fe x1; + fe x2; + fe z2; + fe x3; + fe z3; + fe tmp0; + fe tmp1; + + int pos; + unsigned int swap; + unsigned int b; + + /* copy the private key and make sure it's valid */ + for (i = 0; i < 32; ++i) { + e[i] = private_key[i]; + } + + e[0] &= 248; + e[31] &= 63; + e[31] |= 64; + + /* unpack the public key and convert edwards to montgomery */ + /* due to CodesInChaos: montgomeryX = (edwardsY + 1)*inverse(1 - edwardsY) mod p */ + fe_frombytes(x1, public_key); + fe_1(tmp1); + fe_add(tmp0, x1, tmp1); + fe_sub(tmp1, tmp1, x1); + fe_invert(tmp1, tmp1); + fe_mul(x1, tmp0, tmp1); + + fe_1(x2); + fe_0(z2); + fe_copy(x3, x1); + fe_1(z3); + + swap = 0; + for (pos = 254; pos >= 0; --pos) { + b = e[pos / 8] >> (pos & 7); + b &= 1; + swap ^= b; + fe_cswap(x2, x3, swap); + fe_cswap(z2, z3, swap); + swap = b; + + /* from montgomery.h */ + fe_sub(tmp0, x3, z3); + fe_sub(tmp1, x2, z2); + fe_add(x2, x2, z2); + fe_add(z2, x3, z3); + fe_mul(z3, tmp0, x2); + fe_mul(z2, z2, tmp1); + fe_sq(tmp0, tmp1); + fe_sq(tmp1, x2); + fe_add(x3, z3, z2); + fe_sub(z2, z3, z2); + fe_mul(x2, tmp1, tmp0); + fe_sub(tmp1, tmp1, tmp0); + fe_sq(z2, z2); + fe_mul121666(z3, tmp1); + fe_sq(x3, x3); + fe_add(tmp0, tmp0, z3); + fe_mul(z3, x1, z2); + fe_mul(z2, tmp1, tmp0); + } + + fe_cswap(x2, x3, swap); + fe_cswap(z2, z3, swap); + + fe_invert(z2, z2); + fe_mul(x2, x2, z2); + fe_tobytes(shared_secret, x2); +} diff --git a/src/cryptoconditions/src/include/ed25519/src/keypair.c b/src/cryptoconditions/src/include/ed25519/src/keypair.c new file mode 100644 index 000000000..dc1b8eccc --- /dev/null +++ b/src/cryptoconditions/src/include/ed25519/src/keypair.c @@ -0,0 +1,16 @@ +#include "ed25519.h" +#include "sha512.h" +#include "ge.h" + + +void ed25519_create_keypair(unsigned char *public_key, unsigned char *private_key, const unsigned char *seed) { + ge_p3 A; + + sha512(seed, 32, private_key); + private_key[0] &= 248; + private_key[31] &= 63; + private_key[31] |= 64; + + ge_scalarmult_base(&A, private_key); + ge_p3_tobytes(public_key, &A); +} diff --git a/src/cryptoconditions/src/include/ed25519/src/precomp_data.h b/src/cryptoconditions/src/include/ed25519/src/precomp_data.h new file mode 100644 index 000000000..ff23986c3 --- /dev/null +++ b/src/cryptoconditions/src/include/ed25519/src/precomp_data.h @@ -0,0 +1,1391 @@ +static const ge_precomp Bi[8] = { + { + { 25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605 }, + { -12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378 }, + { -8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546 }, + }, + { + { 15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024 }, + { 16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574 }, + { 30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357 }, + }, + { + { 10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380 }, + { 4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306 }, + { 19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942 }, + }, + { + { 5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766 }, + { -30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701 }, + { 28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300 }, + }, + { + { -22518993, -6692182, 14201702, -8745502, -23510406, 8844726, 18474211, -1361450, -13062696, 13821877 }, + { -6455177, -7839871, 3374702, -4740862, -27098617, -10571707, 31655028, -7212327, 18853322, -14220951 }, + { 4566830, -12963868, -28974889, -12240689, -7602672, -2830569, -8514358, -10431137, 2207753, -3209784 }, + }, + { + { -25154831, -4185821, 29681144, 7868801, -6854661, -9423865, -12437364, -663000, -31111463, -16132436 }, + { 25576264, -2703214, 7349804, -11814844, 16472782, 9300885, 3844789, 15725684, 171356, 6466918 }, + { 23103977, 13316479, 9739013, -16149481, 817875, -15038942, 8965339, -14088058, -30714912, 16193877 }, + }, + { + { -33521811, 3180713, -2394130, 14003687, -16903474, -16270840, 17238398, 4729455, -18074513, 9256800 }, + { -25182317, -4174131, 32336398, 5036987, -21236817, 11360617, 22616405, 9761698, -19827198, 630305 }, + { -13720693, 2639453, -24237460, -7406481, 9494427, -5774029, -6554551, -15960994, -2449256, -14291300 }, + }, + { + { -3151181, -5046075, 9282714, 6866145, -31907062, -863023, -18940575, 15033784, 25105118, -7894876 }, + { -24326370, 15950226, -31801215, -14592823, -11662737, -5090925, 1573892, -2625887, 2198790, -15804619 }, + { -3099351, 10324967, -2241613, 7453183, -5446979, -2735503, -13812022, -16236442, -32461234, -12290683 }, + }, +}; + + +/* base[i][j] = (j+1)*256^i*B */ +static const ge_precomp base[32][8] = { + { + { + { 25967493, -14356035, 29566456, 3660896, -12694345, 4014787, 27544626, -11754271, -6079156, 2047605 }, + { -12545711, 934262, -2722910, 3049990, -727428, 9406986, 12720692, 5043384, 19500929, -15469378 }, + { -8738181, 4489570, 9688441, -14785194, 10184609, -12363380, 29287919, 11864899, -24514362, -4438546 }, + }, + { + { -12815894, -12976347, -21581243, 11784320, -25355658, -2750717, -11717903, -3814571, -358445, -10211303 }, + { -21703237, 6903825, 27185491, 6451973, -29577724, -9554005, -15616551, 11189268, -26829678, -5319081 }, + { 26966642, 11152617, 32442495, 15396054, 14353839, -12752335, -3128826, -9541118, -15472047, -4166697 }, + }, + { + { 15636291, -9688557, 24204773, -7912398, 616977, -16685262, 27787600, -14772189, 28944400, -1550024 }, + { 16568933, 4717097, -11556148, -1102322, 15682896, -11807043, 16354577, -11775962, 7689662, 11199574 }, + { 30464156, -5976125, -11779434, -15670865, 23220365, 15915852, 7512774, 10017326, -17749093, -9920357 }, + }, + { + { -17036878, 13921892, 10945806, -6033431, 27105052, -16084379, -28926210, 15006023, 3284568, -6276540 }, + { 23599295, -8306047, -11193664, -7687416, 13236774, 10506355, 7464579, 9656445, 13059162, 10374397 }, + { 7798556, 16710257, 3033922, 2874086, 28997861, 2835604, 32406664, -3839045, -641708, -101325 }, + }, + { + { 10861363, 11473154, 27284546, 1981175, -30064349, 12577861, 32867885, 14515107, -15438304, 10819380 }, + { 4708026, 6336745, 20377586, 9066809, -11272109, 6594696, -25653668, 12483688, -12668491, 5581306 }, + { 19563160, 16186464, -29386857, 4097519, 10237984, -4348115, 28542350, 13850243, -23678021, -15815942 }, + }, + { + { -15371964, -12862754, 32573250, 4720197, -26436522, 5875511, -19188627, -15224819, -9818940, -12085777 }, + { -8549212, 109983, 15149363, 2178705, 22900618, 4543417, 3044240, -15689887, 1762328, 14866737 }, + { -18199695, -15951423, -10473290, 1707278, -17185920, 3916101, -28236412, 3959421, 27914454, 4383652 }, + }, + { + { 5153746, 9909285, 1723747, -2777874, 30523605, 5516873, 19480852, 5230134, -23952439, -15175766 }, + { -30269007, -3463509, 7665486, 10083793, 28475525, 1649722, 20654025, 16520125, 30598449, 7715701 }, + { 28881845, 14381568, 9657904, 3680757, -20181635, 7843316, -31400660, 1370708, 29794553, -1409300 }, + }, + { + { 14499471, -2729599, -33191113, -4254652, 28494862, 14271267, 30290735, 10876454, -33154098, 2381726 }, + { -7195431, -2655363, -14730155, 462251, -27724326, 3941372, -6236617, 3696005, -32300832, 15351955 }, + { 27431194, 8222322, 16448760, -3907995, -18707002, 11938355, -32961401, -2970515, 29551813, 10109425 }, + }, + }, + { + { + { -13657040, -13155431, -31283750, 11777098, 21447386, 6519384, -2378284, -1627556, 10092783, -4764171 }, + { 27939166, 14210322, 4677035, 16277044, -22964462, -12398139, -32508754, 12005538, -17810127, 12803510 }, + { 17228999, -15661624, -1233527, 300140, -1224870, -11714777, 30364213, -9038194, 18016357, 4397660 }, + }, + { + { -10958843, -7690207, 4776341, -14954238, 27850028, -15602212, -26619106, 14544525, -17477504, 982639 }, + { 29253598, 15796703, -2863982, -9908884, 10057023, 3163536, 7332899, -4120128, -21047696, 9934963 }, + { 5793303, 16271923, -24131614, -10116404, 29188560, 1206517, -14747930, 4559895, -30123922, -10897950 }, + }, + { + { -27643952, -11493006, 16282657, -11036493, 28414021, -15012264, 24191034, 4541697, -13338309, 5500568 }, + { 12650548, -1497113, 9052871, 11355358, -17680037, -8400164, -17430592, 12264343, 10874051, 13524335 }, + { 25556948, -3045990, 714651, 2510400, 23394682, -10415330, 33119038, 5080568, -22528059, 5376628 }, + }, + { + { -26088264, -4011052, -17013699, -3537628, -6726793, 1920897, -22321305, -9447443, 4535768, 1569007 }, + { -2255422, 14606630, -21692440, -8039818, 28430649, 8775819, -30494562, 3044290, 31848280, 12543772 }, + { -22028579, 2943893, -31857513, 6777306, 13784462, -4292203, -27377195, -2062731, 7718482, 14474653 }, + }, + { + { 2385315, 2454213, -22631320, 46603, -4437935, -15680415, 656965, -7236665, 24316168, -5253567 }, + { 13741529, 10911568, -33233417, -8603737, -20177830, -1033297, 33040651, -13424532, -20729456, 8321686 }, + { 21060490, -2212744, 15712757, -4336099, 1639040, 10656336, 23845965, -11874838, -9984458, 608372 }, + }, + { + { -13672732, -15087586, -10889693, -7557059, -6036909, 11305547, 1123968, -6780577, 27229399, 23887 }, + { -23244140, -294205, -11744728, 14712571, -29465699, -2029617, 12797024, -6440308, -1633405, 16678954 }, + { -29500620, 4770662, -16054387, 14001338, 7830047, 9564805, -1508144, -4795045, -17169265, 4904953 }, + }, + { + { 24059557, 14617003, 19037157, -15039908, 19766093, -14906429, 5169211, 16191880, 2128236, -4326833 }, + { -16981152, 4124966, -8540610, -10653797, 30336522, -14105247, -29806336, 916033, -6882542, -2986532 }, + { -22630907, 12419372, -7134229, -7473371, -16478904, 16739175, 285431, 2763829, 15736322, 4143876 }, + }, + { + { 2379352, 11839345, -4110402, -5988665, 11274298, 794957, 212801, -14594663, 23527084, -16458268 }, + { 33431127, -11130478, -17838966, -15626900, 8909499, 8376530, -32625340, 4087881, -15188911, -14416214 }, + { 1767683, 7197987, -13205226, -2022635, -13091350, 448826, 5799055, 4357868, -4774191, -16323038 }, + }, + }, + { + { + { 6721966, 13833823, -23523388, -1551314, 26354293, -11863321, 23365147, -3949732, 7390890, 2759800 }, + { 4409041, 2052381, 23373853, 10530217, 7676779, -12885954, 21302353, -4264057, 1244380, -12919645 }, + { -4421239, 7169619, 4982368, -2957590, 30256825, -2777540, 14086413, 9208236, 15886429, 16489664 }, + }, + { + { 1996075, 10375649, 14346367, 13311202, -6874135, -16438411, -13693198, 398369, -30606455, -712933 }, + { -25307465, 9795880, -2777414, 14878809, -33531835, 14780363, 13348553, 12076947, -30836462, 5113182 }, + { -17770784, 11797796, 31950843, 13929123, -25888302, 12288344, -30341101, -7336386, 13847711, 5387222 }, + }, + { + { -18582163, -3416217, 17824843, -2340966, 22744343, -10442611, 8763061, 3617786, -19600662, 10370991 }, + { 20246567, -14369378, 22358229, -543712, 18507283, -10413996, 14554437, -8746092, 32232924, 16763880 }, + { 9648505, 10094563, 26416693, 14745928, -30374318, -6472621, 11094161, 15689506, 3140038, -16510092 }, + }, + { + { -16160072, 5472695, 31895588, 4744994, 8823515, 10365685, -27224800, 9448613, -28774454, 366295 }, + { 19153450, 11523972, -11096490, -6503142, -24647631, 5420647, 28344573, 8041113, 719605, 11671788 }, + { 8678025, 2694440, -6808014, 2517372, 4964326, 11152271, -15432916, -15266516, 27000813, -10195553 }, + }, + { + { -15157904, 7134312, 8639287, -2814877, -7235688, 10421742, 564065, 5336097, 6750977, -14521026 }, + { 11836410, -3979488, 26297894, 16080799, 23455045, 15735944, 1695823, -8819122, 8169720, 16220347 }, + { -18115838, 8653647, 17578566, -6092619, -8025777, -16012763, -11144307, -2627664, -5990708, -14166033 }, + }, + { + { -23308498, -10968312, 15213228, -10081214, -30853605, -11050004, 27884329, 2847284, 2655861, 1738395 }, + { -27537433, -14253021, -25336301, -8002780, -9370762, 8129821, 21651608, -3239336, -19087449, -11005278 }, + { 1533110, 3437855, 23735889, 459276, 29970501, 11335377, 26030092, 5821408, 10478196, 8544890 }, + }, + { + { 32173121, -16129311, 24896207, 3921497, 22579056, -3410854, 19270449, 12217473, 17789017, -3395995 }, + { -30552961, -2228401, -15578829, -10147201, 13243889, 517024, 15479401, -3853233, 30460520, 1052596 }, + { -11614875, 13323618, 32618793, 8175907, -15230173, 12596687, 27491595, -4612359, 3179268, -9478891 }, + }, + { + { 31947069, -14366651, -4640583, -15339921, -15125977, -6039709, -14756777, -16411740, 19072640, -9511060 }, + { 11685058, 11822410, 3158003, -13952594, 33402194, -4165066, 5977896, -5215017, 473099, 5040608 }, + { -20290863, 8198642, -27410132, 11602123, 1290375, -2799760, 28326862, 1721092, -19558642, -3131606 }, + }, + }, + { + { + { 7881532, 10687937, 7578723, 7738378, -18951012, -2553952, 21820786, 8076149, -27868496, 11538389 }, + { -19935666, 3899861, 18283497, -6801568, -15728660, -11249211, 8754525, 7446702, -5676054, 5797016 }, + { -11295600, -3793569, -15782110, -7964573, 12708869, -8456199, 2014099, -9050574, -2369172, -5877341 }, + }, + { + { -22472376, -11568741, -27682020, 1146375, 18956691, 16640559, 1192730, -3714199, 15123619, 10811505 }, + { 14352098, -3419715, -18942044, 10822655, 32750596, 4699007, -70363, 15776356, -28886779, -11974553 }, + { -28241164, -8072475, -4978962, -5315317, 29416931, 1847569, -20654173, -16484855, 4714547, -9600655 }, + }, + { + { 15200332, 8368572, 19679101, 15970074, -31872674, 1959451, 24611599, -4543832, -11745876, 12340220 }, + { 12876937, -10480056, 33134381, 6590940, -6307776, 14872440, 9613953, 8241152, 15370987, 9608631 }, + { -4143277, -12014408, 8446281, -391603, 4407738, 13629032, -7724868, 15866074, -28210621, -8814099 }, + }, + { + { 26660628, -15677655, 8393734, 358047, -7401291, 992988, -23904233, 858697, 20571223, 8420556 }, + { 14620715, 13067227, -15447274, 8264467, 14106269, 15080814, 33531827, 12516406, -21574435, -12476749 }, + { 236881, 10476226, 57258, -14677024, 6472998, 2466984, 17258519, 7256740, 8791136, 15069930 }, + }, + { + { 1276410, -9371918, 22949635, -16322807, -23493039, -5702186, 14711875, 4874229, -30663140, -2331391 }, + { 5855666, 4990204, -13711848, 7294284, -7804282, 1924647, -1423175, -7912378, -33069337, 9234253 }, + { 20590503, -9018988, 31529744, -7352666, -2706834, 10650548, 31559055, -11609587, 18979186, 13396066 }, + }, + { + { 24474287, 4968103, 22267082, 4407354, 24063882, -8325180, -18816887, 13594782, 33514650, 7021958 }, + { -11566906, -6565505, -21365085, 15928892, -26158305, 4315421, -25948728, -3916677, -21480480, 12868082 }, + { -28635013, 13504661, 19988037, -2132761, 21078225, 6443208, -21446107, 2244500, -12455797, -8089383 }, + }, + { + { -30595528, 13793479, -5852820, 319136, -25723172, -6263899, 33086546, 8957937, -15233648, 5540521 }, + { -11630176, -11503902, -8119500, -7643073, 2620056, 1022908, -23710744, -1568984, -16128528, -14962807 }, + { 23152971, 775386, 27395463, 14006635, -9701118, 4649512, 1689819, 892185, -11513277, -15205948 }, + }, + { + { 9770129, 9586738, 26496094, 4324120, 1556511, -3550024, 27453819, 4763127, -19179614, 5867134 }, + { -32765025, 1927590, 31726409, -4753295, 23962434, -16019500, 27846559, 5931263, -29749703, -16108455 }, + { 27461885, -2977536, 22380810, 1815854, -23033753, -3031938, 7283490, -15148073, -19526700, 7734629 }, + }, + }, + { + { + { -8010264, -9590817, -11120403, 6196038, 29344158, -13430885, 7585295, -3176626, 18549497, 15302069 }, + { -32658337, -6171222, -7672793, -11051681, 6258878, 13504381, 10458790, -6418461, -8872242, 8424746 }, + { 24687205, 8613276, -30667046, -3233545, 1863892, -1830544, 19206234, 7134917, -11284482, -828919 }, + }, + { + { 11334899, -9218022, 8025293, 12707519, 17523892, -10476071, 10243738, -14685461, -5066034, 16498837 }, + { 8911542, 6887158, -9584260, -6958590, 11145641, -9543680, 17303925, -14124238, 6536641, 10543906 }, + { -28946384, 15479763, -17466835, 568876, -1497683, 11223454, -2669190, -16625574, -27235709, 8876771 }, + }, + { + { -25742899, -12566864, -15649966, -846607, -33026686, -796288, -33481822, 15824474, -604426, -9039817 }, + { 10330056, 70051, 7957388, -9002667, 9764902, 15609756, 27698697, -4890037, 1657394, 3084098 }, + { 10477963, -7470260, 12119566, -13250805, 29016247, -5365589, 31280319, 14396151, -30233575, 15272409 }, + }, + { + { -12288309, 3169463, 28813183, 16658753, 25116432, -5630466, -25173957, -12636138, -25014757, 1950504 }, + { -26180358, 9489187, 11053416, -14746161, -31053720, 5825630, -8384306, -8767532, 15341279, 8373727 }, + { 28685821, 7759505, -14378516, -12002860, -31971820, 4079242, 298136, -10232602, -2878207, 15190420 }, + }, + { + { -32932876, 13806336, -14337485, -15794431, -24004620, 10940928, 8669718, 2742393, -26033313, -6875003 }, + { -1580388, -11729417, -25979658, -11445023, -17411874, -10912854, 9291594, -16247779, -12154742, 6048605 }, + { -30305315, 14843444, 1539301, 11864366, 20201677, 1900163, 13934231, 5128323, 11213262, 9168384 }, + }, + { + { -26280513, 11007847, 19408960, -940758, -18592965, -4328580, -5088060, -11105150, 20470157, -16398701 }, + { -23136053, 9282192, 14855179, -15390078, -7362815, -14408560, -22783952, 14461608, 14042978, 5230683 }, + { 29969567, -2741594, -16711867, -8552442, 9175486, -2468974, 21556951, 3506042, -5933891, -12449708 }, + }, + { + { -3144746, 8744661, 19704003, 4581278, -20430686, 6830683, -21284170, 8971513, -28539189, 15326563 }, + { -19464629, 10110288, -17262528, -3503892, -23500387, 1355669, -15523050, 15300988, -20514118, 9168260 }, + { -5353335, 4488613, -23803248, 16314347, 7780487, -15638939, -28948358, 9601605, 33087103, -9011387 }, + }, + { + { -19443170, -15512900, -20797467, -12445323, -29824447, 10229461, -27444329, -15000531, -5996870, 15664672 }, + { 23294591, -16632613, -22650781, -8470978, 27844204, 11461195, 13099750, -2460356, 18151676, 13417686 }, + { -24722913, -4176517, -31150679, 5988919, -26858785, 6685065, 1661597, -12551441, 15271676, -15452665 }, + }, + }, + { + { + { 11433042, -13228665, 8239631, -5279517, -1985436, -725718, -18698764, 2167544, -6921301, -13440182 }, + { -31436171, 15575146, 30436815, 12192228, -22463353, 9395379, -9917708, -8638997, 12215110, 12028277 }, + { 14098400, 6555944, 23007258, 5757252, -15427832, -12950502, 30123440, 4617780, -16900089, -655628 }, + }, + { + { -4026201, -15240835, 11893168, 13718664, -14809462, 1847385, -15819999, 10154009, 23973261, -12684474 }, + { -26531820, -3695990, -1908898, 2534301, -31870557, -16550355, 18341390, -11419951, 32013174, -10103539 }, + { -25479301, 10876443, -11771086, -14625140, -12369567, 1838104, 21911214, 6354752, 4425632, -837822 }, + }, + { + { -10433389, -14612966, 22229858, -3091047, -13191166, 776729, -17415375, -12020462, 4725005, 14044970 }, + { 19268650, -7304421, 1555349, 8692754, -21474059, -9910664, 6347390, -1411784, -19522291, -16109756 }, + { -24864089, 12986008, -10898878, -5558584, -11312371, -148526, 19541418, 8180106, 9282262, 10282508 }, + }, + { + { -26205082, 4428547, -8661196, -13194263, 4098402, -14165257, 15522535, 8372215, 5542595, -10702683 }, + { -10562541, 14895633, 26814552, -16673850, -17480754, -2489360, -2781891, 6993761, -18093885, 10114655 }, + { -20107055, -929418, 31422704, 10427861, -7110749, 6150669, -29091755, -11529146, 25953725, -106158 }, + }, + { + { -4234397, -8039292, -9119125, 3046000, 2101609, -12607294, 19390020, 6094296, -3315279, 12831125 }, + { -15998678, 7578152, 5310217, 14408357, -33548620, -224739, 31575954, 6326196, 7381791, -2421839 }, + { -20902779, 3296811, 24736065, -16328389, 18374254, 7318640, 6295303, 8082724, -15362489, 12339664 }, + }, + { + { 27724736, 2291157, 6088201, -14184798, 1792727, 5857634, 13848414, 15768922, 25091167, 14856294 }, + { -18866652, 8331043, 24373479, 8541013, -701998, -9269457, 12927300, -12695493, -22182473, -9012899 }, + { -11423429, -5421590, 11632845, 3405020, 30536730, -11674039, -27260765, 13866390, 30146206, 9142070 }, + }, + { + { 3924129, -15307516, -13817122, -10054960, 12291820, -668366, -27702774, 9326384, -8237858, 4171294 }, + { -15921940, 16037937, 6713787, 16606682, -21612135, 2790944, 26396185, 3731949, 345228, -5462949 }, + { -21327538, 13448259, 25284571, 1143661, 20614966, -8849387, 2031539, -12391231, -16253183, -13582083 }, + }, + { + { 31016211, -16722429, 26371392, -14451233, -5027349, 14854137, 17477601, 3842657, 28012650, -16405420 }, + { -5075835, 9368966, -8562079, -4600902, -15249953, 6970560, -9189873, 16292057, -8867157, 3507940 }, + { 29439664, 3537914, 23333589, 6997794, -17555561, -11018068, -15209202, -15051267, -9164929, 6580396 }, + }, + }, + { + { + { -12185861, -7679788, 16438269, 10826160, -8696817, -6235611, 17860444, -9273846, -2095802, 9304567 }, + { 20714564, -4336911, 29088195, 7406487, 11426967, -5095705, 14792667, -14608617, 5289421, -477127 }, + { -16665533, -10650790, -6160345, -13305760, 9192020, -1802462, 17271490, 12349094, 26939669, -3752294 }, + }, + { + { -12889898, 9373458, 31595848, 16374215, 21471720, 13221525, -27283495, -12348559, -3698806, 117887 }, + { 22263325, -6560050, 3984570, -11174646, -15114008, -566785, 28311253, 5358056, -23319780, 541964 }, + { 16259219, 3261970, 2309254, -15534474, -16885711, -4581916, 24134070, -16705829, -13337066, -13552195 }, + }, + { + { 9378160, -13140186, -22845982, -12745264, 28198281, -7244098, -2399684, -717351, 690426, 14876244 }, + { 24977353, -314384, -8223969, -13465086, 28432343, -1176353, -13068804, -12297348, -22380984, 6618999 }, + { -1538174, 11685646, 12944378, 13682314, -24389511, -14413193, 8044829, -13817328, 32239829, -5652762 }, + }, + { + { -18603066, 4762990, -926250, 8885304, -28412480, -3187315, 9781647, -10350059, 32779359, 5095274 }, + { -33008130, -5214506, -32264887, -3685216, 9460461, -9327423, -24601656, 14506724, 21639561, -2630236 }, + { -16400943, -13112215, 25239338, 15531969, 3987758, -4499318, -1289502, -6863535, 17874574, 558605 }, + }, + { + { -13600129, 10240081, 9171883, 16131053, -20869254, 9599700, 33499487, 5080151, 2085892, 5119761 }, + { -22205145, -2519528, -16381601, 414691, -25019550, 2170430, 30634760, -8363614, -31999993, -5759884 }, + { -6845704, 15791202, 8550074, -1312654, 29928809, -12092256, 27534430, -7192145, -22351378, 12961482 }, + }, + { + { -24492060, -9570771, 10368194, 11582341, -23397293, -2245287, 16533930, 8206996, -30194652, -5159638 }, + { -11121496, -3382234, 2307366, 6362031, -135455, 8868177, -16835630, 7031275, 7589640, 8945490 }, + { -32152748, 8917967, 6661220, -11677616, -1192060, -15793393, 7251489, -11182180, 24099109, -14456170 }, + }, + { + { 5019558, -7907470, 4244127, -14714356, -26933272, 6453165, -19118182, -13289025, -6231896, -10280736 }, + { 10853594, 10721687, 26480089, 5861829, -22995819, 1972175, -1866647, -10557898, -3363451, -6441124 }, + { -17002408, 5906790, 221599, -6563147, 7828208, -13248918, 24362661, -2008168, -13866408, 7421392 }, + }, + { + { 8139927, -6546497, 32257646, -5890546, 30375719, 1886181, -21175108, 15441252, 28826358, -4123029 }, + { 6267086, 9695052, 7709135, -16603597, -32869068, -1886135, 14795160, -7840124, 13746021, -1742048 }, + { 28584902, 7787108, -6732942, -15050729, 22846041, -7571236, -3181936, -363524, 4771362, -8419958 }, + }, + }, + { + { + { 24949256, 6376279, -27466481, -8174608, -18646154, -9930606, 33543569, -12141695, 3569627, 11342593 }, + { 26514989, 4740088, 27912651, 3697550, 19331575, -11472339, 6809886, 4608608, 7325975, -14801071 }, + { -11618399, -14554430, -24321212, 7655128, -1369274, 5214312, -27400540, 10258390, -17646694, -8186692 }, + }, + { + { 11431204, 15823007, 26570245, 14329124, 18029990, 4796082, -31446179, 15580664, 9280358, -3973687 }, + { -160783, -10326257, -22855316, -4304997, -20861367, -13621002, -32810901, -11181622, -15545091, 4387441 }, + { -20799378, 12194512, 3937617, -5805892, -27154820, 9340370, -24513992, 8548137, 20617071, -7482001 }, + }, + { + { -938825, -3930586, -8714311, 16124718, 24603125, -6225393, -13775352, -11875822, 24345683, 10325460 }, + { -19855277, -1568885, -22202708, 8714034, 14007766, 6928528, 16318175, -1010689, 4766743, 3552007 }, + { -21751364, -16730916, 1351763, -803421, -4009670, 3950935, 3217514, 14481909, 10988822, -3994762 }, + }, + { + { 15564307, -14311570, 3101243, 5684148, 30446780, -8051356, 12677127, -6505343, -8295852, 13296005 }, + { -9442290, 6624296, -30298964, -11913677, -4670981, -2057379, 31521204, 9614054, -30000824, 12074674 }, + { 4771191, -135239, 14290749, -13089852, 27992298, 14998318, -1413936, -1556716, 29832613, -16391035 }, + }, + { + { 7064884, -7541174, -19161962, -5067537, -18891269, -2912736, 25825242, 5293297, -27122660, 13101590 }, + { -2298563, 2439670, -7466610, 1719965, -27267541, -16328445, 32512469, -5317593, -30356070, -4190957 }, + { -30006540, 10162316, -33180176, 3981723, -16482138, -13070044, 14413974, 9515896, 19568978, 9628812 }, + }, + { + { 33053803, 199357, 15894591, 1583059, 27380243, -4580435, -17838894, -6106839, -6291786, 3437740 }, + { -18978877, 3884493, 19469877, 12726490, 15913552, 13614290, -22961733, 70104, 7463304, 4176122 }, + { -27124001, 10659917, 11482427, -16070381, 12771467, -6635117, -32719404, -5322751, 24216882, 5944158 }, + }, + { + { 8894125, 7450974, -2664149, -9765752, -28080517, -12389115, 19345746, 14680796, 11632993, 5847885 }, + { 26942781, -2315317, 9129564, -4906607, 26024105, 11769399, -11518837, 6367194, -9727230, 4782140 }, + { 19916461, -4828410, -22910704, -11414391, 25606324, -5972441, 33253853, 8220911, 6358847, -1873857 }, + }, + { + { 801428, -2081702, 16569428, 11065167, 29875704, 96627, 7908388, -4480480, -13538503, 1387155 }, + { 19646058, 5720633, -11416706, 12814209, 11607948, 12749789, 14147075, 15156355, -21866831, 11835260 }, + { 19299512, 1155910, 28703737, 14890794, 2925026, 7269399, 26121523, 15467869, -26560550, 5052483 }, + }, + }, + { + { + { -3017432, 10058206, 1980837, 3964243, 22160966, 12322533, -6431123, -12618185, 12228557, -7003677 }, + { 32944382, 14922211, -22844894, 5188528, 21913450, -8719943, 4001465, 13238564, -6114803, 8653815 }, + { 22865569, -4652735, 27603668, -12545395, 14348958, 8234005, 24808405, 5719875, 28483275, 2841751 }, + }, + { + { -16420968, -1113305, -327719, -12107856, 21886282, -15552774, -1887966, -315658, 19932058, -12739203 }, + { -11656086, 10087521, -8864888, -5536143, -19278573, -3055912, 3999228, 13239134, -4777469, -13910208 }, + { 1382174, -11694719, 17266790, 9194690, -13324356, 9720081, 20403944, 11284705, -14013818, 3093230 }, + }, + { + { 16650921, -11037932, -1064178, 1570629, -8329746, 7352753, -302424, 16271225, -24049421, -6691850 }, + { -21911077, -5927941, -4611316, -5560156, -31744103, -10785293, 24123614, 15193618, -21652117, -16739389 }, + { -9935934, -4289447, -25279823, 4372842, 2087473, 10399484, 31870908, 14690798, 17361620, 11864968 }, + }, + { + { -11307610, 6210372, 13206574, 5806320, -29017692, -13967200, -12331205, -7486601, -25578460, -16240689 }, + { 14668462, -12270235, 26039039, 15305210, 25515617, 4542480, 10453892, 6577524, 9145645, -6443880 }, + { 5974874, 3053895, -9433049, -10385191, -31865124, 3225009, -7972642, 3936128, -5652273, -3050304 }, + }, + { + { 30625386, -4729400, -25555961, -12792866, -20484575, 7695099, 17097188, -16303496, -27999779, 1803632 }, + { -3553091, 9865099, -5228566, 4272701, -5673832, -16689700, 14911344, 12196514, -21405489, 7047412 }, + { 20093277, 9920966, -11138194, -5343857, 13161587, 12044805, -32856851, 4124601, -32343828, -10257566 }, + }, + { + { -20788824, 14084654, -13531713, 7842147, 19119038, -13822605, 4752377, -8714640, -21679658, 2288038 }, + { -26819236, -3283715, 29965059, 3039786, -14473765, 2540457, 29457502, 14625692, -24819617, 12570232 }, + { -1063558, -11551823, 16920318, 12494842, 1278292, -5869109, -21159943, -3498680, -11974704, 4724943 }, + }, + { + { 17960970, -11775534, -4140968, -9702530, -8876562, -1410617, -12907383, -8659932, -29576300, 1903856 }, + { 23134274, -14279132, -10681997, -1611936, 20684485, 15770816, -12989750, 3190296, 26955097, 14109738 }, + { 15308788, 5320727, -30113809, -14318877, 22902008, 7767164, 29425325, -11277562, 31960942, 11934971 }, + }, + { + { -27395711, 8435796, 4109644, 12222639, -24627868, 14818669, 20638173, 4875028, 10491392, 1379718 }, + { -13159415, 9197841, 3875503, -8936108, -1383712, -5879801, 33518459, 16176658, 21432314, 12180697 }, + { -11787308, 11500838, 13787581, -13832590, -22430679, 10140205, 1465425, 12689540, -10301319, -13872883 }, + }, + }, + { + { + { 5414091, -15386041, -21007664, 9643570, 12834970, 1186149, -2622916, -1342231, 26128231, 6032912 }, + { -26337395, -13766162, 32496025, -13653919, 17847801, -12669156, 3604025, 8316894, -25875034, -10437358 }, + { 3296484, 6223048, 24680646, -12246460, -23052020, 5903205, -8862297, -4639164, 12376617, 3188849 }, + }, + { + { 29190488, -14659046, 27549113, -1183516, 3520066, -10697301, 32049515, -7309113, -16109234, -9852307 }, + { -14744486, -9309156, 735818, -598978, -20407687, -5057904, 25246078, -15795669, 18640741, -960977 }, + { -6928835, -16430795, 10361374, 5642961, 4910474, 12345252, -31638386, -494430, 10530747, 1053335 }, + }, + { + { -29265967, -14186805, -13538216, -12117373, -19457059, -10655384, -31462369, -2948985, 24018831, 15026644 }, + { -22592535, -3145277, -2289276, 5953843, -13440189, 9425631, 25310643, 13003497, -2314791, -15145616 }, + { -27419985, -603321, -8043984, -1669117, -26092265, 13987819, -27297622, 187899, -23166419, -2531735 }, + }, + { + { -21744398, -13810475, 1844840, 5021428, -10434399, -15911473, 9716667, 16266922, -5070217, 726099 }, + { 29370922, -6053998, 7334071, -15342259, 9385287, 2247707, -13661962, -4839461, 30007388, -15823341 }, + { -936379, 16086691, 23751945, -543318, -1167538, -5189036, 9137109, 730663, 9835848, 4555336 }, + }, + { + { -23376435, 1410446, -22253753, -12899614, 30867635, 15826977, 17693930, 544696, -11985298, 12422646 }, + { 31117226, -12215734, -13502838, 6561947, -9876867, -12757670, -5118685, -4096706, 29120153, 13924425 }, + { -17400879, -14233209, 19675799, -2734756, -11006962, -5858820, -9383939, -11317700, 7240931, -237388 }, + }, + { + { -31361739, -11346780, -15007447, -5856218, -22453340, -12152771, 1222336, 4389483, 3293637, -15551743 }, + { -16684801, -14444245, 11038544, 11054958, -13801175, -3338533, -24319580, 7733547, 12796905, -6335822 }, + { -8759414, -10817836, -25418864, 10783769, -30615557, -9746811, -28253339, 3647836, 3222231, -11160462 }, + }, + { + { 18606113, 1693100, -25448386, -15170272, 4112353, 10045021, 23603893, -2048234, -7550776, 2484985 }, + { 9255317, -3131197, -12156162, -1004256, 13098013, -9214866, 16377220, -2102812, -19802075, -3034702 }, + { -22729289, 7496160, -5742199, 11329249, 19991973, -3347502, -31718148, 9936966, -30097688, -10618797 }, + }, + { + { 21878590, -5001297, 4338336, 13643897, -3036865, 13160960, 19708896, 5415497, -7360503, -4109293 }, + { 27736861, 10103576, 12500508, 8502413, -3413016, -9633558, 10436918, -1550276, -23659143, -8132100 }, + { 19492550, -12104365, -29681976, -852630, -3208171, 12403437, 30066266, 8367329, 13243957, 8709688 }, + }, + }, + { + { + { 12015105, 2801261, 28198131, 10151021, 24818120, -4743133, -11194191, -5645734, 5150968, 7274186 }, + { 2831366, -12492146, 1478975, 6122054, 23825128, -12733586, 31097299, 6083058, 31021603, -9793610 }, + { -2529932, -2229646, 445613, 10720828, -13849527, -11505937, -23507731, 16354465, 15067285, -14147707 }, + }, + { + { 7840942, 14037873, -33364863, 15934016, -728213, -3642706, 21403988, 1057586, -19379462, -12403220 }, + { 915865, -16469274, 15608285, -8789130, -24357026, 6060030, -17371319, 8410997, -7220461, 16527025 }, + { 32922597, -556987, 20336074, -16184568, 10903705, -5384487, 16957574, 52992, 23834301, 6588044 }, + }, + { + { 32752030, 11232950, 3381995, -8714866, 22652988, -10744103, 17159699, 16689107, -20314580, -1305992 }, + { -4689649, 9166776, -25710296, -10847306, 11576752, 12733943, 7924251, -2752281, 1976123, -7249027 }, + { 21251222, 16309901, -2983015, -6783122, 30810597, 12967303, 156041, -3371252, 12331345, -8237197 }, + }, + { + { 8651614, -4477032, -16085636, -4996994, 13002507, 2950805, 29054427, -5106970, 10008136, -4667901 }, + { 31486080, 15114593, -14261250, 12951354, 14369431, -7387845, 16347321, -13662089, 8684155, -10532952 }, + { 19443825, 11385320, 24468943, -9659068, -23919258, 2187569, -26263207, -6086921, 31316348, 14219878 }, + }, + { + { -28594490, 1193785, 32245219, 11392485, 31092169, 15722801, 27146014, 6992409, 29126555, 9207390 }, + { 32382935, 1110093, 18477781, 11028262, -27411763, -7548111, -4980517, 10843782, -7957600, -14435730 }, + { 2814918, 7836403, 27519878, -7868156, -20894015, -11553689, -21494559, 8550130, 28346258, 1994730 }, + }, + { + { -19578299, 8085545, -14000519, -3948622, 2785838, -16231307, -19516951, 7174894, 22628102, 8115180 }, + { -30405132, 955511, -11133838, -15078069, -32447087, -13278079, -25651578, 3317160, -9943017, 930272 }, + { -15303681, -6833769, 28856490, 1357446, 23421993, 1057177, 24091212, -1388970, -22765376, -10650715 }, + }, + { + { -22751231, -5303997, -12907607, -12768866, -15811511, -7797053, -14839018, -16554220, -1867018, 8398970 }, + { -31969310, 2106403, -4736360, 1362501, 12813763, 16200670, 22981545, -6291273, 18009408, -15772772 }, + { -17220923, -9545221, -27784654, 14166835, 29815394, 7444469, 29551787, -3727419, 19288549, 1325865 }, + }, + { + { 15100157, -15835752, -23923978, -1005098, -26450192, 15509408, 12376730, -3479146, 33166107, -8042750 }, + { 20909231, 13023121, -9209752, 16251778, -5778415, -8094914, 12412151, 10018715, 2213263, -13878373 }, + { 32529814, -11074689, 30361439, -16689753, -9135940, 1513226, 22922121, 6382134, -5766928, 8371348 }, + }, + }, + { + { + { 9923462, 11271500, 12616794, 3544722, -29998368, -1721626, 12891687, -8193132, -26442943, 10486144 }, + { -22597207, -7012665, 8587003, -8257861, 4084309, -12970062, 361726, 2610596, -23921530, -11455195 }, + { 5408411, -1136691, -4969122, 10561668, 24145918, 14240566, 31319731, -4235541, 19985175, -3436086 }, + }, + { + { -13994457, 16616821, 14549246, 3341099, 32155958, 13648976, -17577068, 8849297, 65030, 8370684 }, + { -8320926, -12049626, 31204563, 5839400, -20627288, -1057277, -19442942, 6922164, 12743482, -9800518 }, + { -2361371, 12678785, 28815050, 4759974, -23893047, 4884717, 23783145, 11038569, 18800704, 255233 }, + }, + { + { -5269658, -1773886, 13957886, 7990715, 23132995, 728773, 13393847, 9066957, 19258688, -14753793 }, + { -2936654, -10827535, -10432089, 14516793, -3640786, 4372541, -31934921, 2209390, -1524053, 2055794 }, + { 580882, 16705327, 5468415, -2683018, -30926419, -14696000, -7203346, -8994389, -30021019, 7394435 }, + }, + { + { 23838809, 1822728, -15738443, 15242727, 8318092, -3733104, -21672180, -3492205, -4821741, 14799921 }, + { 13345610, 9759151, 3371034, -16137791, 16353039, 8577942, 31129804, 13496856, -9056018, 7402518 }, + { 2286874, -4435931, -20042458, -2008336, -13696227, 5038122, 11006906, -15760352, 8205061, 1607563 }, + }, + { + { 14414086, -8002132, 3331830, -3208217, 22249151, -5594188, 18364661, -2906958, 30019587, -9029278 }, + { -27688051, 1585953, -10775053, 931069, -29120221, -11002319, -14410829, 12029093, 9944378, 8024 }, + { 4368715, -3709630, 29874200, -15022983, -20230386, -11410704, -16114594, -999085, -8142388, 5640030 }, + }, + { + { 10299610, 13746483, 11661824, 16234854, 7630238, 5998374, 9809887, -16694564, 15219798, -14327783 }, + { 27425505, -5719081, 3055006, 10660664, 23458024, 595578, -15398605, -1173195, -18342183, 9742717 }, + { 6744077, 2427284, 26042789, 2720740, -847906, 1118974, 32324614, 7406442, 12420155, 1994844 }, + }, + { + { 14012521, -5024720, -18384453, -9578469, -26485342, -3936439, -13033478, -10909803, 24319929, -6446333 }, + { 16412690, -4507367, 10772641, 15929391, -17068788, -4658621, 10555945, -10484049, -30102368, -4739048 }, + { 22397382, -7767684, -9293161, -12792868, 17166287, -9755136, -27333065, 6199366, 21880021, -12250760 }, + }, + { + { -4283307, 5368523, -31117018, 8163389, -30323063, 3209128, 16557151, 8890729, 8840445, 4957760 }, + { -15447727, 709327, -6919446, -10870178, -29777922, 6522332, -21720181, 12130072, -14796503, 5005757 }, + { -2114751, -14308128, 23019042, 15765735, -25269683, 6002752, 10183197, -13239326, -16395286, -2176112 }, + }, + }, + { + { + { -19025756, 1632005, 13466291, -7995100, -23640451, 16573537, -32013908, -3057104, 22208662, 2000468 }, + { 3065073, -1412761, -25598674, -361432, -17683065, -5703415, -8164212, 11248527, -3691214, -7414184 }, + { 10379208, -6045554, 8877319, 1473647, -29291284, -12507580, 16690915, 2553332, -3132688, 16400289 }, + }, + { + { 15716668, 1254266, -18472690, 7446274, -8448918, 6344164, -22097271, -7285580, 26894937, 9132066 }, + { 24158887, 12938817, 11085297, -8177598, -28063478, -4457083, -30576463, 64452, -6817084, -2692882 }, + { 13488534, 7794716, 22236231, 5989356, 25426474, -12578208, 2350710, -3418511, -4688006, 2364226 }, + }, + { + { 16335052, 9132434, 25640582, 6678888, 1725628, 8517937, -11807024, -11697457, 15445875, -7798101 }, + { 29004207, -7867081, 28661402, -640412, -12794003, -7943086, 31863255, -4135540, -278050, -15759279 }, + { -6122061, -14866665, -28614905, 14569919, -10857999, -3591829, 10343412, -6976290, -29828287, -10815811 }, + }, + { + { 27081650, 3463984, 14099042, -4517604, 1616303, -6205604, 29542636, 15372179, 17293797, 960709 }, + { 20263915, 11434237, -5765435, 11236810, 13505955, -10857102, -16111345, 6493122, -19384511, 7639714 }, + { -2830798, -14839232, 25403038, -8215196, -8317012, -16173699, 18006287, -16043750, 29994677, -15808121 }, + }, + { + { 9769828, 5202651, -24157398, -13631392, -28051003, -11561624, -24613141, -13860782, -31184575, 709464 }, + { 12286395, 13076066, -21775189, -1176622, -25003198, 4057652, -32018128, -8890874, 16102007, 13205847 }, + { 13733362, 5599946, 10557076, 3195751, -5557991, 8536970, -25540170, 8525972, 10151379, 10394400 }, + }, + { + { 4024660, -16137551, 22436262, 12276534, -9099015, -2686099, 19698229, 11743039, -33302334, 8934414 }, + { -15879800, -4525240, -8580747, -2934061, 14634845, -698278, -9449077, 3137094, -11536886, 11721158 }, + { 17555939, -5013938, 8268606, 2331751, -22738815, 9761013, 9319229, 8835153, -9205489, -1280045 }, + }, + { + { -461409, -7830014, 20614118, 16688288, -7514766, -4807119, 22300304, 505429, 6108462, -6183415 }, + { -5070281, 12367917, -30663534, 3234473, 32617080, -8422642, 29880583, -13483331, -26898490, -7867459 }, + { -31975283, 5726539, 26934134, 10237677, -3173717, -605053, 24199304, 3795095, 7592688, -14992079 }, + }, + { + { 21594432, -14964228, 17466408, -4077222, 32537084, 2739898, 6407723, 12018833, -28256052, 4298412 }, + { -20650503, -11961496, -27236275, 570498, 3767144, -1717540, 13891942, -1569194, 13717174, 10805743 }, + { -14676630, -15644296, 15287174, 11927123, 24177847, -8175568, -796431, 14860609, -26938930, -5863836 }, + }, + }, + { + { + { 12962541, 5311799, -10060768, 11658280, 18855286, -7954201, 13286263, -12808704, -4381056, 9882022 }, + { 18512079, 11319350, -20123124, 15090309, 18818594, 5271736, -22727904, 3666879, -23967430, -3299429 }, + { -6789020, -3146043, 16192429, 13241070, 15898607, -14206114, -10084880, -6661110, -2403099, 5276065 }, + }, + { + { 30169808, -5317648, 26306206, -11750859, 27814964, 7069267, 7152851, 3684982, 1449224, 13082861 }, + { 10342826, 3098505, 2119311, 193222, 25702612, 12233820, 23697382, 15056736, -21016438, -8202000 }, + { -33150110, 3261608, 22745853, 7948688, 19370557, -15177665, -26171976, 6482814, -10300080, -11060101 }, + }, + { + { 32869458, -5408545, 25609743, 15678670, -10687769, -15471071, 26112421, 2521008, -22664288, 6904815 }, + { 29506923, 4457497, 3377935, -9796444, -30510046, 12935080, 1561737, 3841096, -29003639, -6657642 }, + { 10340844, -6630377, -18656632, -2278430, 12621151, -13339055, 30878497, -11824370, -25584551, 5181966 }, + }, + { + { 25940115, -12658025, 17324188, -10307374, -8671468, 15029094, 24396252, -16450922, -2322852, -12388574 }, + { -21765684, 9916823, -1300409, 4079498, -1028346, 11909559, 1782390, 12641087, 20603771, -6561742 }, + { -18882287, -11673380, 24849422, 11501709, 13161720, -4768874, 1925523, 11914390, 4662781, 7820689 }, + }, + { + { 12241050, -425982, 8132691, 9393934, 32846760, -1599620, 29749456, 12172924, 16136752, 15264020 }, + { -10349955, -14680563, -8211979, 2330220, -17662549, -14545780, 10658213, 6671822, 19012087, 3772772 }, + { 3753511, -3421066, 10617074, 2028709, 14841030, -6721664, 28718732, -15762884, 20527771, 12988982 }, + }, + { + { -14822485, -5797269, -3707987, 12689773, -898983, -10914866, -24183046, -10564943, 3299665, -12424953 }, + { -16777703, -15253301, -9642417, 4978983, 3308785, 8755439, 6943197, 6461331, -25583147, 8991218 }, + { -17226263, 1816362, -1673288, -6086439, 31783888, -8175991, -32948145, 7417950, -30242287, 1507265 }, + }, + { + { 29692663, 6829891, -10498800, 4334896, 20945975, -11906496, -28887608, 8209391, 14606362, -10647073 }, + { -3481570, 8707081, 32188102, 5672294, 22096700, 1711240, -33020695, 9761487, 4170404, -2085325 }, + { -11587470, 14855945, -4127778, -1531857, -26649089, 15084046, 22186522, 16002000, -14276837, -8400798 }, + }, + { + { -4811456, 13761029, -31703877, -2483919, -3312471, 7869047, -7113572, -9620092, 13240845, 10965870 }, + { -7742563, -8256762, -14768334, -13656260, -23232383, 12387166, 4498947, 14147411, 29514390, 4302863 }, + { -13413405, -12407859, 20757302, -13801832, 14785143, 8976368, -5061276, -2144373, 17846988, -13971927 }, + }, + }, + { + { + { -2244452, -754728, -4597030, -1066309, -6247172, 1455299, -21647728, -9214789, -5222701, 12650267 }, + { -9906797, -16070310, 21134160, 12198166, -27064575, 708126, 387813, 13770293, -19134326, 10958663 }, + { 22470984, 12369526, 23446014, -5441109, -21520802, -9698723, -11772496, -11574455, -25083830, 4271862 }, + }, + { + { -25169565, -10053642, -19909332, 15361595, -5984358, 2159192, 75375, -4278529, -32526221, 8469673 }, + { 15854970, 4148314, -8893890, 7259002, 11666551, 13824734, -30531198, 2697372, 24154791, -9460943 }, + { 15446137, -15806644, 29759747, 14019369, 30811221, -9610191, -31582008, 12840104, 24913809, 9815020 }, + }, + { + { -4709286, -5614269, -31841498, -12288893, -14443537, 10799414, -9103676, 13438769, 18735128, 9466238 }, + { 11933045, 9281483, 5081055, -5183824, -2628162, -4905629, -7727821, -10896103, -22728655, 16199064 }, + { 14576810, 379472, -26786533, -8317236, -29426508, -10812974, -102766, 1876699, 30801119, 2164795 }, + }, + { + { 15995086, 3199873, 13672555, 13712240, -19378835, -4647646, -13081610, -15496269, -13492807, 1268052 }, + { -10290614, -3659039, -3286592, 10948818, 23037027, 3794475, -3470338, -12600221, -17055369, 3565904 }, + { 29210088, -9419337, -5919792, -4952785, 10834811, -13327726, -16512102, -10820713, -27162222, -14030531 }, + }, + { + { -13161890, 15508588, 16663704, -8156150, -28349942, 9019123, -29183421, -3769423, 2244111, -14001979 }, + { -5152875, -3800936, -9306475, -6071583, 16243069, 14684434, -25673088, -16180800, 13491506, 4641841 }, + { 10813417, 643330, -19188515, -728916, 30292062, -16600078, 27548447, -7721242, 14476989, -12767431 }, + }, + { + { 10292079, 9984945, 6481436, 8279905, -7251514, 7032743, 27282937, -1644259, -27912810, 12651324 }, + { -31185513, -813383, 22271204, 11835308, 10201545, 15351028, 17099662, 3988035, 21721536, -3148940 }, + { 10202177, -6545839, -31373232, -9574638, -32150642, -8119683, -12906320, 3852694, 13216206, 14842320 }, + }, + { + { -15815640, -10601066, -6538952, -7258995, -6984659, -6581778, -31500847, 13765824, -27434397, 9900184 }, + { 14465505, -13833331, -32133984, -14738873, -27443187, 12990492, 33046193, 15796406, -7051866, -8040114 }, + { 30924417, -8279620, 6359016, -12816335, 16508377, 9071735, -25488601, 15413635, 9524356, -7018878 }, + }, + { + { 12274201, -13175547, 32627641, -1785326, 6736625, 13267305, 5237659, -5109483, 15663516, 4035784 }, + { -2951309, 8903985, 17349946, 601635, -16432815, -4612556, -13732739, -15889334, -22258478, 4659091 }, + { -16916263, -4952973, -30393711, -15158821, 20774812, 15897498, 5736189, 15026997, -2178256, -13455585 }, + }, + }, + { + { + { -8858980, -2219056, 28571666, -10155518, -474467, -10105698, -3801496, 278095, 23440562, -290208 }, + { 10226241, -5928702, 15139956, 120818, -14867693, 5218603, 32937275, 11551483, -16571960, -7442864 }, + { 17932739, -12437276, -24039557, 10749060, 11316803, 7535897, 22503767, 5561594, -3646624, 3898661 }, + }, + { + { 7749907, -969567, -16339731, -16464, -25018111, 15122143, -1573531, 7152530, 21831162, 1245233 }, + { 26958459, -14658026, 4314586, 8346991, -5677764, 11960072, -32589295, -620035, -30402091, -16716212 }, + { -12165896, 9166947, 33491384, 13673479, 29787085, 13096535, 6280834, 14587357, -22338025, 13987525 }, + }, + { + { -24349909, 7778775, 21116000, 15572597, -4833266, -5357778, -4300898, -5124639, -7469781, -2858068 }, + { 9681908, -6737123, -31951644, 13591838, -6883821, 386950, 31622781, 6439245, -14581012, 4091397 }, + { -8426427, 1470727, -28109679, -1596990, 3978627, -5123623, -19622683, 12092163, 29077877, -14741988 }, + }, + { + { 5269168, -6859726, -13230211, -8020715, 25932563, 1763552, -5606110, -5505881, -20017847, 2357889 }, + { 32264008, -15407652, -5387735, -1160093, -2091322, -3946900, 23104804, -12869908, 5727338, 189038 }, + { 14609123, -8954470, -6000566, -16622781, -14577387, -7743898, -26745169, 10942115, -25888931, -14884697 }, + }, + { + { 20513500, 5557931, -15604613, 7829531, 26413943, -2019404, -21378968, 7471781, 13913677, -5137875 }, + { -25574376, 11967826, 29233242, 12948236, -6754465, 4713227, -8940970, 14059180, 12878652, 8511905 }, + { -25656801, 3393631, -2955415, -7075526, -2250709, 9366908, -30223418, 6812974, 5568676, -3127656 }, + }, + { + { 11630004, 12144454, 2116339, 13606037, 27378885, 15676917, -17408753, -13504373, -14395196, 8070818 }, + { 27117696, -10007378, -31282771, -5570088, 1127282, 12772488, -29845906, 10483306, -11552749, -1028714 }, + { 10637467, -5688064, 5674781, 1072708, -26343588, -6982302, -1683975, 9177853, -27493162, 15431203 }, + }, + { + { 20525145, 10892566, -12742472, 12779443, -29493034, 16150075, -28240519, 14943142, -15056790, -7935931 }, + { -30024462, 5626926, -551567, -9981087, 753598, 11981191, 25244767, -3239766, -3356550, 9594024 }, + { -23752644, 2636870, -5163910, -10103818, 585134, 7877383, 11345683, -6492290, 13352335, -10977084 }, + }, + { + { -1931799, -5407458, 3304649, -12884869, 17015806, -4877091, -29783850, -7752482, -13215537, -319204 }, + { 20239939, 6607058, 6203985, 3483793, -18386976, -779229, -20723742, 15077870, -22750759, 14523817 }, + { 27406042, -6041657, 27423596, -4497394, 4996214, 10002360, -28842031, -4545494, -30172742, -4805667 }, + }, + }, + { + { + { 11374242, 12660715, 17861383, -12540833, 10935568, 1099227, -13886076, -9091740, -27727044, 11358504 }, + { -12730809, 10311867, 1510375, 10778093, -2119455, -9145702, 32676003, 11149336, -26123651, 4985768 }, + { -19096303, 341147, -6197485, -239033, 15756973, -8796662, -983043, 13794114, -19414307, -15621255 }, + }, + { + { 6490081, 11940286, 25495923, -7726360, 8668373, -8751316, 3367603, 6970005, -1691065, -9004790 }, + { 1656497, 13457317, 15370807, 6364910, 13605745, 8362338, -19174622, -5475723, -16796596, -5031438 }, + { -22273315, -13524424, -64685, -4334223, -18605636, -10921968, -20571065, -7007978, -99853, -10237333 }, + }, + { + { 17747465, 10039260, 19368299, -4050591, -20630635, -16041286, 31992683, -15857976, -29260363, -5511971 }, + { 31932027, -4986141, -19612382, 16366580, 22023614, 88450, 11371999, -3744247, 4882242, -10626905 }, + { 29796507, 37186, 19818052, 10115756, -11829032, 3352736, 18551198, 3272828, -5190932, -4162409 }, + }, + { + { 12501286, 4044383, -8612957, -13392385, -32430052, 5136599, -19230378, -3529697, 330070, -3659409 }, + { 6384877, 2899513, 17807477, 7663917, -2358888, 12363165, 25366522, -8573892, -271295, 12071499 }, + { -8365515, -4042521, 25133448, -4517355, -6211027, 2265927, -32769618, 1936675, -5159697, 3829363 }, + }, + { + { 28425966, -5835433, -577090, -4697198, -14217555, 6870930, 7921550, -6567787, 26333140, 14267664 }, + { -11067219, 11871231, 27385719, -10559544, -4585914, -11189312, 10004786, -8709488, -21761224, 8930324 }, + { -21197785, -16396035, 25654216, -1725397, 12282012, 11008919, 1541940, 4757911, -26491501, -16408940 }, + }, + { + { 13537262, -7759490, -20604840, 10961927, -5922820, -13218065, -13156584, 6217254, -15943699, 13814990 }, + { -17422573, 15157790, 18705543, 29619, 24409717, -260476, 27361681, 9257833, -1956526, -1776914 }, + { -25045300, -10191966, 15366585, 15166509, -13105086, 8423556, -29171540, 12361135, -18685978, 4578290 }, + }, + { + { 24579768, 3711570, 1342322, -11180126, -27005135, 14124956, -22544529, 14074919, 21964432, 8235257 }, + { -6528613, -2411497, 9442966, -5925588, 12025640, -1487420, -2981514, -1669206, 13006806, 2355433 }, + { -16304899, -13605259, -6632427, -5142349, 16974359, -10911083, 27202044, 1719366, 1141648, -12796236 }, + }, + { + { -12863944, -13219986, -8318266, -11018091, -6810145, -4843894, 13475066, -3133972, 32674895, 13715045 }, + { 11423335, -5468059, 32344216, 8962751, 24989809, 9241752, -13265253, 16086212, -28740881, -15642093 }, + { -1409668, 12530728, -6368726, 10847387, 19531186, -14132160, -11709148, 7791794, -27245943, 4383347 }, + }, + }, + { + { + { -28970898, 5271447, -1266009, -9736989, -12455236, 16732599, -4862407, -4906449, 27193557, 6245191 }, + { -15193956, 5362278, -1783893, 2695834, 4960227, 12840725, 23061898, 3260492, 22510453, 8577507 }, + { -12632451, 11257346, -32692994, 13548177, -721004, 10879011, 31168030, 13952092, -29571492, -3635906 }, + }, + { + { 3877321, -9572739, 32416692, 5405324, -11004407, -13656635, 3759769, 11935320, 5611860, 8164018 }, + { -16275802, 14667797, 15906460, 12155291, -22111149, -9039718, 32003002, -8832289, 5773085, -8422109 }, + { -23788118, -8254300, 1950875, 8937633, 18686727, 16459170, -905725, 12376320, 31632953, 190926 }, + }, + { + { -24593607, -16138885, -8423991, 13378746, 14162407, 6901328, -8288749, 4508564, -25341555, -3627528 }, + { 8884438, -5884009, 6023974, 10104341, -6881569, -4941533, 18722941, -14786005, -1672488, 827625 }, + { -32720583, -16289296, -32503547, 7101210, 13354605, 2659080, -1800575, -14108036, -24878478, 1541286 }, + }, + { + { 2901347, -1117687, 3880376, -10059388, -17620940, -3612781, -21802117, -3567481, 20456845, -1885033 }, + { 27019610, 12299467, -13658288, -1603234, -12861660, -4861471, -19540150, -5016058, 29439641, 15138866 }, + { 21536104, -6626420, -32447818, -10690208, -22408077, 5175814, -5420040, -16361163, 7779328, 109896 }, + }, + { + { 30279744, 14648750, -8044871, 6425558, 13639621, -743509, 28698390, 12180118, 23177719, -554075 }, + { 26572847, 3405927, -31701700, 12890905, -19265668, 5335866, -6493768, 2378492, 4439158, -13279347 }, + { -22716706, 3489070, -9225266, -332753, 18875722, -1140095, 14819434, -12731527, -17717757, -5461437 }, + }, + { + { -5056483, 16566551, 15953661, 3767752, -10436499, 15627060, -820954, 2177225, 8550082, -15114165 }, + { -18473302, 16596775, -381660, 15663611, 22860960, 15585581, -27844109, -3582739, -23260460, -8428588 }, + { -32480551, 15707275, -8205912, -5652081, 29464558, 2713815, -22725137, 15860482, -21902570, 1494193 }, + }, + { + { -19562091, -14087393, -25583872, -9299552, 13127842, 759709, 21923482, 16529112, 8742704, 12967017 }, + { -28464899, 1553205, 32536856, -10473729, -24691605, -406174, -8914625, -2933896, -29903758, 15553883 }, + { 21877909, 3230008, 9881174, 10539357, -4797115, 2841332, 11543572, 14513274, 19375923, -12647961 }, + }, + { + { 8832269, -14495485, 13253511, 5137575, 5037871, 4078777, 24880818, -6222716, 2862653, 9455043 }, + { 29306751, 5123106, 20245049, -14149889, 9592566, 8447059, -2077124, -2990080, 15511449, 4789663 }, + { -20679756, 7004547, 8824831, -9434977, -4045704, -3750736, -5754762, 108893, 23513200, 16652362 }, + }, + }, + { + { + { -33256173, 4144782, -4476029, -6579123, 10770039, -7155542, -6650416, -12936300, -18319198, 10212860 }, + { 2756081, 8598110, 7383731, -6859892, 22312759, -1105012, 21179801, 2600940, -9988298, -12506466 }, + { -24645692, 13317462, -30449259, -15653928, 21365574, -10869657, 11344424, 864440, -2499677, -16710063 }, + }, + { + { -26432803, 6148329, -17184412, -14474154, 18782929, -275997, -22561534, 211300, 2719757, 4940997 }, + { -1323882, 3911313, -6948744, 14759765, -30027150, 7851207, 21690126, 8518463, 26699843, 5276295 }, + { -13149873, -6429067, 9396249, 365013, 24703301, -10488939, 1321586, 149635, -15452774, 7159369 }, + }, + { + { 9987780, -3404759, 17507962, 9505530, 9731535, -2165514, 22356009, 8312176, 22477218, -8403385 }, + { 18155857, -16504990, 19744716, 9006923, 15154154, -10538976, 24256460, -4864995, -22548173, 9334109 }, + { 2986088, -4911893, 10776628, -3473844, 10620590, -7083203, -21413845, 14253545, -22587149, 536906 }, + }, + { + { 4377756, 8115836, 24567078, 15495314, 11625074, 13064599, 7390551, 10589625, 10838060, -15420424 }, + { -19342404, 867880, 9277171, -3218459, -14431572, -1986443, 19295826, -15796950, 6378260, 699185 }, + { 7895026, 4057113, -7081772, -13077756, -17886831, -323126, -716039, 15693155, -5045064, -13373962 }, + }, + { + { -7737563, -5869402, -14566319, -7406919, 11385654, 13201616, 31730678, -10962840, -3918636, -9669325 }, + { 10188286, -15770834, -7336361, 13427543, 22223443, 14896287, 30743455, 7116568, -21786507, 5427593 }, + { 696102, 13206899, 27047647, -10632082, 15285305, -9853179, 10798490, -4578720, 19236243, 12477404 }, + }, + { + { -11229439, 11243796, -17054270, -8040865, -788228, -8167967, -3897669, 11180504, -23169516, 7733644 }, + { 17800790, -14036179, -27000429, -11766671, 23887827, 3149671, 23466177, -10538171, 10322027, 15313801 }, + { 26246234, 11968874, 32263343, -5468728, 6830755, -13323031, -15794704, -101982, -24449242, 10890804 }, + }, + { + { -31365647, 10271363, -12660625, -6267268, 16690207, -13062544, -14982212, 16484931, 25180797, -5334884 }, + { -586574, 10376444, -32586414, -11286356, 19801893, 10997610, 2276632, 9482883, 316878, 13820577 }, + { -9882808, -4510367, -2115506, 16457136, -11100081, 11674996, 30756178, -7515054, 30696930, -3712849 }, + }, + { + { 32988917, -9603412, 12499366, 7910787, -10617257, -11931514, -7342816, -9985397, -32349517, 7392473 }, + { -8855661, 15927861, 9866406, -3649411, -2396914, -16655781, -30409476, -9134995, 25112947, -2926644 }, + { -2504044, -436966, 25621774, -5678772, 15085042, -5479877, -24884878, -13526194, 5537438, -13914319 }, + }, + }, + { + { + { -11225584, 2320285, -9584280, 10149187, -33444663, 5808648, -14876251, -1729667, 31234590, 6090599 }, + { -9633316, 116426, 26083934, 2897444, -6364437, -2688086, 609721, 15878753, -6970405, -9034768 }, + { -27757857, 247744, -15194774, -9002551, 23288161, -10011936, -23869595, 6503646, 20650474, 1804084 }, + }, + { + { -27589786, 15456424, 8972517, 8469608, 15640622, 4439847, 3121995, -10329713, 27842616, -202328 }, + { -15306973, 2839644, 22530074, 10026331, 4602058, 5048462, 28248656, 5031932, -11375082, 12714369 }, + { 20807691, -7270825, 29286141, 11421711, -27876523, -13868230, -21227475, 1035546, -19733229, 12796920 }, + }, + { + { 12076899, -14301286, -8785001, -11848922, -25012791, 16400684, -17591495, -12899438, 3480665, -15182815 }, + { -32361549, 5457597, 28548107, 7833186, 7303070, -11953545, -24363064, -15921875, -33374054, 2771025 }, + { -21389266, 421932, 26597266, 6860826, 22486084, -6737172, -17137485, -4210226, -24552282, 15673397 }, + }, + { + { -20184622, 2338216, 19788685, -9620956, -4001265, -8740893, -20271184, 4733254, 3727144, -12934448 }, + { 6120119, 814863, -11794402, -622716, 6812205, -15747771, 2019594, 7975683, 31123697, -10958981 }, + { 30069250, -11435332, 30434654, 2958439, 18399564, -976289, 12296869, 9204260, -16432438, 9648165 }, + }, + { + { 32705432, -1550977, 30705658, 7451065, -11805606, 9631813, 3305266, 5248604, -26008332, -11377501 }, + { 17219865, 2375039, -31570947, -5575615, -19459679, 9219903, 294711, 15298639, 2662509, -16297073 }, + { -1172927, -7558695, -4366770, -4287744, -21346413, -8434326, 32087529, -1222777, 32247248, -14389861 }, + }, + { + { 14312628, 1221556, 17395390, -8700143, -4945741, -8684635, -28197744, -9637817, -16027623, -13378845 }, + { -1428825, -9678990, -9235681, 6549687, -7383069, -468664, 23046502, 9803137, 17597934, 2346211 }, + { 18510800, 15337574, 26171504, 981392, -22241552, 7827556, -23491134, -11323352, 3059833, -11782870 }, + }, + { + { 10141598, 6082907, 17829293, -1947643, 9830092, 13613136, -25556636, -5544586, -33502212, 3592096 }, + { 33114168, -15889352, -26525686, -13343397, 33076705, 8716171, 1151462, 1521897, -982665, -6837803 }, + { -32939165, -4255815, 23947181, -324178, -33072974, -12305637, -16637686, 3891704, 26353178, 693168 }, + }, + { + { 30374239, 1595580, -16884039, 13186931, 4600344, 406904, 9585294, -400668, 31375464, 14369965 }, + { -14370654, -7772529, 1510301, 6434173, -18784789, -6262728, 32732230, -13108839, 17901441, 16011505 }, + { 18171223, -11934626, -12500402, 15197122, -11038147, -15230035, -19172240, -16046376, 8764035, 12309598 }, + }, + }, + { + { + { 5975908, -5243188, -19459362, -9681747, -11541277, 14015782, -23665757, 1228319, 17544096, -10593782 }, + { 5811932, -1715293, 3442887, -2269310, -18367348, -8359541, -18044043, -15410127, -5565381, 12348900 }, + { -31399660, 11407555, 25755363, 6891399, -3256938, 14872274, -24849353, 8141295, -10632534, -585479 }, + }, + { + { -12675304, 694026, -5076145, 13300344, 14015258, -14451394, -9698672, -11329050, 30944593, 1130208 }, + { 8247766, -6710942, -26562381, -7709309, -14401939, -14648910, 4652152, 2488540, 23550156, -271232 }, + { 17294316, -3788438, 7026748, 15626851, 22990044, 113481, 2267737, -5908146, -408818, -137719 }, + }, + { + { 16091085, -16253926, 18599252, 7340678, 2137637, -1221657, -3364161, 14550936, 3260525, -7166271 }, + { -4910104, -13332887, 18550887, 10864893, -16459325, -7291596, -23028869, -13204905, -12748722, 2701326 }, + { -8574695, 16099415, 4629974, -16340524, -20786213, -6005432, -10018363, 9276971, 11329923, 1862132 }, + }, + { + { 14763076, -15903608, -30918270, 3689867, 3511892, 10313526, -21951088, 12219231, -9037963, -940300 }, + { 8894987, -3446094, 6150753, 3013931, 301220, 15693451, -31981216, -2909717, -15438168, 11595570 }, + { 15214962, 3537601, -26238722, -14058872, 4418657, -15230761, 13947276, 10730794, -13489462, -4363670 }, + }, + { + { -2538306, 7682793, 32759013, 263109, -29984731, -7955452, -22332124, -10188635, 977108, 699994 }, + { -12466472, 4195084, -9211532, 550904, -15565337, 12917920, 19118110, -439841, -30534533, -14337913 }, + { 31788461, -14507657, 4799989, 7372237, 8808585, -14747943, 9408237, -10051775, 12493932, -5409317 }, + }, + { + { -25680606, 5260744, -19235809, -6284470, -3695942, 16566087, 27218280, 2607121, 29375955, 6024730 }, + { 842132, -2794693, -4763381, -8722815, 26332018, -12405641, 11831880, 6985184, -9940361, 2854096 }, + { -4847262, -7969331, 2516242, -5847713, 9695691, -7221186, 16512645, 960770, 12121869, 16648078 }, + }, + { + { -15218652, 14667096, -13336229, 2013717, 30598287, -464137, -31504922, -7882064, 20237806, 2838411 }, + { -19288047, 4453152, 15298546, -16178388, 22115043, -15972604, 12544294, -13470457, 1068881, -12499905 }, + { -9558883, -16518835, 33238498, 13506958, 30505848, -1114596, -8486907, -2630053, 12521378, 4845654 }, + }, + { + { -28198521, 10744108, -2958380, 10199664, 7759311, -13088600, 3409348, -873400, -6482306, -12885870 }, + { -23561822, 6230156, -20382013, 10655314, -24040585, -11621172, 10477734, -1240216, -3113227, 13974498 }, + { 12966261, 15550616, -32038948, -1615346, 21025980, -629444, 5642325, 7188737, 18895762, 12629579 }, + }, + }, + { + { + { 14741879, -14946887, 22177208, -11721237, 1279741, 8058600, 11758140, 789443, 32195181, 3895677 }, + { 10758205, 15755439, -4509950, 9243698, -4879422, 6879879, -2204575, -3566119, -8982069, 4429647 }, + { -2453894, 15725973, -20436342, -10410672, -5803908, -11040220, -7135870, -11642895, 18047436, -15281743 }, + }, + { + { -25173001, -11307165, 29759956, 11776784, -22262383, -15820455, 10993114, -12850837, -17620701, -9408468 }, + { 21987233, 700364, -24505048, 14972008, -7774265, -5718395, 32155026, 2581431, -29958985, 8773375 }, + { -25568350, 454463, -13211935, 16126715, 25240068, 8594567, 20656846, 12017935, -7874389, -13920155 }, + }, + { + { 6028182, 6263078, -31011806, -11301710, -818919, 2461772, -31841174, -5468042, -1721788, -2776725 }, + { -12278994, 16624277, 987579, -5922598, 32908203, 1248608, 7719845, -4166698, 28408820, 6816612 }, + { -10358094, -8237829, 19549651, -12169222, 22082623, 16147817, 20613181, 13982702, -10339570, 5067943 }, + }, + { + { -30505967, -3821767, 12074681, 13582412, -19877972, 2443951, -19719286, 12746132, 5331210, -10105944 }, + { 30528811, 3601899, -1957090, 4619785, -27361822, -15436388, 24180793, -12570394, 27679908, -1648928 }, + { 9402404, -13957065, 32834043, 10838634, -26580150, -13237195, 26653274, -8685565, 22611444, -12715406 }, + }, + { + { 22190590, 1118029, 22736441, 15130463, -30460692, -5991321, 19189625, -4648942, 4854859, 6622139 }, + { -8310738, -2953450, -8262579, -3388049, -10401731, -271929, 13424426, -3567227, 26404409, 13001963 }, + { -31241838, -15415700, -2994250, 8939346, 11562230, -12840670, -26064365, -11621720, -15405155, 11020693 }, + }, + { + { 1866042, -7949489, -7898649, -10301010, 12483315, 13477547, 3175636, -12424163, 28761762, 1406734 }, + { -448555, -1777666, 13018551, 3194501, -9580420, -11161737, 24760585, -4347088, 25577411, -13378680 }, + { -24290378, 4759345, -690653, -1852816, 2066747, 10693769, -29595790, 9884936, -9368926, 4745410 }, + }, + { + { -9141284, 6049714, -19531061, -4341411, -31260798, 9944276, -15462008, -11311852, 10931924, -11931931 }, + { -16561513, 14112680, -8012645, 4817318, -8040464, -11414606, -22853429, 10856641, -20470770, 13434654 }, + { 22759489, -10073434, -16766264, -1871422, 13637442, -10168091, 1765144, -12654326, 28445307, -5364710 }, + }, + { + { 29875063, 12493613, 2795536, -3786330, 1710620, 15181182, -10195717, -8788675, 9074234, 1167180 }, + { -26205683, 11014233, -9842651, -2635485, -26908120, 7532294, -18716888, -9535498, 3843903, 9367684 }, + { -10969595, -6403711, 9591134, 9582310, 11349256, 108879, 16235123, 8601684, -139197, 4242895 }, + }, + }, + { + { + { 22092954, -13191123, -2042793, -11968512, 32186753, -11517388, -6574341, 2470660, -27417366, 16625501 }, + { -11057722, 3042016, 13770083, -9257922, 584236, -544855, -7770857, 2602725, -27351616, 14247413 }, + { 6314175, -10264892, -32772502, 15957557, -10157730, 168750, -8618807, 14290061, 27108877, -1180880 }, + }, + { + { -8586597, -7170966, 13241782, 10960156, -32991015, -13794596, 33547976, -11058889, -27148451, 981874 }, + { 22833440, 9293594, -32649448, -13618667, -9136966, 14756819, -22928859, -13970780, -10479804, -16197962 }, + { -7768587, 3326786, -28111797, 10783824, 19178761, 14905060, 22680049, 13906969, -15933690, 3797899 }, + }, + { + { 21721356, -4212746, -12206123, 9310182, -3882239, -13653110, 23740224, -2709232, 20491983, -8042152 }, + { 9209270, -15135055, -13256557, -6167798, -731016, 15289673, 25947805, 15286587, 30997318, -6703063 }, + { 7392032, 16618386, 23946583, -8039892, -13265164, -1533858, -14197445, -2321576, 17649998, -250080 }, + }, + { + { -9301088, -14193827, 30609526, -3049543, -25175069, -1283752, -15241566, -9525724, -2233253, 7662146 }, + { -17558673, 1763594, -33114336, 15908610, -30040870, -12174295, 7335080, -8472199, -3174674, 3440183 }, + { -19889700, -5977008, -24111293, -9688870, 10799743, -16571957, 40450, -4431835, 4862400, 1133 }, + }, + { + { -32856209, -7873957, -5422389, 14860950, -16319031, 7956142, 7258061, 311861, -30594991, -7379421 }, + { -3773428, -1565936, 28985340, 7499440, 24445838, 9325937, 29727763, 16527196, 18278453, 15405622 }, + { -4381906, 8508652, -19898366, -3674424, -5984453, 15149970, -13313598, 843523, -21875062, 13626197 }, + }, + { + { 2281448, -13487055, -10915418, -2609910, 1879358, 16164207, -10783882, 3953792, 13340839, 15928663 }, + { 31727126, -7179855, -18437503, -8283652, 2875793, -16390330, -25269894, -7014826, -23452306, 5964753 }, + { 4100420, -5959452, -17179337, 6017714, -18705837, 12227141, -26684835, 11344144, 2538215, -7570755 }, + }, + { + { -9433605, 6123113, 11159803, -2156608, 30016280, 14966241, -20474983, 1485421, -629256, -15958862 }, + { -26804558, 4260919, 11851389, 9658551, -32017107, 16367492, -20205425, -13191288, 11659922, -11115118 }, + { 26180396, 10015009, -30844224, -8581293, 5418197, 9480663, 2231568, -10170080, 33100372, -1306171 }, + }, + { + { 15121113, -5201871, -10389905, 15427821, -27509937, -15992507, 21670947, 4486675, -5931810, -14466380 }, + { 16166486, -9483733, -11104130, 6023908, -31926798, -1364923, 2340060, -16254968, -10735770, -10039824 }, + { 28042865, -3557089, -12126526, 12259706, -3717498, -6945899, 6766453, -8689599, 18036436, 5803270 }, + }, + }, + { + { + { -817581, 6763912, 11803561, 1585585, 10958447, -2671165, 23855391, 4598332, -6159431, -14117438 }, + { -31031306, -14256194, 17332029, -2383520, 31312682, -5967183, 696309, 50292, -20095739, 11763584 }, + { -594563, -2514283, -32234153, 12643980, 12650761, 14811489, 665117, -12613632, -19773211, -10713562 }, + }, + { + { 30464590, -11262872, -4127476, -12734478, 19835327, -7105613, -24396175, 2075773, -17020157, 992471 }, + { 18357185, -6994433, 7766382, 16342475, -29324918, 411174, 14578841, 8080033, -11574335, -10601610 }, + { 19598397, 10334610, 12555054, 2555664, 18821899, -10339780, 21873263, 16014234, 26224780, 16452269 }, + }, + { + { -30223925, 5145196, 5944548, 16385966, 3976735, 2009897, -11377804, -7618186, -20533829, 3698650 }, + { 14187449, 3448569, -10636236, -10810935, -22663880, -3433596, 7268410, -10890444, 27394301, 12015369 }, + { 19695761, 16087646, 28032085, 12999827, 6817792, 11427614, 20244189, -1312777, -13259127, -3402461 }, + }, + { + { 30860103, 12735208, -1888245, -4699734, -16974906, 2256940, -8166013, 12298312, -8550524, -10393462 }, + { -5719826, -11245325, -1910649, 15569035, 26642876, -7587760, -5789354, -15118654, -4976164, 12651793 }, + { -2848395, 9953421, 11531313, -5282879, 26895123, -12697089, -13118820, -16517902, 9768698, -2533218 }, + }, + { + { -24719459, 1894651, -287698, -4704085, 15348719, -8156530, 32767513, 12765450, 4940095, 10678226 }, + { 18860224, 15980149, -18987240, -1562570, -26233012, -11071856, -7843882, 13944024, -24372348, 16582019 }, + { -15504260, 4970268, -29893044, 4175593, -20993212, -2199756, -11704054, 15444560, -11003761, 7989037 }, + }, + { + { 31490452, 5568061, -2412803, 2182383, -32336847, 4531686, -32078269, 6200206, -19686113, -14800171 }, + { -17308668, -15879940, -31522777, -2831, -32887382, 16375549, 8680158, -16371713, 28550068, -6857132 }, + { -28126887, -5688091, 16837845, -1820458, -6850681, 12700016, -30039981, 4364038, 1155602, 5988841 }, + }, + { + { 21890435, -13272907, -12624011, 12154349, -7831873, 15300496, 23148983, -4470481, 24618407, 8283181 }, + { -33136107, -10512751, 9975416, 6841041, -31559793, 16356536, 3070187, -7025928, 1466169, 10740210 }, + { -1509399, -15488185, -13503385, -10655916, 32799044, 909394, -13938903, -5779719, -32164649, -15327040 }, + }, + { + { 3960823, -14267803, -28026090, -15918051, -19404858, 13146868, 15567327, 951507, -3260321, -573935 }, + { 24740841, 5052253, -30094131, 8961361, 25877428, 6165135, -24368180, 14397372, -7380369, -6144105 }, + { -28888365, 3510803, -28103278, -1158478, -11238128, -10631454, -15441463, -14453128, -1625486, -6494814 }, + }, + }, + { + { + { 793299, -9230478, 8836302, -6235707, -27360908, -2369593, 33152843, -4885251, -9906200, -621852 }, + { 5666233, 525582, 20782575, -8038419, -24538499, 14657740, 16099374, 1468826, -6171428, -15186581 }, + { -4859255, -3779343, -2917758, -6748019, 7778750, 11688288, -30404353, -9871238, -1558923, -9863646 }, + }, + { + { 10896332, -7719704, 824275, 472601, -19460308, 3009587, 25248958, 14783338, -30581476, -15757844 }, + { 10566929, 12612572, -31944212, 11118703, -12633376, 12362879, 21752402, 8822496, 24003793, 14264025 }, + { 27713862, -7355973, -11008240, 9227530, 27050101, 2504721, 23886875, -13117525, 13958495, -5732453 }, + }, + { + { -23481610, 4867226, -27247128, 3900521, 29838369, -8212291, -31889399, -10041781, 7340521, -15410068 }, + { 4646514, -8011124, -22766023, -11532654, 23184553, 8566613, 31366726, -1381061, -15066784, -10375192 }, + { -17270517, 12723032, -16993061, 14878794, 21619651, -6197576, 27584817, 3093888, -8843694, 3849921 }, + }, + { + { -9064912, 2103172, 25561640, -15125738, -5239824, 9582958, 32477045, -9017955, 5002294, -15550259 }, + { -12057553, -11177906, 21115585, -13365155, 8808712, -12030708, 16489530, 13378448, -25845716, 12741426 }, + { -5946367, 10645103, -30911586, 15390284, -3286982, -7118677, 24306472, 15852464, 28834118, -7646072 }, + }, + { + { -17335748, -9107057, -24531279, 9434953, -8472084, -583362, -13090771, 455841, 20461858, 5491305 }, + { 13669248, -16095482, -12481974, -10203039, -14569770, -11893198, -24995986, 11293807, -28588204, -9421832 }, + { 28497928, 6272777, -33022994, 14470570, 8906179, -1225630, 18504674, -14165166, 29867745, -8795943 }, + }, + { + { -16207023, 13517196, -27799630, -13697798, 24009064, -6373891, -6367600, -13175392, 22853429, -4012011 }, + { 24191378, 16712145, -13931797, 15217831, 14542237, 1646131, 18603514, -11037887, 12876623, -2112447 }, + { 17902668, 4518229, -411702, -2829247, 26878217, 5258055, -12860753, 608397, 16031844, 3723494 }, + }, + { + { -28632773, 12763728, -20446446, 7577504, 33001348, -13017745, 17558842, -7872890, 23896954, -4314245 }, + { -20005381, -12011952, 31520464, 605201, 2543521, 5991821, -2945064, 7229064, -9919646, -8826859 }, + { 28816045, 298879, -28165016, -15920938, 19000928, -1665890, -12680833, -2949325, -18051778, -2082915 }, + }, + { + { 16000882, -344896, 3493092, -11447198, -29504595, -13159789, 12577740, 16041268, -19715240, 7847707 }, + { 10151868, 10572098, 27312476, 7922682, 14825339, 4723128, -32855931, -6519018, -10020567, 3852848 }, + { -11430470, 15697596, -21121557, -4420647, 5386314, 15063598, 16514493, -15932110, 29330899, -15076224 }, + }, + }, + { + { + { -25499735, -4378794, -15222908, -6901211, 16615731, 2051784, 3303702, 15490, -27548796, 12314391 }, + { 15683520, -6003043, 18109120, -9980648, 15337968, -5997823, -16717435, 15921866, 16103996, -3731215 }, + { -23169824, -10781249, 13588192, -1628807, -3798557, -1074929, -19273607, 5402699, -29815713, -9841101 }, + }, + { + { 23190676, 2384583, -32714340, 3462154, -29903655, -1529132, -11266856, 8911517, -25205859, 2739713 }, + { 21374101, -3554250, -33524649, 9874411, 15377179, 11831242, -33529904, 6134907, 4931255, 11987849 }, + { -7732, -2978858, -16223486, 7277597, 105524, -322051, -31480539, 13861388, -30076310, 10117930 }, + }, + { + { -29501170, -10744872, -26163768, 13051539, -25625564, 5089643, -6325503, 6704079, 12890019, 15728940 }, + { -21972360, -11771379, -951059, -4418840, 14704840, 2695116, 903376, -10428139, 12885167, 8311031 }, + { -17516482, 5352194, 10384213, -13811658, 7506451, 13453191, 26423267, 4384730, 1888765, -5435404 }, + }, + { + { -25817338, -3107312, -13494599, -3182506, 30896459, -13921729, -32251644, -12707869, -19464434, -3340243 }, + { -23607977, -2665774, -526091, 4651136, 5765089, 4618330, 6092245, 14845197, 17151279, -9854116 }, + { -24830458, -12733720, -15165978, 10367250, -29530908, -265356, 22825805, -7087279, -16866484, 16176525 }, + }, + { + { -23583256, 6564961, 20063689, 3798228, -4740178, 7359225, 2006182, -10363426, -28746253, -10197509 }, + { -10626600, -4486402, -13320562, -5125317, 3432136, -6393229, 23632037, -1940610, 32808310, 1099883 }, + { 15030977, 5768825, -27451236, -2887299, -6427378, -15361371, -15277896, -6809350, 2051441, -15225865 }, + }, + { + { -3362323, -7239372, 7517890, 9824992, 23555850, 295369, 5148398, -14154188, -22686354, 16633660 }, + { 4577086, -16752288, 13249841, -15304328, 19958763, -14537274, 18559670, -10759549, 8402478, -9864273 }, + { -28406330, -1051581, -26790155, -907698, -17212414, -11030789, 9453451, -14980072, 17983010, 9967138 }, + }, + { + { -25762494, 6524722, 26585488, 9969270, 24709298, 1220360, -1677990, 7806337, 17507396, 3651560 }, + { -10420457, -4118111, 14584639, 15971087, -15768321, 8861010, 26556809, -5574557, -18553322, -11357135 }, + { 2839101, 14284142, 4029895, 3472686, 14402957, 12689363, -26642121, 8459447, -5605463, -7621941 }, + }, + { + { -4839289, -3535444, 9744961, 2871048, 25113978, 3187018, -25110813, -849066, 17258084, -7977739 }, + { 18164541, -10595176, -17154882, -1542417, 19237078, -9745295, 23357533, -15217008, 26908270, 12150756 }, + { -30264870, -7647865, 5112249, -7036672, -1499807, -6974257, 43168, -5537701, -32302074, 16215819 }, + }, + }, + { + { + { -6898905, 9824394, -12304779, -4401089, -31397141, -6276835, 32574489, 12532905, -7503072, -8675347 }, + { -27343522, -16515468, -27151524, -10722951, 946346, 16291093, 254968, 7168080, 21676107, -1943028 }, + { 21260961, -8424752, -16831886, -11920822, -23677961, 3968121, -3651949, -6215466, -3556191, -7913075 }, + }, + { + { 16544754, 13250366, -16804428, 15546242, -4583003, 12757258, -2462308, -8680336, -18907032, -9662799 }, + { -2415239, -15577728, 18312303, 4964443, -15272530, -12653564, 26820651, 16690659, 25459437, -4564609 }, + { -25144690, 11425020, 28423002, -11020557, -6144921, -15826224, 9142795, -2391602, -6432418, -1644817 }, + }, + { + { -23104652, 6253476, 16964147, -3768872, -25113972, -12296437, -27457225, -16344658, 6335692, 7249989 }, + { -30333227, 13979675, 7503222, -12368314, -11956721, -4621693, -30272269, 2682242, 25993170, -12478523 }, + { 4364628, 5930691, 32304656, -10044554, -8054781, 15091131, 22857016, -10598955, 31820368, 15075278 }, + }, + { + { 31879134, -8918693, 17258761, 90626, -8041836, -4917709, 24162788, -9650886, -17970238, 12833045 }, + { 19073683, 14851414, -24403169, -11860168, 7625278, 11091125, -19619190, 2074449, -9413939, 14905377 }, + { 24483667, -11935567, -2518866, -11547418, -1553130, 15355506, -25282080, 9253129, 27628530, -7555480 }, + }, + { + { 17597607, 8340603, 19355617, 552187, 26198470, -3176583, 4593324, -9157582, -14110875, 15297016 }, + { 510886, 14337390, -31785257, 16638632, 6328095, 2713355, -20217417, -11864220, 8683221, 2921426 }, + { 18606791, 11874196, 27155355, -5281482, -24031742, 6265446, -25178240, -1278924, 4674690, 13890525 }, + }, + { + { 13609624, 13069022, -27372361, -13055908, 24360586, 9592974, 14977157, 9835105, 4389687, 288396 }, + { 9922506, -519394, 13613107, 5883594, -18758345, -434263, -12304062, 8317628, 23388070, 16052080 }, + { 12720016, 11937594, -31970060, -5028689, 26900120, 8561328, -20155687, -11632979, -14754271, -10812892 }, + }, + { + { 15961858, 14150409, 26716931, -665832, -22794328, 13603569, 11829573, 7467844, -28822128, 929275 }, + { 11038231, -11582396, -27310482, -7316562, -10498527, -16307831, -23479533, -9371869, -21393143, 2465074 }, + { 20017163, -4323226, 27915242, 1529148, 12396362, 15675764, 13817261, -9658066, 2463391, -4622140 }, + }, + { + { -16358878, -12663911, -12065183, 4996454, -1256422, 1073572, 9583558, 12851107, 4003896, 12673717 }, + { -1731589, -15155870, -3262930, 16143082, 19294135, 13385325, 14741514, -9103726, 7903886, 2348101 }, + { 24536016, -16515207, 12715592, -3862155, 1511293, 10047386, -3842346, -7129159, -28377538, 10048127 }, + }, + }, + { + { + { -12622226, -6204820, 30718825, 2591312, -10617028, 12192840, 18873298, -7297090, -32297756, 15221632 }, + { -26478122, -11103864, 11546244, -1852483, 9180880, 7656409, -21343950, 2095755, 29769758, 6593415 }, + { -31994208, -2907461, 4176912, 3264766, 12538965, -868111, 26312345, -6118678, 30958054, 8292160 }, + }, + { + { 31429822, -13959116, 29173532, 15632448, 12174511, -2760094, 32808831, 3977186, 26143136, -3148876 }, + { 22648901, 1402143, -22799984, 13746059, 7936347, 365344, -8668633, -1674433, -3758243, -2304625 }, + { -15491917, 8012313, -2514730, -12702462, -23965846, -10254029, -1612713, -1535569, -16664475, 8194478 }, + }, + { + { 27338066, -7507420, -7414224, 10140405, -19026427, -6589889, 27277191, 8855376, 28572286, 3005164 }, + { 26287124, 4821776, 25476601, -4145903, -3764513, -15788984, -18008582, 1182479, -26094821, -13079595 }, + { -7171154, 3178080, 23970071, 6201893, -17195577, -4489192, -21876275, -13982627, 32208683, -1198248 }, + }, + { + { -16657702, 2817643, -10286362, 14811298, 6024667, 13349505, -27315504, -10497842, -27672585, -11539858 }, + { 15941029, -9405932, -21367050, 8062055, 31876073, -238629, -15278393, -1444429, 15397331, -4130193 }, + { 8934485, -13485467, -23286397, -13423241, -32446090, 14047986, 31170398, -1441021, -27505566, 15087184 }, + }, + { + { -18357243, -2156491, 24524913, -16677868, 15520427, -6360776, -15502406, 11461896, 16788528, -5868942 }, + { -1947386, 16013773, 21750665, 3714552, -17401782, -16055433, -3770287, -10323320, 31322514, -11615635 }, + { 21426655, -5650218, -13648287, -5347537, -28812189, -4920970, -18275391, -14621414, 13040862, -12112948 }, + }, + { + { 11293895, 12478086, -27136401, 15083750, -29307421, 14748872, 14555558, -13417103, 1613711, 4896935 }, + { -25894883, 15323294, -8489791, -8057900, 25967126, -13425460, 2825960, -4897045, -23971776, -11267415 }, + { -15924766, -5229880, -17443532, 6410664, 3622847, 10243618, 20615400, 12405433, -23753030, -8436416 }, + }, + { + { -7091295, 12556208, -20191352, 9025187, -17072479, 4333801, 4378436, 2432030, 23097949, -566018 }, + { 4565804, -16025654, 20084412, -7842817, 1724999, 189254, 24767264, 10103221, -18512313, 2424778 }, + { 366633, -11976806, 8173090, -6890119, 30788634, 5745705, -7168678, 1344109, -3642553, 12412659 }, + }, + { + { -24001791, 7690286, 14929416, -168257, -32210835, -13412986, 24162697, -15326504, -3141501, 11179385 }, + { 18289522, -14724954, 8056945, 16430056, -21729724, 7842514, -6001441, -1486897, -18684645, -11443503 }, + { 476239, 6601091, -6152790, -9723375, 17503545, -4863900, 27672959, 13403813, 11052904, 5219329 }, + }, + }, + { + { + { 20678546, -8375738, -32671898, 8849123, -5009758, 14574752, 31186971, -3973730, 9014762, -8579056 }, + { -13644050, -10350239, -15962508, 5075808, -1514661, -11534600, -33102500, 9160280, 8473550, -3256838 }, + { 24900749, 14435722, 17209120, -15292541, -22592275, 9878983, -7689309, -16335821, -24568481, 11788948 }, + }, + { + { -3118155, -11395194, -13802089, 14797441, 9652448, -6845904, -20037437, 10410733, -24568470, -1458691 }, + { -15659161, 16736706, -22467150, 10215878, -9097177, 7563911, 11871841, -12505194, -18513325, 8464118 }, + { -23400612, 8348507, -14585951, -861714, -3950205, -6373419, 14325289, 8628612, 33313881, -8370517 }, + }, + { + { -20186973, -4967935, 22367356, 5271547, -1097117, -4788838, -24805667, -10236854, -8940735, -5818269 }, + { -6948785, -1795212, -32625683, -16021179, 32635414, -7374245, 15989197, -12838188, 28358192, -4253904 }, + { -23561781, -2799059, -32351682, -1661963, -9147719, 10429267, -16637684, 4072016, -5351664, 5596589 }, + }, + { + { -28236598, -3390048, 12312896, 6213178, 3117142, 16078565, 29266239, 2557221, 1768301, 15373193 }, + { -7243358, -3246960, -4593467, -7553353, -127927, -912245, -1090902, -4504991, -24660491, 3442910 }, + { -30210571, 5124043, 14181784, 8197961, 18964734, -11939093, 22597931, 7176455, -18585478, 13365930 }, + }, + { + { -7877390, -1499958, 8324673, 4690079, 6261860, 890446, 24538107, -8570186, -9689599, -3031667 }, + { 25008904, -10771599, -4305031, -9638010, 16265036, 15721635, 683793, -11823784, 15723479, -15163481 }, + { -9660625, 12374379, -27006999, -7026148, -7724114, -12314514, 11879682, 5400171, 519526, -1235876 }, + }, + { + { 22258397, -16332233, -7869817, 14613016, -22520255, -2950923, -20353881, 7315967, 16648397, 7605640 }, + { -8081308, -8464597, -8223311, 9719710, 19259459, -15348212, 23994942, -5281555, -9468848, 4763278 }, + { -21699244, 9220969, -15730624, 1084137, -25476107, -2852390, 31088447, -7764523, -11356529, 728112 }, + }, + { + { 26047220, -11751471, -6900323, -16521798, 24092068, 9158119, -4273545, -12555558, -29365436, -5498272 }, + { 17510331, -322857, 5854289, 8403524, 17133918, -3112612, -28111007, 12327945, 10750447, 10014012 }, + { -10312768, 3936952, 9156313, -8897683, 16498692, -994647, -27481051, -666732, 3424691, 7540221 }, + }, + { + { 30322361, -6964110, 11361005, -4143317, 7433304, 4989748, -7071422, -16317219, -9244265, 15258046 }, + { 13054562, -2779497, 19155474, 469045, -12482797, 4566042, 5631406, 2711395, 1062915, -5136345 }, + { -19240248, -11254599, -29509029, -7499965, -5835763, 13005411, -6066489, 12194497, 32960380, 1459310 }, + }, + }, + { + { + { 19852034, 7027924, 23669353, 10020366, 8586503, -6657907, 394197, -6101885, 18638003, -11174937 }, + { 31395534, 15098109, 26581030, 8030562, -16527914, -5007134, 9012486, -7584354, -6643087, -5442636 }, + { -9192165, -2347377, -1997099, 4529534, 25766844, 607986, -13222, 9677543, -32294889, -6456008 }, + }, + { + { -2444496, -149937, 29348902, 8186665, 1873760, 12489863, -30934579, -7839692, -7852844, -8138429 }, + { -15236356, -15433509, 7766470, 746860, 26346930, -10221762, -27333451, 10754588, -9431476, 5203576 }, + { 31834314, 14135496, -770007, 5159118, 20917671, -16768096, -7467973, -7337524, 31809243, 7347066 }, + }, + { + { -9606723, -11874240, 20414459, 13033986, 13716524, -11691881, 19797970, -12211255, 15192876, -2087490 }, + { -12663563, -2181719, 1168162, -3804809, 26747877, -14138091, 10609330, 12694420, 33473243, -13382104 }, + { 33184999, 11180355, 15832085, -11385430, -1633671, 225884, 15089336, -11023903, -6135662, 14480053 }, + }, + { + { 31308717, -5619998, 31030840, -1897099, 15674547, -6582883, 5496208, 13685227, 27595050, 8737275 }, + { -20318852, -15150239, 10933843, -16178022, 8335352, -7546022, -31008351, -12610604, 26498114, 66511 }, + { 22644454, -8761729, -16671776, 4884562, -3105614, -13559366, 30540766, -4286747, -13327787, -7515095 }, + }, + { + { -28017847, 9834845, 18617207, -2681312, -3401956, -13307506, 8205540, 13585437, -17127465, 15115439 }, + { 23711543, -672915, 31206561, -8362711, 6164647, -9709987, -33535882, -1426096, 8236921, 16492939 }, + { -23910559, -13515526, -26299483, -4503841, 25005590, -7687270, 19574902, 10071562, 6708380, -6222424 }, + }, + { + { 2101391, -4930054, 19702731, 2367575, -15427167, 1047675, 5301017, 9328700, 29955601, -11678310 }, + { 3096359, 9271816, -21620864, -15521844, -14847996, -7592937, -25892142, -12635595, -9917575, 6216608 }, + { -32615849, 338663, -25195611, 2510422, -29213566, -13820213, 24822830, -6146567, -26767480, 7525079 }, + }, + { + { -23066649, -13985623, 16133487, -7896178, -3389565, 778788, -910336, -2782495, -19386633, 11994101 }, + { 21691500, -13624626, -641331, -14367021, 3285881, -3483596, -25064666, 9718258, -7477437, 13381418 }, + { 18445390, -4202236, 14979846, 11622458, -1727110, -3582980, 23111648, -6375247, 28535282, 15779576 }, + }, + { + { 30098053, 3089662, -9234387, 16662135, -21306940, 11308411, -14068454, 12021730, 9955285, -16303356 }, + { 9734894, -14576830, -7473633, -9138735, 2060392, 11313496, -18426029, 9924399, 20194861, 13380996 }, + { -26378102, -7965207, -22167821, 15789297, -18055342, -6168792, -1984914, 15707771, 26342023, 10146099 }, + }, + }, + { + { + { -26016874, -219943, 21339191, -41388, 19745256, -2878700, -29637280, 2227040, 21612326, -545728 }, + { -13077387, 1184228, 23562814, -5970442, -20351244, -6348714, 25764461, 12243797, -20856566, 11649658 }, + { -10031494, 11262626, 27384172, 2271902, 26947504, -15997771, 39944, 6114064, 33514190, 2333242 }, + }, + { + { -21433588, -12421821, 8119782, 7219913, -21830522, -9016134, -6679750, -12670638, 24350578, -13450001 }, + { -4116307, -11271533, -23886186, 4843615, -30088339, 690623, -31536088, -10406836, 8317860, 12352766 }, + { 18200138, -14475911, -33087759, -2696619, -23702521, -9102511, -23552096, -2287550, 20712163, 6719373 }, + }, + { + { 26656208, 6075253, -7858556, 1886072, -28344043, 4262326, 11117530, -3763210, 26224235, -3297458 }, + { -17168938, -14854097, -3395676, -16369877, -19954045, 14050420, 21728352, 9493610, 18620611, -16428628 }, + { -13323321, 13325349, 11432106, 5964811, 18609221, 6062965, -5269471, -9725556, -30701573, -16479657 }, + }, + { + { -23860538, -11233159, 26961357, 1640861, -32413112, -16737940, 12248509, -5240639, 13735342, 1934062 }, + { 25089769, 6742589, 17081145, -13406266, 21909293, -16067981, -15136294, -3765346, -21277997, 5473616 }, + { 31883677, -7961101, 1083432, -11572403, 22828471, 13290673, -7125085, 12469656, 29111212, -5451014 }, + }, + { + { 24244947, -15050407, -26262976, 2791540, -14997599, 16666678, 24367466, 6388839, -10295587, 452383 }, + { -25640782, -3417841, 5217916, 16224624, 19987036, -4082269, -24236251, -5915248, 15766062, 8407814 }, + { -20406999, 13990231, 15495425, 16395525, 5377168, 15166495, -8917023, -4388953, -8067909, 2276718 }, + }, + { + { 30157918, 12924066, -17712050, 9245753, 19895028, 3368142, -23827587, 5096219, 22740376, -7303417 }, + { 2041139, -14256350, 7783687, 13876377, -25946985, -13352459, 24051124, 13742383, -15637599, 13295222 }, + { 33338237, -8505733, 12532113, 7977527, 9106186, -1715251, -17720195, -4612972, -4451357, -14669444 }, + }, + { + { -20045281, 5454097, -14346548, 6447146, 28862071, 1883651, -2469266, -4141880, 7770569, 9620597 }, + { 23208068, 7979712, 33071466, 8149229, 1758231, -10834995, 30945528, -1694323, -33502340, -14767970 }, + { 1439958, -16270480, -1079989, -793782, 4625402, 10647766, -5043801, 1220118, 30494170, -11440799 }, + }, + { + { -5037580, -13028295, -2970559, -3061767, 15640974, -6701666, -26739026, 926050, -1684339, -13333647 }, + { 13908495, -3549272, 30919928, -6273825, -21521863, 7989039, 9021034, 9078865, 3353509, 4033511 }, + { -29663431, -15113610, 32259991, -344482, 24295849, -12912123, 23161163, 8839127, 27485041, 7356032 }, + }, + }, + { + { + { 9661027, 705443, 11980065, -5370154, -1628543, 14661173, -6346142, 2625015, 28431036, -16771834 }, + { -23839233, -8311415, -25945511, 7480958, -17681669, -8354183, -22545972, 14150565, 15970762, 4099461 }, + { 29262576, 16756590, 26350592, -8793563, 8529671, -11208050, 13617293, -9937143, 11465739, 8317062 }, + }, + { + { -25493081, -6962928, 32500200, -9419051, -23038724, -2302222, 14898637, 3848455, 20969334, -5157516 }, + { -20384450, -14347713, -18336405, 13884722, -33039454, 2842114, -21610826, -3649888, 11177095, 14989547 }, + { -24496721, -11716016, 16959896, 2278463, 12066309, 10137771, 13515641, 2581286, -28487508, 9930240 }, + }, + { + { -17751622, -2097826, 16544300, -13009300, -15914807, -14949081, 18345767, -13403753, 16291481, -5314038 }, + { -33229194, 2553288, 32678213, 9875984, 8534129, 6889387, -9676774, 6957617, 4368891, 9788741 }, + { 16660756, 7281060, -10830758, 12911820, 20108584, -8101676, -21722536, -8613148, 16250552, -11111103 }, + }, + { + { -19765507, 2390526, -16551031, 14161980, 1905286, 6414907, 4689584, 10604807, -30190403, 4782747 }, + { -1354539, 14736941, -7367442, -13292886, 7710542, -14155590, -9981571, 4383045, 22546403, 437323 }, + { 31665577, -12180464, -16186830, 1491339, -18368625, 3294682, 27343084, 2786261, -30633590, -14097016 }, + }, + { + { -14467279, -683715, -33374107, 7448552, 19294360, 14334329, -19690631, 2355319, -19284671, -6114373 }, + { 15121312, -15796162, 6377020, -6031361, -10798111, -12957845, 18952177, 15496498, -29380133, 11754228 }, + { -2637277, -13483075, 8488727, -14303896, 12728761, -1622493, 7141596, 11724556, 22761615, -10134141 }, + }, + { + { 16918416, 11729663, -18083579, 3022987, -31015732, -13339659, -28741185, -12227393, 32851222, 11717399 }, + { 11166634, 7338049, -6722523, 4531520, -29468672, -7302055, 31474879, 3483633, -1193175, -4030831 }, + { -185635, 9921305, 31456609, -13536438, -12013818, 13348923, 33142652, 6546660, -19985279, -3948376 }, + }, + { + { -32460596, 11266712, -11197107, -7899103, 31703694, 3855903, -8537131, -12833048, -30772034, -15486313 }, + { -18006477, 12709068, 3991746, -6479188, -21491523, -10550425, -31135347, -16049879, 10928917, 3011958 }, + { -6957757, -15594337, 31696059, 334240, 29576716, 14796075, -30831056, -12805180, 18008031, 10258577 }, + }, + { + { -22448644, 15655569, 7018479, -4410003, -30314266, -1201591, -1853465, 1367120, 25127874, 6671743 }, + { 29701166, -14373934, -10878120, 9279288, -17568, 13127210, 21382910, 11042292, 25838796, 4642684 }, + { -20430234, 14955537, -24126347, 8124619, -5369288, -5990470, 30468147, -13900640, 18423289, 4177476 }, + }, + }, +}; diff --git a/src/cryptoconditions/src/include/ed25519/src/sc.c b/src/cryptoconditions/src/include/ed25519/src/sc.c new file mode 100644 index 000000000..ca5bad2ca --- /dev/null +++ b/src/cryptoconditions/src/include/ed25519/src/sc.c @@ -0,0 +1,809 @@ +#include "fixedint.h" +#include "sc.h" + +static uint64_t load_3(const unsigned char *in) { + uint64_t result; + + result = (uint64_t) in[0]; + result |= ((uint64_t) in[1]) << 8; + result |= ((uint64_t) in[2]) << 16; + + return result; +} + +static uint64_t load_4(const unsigned char *in) { + uint64_t result; + + result = (uint64_t) in[0]; + result |= ((uint64_t) in[1]) << 8; + result |= ((uint64_t) in[2]) << 16; + result |= ((uint64_t) in[3]) << 24; + + return result; +} + +/* +Input: + s[0]+256*s[1]+...+256^63*s[63] = s + +Output: + s[0]+256*s[1]+...+256^31*s[31] = s mod l + where l = 2^252 + 27742317777372353535851937790883648493. + Overwrites s in place. +*/ + +void sc_reduce(unsigned char *s) { + int64_t s0 = 2097151 & load_3(s); + int64_t s1 = 2097151 & (load_4(s + 2) >> 5); + int64_t s2 = 2097151 & (load_3(s + 5) >> 2); + int64_t s3 = 2097151 & (load_4(s + 7) >> 7); + int64_t s4 = 2097151 & (load_4(s + 10) >> 4); + int64_t s5 = 2097151 & (load_3(s + 13) >> 1); + int64_t s6 = 2097151 & (load_4(s + 15) >> 6); + int64_t s7 = 2097151 & (load_3(s + 18) >> 3); + int64_t s8 = 2097151 & load_3(s + 21); + int64_t s9 = 2097151 & (load_4(s + 23) >> 5); + int64_t s10 = 2097151 & (load_3(s + 26) >> 2); + int64_t s11 = 2097151 & (load_4(s + 28) >> 7); + int64_t s12 = 2097151 & (load_4(s + 31) >> 4); + int64_t s13 = 2097151 & (load_3(s + 34) >> 1); + int64_t s14 = 2097151 & (load_4(s + 36) >> 6); + int64_t s15 = 2097151 & (load_3(s + 39) >> 3); + int64_t s16 = 2097151 & load_3(s + 42); + int64_t s17 = 2097151 & (load_4(s + 44) >> 5); + int64_t s18 = 2097151 & (load_3(s + 47) >> 2); + int64_t s19 = 2097151 & (load_4(s + 49) >> 7); + int64_t s20 = 2097151 & (load_4(s + 52) >> 4); + int64_t s21 = 2097151 & (load_3(s + 55) >> 1); + int64_t s22 = 2097151 & (load_4(s + 57) >> 6); + int64_t s23 = (load_4(s + 60) >> 3); + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + int64_t carry10; + int64_t carry11; + int64_t carry12; + int64_t carry13; + int64_t carry14; + int64_t carry15; + int64_t carry16; + + s11 += s23 * 666643; + s12 += s23 * 470296; + s13 += s23 * 654183; + s14 -= s23 * 997805; + s15 += s23 * 136657; + s16 -= s23 * 683901; + s23 = 0; + s10 += s22 * 666643; + s11 += s22 * 470296; + s12 += s22 * 654183; + s13 -= s22 * 997805; + s14 += s22 * 136657; + s15 -= s22 * 683901; + s22 = 0; + s9 += s21 * 666643; + s10 += s21 * 470296; + s11 += s21 * 654183; + s12 -= s21 * 997805; + s13 += s21 * 136657; + s14 -= s21 * 683901; + s21 = 0; + s8 += s20 * 666643; + s9 += s20 * 470296; + s10 += s20 * 654183; + s11 -= s20 * 997805; + s12 += s20 * 136657; + s13 -= s20 * 683901; + s20 = 0; + s7 += s19 * 666643; + s8 += s19 * 470296; + s9 += s19 * 654183; + s10 -= s19 * 997805; + s11 += s19 * 136657; + s12 -= s19 * 683901; + s19 = 0; + s6 += s18 * 666643; + s7 += s18 * 470296; + s8 += s18 * 654183; + s9 -= s18 * 997805; + s10 += s18 * 136657; + s11 -= s18 * 683901; + s18 = 0; + carry6 = (s6 + (1 << 20)) >> 21; + s7 += carry6; + s6 -= carry6 << 21; + carry8 = (s8 + (1 << 20)) >> 21; + s9 += carry8; + s8 -= carry8 << 21; + carry10 = (s10 + (1 << 20)) >> 21; + s11 += carry10; + s10 -= carry10 << 21; + carry12 = (s12 + (1 << 20)) >> 21; + s13 += carry12; + s12 -= carry12 << 21; + carry14 = (s14 + (1 << 20)) >> 21; + s15 += carry14; + s14 -= carry14 << 21; + carry16 = (s16 + (1 << 20)) >> 21; + s17 += carry16; + s16 -= carry16 << 21; + carry7 = (s7 + (1 << 20)) >> 21; + s8 += carry7; + s7 -= carry7 << 21; + carry9 = (s9 + (1 << 20)) >> 21; + s10 += carry9; + s9 -= carry9 << 21; + carry11 = (s11 + (1 << 20)) >> 21; + s12 += carry11; + s11 -= carry11 << 21; + carry13 = (s13 + (1 << 20)) >> 21; + s14 += carry13; + s13 -= carry13 << 21; + carry15 = (s15 + (1 << 20)) >> 21; + s16 += carry15; + s15 -= carry15 << 21; + s5 += s17 * 666643; + s6 += s17 * 470296; + s7 += s17 * 654183; + s8 -= s17 * 997805; + s9 += s17 * 136657; + s10 -= s17 * 683901; + s17 = 0; + s4 += s16 * 666643; + s5 += s16 * 470296; + s6 += s16 * 654183; + s7 -= s16 * 997805; + s8 += s16 * 136657; + s9 -= s16 * 683901; + s16 = 0; + s3 += s15 * 666643; + s4 += s15 * 470296; + s5 += s15 * 654183; + s6 -= s15 * 997805; + s7 += s15 * 136657; + s8 -= s15 * 683901; + s15 = 0; + s2 += s14 * 666643; + s3 += s14 * 470296; + s4 += s14 * 654183; + s5 -= s14 * 997805; + s6 += s14 * 136657; + s7 -= s14 * 683901; + s14 = 0; + s1 += s13 * 666643; + s2 += s13 * 470296; + s3 += s13 * 654183; + s4 -= s13 * 997805; + s5 += s13 * 136657; + s6 -= s13 * 683901; + s13 = 0; + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + carry0 = (s0 + (1 << 20)) >> 21; + s1 += carry0; + s0 -= carry0 << 21; + carry2 = (s2 + (1 << 20)) >> 21; + s3 += carry2; + s2 -= carry2 << 21; + carry4 = (s4 + (1 << 20)) >> 21; + s5 += carry4; + s4 -= carry4 << 21; + carry6 = (s6 + (1 << 20)) >> 21; + s7 += carry6; + s6 -= carry6 << 21; + carry8 = (s8 + (1 << 20)) >> 21; + s9 += carry8; + s8 -= carry8 << 21; + carry10 = (s10 + (1 << 20)) >> 21; + s11 += carry10; + s10 -= carry10 << 21; + carry1 = (s1 + (1 << 20)) >> 21; + s2 += carry1; + s1 -= carry1 << 21; + carry3 = (s3 + (1 << 20)) >> 21; + s4 += carry3; + s3 -= carry3 << 21; + carry5 = (s5 + (1 << 20)) >> 21; + s6 += carry5; + s5 -= carry5 << 21; + carry7 = (s7 + (1 << 20)) >> 21; + s8 += carry7; + s7 -= carry7 << 21; + carry9 = (s9 + (1 << 20)) >> 21; + s10 += carry9; + s9 -= carry9 << 21; + carry11 = (s11 + (1 << 20)) >> 21; + s12 += carry11; + s11 -= carry11 << 21; + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + carry0 = s0 >> 21; + s1 += carry0; + s0 -= carry0 << 21; + carry1 = s1 >> 21; + s2 += carry1; + s1 -= carry1 << 21; + carry2 = s2 >> 21; + s3 += carry2; + s2 -= carry2 << 21; + carry3 = s3 >> 21; + s4 += carry3; + s3 -= carry3 << 21; + carry4 = s4 >> 21; + s5 += carry4; + s4 -= carry4 << 21; + carry5 = s5 >> 21; + s6 += carry5; + s5 -= carry5 << 21; + carry6 = s6 >> 21; + s7 += carry6; + s6 -= carry6 << 21; + carry7 = s7 >> 21; + s8 += carry7; + s7 -= carry7 << 21; + carry8 = s8 >> 21; + s9 += carry8; + s8 -= carry8 << 21; + carry9 = s9 >> 21; + s10 += carry9; + s9 -= carry9 << 21; + carry10 = s10 >> 21; + s11 += carry10; + s10 -= carry10 << 21; + carry11 = s11 >> 21; + s12 += carry11; + s11 -= carry11 << 21; + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + carry0 = s0 >> 21; + s1 += carry0; + s0 -= carry0 << 21; + carry1 = s1 >> 21; + s2 += carry1; + s1 -= carry1 << 21; + carry2 = s2 >> 21; + s3 += carry2; + s2 -= carry2 << 21; + carry3 = s3 >> 21; + s4 += carry3; + s3 -= carry3 << 21; + carry4 = s4 >> 21; + s5 += carry4; + s4 -= carry4 << 21; + carry5 = s5 >> 21; + s6 += carry5; + s5 -= carry5 << 21; + carry6 = s6 >> 21; + s7 += carry6; + s6 -= carry6 << 21; + carry7 = s7 >> 21; + s8 += carry7; + s7 -= carry7 << 21; + carry8 = s8 >> 21; + s9 += carry8; + s8 -= carry8 << 21; + carry9 = s9 >> 21; + s10 += carry9; + s9 -= carry9 << 21; + carry10 = s10 >> 21; + s11 += carry10; + s10 -= carry10 << 21; + + s[0] = (unsigned char) (s0 >> 0); + s[1] = (unsigned char) (s0 >> 8); + s[2] = (unsigned char) ((s0 >> 16) | (s1 << 5)); + s[3] = (unsigned char) (s1 >> 3); + s[4] = (unsigned char) (s1 >> 11); + s[5] = (unsigned char) ((s1 >> 19) | (s2 << 2)); + s[6] = (unsigned char) (s2 >> 6); + s[7] = (unsigned char) ((s2 >> 14) | (s3 << 7)); + s[8] = (unsigned char) (s3 >> 1); + s[9] = (unsigned char) (s3 >> 9); + s[10] = (unsigned char) ((s3 >> 17) | (s4 << 4)); + s[11] = (unsigned char) (s4 >> 4); + s[12] = (unsigned char) (s4 >> 12); + s[13] = (unsigned char) ((s4 >> 20) | (s5 << 1)); + s[14] = (unsigned char) (s5 >> 7); + s[15] = (unsigned char) ((s5 >> 15) | (s6 << 6)); + s[16] = (unsigned char) (s6 >> 2); + s[17] = (unsigned char) (s6 >> 10); + s[18] = (unsigned char) ((s6 >> 18) | (s7 << 3)); + s[19] = (unsigned char) (s7 >> 5); + s[20] = (unsigned char) (s7 >> 13); + s[21] = (unsigned char) (s8 >> 0); + s[22] = (unsigned char) (s8 >> 8); + s[23] = (unsigned char) ((s8 >> 16) | (s9 << 5)); + s[24] = (unsigned char) (s9 >> 3); + s[25] = (unsigned char) (s9 >> 11); + s[26] = (unsigned char) ((s9 >> 19) | (s10 << 2)); + s[27] = (unsigned char) (s10 >> 6); + s[28] = (unsigned char) ((s10 >> 14) | (s11 << 7)); + s[29] = (unsigned char) (s11 >> 1); + s[30] = (unsigned char) (s11 >> 9); + s[31] = (unsigned char) (s11 >> 17); +} + + + +/* +Input: + a[0]+256*a[1]+...+256^31*a[31] = a + b[0]+256*b[1]+...+256^31*b[31] = b + c[0]+256*c[1]+...+256^31*c[31] = c + +Output: + s[0]+256*s[1]+...+256^31*s[31] = (ab+c) mod l + where l = 2^252 + 27742317777372353535851937790883648493. +*/ + +void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c) { + int64_t a0 = 2097151 & load_3(a); + int64_t a1 = 2097151 & (load_4(a + 2) >> 5); + int64_t a2 = 2097151 & (load_3(a + 5) >> 2); + int64_t a3 = 2097151 & (load_4(a + 7) >> 7); + int64_t a4 = 2097151 & (load_4(a + 10) >> 4); + int64_t a5 = 2097151 & (load_3(a + 13) >> 1); + int64_t a6 = 2097151 & (load_4(a + 15) >> 6); + int64_t a7 = 2097151 & (load_3(a + 18) >> 3); + int64_t a8 = 2097151 & load_3(a + 21); + int64_t a9 = 2097151 & (load_4(a + 23) >> 5); + int64_t a10 = 2097151 & (load_3(a + 26) >> 2); + int64_t a11 = (load_4(a + 28) >> 7); + int64_t b0 = 2097151 & load_3(b); + int64_t b1 = 2097151 & (load_4(b + 2) >> 5); + int64_t b2 = 2097151 & (load_3(b + 5) >> 2); + int64_t b3 = 2097151 & (load_4(b + 7) >> 7); + int64_t b4 = 2097151 & (load_4(b + 10) >> 4); + int64_t b5 = 2097151 & (load_3(b + 13) >> 1); + int64_t b6 = 2097151 & (load_4(b + 15) >> 6); + int64_t b7 = 2097151 & (load_3(b + 18) >> 3); + int64_t b8 = 2097151 & load_3(b + 21); + int64_t b9 = 2097151 & (load_4(b + 23) >> 5); + int64_t b10 = 2097151 & (load_3(b + 26) >> 2); + int64_t b11 = (load_4(b + 28) >> 7); + int64_t c0 = 2097151 & load_3(c); + int64_t c1 = 2097151 & (load_4(c + 2) >> 5); + int64_t c2 = 2097151 & (load_3(c + 5) >> 2); + int64_t c3 = 2097151 & (load_4(c + 7) >> 7); + int64_t c4 = 2097151 & (load_4(c + 10) >> 4); + int64_t c5 = 2097151 & (load_3(c + 13) >> 1); + int64_t c6 = 2097151 & (load_4(c + 15) >> 6); + int64_t c7 = 2097151 & (load_3(c + 18) >> 3); + int64_t c8 = 2097151 & load_3(c + 21); + int64_t c9 = 2097151 & (load_4(c + 23) >> 5); + int64_t c10 = 2097151 & (load_3(c + 26) >> 2); + int64_t c11 = (load_4(c + 28) >> 7); + int64_t s0; + int64_t s1; + int64_t s2; + int64_t s3; + int64_t s4; + int64_t s5; + int64_t s6; + int64_t s7; + int64_t s8; + int64_t s9; + int64_t s10; + int64_t s11; + int64_t s12; + int64_t s13; + int64_t s14; + int64_t s15; + int64_t s16; + int64_t s17; + int64_t s18; + int64_t s19; + int64_t s20; + int64_t s21; + int64_t s22; + int64_t s23; + int64_t carry0; + int64_t carry1; + int64_t carry2; + int64_t carry3; + int64_t carry4; + int64_t carry5; + int64_t carry6; + int64_t carry7; + int64_t carry8; + int64_t carry9; + int64_t carry10; + int64_t carry11; + int64_t carry12; + int64_t carry13; + int64_t carry14; + int64_t carry15; + int64_t carry16; + int64_t carry17; + int64_t carry18; + int64_t carry19; + int64_t carry20; + int64_t carry21; + int64_t carry22; + + s0 = c0 + a0 * b0; + s1 = c1 + a0 * b1 + a1 * b0; + s2 = c2 + a0 * b2 + a1 * b1 + a2 * b0; + s3 = c3 + a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0; + s4 = c4 + a0 * b4 + a1 * b3 + a2 * b2 + a3 * b1 + a4 * b0; + s5 = c5 + a0 * b5 + a1 * b4 + a2 * b3 + a3 * b2 + a4 * b1 + a5 * b0; + s6 = c6 + a0 * b6 + a1 * b5 + a2 * b4 + a3 * b3 + a4 * b2 + a5 * b1 + a6 * b0; + s7 = c7 + a0 * b7 + a1 * b6 + a2 * b5 + a3 * b4 + a4 * b3 + a5 * b2 + a6 * b1 + a7 * b0; + s8 = c8 + a0 * b8 + a1 * b7 + a2 * b6 + a3 * b5 + a4 * b4 + a5 * b3 + a6 * b2 + a7 * b1 + a8 * b0; + s9 = c9 + a0 * b9 + a1 * b8 + a2 * b7 + a3 * b6 + a4 * b5 + a5 * b4 + a6 * b3 + a7 * b2 + a8 * b1 + a9 * b0; + s10 = c10 + a0 * b10 + a1 * b9 + a2 * b8 + a3 * b7 + a4 * b6 + a5 * b5 + a6 * b4 + a7 * b3 + a8 * b2 + a9 * b1 + a10 * b0; + s11 = c11 + a0 * b11 + a1 * b10 + a2 * b9 + a3 * b8 + a4 * b7 + a5 * b6 + a6 * b5 + a7 * b4 + a8 * b3 + a9 * b2 + a10 * b1 + a11 * b0; + s12 = a1 * b11 + a2 * b10 + a3 * b9 + a4 * b8 + a5 * b7 + a6 * b6 + a7 * b5 + a8 * b4 + a9 * b3 + a10 * b2 + a11 * b1; + s13 = a2 * b11 + a3 * b10 + a4 * b9 + a5 * b8 + a6 * b7 + a7 * b6 + a8 * b5 + a9 * b4 + a10 * b3 + a11 * b2; + s14 = a3 * b11 + a4 * b10 + a5 * b9 + a6 * b8 + a7 * b7 + a8 * b6 + a9 * b5 + a10 * b4 + a11 * b3; + s15 = a4 * b11 + a5 * b10 + a6 * b9 + a7 * b8 + a8 * b7 + a9 * b6 + a10 * b5 + a11 * b4; + s16 = a5 * b11 + a6 * b10 + a7 * b9 + a8 * b8 + a9 * b7 + a10 * b6 + a11 * b5; + s17 = a6 * b11 + a7 * b10 + a8 * b9 + a9 * b8 + a10 * b7 + a11 * b6; + s18 = a7 * b11 + a8 * b10 + a9 * b9 + a10 * b8 + a11 * b7; + s19 = a8 * b11 + a9 * b10 + a10 * b9 + a11 * b8; + s20 = a9 * b11 + a10 * b10 + a11 * b9; + s21 = a10 * b11 + a11 * b10; + s22 = a11 * b11; + s23 = 0; + carry0 = (s0 + (1 << 20)) >> 21; + s1 += carry0; + s0 -= carry0 << 21; + carry2 = (s2 + (1 << 20)) >> 21; + s3 += carry2; + s2 -= carry2 << 21; + carry4 = (s4 + (1 << 20)) >> 21; + s5 += carry4; + s4 -= carry4 << 21; + carry6 = (s6 + (1 << 20)) >> 21; + s7 += carry6; + s6 -= carry6 << 21; + carry8 = (s8 + (1 << 20)) >> 21; + s9 += carry8; + s8 -= carry8 << 21; + carry10 = (s10 + (1 << 20)) >> 21; + s11 += carry10; + s10 -= carry10 << 21; + carry12 = (s12 + (1 << 20)) >> 21; + s13 += carry12; + s12 -= carry12 << 21; + carry14 = (s14 + (1 << 20)) >> 21; + s15 += carry14; + s14 -= carry14 << 21; + carry16 = (s16 + (1 << 20)) >> 21; + s17 += carry16; + s16 -= carry16 << 21; + carry18 = (s18 + (1 << 20)) >> 21; + s19 += carry18; + s18 -= carry18 << 21; + carry20 = (s20 + (1 << 20)) >> 21; + s21 += carry20; + s20 -= carry20 << 21; + carry22 = (s22 + (1 << 20)) >> 21; + s23 += carry22; + s22 -= carry22 << 21; + carry1 = (s1 + (1 << 20)) >> 21; + s2 += carry1; + s1 -= carry1 << 21; + carry3 = (s3 + (1 << 20)) >> 21; + s4 += carry3; + s3 -= carry3 << 21; + carry5 = (s5 + (1 << 20)) >> 21; + s6 += carry5; + s5 -= carry5 << 21; + carry7 = (s7 + (1 << 20)) >> 21; + s8 += carry7; + s7 -= carry7 << 21; + carry9 = (s9 + (1 << 20)) >> 21; + s10 += carry9; + s9 -= carry9 << 21; + carry11 = (s11 + (1 << 20)) >> 21; + s12 += carry11; + s11 -= carry11 << 21; + carry13 = (s13 + (1 << 20)) >> 21; + s14 += carry13; + s13 -= carry13 << 21; + carry15 = (s15 + (1 << 20)) >> 21; + s16 += carry15; + s15 -= carry15 << 21; + carry17 = (s17 + (1 << 20)) >> 21; + s18 += carry17; + s17 -= carry17 << 21; + carry19 = (s19 + (1 << 20)) >> 21; + s20 += carry19; + s19 -= carry19 << 21; + carry21 = (s21 + (1 << 20)) >> 21; + s22 += carry21; + s21 -= carry21 << 21; + s11 += s23 * 666643; + s12 += s23 * 470296; + s13 += s23 * 654183; + s14 -= s23 * 997805; + s15 += s23 * 136657; + s16 -= s23 * 683901; + s23 = 0; + s10 += s22 * 666643; + s11 += s22 * 470296; + s12 += s22 * 654183; + s13 -= s22 * 997805; + s14 += s22 * 136657; + s15 -= s22 * 683901; + s22 = 0; + s9 += s21 * 666643; + s10 += s21 * 470296; + s11 += s21 * 654183; + s12 -= s21 * 997805; + s13 += s21 * 136657; + s14 -= s21 * 683901; + s21 = 0; + s8 += s20 * 666643; + s9 += s20 * 470296; + s10 += s20 * 654183; + s11 -= s20 * 997805; + s12 += s20 * 136657; + s13 -= s20 * 683901; + s20 = 0; + s7 += s19 * 666643; + s8 += s19 * 470296; + s9 += s19 * 654183; + s10 -= s19 * 997805; + s11 += s19 * 136657; + s12 -= s19 * 683901; + s19 = 0; + s6 += s18 * 666643; + s7 += s18 * 470296; + s8 += s18 * 654183; + s9 -= s18 * 997805; + s10 += s18 * 136657; + s11 -= s18 * 683901; + s18 = 0; + carry6 = (s6 + (1 << 20)) >> 21; + s7 += carry6; + s6 -= carry6 << 21; + carry8 = (s8 + (1 << 20)) >> 21; + s9 += carry8; + s8 -= carry8 << 21; + carry10 = (s10 + (1 << 20)) >> 21; + s11 += carry10; + s10 -= carry10 << 21; + carry12 = (s12 + (1 << 20)) >> 21; + s13 += carry12; + s12 -= carry12 << 21; + carry14 = (s14 + (1 << 20)) >> 21; + s15 += carry14; + s14 -= carry14 << 21; + carry16 = (s16 + (1 << 20)) >> 21; + s17 += carry16; + s16 -= carry16 << 21; + carry7 = (s7 + (1 << 20)) >> 21; + s8 += carry7; + s7 -= carry7 << 21; + carry9 = (s9 + (1 << 20)) >> 21; + s10 += carry9; + s9 -= carry9 << 21; + carry11 = (s11 + (1 << 20)) >> 21; + s12 += carry11; + s11 -= carry11 << 21; + carry13 = (s13 + (1 << 20)) >> 21; + s14 += carry13; + s13 -= carry13 << 21; + carry15 = (s15 + (1 << 20)) >> 21; + s16 += carry15; + s15 -= carry15 << 21; + s5 += s17 * 666643; + s6 += s17 * 470296; + s7 += s17 * 654183; + s8 -= s17 * 997805; + s9 += s17 * 136657; + s10 -= s17 * 683901; + s17 = 0; + s4 += s16 * 666643; + s5 += s16 * 470296; + s6 += s16 * 654183; + s7 -= s16 * 997805; + s8 += s16 * 136657; + s9 -= s16 * 683901; + s16 = 0; + s3 += s15 * 666643; + s4 += s15 * 470296; + s5 += s15 * 654183; + s6 -= s15 * 997805; + s7 += s15 * 136657; + s8 -= s15 * 683901; + s15 = 0; + s2 += s14 * 666643; + s3 += s14 * 470296; + s4 += s14 * 654183; + s5 -= s14 * 997805; + s6 += s14 * 136657; + s7 -= s14 * 683901; + s14 = 0; + s1 += s13 * 666643; + s2 += s13 * 470296; + s3 += s13 * 654183; + s4 -= s13 * 997805; + s5 += s13 * 136657; + s6 -= s13 * 683901; + s13 = 0; + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + carry0 = (s0 + (1 << 20)) >> 21; + s1 += carry0; + s0 -= carry0 << 21; + carry2 = (s2 + (1 << 20)) >> 21; + s3 += carry2; + s2 -= carry2 << 21; + carry4 = (s4 + (1 << 20)) >> 21; + s5 += carry4; + s4 -= carry4 << 21; + carry6 = (s6 + (1 << 20)) >> 21; + s7 += carry6; + s6 -= carry6 << 21; + carry8 = (s8 + (1 << 20)) >> 21; + s9 += carry8; + s8 -= carry8 << 21; + carry10 = (s10 + (1 << 20)) >> 21; + s11 += carry10; + s10 -= carry10 << 21; + carry1 = (s1 + (1 << 20)) >> 21; + s2 += carry1; + s1 -= carry1 << 21; + carry3 = (s3 + (1 << 20)) >> 21; + s4 += carry3; + s3 -= carry3 << 21; + carry5 = (s5 + (1 << 20)) >> 21; + s6 += carry5; + s5 -= carry5 << 21; + carry7 = (s7 + (1 << 20)) >> 21; + s8 += carry7; + s7 -= carry7 << 21; + carry9 = (s9 + (1 << 20)) >> 21; + s10 += carry9; + s9 -= carry9 << 21; + carry11 = (s11 + (1 << 20)) >> 21; + s12 += carry11; + s11 -= carry11 << 21; + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + carry0 = s0 >> 21; + s1 += carry0; + s0 -= carry0 << 21; + carry1 = s1 >> 21; + s2 += carry1; + s1 -= carry1 << 21; + carry2 = s2 >> 21; + s3 += carry2; + s2 -= carry2 << 21; + carry3 = s3 >> 21; + s4 += carry3; + s3 -= carry3 << 21; + carry4 = s4 >> 21; + s5 += carry4; + s4 -= carry4 << 21; + carry5 = s5 >> 21; + s6 += carry5; + s5 -= carry5 << 21; + carry6 = s6 >> 21; + s7 += carry6; + s6 -= carry6 << 21; + carry7 = s7 >> 21; + s8 += carry7; + s7 -= carry7 << 21; + carry8 = s8 >> 21; + s9 += carry8; + s8 -= carry8 << 21; + carry9 = s9 >> 21; + s10 += carry9; + s9 -= carry9 << 21; + carry10 = s10 >> 21; + s11 += carry10; + s10 -= carry10 << 21; + carry11 = s11 >> 21; + s12 += carry11; + s11 -= carry11 << 21; + s0 += s12 * 666643; + s1 += s12 * 470296; + s2 += s12 * 654183; + s3 -= s12 * 997805; + s4 += s12 * 136657; + s5 -= s12 * 683901; + s12 = 0; + carry0 = s0 >> 21; + s1 += carry0; + s0 -= carry0 << 21; + carry1 = s1 >> 21; + s2 += carry1; + s1 -= carry1 << 21; + carry2 = s2 >> 21; + s3 += carry2; + s2 -= carry2 << 21; + carry3 = s3 >> 21; + s4 += carry3; + s3 -= carry3 << 21; + carry4 = s4 >> 21; + s5 += carry4; + s4 -= carry4 << 21; + carry5 = s5 >> 21; + s6 += carry5; + s5 -= carry5 << 21; + carry6 = s6 >> 21; + s7 += carry6; + s6 -= carry6 << 21; + carry7 = s7 >> 21; + s8 += carry7; + s7 -= carry7 << 21; + carry8 = s8 >> 21; + s9 += carry8; + s8 -= carry8 << 21; + carry9 = s9 >> 21; + s10 += carry9; + s9 -= carry9 << 21; + carry10 = s10 >> 21; + s11 += carry10; + s10 -= carry10 << 21; + + s[0] = (unsigned char) (s0 >> 0); + s[1] = (unsigned char) (s0 >> 8); + s[2] = (unsigned char) ((s0 >> 16) | (s1 << 5)); + s[3] = (unsigned char) (s1 >> 3); + s[4] = (unsigned char) (s1 >> 11); + s[5] = (unsigned char) ((s1 >> 19) | (s2 << 2)); + s[6] = (unsigned char) (s2 >> 6); + s[7] = (unsigned char) ((s2 >> 14) | (s3 << 7)); + s[8] = (unsigned char) (s3 >> 1); + s[9] = (unsigned char) (s3 >> 9); + s[10] = (unsigned char) ((s3 >> 17) | (s4 << 4)); + s[11] = (unsigned char) (s4 >> 4); + s[12] = (unsigned char) (s4 >> 12); + s[13] = (unsigned char) ((s4 >> 20) | (s5 << 1)); + s[14] = (unsigned char) (s5 >> 7); + s[15] = (unsigned char) ((s5 >> 15) | (s6 << 6)); + s[16] = (unsigned char) (s6 >> 2); + s[17] = (unsigned char) (s6 >> 10); + s[18] = (unsigned char) ((s6 >> 18) | (s7 << 3)); + s[19] = (unsigned char) (s7 >> 5); + s[20] = (unsigned char) (s7 >> 13); + s[21] = (unsigned char) (s8 >> 0); + s[22] = (unsigned char) (s8 >> 8); + s[23] = (unsigned char) ((s8 >> 16) | (s9 << 5)); + s[24] = (unsigned char) (s9 >> 3); + s[25] = (unsigned char) (s9 >> 11); + s[26] = (unsigned char) ((s9 >> 19) | (s10 << 2)); + s[27] = (unsigned char) (s10 >> 6); + s[28] = (unsigned char) ((s10 >> 14) | (s11 << 7)); + s[29] = (unsigned char) (s11 >> 1); + s[30] = (unsigned char) (s11 >> 9); + s[31] = (unsigned char) (s11 >> 17); +} diff --git a/src/cryptoconditions/src/include/ed25519/src/sc.h b/src/cryptoconditions/src/include/ed25519/src/sc.h new file mode 100644 index 000000000..e29e7fa5a --- /dev/null +++ b/src/cryptoconditions/src/include/ed25519/src/sc.h @@ -0,0 +1,12 @@ +#ifndef SC_H +#define SC_H + +/* +The set of scalars is \Z/l +where l = 2^252 + 27742317777372353535851937790883648493. +*/ + +void sc_reduce(unsigned char *s); +void sc_muladd(unsigned char *s, const unsigned char *a, const unsigned char *b, const unsigned char *c); + +#endif diff --git a/src/cryptoconditions/src/include/ed25519/src/seed.c b/src/cryptoconditions/src/include/ed25519/src/seed.c new file mode 100644 index 000000000..11a2e3ec4 --- /dev/null +++ b/src/cryptoconditions/src/include/ed25519/src/seed.c @@ -0,0 +1,40 @@ +#include "ed25519.h" + +#ifndef ED25519_NO_SEED + +#ifdef _WIN32 +#include +#include +#else +#include +#endif + +int ed25519_create_seed(unsigned char *seed) { +#ifdef _WIN32 + HCRYPTPROV prov; + + if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { + return 1; + } + + if (!CryptGenRandom(prov, 32, seed)) { + CryptReleaseContext(prov, 0); + return 1; + } + + CryptReleaseContext(prov, 0); +#else + FILE *f = fopen("/dev/urandom", "rb"); + + if (f == NULL) { + return 1; + } + + fread(seed, 1, 32, f); + fclose(f); +#endif + + return 0; +} + +#endif diff --git a/src/cryptoconditions/src/include/ed25519/src/sha512.c b/src/cryptoconditions/src/include/ed25519/src/sha512.c new file mode 100644 index 000000000..cb8ae7175 --- /dev/null +++ b/src/cryptoconditions/src/include/ed25519/src/sha512.c @@ -0,0 +1,275 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://libtom.org + */ + +#include "fixedint.h" +#include "sha512.h" + +/* the K array */ +static const uint64_t K[80] = { + UINT64_C(0x428a2f98d728ae22), UINT64_C(0x7137449123ef65cd), + UINT64_C(0xb5c0fbcfec4d3b2f), UINT64_C(0xe9b5dba58189dbbc), + UINT64_C(0x3956c25bf348b538), UINT64_C(0x59f111f1b605d019), + UINT64_C(0x923f82a4af194f9b), UINT64_C(0xab1c5ed5da6d8118), + UINT64_C(0xd807aa98a3030242), UINT64_C(0x12835b0145706fbe), + UINT64_C(0x243185be4ee4b28c), UINT64_C(0x550c7dc3d5ffb4e2), + UINT64_C(0x72be5d74f27b896f), UINT64_C(0x80deb1fe3b1696b1), + UINT64_C(0x9bdc06a725c71235), UINT64_C(0xc19bf174cf692694), + UINT64_C(0xe49b69c19ef14ad2), UINT64_C(0xefbe4786384f25e3), + UINT64_C(0x0fc19dc68b8cd5b5), UINT64_C(0x240ca1cc77ac9c65), + UINT64_C(0x2de92c6f592b0275), UINT64_C(0x4a7484aa6ea6e483), + UINT64_C(0x5cb0a9dcbd41fbd4), UINT64_C(0x76f988da831153b5), + UINT64_C(0x983e5152ee66dfab), UINT64_C(0xa831c66d2db43210), + UINT64_C(0xb00327c898fb213f), UINT64_C(0xbf597fc7beef0ee4), + UINT64_C(0xc6e00bf33da88fc2), UINT64_C(0xd5a79147930aa725), + UINT64_C(0x06ca6351e003826f), UINT64_C(0x142929670a0e6e70), + UINT64_C(0x27b70a8546d22ffc), UINT64_C(0x2e1b21385c26c926), + UINT64_C(0x4d2c6dfc5ac42aed), UINT64_C(0x53380d139d95b3df), + UINT64_C(0x650a73548baf63de), UINT64_C(0x766a0abb3c77b2a8), + UINT64_C(0x81c2c92e47edaee6), UINT64_C(0x92722c851482353b), + UINT64_C(0xa2bfe8a14cf10364), UINT64_C(0xa81a664bbc423001), + UINT64_C(0xc24b8b70d0f89791), UINT64_C(0xc76c51a30654be30), + UINT64_C(0xd192e819d6ef5218), UINT64_C(0xd69906245565a910), + UINT64_C(0xf40e35855771202a), UINT64_C(0x106aa07032bbd1b8), + UINT64_C(0x19a4c116b8d2d0c8), UINT64_C(0x1e376c085141ab53), + UINT64_C(0x2748774cdf8eeb99), UINT64_C(0x34b0bcb5e19b48a8), + UINT64_C(0x391c0cb3c5c95a63), UINT64_C(0x4ed8aa4ae3418acb), + UINT64_C(0x5b9cca4f7763e373), UINT64_C(0x682e6ff3d6b2b8a3), + UINT64_C(0x748f82ee5defb2fc), UINT64_C(0x78a5636f43172f60), + UINT64_C(0x84c87814a1f0ab72), UINT64_C(0x8cc702081a6439ec), + UINT64_C(0x90befffa23631e28), UINT64_C(0xa4506cebde82bde9), + UINT64_C(0xbef9a3f7b2c67915), UINT64_C(0xc67178f2e372532b), + UINT64_C(0xca273eceea26619c), UINT64_C(0xd186b8c721c0c207), + UINT64_C(0xeada7dd6cde0eb1e), UINT64_C(0xf57d4f7fee6ed178), + UINT64_C(0x06f067aa72176fba), UINT64_C(0x0a637dc5a2c898a6), + UINT64_C(0x113f9804bef90dae), UINT64_C(0x1b710b35131c471b), + UINT64_C(0x28db77f523047d84), UINT64_C(0x32caab7b40c72493), + UINT64_C(0x3c9ebe0a15c9bebc), UINT64_C(0x431d67c49c100d4c), + UINT64_C(0x4cc5d4becb3e42b6), UINT64_C(0x597f299cfc657e2a), + UINT64_C(0x5fcb6fab3ad6faec), UINT64_C(0x6c44198c4a475817) +}; + +/* Various logical functions */ + +#define ROR64c(x, y) \ + ( ((((x)&UINT64_C(0xFFFFFFFFFFFFFFFF))>>((uint64_t)(y)&UINT64_C(63))) | \ + ((x)<<((uint64_t)(64-((y)&UINT64_C(63)))))) & UINT64_C(0xFFFFFFFFFFFFFFFF)) + +#define STORE64H(x, y) \ + { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \ + (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \ + (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \ + (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); } + +#define LOAD64H(x, y) \ + { x = (((uint64_t)((y)[0] & 255))<<56)|(((uint64_t)((y)[1] & 255))<<48) | \ + (((uint64_t)((y)[2] & 255))<<40)|(((uint64_t)((y)[3] & 255))<<32) | \ + (((uint64_t)((y)[4] & 255))<<24)|(((uint64_t)((y)[5] & 255))<<16) | \ + (((uint64_t)((y)[6] & 255))<<8)|(((uint64_t)((y)[7] & 255))); } + + +#define Ch(x,y,z) (z ^ (x & (y ^ z))) +#define Maj(x,y,z) (((x | y) & z) | (x & y)) +#define S(x, n) ROR64c(x, n) +#define R(x, n) (((x) &UINT64_C(0xFFFFFFFFFFFFFFFF))>>((uint64_t)n)) +#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39)) +#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41)) +#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7)) +#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6)) +#ifndef MIN + #define MIN(x, y) ( ((x)<(y))?(x):(y) ) +#endif + +/* compress 1024-bits */ +static int sha512_compress(sha512_context *md, unsigned char *buf) +{ + uint64_t S[8], W[80], t0, t1; + int i; + + /* copy state into S */ + for (i = 0; i < 8; i++) { + S[i] = md->state[i]; + } + + /* copy the state into 1024-bits into W[0..15] */ + for (i = 0; i < 16; i++) { + LOAD64H(W[i], buf + (8*i)); + } + + /* fill W[16..79] */ + for (i = 16; i < 80; i++) { + W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; + } + +/* Compress */ + #define RND(a,b,c,d,e,f,g,h,i) \ + t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ + t1 = Sigma0(a) + Maj(a, b, c);\ + d += t0; \ + h = t0 + t1; + + for (i = 0; i < 80; i += 8) { + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7); + } + + #undef RND + + + + /* feedback */ + for (i = 0; i < 8; i++) { + md->state[i] = md->state[i] + S[i]; + } + + return 0; +} + + +/** + Initialize the hash state + @param md The hash state you wish to initialize + @return 0 if successful +*/ +int sha512_init(sha512_context * md) { + if (md == NULL) return 1; + + md->curlen = 0; + md->length = 0; + md->state[0] = UINT64_C(0x6a09e667f3bcc908); + md->state[1] = UINT64_C(0xbb67ae8584caa73b); + md->state[2] = UINT64_C(0x3c6ef372fe94f82b); + md->state[3] = UINT64_C(0xa54ff53a5f1d36f1); + md->state[4] = UINT64_C(0x510e527fade682d1); + md->state[5] = UINT64_C(0x9b05688c2b3e6c1f); + md->state[6] = UINT64_C(0x1f83d9abfb41bd6b); + md->state[7] = UINT64_C(0x5be0cd19137e2179); + + return 0; +} + +/** + Process a block of memory though the hash + @param md The hash state + @param in The data to hash + @param inlen The length of the data (octets) + @return 0 if successful +*/ +int sha512_update (sha512_context * md, const unsigned char *in, size_t inlen) +{ + size_t n; + size_t i; + int err; + if (md == NULL) return 1; + if (in == NULL) return 1; + if (md->curlen > sizeof(md->buf)) { + return 1; + } + while (inlen > 0) { + if (md->curlen == 0 && inlen >= 128) { + if ((err = sha512_compress (md, (unsigned char *)in)) != 0) { + return err; + } + md->length += 128 * 8; + in += 128; + inlen -= 128; + } else { + n = MIN(inlen, (128 - md->curlen)); + + for (i = 0; i < n; i++) { + md->buf[i + md->curlen] = in[i]; + } + + + md->curlen += n; + in += n; + inlen -= n; + if (md->curlen == 128) { + if ((err = sha512_compress (md, md->buf)) != 0) { + return err; + } + md->length += 8*128; + md->curlen = 0; + } + } + } + return 0; +} + +/** + Terminate the hash to get the digest + @param md The hash state + @param out [out] The destination of the hash (64 bytes) + @return 0 if successful +*/ + int sha512_final(sha512_context * md, unsigned char *out) + { + int i; + + if (md == NULL) return 1; + if (out == NULL) return 1; + + if (md->curlen >= sizeof(md->buf)) { + return 1; + } + + /* increase the length of the message */ + md->length += md->curlen * UINT64_C(8); + + /* append the '1' bit */ + md->buf[md->curlen++] = (unsigned char)0x80; + + /* if the length is currently above 112 bytes we append zeros + * then compress. Then we can fall back to padding zeros and length + * encoding like normal. + */ + if (md->curlen > 112) { + while (md->curlen < 128) { + md->buf[md->curlen++] = (unsigned char)0; + } + sha512_compress(md, md->buf); + md->curlen = 0; + } + + /* pad upto 120 bytes of zeroes + * note: that from 112 to 120 is the 64 MSB of the length. We assume that you won't hash + * > 2^64 bits of data... :-) + */ +while (md->curlen < 120) { + md->buf[md->curlen++] = (unsigned char)0; +} + + /* store length */ +STORE64H(md->length, md->buf+120); +sha512_compress(md, md->buf); + + /* copy output */ +for (i = 0; i < 8; i++) { + STORE64H(md->state[i], out+(8*i)); +} + +return 0; +} + +int sha512(const unsigned char *message, size_t message_len, unsigned char *out) +{ + sha512_context ctx; + int ret; + if ((ret = sha512_init(&ctx))) return ret; + if ((ret = sha512_update(&ctx, message, message_len))) return ret; + if ((ret = sha512_final(&ctx, out))) return ret; + return 0; +} diff --git a/src/cryptoconditions/src/include/ed25519/src/sha512.h b/src/cryptoconditions/src/include/ed25519/src/sha512.h new file mode 100644 index 000000000..a34dd5e42 --- /dev/null +++ b/src/cryptoconditions/src/include/ed25519/src/sha512.h @@ -0,0 +1,21 @@ +#ifndef SHA512_H +#define SHA512_H + +#include + +#include "fixedint.h" + +/* state */ +typedef struct sha512_context_ { + uint64_t length, state[8]; + size_t curlen; + unsigned char buf[128]; +} sha512_context; + + +int sha512_init(sha512_context * md); +int sha512_final(sha512_context * md, unsigned char *out); +int sha512_update(sha512_context * md, const unsigned char *in, size_t inlen); +int sha512(const unsigned char *message, size_t message_len, unsigned char *out); + +#endif diff --git a/src/cryptoconditions/src/include/ed25519/src/sign.c b/src/cryptoconditions/src/include/ed25519/src/sign.c new file mode 100644 index 000000000..199a8393b --- /dev/null +++ b/src/cryptoconditions/src/include/ed25519/src/sign.c @@ -0,0 +1,31 @@ +#include "ed25519.h" +#include "sha512.h" +#include "ge.h" +#include "sc.h" + + +void ed25519_sign(unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key, const unsigned char *private_key) { + sha512_context hash; + unsigned char hram[64]; + unsigned char r[64]; + ge_p3 R; + + + sha512_init(&hash); + sha512_update(&hash, private_key + 32, 32); + sha512_update(&hash, message, message_len); + sha512_final(&hash, r); + + sc_reduce(r); + ge_scalarmult_base(&R, r); + ge_p3_tobytes(signature, &R); + + sha512_init(&hash); + sha512_update(&hash, signature, 32); + sha512_update(&hash, public_key, 32); + sha512_update(&hash, message, message_len); + sha512_final(&hash, hram); + + sc_reduce(hram); + sc_muladd(signature + 32, hram, private_key, r); +} diff --git a/src/cryptoconditions/src/include/ed25519/src/verify.c b/src/cryptoconditions/src/include/ed25519/src/verify.c new file mode 100644 index 000000000..32f988edc --- /dev/null +++ b/src/cryptoconditions/src/include/ed25519/src/verify.c @@ -0,0 +1,77 @@ +#include "ed25519.h" +#include "sha512.h" +#include "ge.h" +#include "sc.h" + +static int consttime_equal(const unsigned char *x, const unsigned char *y) { + unsigned char r = 0; + + r = x[0] ^ y[0]; + #define F(i) r |= x[i] ^ y[i] + F(1); + F(2); + F(3); + F(4); + F(5); + F(6); + F(7); + F(8); + F(9); + F(10); + F(11); + F(12); + F(13); + F(14); + F(15); + F(16); + F(17); + F(18); + F(19); + F(20); + F(21); + F(22); + F(23); + F(24); + F(25); + F(26); + F(27); + F(28); + F(29); + F(30); + F(31); + #undef F + + return !r; +} + +int ed25519_verify(const unsigned char *signature, const unsigned char *message, size_t message_len, const unsigned char *public_key) { + unsigned char h[64]; + unsigned char checker[32]; + sha512_context hash; + ge_p3 A; + ge_p2 R; + + if (signature[63] & 224) { + return 0; + } + + if (ge_frombytes_negate_vartime(&A, public_key) != 0) { + return 0; + } + + sha512_init(&hash); + sha512_update(&hash, signature, 32); + sha512_update(&hash, public_key, 32); + sha512_update(&hash, message, message_len); + sha512_final(&hash, h); + + sc_reduce(h); + ge_double_scalarmult_vartime(&R, h, &A, signature + 32); + ge_tobytes(checker, &R); + + if (!consttime_equal(checker, signature)) { + return 0; + } + + return 1; +} diff --git a/src/cryptoconditions/src/include/ed25519/test.c b/src/cryptoconditions/src/include/ed25519/test.c new file mode 100644 index 000000000..e2159a9af --- /dev/null +++ b/src/cryptoconditions/src/include/ed25519/test.c @@ -0,0 +1,150 @@ +#include +#include +#include +#include + +/* #define ED25519_DLL */ +#include "src/ed25519.h" + +#include "src/ge.h" +#include "src/sc.h" + + +int main() { + unsigned char public_key[32], private_key[64], seed[32], scalar[32]; + unsigned char other_public_key[32], other_private_key[64]; + unsigned char shared_secret[32], other_shared_secret[32]; + unsigned char signature[64]; + + clock_t start; + clock_t end; + int i; + + const unsigned char message[] = "Hello, world!"; + const int message_len = strlen((char*) message); + + /* create a random seed, and a keypair out of that seed */ + ed25519_create_seed(seed); + ed25519_create_keypair(public_key, private_key, seed); + + /* create signature on the message with the keypair */ + ed25519_sign(signature, message, message_len, public_key, private_key); + + /* verify the signature */ + if (ed25519_verify(signature, message, message_len, public_key)) { + printf("valid signature\n"); + } else { + printf("invalid signature\n"); + } + + /* create scalar and add it to the keypair */ + ed25519_create_seed(scalar); + ed25519_add_scalar(public_key, private_key, scalar); + + /* create signature with the new keypair */ + ed25519_sign(signature, message, message_len, public_key, private_key); + + /* verify the signature with the new keypair */ + if (ed25519_verify(signature, message, message_len, public_key)) { + printf("valid signature\n"); + } else { + printf("invalid signature\n"); + } + + /* make a slight adjustment and verify again */ + signature[44] ^= 0x10; + if (ed25519_verify(signature, message, message_len, public_key)) { + printf("did not detect signature change\n"); + } else { + printf("correctly detected signature change\n"); + } + + /* generate two keypairs for testing key exchange */ + ed25519_create_seed(seed); + ed25519_create_keypair(public_key, private_key, seed); + ed25519_create_seed(seed); + ed25519_create_keypair(other_public_key, other_private_key, seed); + + /* create two shared secrets - from both perspectives - and check if they're equal */ + ed25519_key_exchange(shared_secret, other_public_key, private_key); + ed25519_key_exchange(other_shared_secret, public_key, other_private_key); + + for (i = 0; i < 32; ++i) { + if (shared_secret[i] != other_shared_secret[i]) { + printf("key exchange was incorrect\n"); + break; + } + } + + if (i == 32) { + printf("key exchange was correct\n"); + } + + /* test performance */ + printf("testing seed generation performance: "); + start = clock(); + for (i = 0; i < 10000; ++i) { + ed25519_create_seed(seed); + } + end = clock(); + + printf("%fus per seed\n", ((double) ((end - start) * 1000)) / CLOCKS_PER_SEC / i * 1000); + + + printf("testing key generation performance: "); + start = clock(); + for (i = 0; i < 10000; ++i) { + ed25519_create_keypair(public_key, private_key, seed); + } + end = clock(); + + printf("%fus per keypair\n", ((double) ((end - start) * 1000)) / CLOCKS_PER_SEC / i * 1000); + + printf("testing sign performance: "); + start = clock(); + for (i = 0; i < 10000; ++i) { + ed25519_sign(signature, message, message_len, public_key, private_key); + } + end = clock(); + + printf("%fus per signature\n", ((double) ((end - start) * 1000)) / CLOCKS_PER_SEC / i * 1000); + + printf("testing verify performance: "); + start = clock(); + for (i = 0; i < 10000; ++i) { + ed25519_verify(signature, message, message_len, public_key); + } + end = clock(); + + printf("%fus per signature\n", ((double) ((end - start) * 1000)) / CLOCKS_PER_SEC / i * 1000); + + + printf("testing keypair scalar addition performance: "); + start = clock(); + for (i = 0; i < 10000; ++i) { + ed25519_add_scalar(public_key, private_key, scalar); + } + end = clock(); + + printf("%fus per keypair\n", ((double) ((end - start) * 1000)) / CLOCKS_PER_SEC / i * 1000); + + printf("testing public key scalar addition performance: "); + start = clock(); + for (i = 0; i < 10000; ++i) { + ed25519_add_scalar(public_key, NULL, scalar); + } + end = clock(); + + printf("%fus per key\n", ((double) ((end - start) * 1000)) / CLOCKS_PER_SEC / i * 1000); + + printf("testing key exchange performance: "); + start = clock(); + for (i = 0; i < 10000; ++i) { + ed25519_key_exchange(shared_secret, other_public_key, private_key); + } + end = clock(); + + printf("%fus per shared secret\n", ((double) ((end - start) * 1000)) / CLOCKS_PER_SEC / i * 1000); + + return 0; +} diff --git a/src/cryptoconditions/src/include/libbase58.h b/src/cryptoconditions/src/include/libbase58.h new file mode 100644 index 000000000..fafe6539f --- /dev/null +++ b/src/cryptoconditions/src/include/libbase58.h @@ -0,0 +1,23 @@ +#ifndef LIBBASE58_H +#define LIBBASE58_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern bool (*b58_sha256_impl)(void *, const void *, size_t); + +extern bool b58tobin(void *bin, size_t *binsz, const char *b58, size_t b58sz); +extern int b58check(const void *bin, size_t binsz, const char *b58, size_t b58sz); + +extern bool b58enc(char *b58, size_t *b58sz, const void *bin, size_t binsz); +extern bool b58check_enc(char *b58c, size_t *b58c_sz, uint8_t ver, const void *data, size_t datasz); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/.gitignore b/src/cryptoconditions/src/include/secp256k1/.gitignore new file mode 100644 index 000000000..076ff1295 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/.gitignore @@ -0,0 +1,37 @@ +bench_inv +bench_sign +bench_verify +bench_recover +bench_internal +tests +*.exe +*.so +*.a +!.gitignore + +Makefile +configure +.libs/ +Makefile.in +aclocal.m4 +autom4te.cache/ +config.log +config.status +*.tar.gz +*.la +libtool +.deps/ +.dirstamp +build-aux/ +*.lo +*.o +*~ +src/libsecp256k1-config.h +src/libsecp256k1-config.h.in +m4/libtool.m4 +m4/ltoptions.m4 +m4/ltsugar.m4 +m4/ltversion.m4 +m4/lt~obsolete.m4 +src/stamp-h1 +libsecp256k1.pc diff --git a/src/cryptoconditions/src/include/secp256k1/.travis.yml b/src/cryptoconditions/src/include/secp256k1/.travis.yml new file mode 100644 index 000000000..0d8089cfe --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/.travis.yml @@ -0,0 +1,59 @@ +language: c +sudo: false +addons: + apt: + packages: libgmp-dev +compiler: + - clang + - gcc +env: + global: + - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no ASM=no BUILD=check EXTRAFLAGS= HOST= + matrix: + - SCALAR=32bit + - SCALAR=64bit + - FIELD=64bit + - FIELD=64bit ENDOMORPHISM=yes + - FIELD=64bit ASM=x86_64 + - FIELD=64bit ENDOMORPHISM=yes ASM=x86_64 + - FIELD=32bit + - FIELD=32bit ENDOMORPHISM=yes + - BIGNUM=no + - BIGNUM=no ENDOMORPHISM=yes + - BUILD=distcheck + - EXTRAFLAGS=CFLAGS=-DDETERMINISTIC +matrix: + fast_finish: true + include: + - compiler: clang + env: HOST=i686-linux-gnu ENDOMORPHISM=yes + addons: + apt: + packages: + - gcc-multilib + - libgmp-dev:i386 + - compiler: clang + env: HOST=i686-linux-gnu + addons: + apt: + packages: + - gcc-multilib + - compiler: gcc + env: HOST=i686-linux-gnu ENDOMORPHISM=yes + addons: + apt: + packages: + - gcc-multilib + - compiler: gcc + env: HOST=i686-linux-gnu + addons: + apt: + packages: + - gcc-multilib + - libgmp-dev:i386 +before_script: ./autogen.sh +script: + - if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi + - if [ "x$HOST" = "xi686-linux-gnu" ]; then export CC="$CC -m32"; fi + - ./configure --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR $EXTRAFLAGS $USE_HOST && make -j2 $BUILD +os: linux diff --git a/src/cryptoconditions/src/include/secp256k1/COPYING b/src/cryptoconditions/src/include/secp256k1/COPYING new file mode 100644 index 000000000..4522a5990 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/COPYING @@ -0,0 +1,19 @@ +Copyright (c) 2013 Pieter Wuille + +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/cryptoconditions/src/include/secp256k1/Makefile.am b/src/cryptoconditions/src/include/secp256k1/Makefile.am new file mode 100644 index 000000000..5f388f3fd --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/Makefile.am @@ -0,0 +1,77 @@ +ACLOCAL_AMFLAGS = -I build-aux/m4 + +lib_LTLIBRARIES = libsecp256k1.la +include_HEADERS = include/secp256k1.h +noinst_HEADERS = +noinst_HEADERS += src/scalar.h +noinst_HEADERS += src/scalar_4x64.h +noinst_HEADERS += src/scalar_8x32.h +noinst_HEADERS += src/scalar_impl.h +noinst_HEADERS += src/scalar_4x64_impl.h +noinst_HEADERS += src/scalar_8x32_impl.h +noinst_HEADERS += src/group.h +noinst_HEADERS += src/group_impl.h +noinst_HEADERS += src/num_gmp.h +noinst_HEADERS += src/num_gmp_impl.h +noinst_HEADERS += src/ecdsa.h +noinst_HEADERS += src/ecdsa_impl.h +noinst_HEADERS += src/eckey.h +noinst_HEADERS += src/eckey_impl.h +noinst_HEADERS += src/ecmult.h +noinst_HEADERS += src/ecmult_impl.h +noinst_HEADERS += src/ecmult_gen.h +noinst_HEADERS += src/ecmult_gen_impl.h +noinst_HEADERS += src/num.h +noinst_HEADERS += src/num_impl.h +noinst_HEADERS += src/field_10x26.h +noinst_HEADERS += src/field_10x26_impl.h +noinst_HEADERS += src/field_5x52.h +noinst_HEADERS += src/field_5x52_impl.h +noinst_HEADERS += src/field_5x52_int128_impl.h +noinst_HEADERS += src/field_5x52_asm_impl.h +noinst_HEADERS += src/java/org_bitcoin_NativeSecp256k1.h +noinst_HEADERS += src/util.h +noinst_HEADERS += src/testrand.h +noinst_HEADERS += src/testrand_impl.h +noinst_HEADERS += src/hash.h +noinst_HEADERS += src/hash_impl.h +noinst_HEADERS += src/field.h +noinst_HEADERS += src/field_impl.h +noinst_HEADERS += src/bench.h + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libsecp256k1.pc + +libsecp256k1_la_SOURCES = src/secp256k1.c +libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include $(SECP_INCLUDES) +libsecp256k1_la_LIBADD = $(SECP_LIBS) + + +noinst_PROGRAMS = +if USE_BENCHMARK +noinst_PROGRAMS += bench_verify bench_recover bench_sign bench_internal +bench_verify_SOURCES = src/bench_verify.c +bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) +bench_verify_LDFLAGS = -static +bench_recover_SOURCES = src/bench_recover.c +bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS) +bench_recover_LDFLAGS = -static +bench_sign_SOURCES = src/bench_sign.c +bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) +bench_sign_LDFLAGS = -static +bench_internal_SOURCES = src/bench_internal.c +bench_internal_LDADD = $(SECP_LIBS) +bench_internal_LDFLAGS = -static +bench_internal_CPPFLAGS = $(SECP_INCLUDES) +endif + +if USE_TESTS +noinst_PROGRAMS += tests +tests_SOURCES = src/tests.c +tests_CPPFLAGS = -DVERIFY $(SECP_INCLUDES) $(SECP_TEST_INCLUDES) +tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) +tests_LDFLAGS = -static -pthread +TESTS = tests +endif + +EXTRA_DIST = autogen.sh diff --git a/src/cryptoconditions/src/include/secp256k1/README.md b/src/cryptoconditions/src/include/secp256k1/README.md new file mode 100644 index 000000000..6095db422 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/README.md @@ -0,0 +1,61 @@ +libsecp256k1 +============ + +[![Build Status](https://travis-ci.org/bitcoin/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin/secp256k1) + +Optimized C library for EC operations on curve secp256k1. + +This library is a work in progress and is being used to research best practices. Use at your own risk. + +Features: +* secp256k1 ECDSA signing/verification and key generation. +* Adding/multiplying private/public keys. +* Serialization/parsing of private keys, public keys, signatures. +* Constant time, constant memory access signing and pubkey generation. +* Derandomized DSA (via RFC6979 or with a caller provided function.) +* Very efficient implementation. + +Implementation details +---------------------- + +* General + * No runtime heap allocation. + * Extensive testing infrastructure. + * Structured to facilitate review and analysis. + * Intended to be portable to any system with a C89 compiler and uint64_t support. + * Expose only higher level interfaces to minimize the API surface and improve application security. ("Be difficult to use insecurely.") +* Field operations + * Optimized implementation of arithmetic modulo the curve's field size (2^256 - 0x1000003D1). + * Using 5 52-bit limbs (including hand-optimized assembly for x86_64, by Diederik Huys). + * Using 10 26-bit limbs. + * Field inverses and square roots using a sliding window over blocks of 1s (by Peter Dettman). +* Scalar operations + * Optimized implementation without data-dependent branches of arithmetic modulo the curve's order. + * Using 4 64-bit limbs (relying on __int128 support in the compiler). + * Using 8 32-bit limbs. +* Group operations + * Point addition formula specifically simplified for the curve equation (y^2 = x^3 + 7). + * Use addition between points in Jacobian and affine coordinates where possible. + * Use a unified addition/doubling formula where necessary to avoid data-dependent branches. + * Point/x comparison without a field inversion by comparison in the Jacobian coordinate space. +* Point multiplication for verification (a*P + b*G). + * Use wNAF notation for point multiplicands. + * Use a much larger window for multiples of G, using precomputed multiples. + * Use Shamir's trick to do the multiplication with the public key and the generator simultaneously. + * Optionally (off by default) use secp256k1's efficiently-computable endomorphism to split the P multiplicand into 2 half-sized ones. +* Point multiplication for signing + * Use a precomputed table of multiples of powers of 16 multiplied with the generator, so general multiplication becomes a series of additions. + * Access the table with branch-free conditional moves so memory access is uniform. + * No data-dependent branches + * The precomputed tables add and eventually subtract points for which no known scalar (private key) is known, preventing even an attacker with control over the private key used to control the data internally. + +Build steps +----------- + +libsecp256k1 is built using autotools: + + $ ./autogen.sh + $ ./configure + $ make + $ ./tests + $ sudo make install # optional diff --git a/src/cryptoconditions/src/include/secp256k1/TODO b/src/cryptoconditions/src/include/secp256k1/TODO new file mode 100644 index 000000000..a300e1c5e --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/TODO @@ -0,0 +1,3 @@ +* Unit tests for fieldelem/groupelem, including ones intended to + trigger fieldelem's boundary cases. +* Complete constant-time operations for signing/keygen diff --git a/src/cryptoconditions/src/include/secp256k1/autogen.sh b/src/cryptoconditions/src/include/secp256k1/autogen.sh new file mode 100755 index 000000000..65286b935 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/autogen.sh @@ -0,0 +1,3 @@ +#!/bin/sh +set -e +autoreconf -if --warnings=all diff --git a/src/cryptoconditions/src/include/secp256k1/configure.ac b/src/cryptoconditions/src/include/secp256k1/configure.ac new file mode 100644 index 000000000..3dc182951 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/configure.ac @@ -0,0 +1,330 @@ +AC_PREREQ([2.60]) +AC_INIT([libsecp256k1],[0.1]) +AC_CONFIG_AUX_DIR([build-aux]) +AC_CONFIG_MACRO_DIR([build-aux/m4]) +AC_CANONICAL_HOST +AH_TOP([#ifndef LIBSECP256K1_CONFIG_H]) +AH_TOP([#define LIBSECP256K1_CONFIG_H]) +AH_BOTTOM([#endif /*LIBSECP256K1_CONFIG_H*/]) +AM_INIT_AUTOMAKE([foreign subdir-objects]) +LT_INIT + +dnl make the compilation flags quiet unless V=1 is used +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +PKG_PROG_PKG_CONFIG + +AC_PATH_TOOL(AR, ar) +AC_PATH_TOOL(RANLIB, ranlib) +AC_PATH_TOOL(STRIP, strip) + +if test "x$CFLAGS" = "x"; then + CFLAGS="-O3 -g" +fi + +AC_PROG_CC_C89 +if test x"$ac_cv_prog_cc_c89" = x"no"; then + AC_MSG_ERROR([c89 compiler support required]) +fi + +case $host in + *mingw*) + use_pkgconfig=no + ;; + *) + use_pkgconfig=yes + ;; +esac + +case $host_os in + *darwin*) + if test x$cross_compiling != xyes; then + AC_PATH_PROG([BREW],brew,) + if test x$BREW != x; then + dnl These Homebrew packages may be keg-only, meaning that they won't be found + dnl in expected paths because they may conflict with system files. Ask + dnl Homebrew where each one is located, then adjust paths accordingly. + + openssl_prefix=`$BREW --prefix openssl 2>/dev/null` + gmp_prefix=`$BREW --prefix gmp 2>/dev/null` + if test x$openssl_prefix != x; then + PKG_CONFIG_PATH="$openssl_prefix/lib/pkgconfig:$PKG_CONFIG_PATH" + export PKG_CONFIG_PATH + fi + if test x$gmp_prefix != x; then + GMP_CPPFLAGS="-I$gmp_prefix/include" + GMP_LIBS="-L$gmp_prefix/lib" + fi + else + AC_PATH_PROG([PORT],port,) + dnl if homebrew isn't installed and macports is, add the macports default paths + dnl as a last resort. + if test x$PORT != x; then + CPPFLAGS="$CPPFLAGS -isystem /opt/local/include" + LDFLAGS="$LDFLAGS -L/opt/local/lib" + fi + fi + fi + ;; +esac + +CFLAGS="$CFLAGS -W" + +warn_CFLAGS="-std=c89 -pedantic -Wall -Wextra -Wcast-align -Wnested-externs -Wshadow -Wstrict-prototypes -Wno-unused-function -Wno-long-long -Wno-overlength-strings" +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS $warn_CFLAGS" +AC_MSG_CHECKING([if ${CC} supports ${warn_CFLAGS}]) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], + [ AC_MSG_RESULT([yes]) ], + [ AC_MSG_RESULT([no]) + CFLAGS="$saved_CFLAGS" + ]) + + +AC_ARG_ENABLE(benchmark, + AS_HELP_STRING([--enable-benchmark],[compile benchmark (default is no)]), + [use_benchmark=$enableval], + [use_benchmark=no]) + +AC_ARG_ENABLE(tests, + AS_HELP_STRING([--enable-tests],[compile tests (default is yes)]), + [use_tests=$enableval], + [use_tests=yes]) + +AC_ARG_ENABLE(endomorphism, + AS_HELP_STRING([--enable-endomorphism],[enable endomorphism (default is no)]), + [use_endomorphism=$enableval], + [use_endomorphism=no]) + +AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto], +[Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto]) + +AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|no|auto], +[Specify Bignum Implementation. Default is auto])],[req_bignum=$withval], [req_bignum=auto]) + +AC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|auto], +[Specify scalar implementation. Default is auto])],[req_scalar=$withval], [req_scalar=auto]) + +AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|no|auto] +[Specify assembly optimizations to use. Default is auto])],[req_asm=$withval], [req_asm=auto]) + +AC_CHECK_TYPES([__int128]) + +AC_MSG_CHECKING([for __builtin_expect]) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_expect(0,0);}]])], + [ AC_MSG_RESULT([yes]);AC_DEFINE(HAVE_BUILTIN_EXPECT,1,[Define this symbol if __builtin_expect is available]) ], + [ AC_MSG_RESULT([no]) + ]) + +if test x"$req_asm" = x"auto"; then + SECP_64BIT_ASM_CHECK + if test x"$has_64bit_asm" = x"yes"; then + set_asm=x86_64 + fi + if test x"$set_asm" = x; then + set_asm=no + fi +else + set_asm=$req_asm + case $set_asm in + x86_64) + SECP_64BIT_ASM_CHECK + if test x"$has_64bit_asm" != x"yes"; then + AC_MSG_ERROR([x86_64 assembly optimization requested but not available]) + fi + ;; + no) + ;; + *) + AC_MSG_ERROR([invalid assembly optimization selection]) + ;; + esac +fi + +if test x"$req_field" = x"auto"; then + if test x"set_asm" = x"x86_64"; then + set_field=64bit + fi + if test x"$set_field" = x; then + SECP_INT128_CHECK + if test x"$has_int128" = x"yes"; then + set_field=64bit + fi + fi + if test x"$set_field" = x; then + set_field=32bit + fi +else + set_field=$req_field + case $set_field in + 64bit) + if test x"$set_asm" != x"x86_64"; then + SECP_INT128_CHECK + if test x"$has_int128" != x"yes"; then + AC_MSG_ERROR([64bit field explicitly requested but neither __int128 support or x86_64 assembly available]) + fi + fi + ;; + 32bit) + ;; + *) + AC_MSG_ERROR([invalid field implementation selection]) + ;; + esac +fi + +if test x"$req_scalar" = x"auto"; then + SECP_INT128_CHECK + if test x"$has_int128" = x"yes"; then + set_scalar=64bit + fi + if test x"$set_scalar" = x; then + set_scalar=32bit + fi +else + set_scalar=$req_scalar + case $set_scalar in + 64bit) + SECP_INT128_CHECK + if test x"$has_int128" != x"yes"; then + AC_MSG_ERROR([64bit scalar explicitly requested but __int128 support not available]) + fi + ;; + 32bit) + ;; + *) + AC_MSG_ERROR([invalid scalar implementation selected]) + ;; + esac +fi + +if test x"$req_bignum" = x"auto"; then + SECP_GMP_CHECK + if test x"$has_gmp" = x"yes"; then + set_bignum=gmp + fi + + if test x"$set_bignum" = x; then + set_bignum=no + fi +else + set_bignum=$req_bignum + case $set_bignum in + gmp) + SECP_GMP_CHECK + if test x"$has_gmp" != x"yes"; then + AC_MSG_ERROR([gmp bignum explicitly requested but libgmp not available]) + fi + ;; + no) + ;; + *) + AC_MSG_ERROR([invalid bignum implementation selection]) + ;; + esac +fi + +# select assembly optimization +case $set_asm in +x86_64) + AC_DEFINE(USE_ASM_X86_64, 1, [Define this symbol to enable x86_64 assembly optimizations]) + ;; +no) + ;; +*) + AC_MSG_ERROR([invalid assembly optimizations]) + ;; +esac + +# select field implementation +case $set_field in +64bit) + AC_DEFINE(USE_FIELD_5X52, 1, [Define this symbol to use the FIELD_5X52 implementation]) + ;; +32bit) + AC_DEFINE(USE_FIELD_10X26, 1, [Define this symbol to use the FIELD_10X26 implementation]) + ;; +*) + AC_MSG_ERROR([invalid field implementation]) + ;; +esac + +# select bignum implementation +case $set_bignum in +gmp) + AC_DEFINE(HAVE_LIBGMP, 1, [Define this symbol if libgmp is installed]) + AC_DEFINE(USE_NUM_GMP, 1, [Define this symbol to use the gmp implementation for num]) + AC_DEFINE(USE_FIELD_INV_NUM, 1, [Define this symbol to use the num-based field inverse implementation]) + AC_DEFINE(USE_SCALAR_INV_NUM, 1, [Define this symbol to use the num-based scalar inverse implementation]) + ;; +no) + AC_DEFINE(USE_NUM_NONE, 1, [Define this symbol to use no num implementation]) + AC_DEFINE(USE_FIELD_INV_BUILTIN, 1, [Define this symbol to use the native field inverse implementation]) + AC_DEFINE(USE_SCALAR_INV_BUILTIN, 1, [Define this symbol to use the native scalar inverse implementation]) + ;; +*) + AC_MSG_ERROR([invalid bignum implementation]) + ;; +esac + +#select scalar implementation +case $set_scalar in +64bit) + AC_DEFINE(USE_SCALAR_4X64, 1, [Define this symbol to use the 4x64 scalar implementation]) + ;; +32bit) + AC_DEFINE(USE_SCALAR_8X32, 1, [Define this symbol to use the 8x32 scalar implementation]) + ;; +*) + AC_MSG_ERROR([invalid scalar implementation]) + ;; +esac + +if test x"$use_tests" = x"yes"; then + SECP_OPENSSL_CHECK + if test x"$has_openssl_ec" = x"yes"; then + AC_DEFINE(ENABLE_OPENSSL_TESTS, 1, [Define this symbol if OpenSSL EC functions are available]) + SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS" + SECP_TEST_LIBS="$CRYPTO_LIBS" + + case $host in + *mingw*) + SECP_TEST_LIBS="$SECP_TEST_LIBS -lgdi32" + ;; + esac + + fi +fi + +if test x"$set_bignum" = x"gmp"; then + SECP_LIBS="$SECP_LIBS $GMP_LIBS" + SECP_INCLUDES="$SECP_INCLUDES $GMP_CPPFLAGS" +fi + +if test x"$use_endomorphism" = x"yes"; then + AC_DEFINE(USE_ENDOMORPHISM, 1, [Define this symbol to use endomorphism optimization]) +fi + +AC_C_BIGENDIAN() + +AC_MSG_NOTICE([Using assembly optimizations: $set_asm]) +AC_MSG_NOTICE([Using field implementation: $set_field]) +AC_MSG_NOTICE([Using bignum implementation: $set_bignum]) +AC_MSG_NOTICE([Using scalar implementation: $set_scalar]) +AC_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism]) + +AC_CONFIG_HEADERS([src/libsecp256k1-config.h]) +AC_CONFIG_FILES([Makefile libsecp256k1.pc]) +AC_SUBST(SECP_INCLUDES) +AC_SUBST(SECP_LIBS) +AC_SUBST(SECP_TEST_LIBS) +AC_SUBST(SECP_TEST_INCLUDES) +AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"]) +AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"]) + +dnl make sure nothing new is exported so that we don't break the cache +PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH" +unset PKG_CONFIG_PATH +PKG_CONFIG_PATH="$PKGCONFIG_PATH_TEMP" + +AC_OUTPUT diff --git a/src/cryptoconditions/src/include/secp256k1/include/secp256k1.h b/src/cryptoconditions/src/include/secp256k1/include/secp256k1.h new file mode 100644 index 000000000..06afd4c65 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/include/secp256k1.h @@ -0,0 +1,347 @@ +#ifndef _SECP256K1_ +# define _SECP256K1_ + +# ifdef __cplusplus +extern "C" { +# endif + +# if !defined(SECP256K1_GNUC_PREREQ) +# if defined(__GNUC__)&&defined(__GNUC_MINOR__) +# define SECP256K1_GNUC_PREREQ(_maj,_min) \ + ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min)) +# else +# define SECP256K1_GNUC_PREREQ(_maj,_min) 0 +# endif +# endif + +# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) +# if SECP256K1_GNUC_PREREQ(2,7) +# define SECP256K1_INLINE __inline__ +# elif (defined(_MSC_VER)) +# define SECP256K1_INLINE __inline +# else +# define SECP256K1_INLINE +# endif +# else +# define SECP256K1_INLINE inline +# endif + +/**Warning attributes + * NONNULL is not used if SECP256K1_BUILD is set to avoid the compiler optimizing out + * some paranoid null checks. */ +# if defined(__GNUC__) && SECP256K1_GNUC_PREREQ(3, 4) +# define SECP256K1_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__)) +# else +# define SECP256K1_WARN_UNUSED_RESULT +# endif +# if !defined(SECP256K1_BUILD) && defined(__GNUC__) && SECP256K1_GNUC_PREREQ(3, 4) +# define SECP256K1_ARG_NONNULL(_x) __attribute__ ((__nonnull__(_x))) +# else +# define SECP256K1_ARG_NONNULL(_x) +# endif + +/** Opaque data structure that holds context information (precomputed tables etc.). + * Only functions that take a pointer to a non-const context require exclusive + * access to it. Multiple functions that take a pointer to a const context may + * run simultaneously. + */ +typedef struct secp256k1_context_struct secp256k1_context_t; + +/** Flags to pass to secp256k1_context_create. */ +# define SECP256K1_CONTEXT_VERIFY (1 << 0) +# define SECP256K1_CONTEXT_SIGN (1 << 1) + +/** Create a secp256k1 context object. + * Returns: a newly created context object. + * In: flags: which parts of the context to initialize. + */ +secp256k1_context_t* secp256k1_context_create( + int flags +) SECP256K1_WARN_UNUSED_RESULT; + +/** Copies a secp256k1 context object. + * Returns: a newly created context object. + * In: ctx: an existing context to copy + */ +secp256k1_context_t* secp256k1_context_clone( + const secp256k1_context_t* ctx +) SECP256K1_WARN_UNUSED_RESULT; + +/** Destroy a secp256k1 context object. + * The context pointer may not be used afterwards. + */ +void secp256k1_context_destroy( + secp256k1_context_t* ctx +) SECP256K1_ARG_NONNULL(1); + +/** Verify an ECDSA signature. + * Returns: 1: correct signature + * 0: incorrect signature + * -1: invalid public key + * -2: invalid signature + * In: ctx: a secp256k1 context object, initialized for verification. + * msg32: the 32-byte message hash being verified (cannot be NULL) + * sig: the signature being verified (cannot be NULL) + * siglen: the length of the signature + * pubkey: the public key to verify with (cannot be NULL) + * pubkeylen: the length of pubkey + */ +SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify( + const secp256k1_context_t* ctx, + const unsigned char *msg32, + const unsigned char *sig, + int siglen, + const unsigned char *pubkey, + int pubkeylen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5); + +/** A pointer to a function to deterministically generate a nonce. + * Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail. + * In: msg32: the 32-byte message hash being verified (will not be NULL) + * key32: pointer to a 32-byte secret key (will not be NULL) + * attempt: how many iterations we have tried to find a nonce. + * This will almost always be 0, but different attempt values + * are required to result in a different nonce. + * data: Arbitrary data pointer that is passed through. + * Out: nonce32: pointer to a 32-byte array to be filled by the function. + * Except for test cases, this function should compute some cryptographic hash of + * the message, the key and the attempt. + */ +typedef int (*secp256k1_nonce_function_t)( + unsigned char *nonce32, + const unsigned char *msg32, + const unsigned char *key32, + unsigned int attempt, + const void *data +); + +/** An implementation of RFC6979 (using HMAC-SHA256) as nonce generation function. + * If a data pointer is passed, it is assumed to be a pointer to 32 bytes of + * extra entropy. + */ +extern const secp256k1_nonce_function_t secp256k1_nonce_function_rfc6979; + +/** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */ +extern const secp256k1_nonce_function_t secp256k1_nonce_function_default; + + +/** Create an ECDSA signature. + * Returns: 1: signature created + * 0: the nonce generation function failed, the private key was invalid, or there is not + * enough space in the signature (as indicated by siglen). + * In: ctx: pointer to a context object, initialized for signing (cannot be NULL) + * msg32: the 32-byte message hash being signed (cannot be NULL) + * seckey: pointer to a 32-byte secret key (cannot be NULL) + * noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used + * ndata: pointer to arbitrary data used by the nonce generation function (can be NULL) + * Out: sig: pointer to an array where the signature will be placed (cannot be NULL) + * In/Out: siglen: pointer to an int with the length of sig, which will be updated + * to contain the actual signature length (<=72). + * + * The sig always has an s value in the lower half of the range (From 0x1 + * to 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, + * inclusive), unlike many other implementations. + * With ECDSA a third-party can can forge a second distinct signature + * of the same message given a single initial signature without knowing + * the key by setting s to its additive inverse mod-order, 'flipping' the + * sign of the random point R which is not included in the signature. + * Since the forgery is of the same message this isn't universally + * problematic, but in systems where message malleability or uniqueness + * of signatures is important this can cause issues. This forgery can be + * blocked by all verifiers forcing signers to use a canonical form. The + * lower-S form reduces the size of signatures slightly on average when + * variable length encodings (such as DER) are used and is cheap to + * verify, making it a good choice. Security of always using lower-S is + * assured because anyone can trivially modify a signature after the + * fact to enforce this property. Adjusting it inside the signing + * function avoids the need to re-serialize or have curve specific + * constants outside of the library. By always using a canonical form + * even in applications where it isn't needed it becomes possible to + * impose a requirement later if a need is discovered. + * No other forms of ECDSA malleability are known and none seem likely, + * but there is no formal proof that ECDSA, even with this additional + * restriction, is free of other malleability. Commonly used serialization + * schemes will also accept various non-unique encodings, so care should + * be taken when this property is required for an application. + */ +int secp256k1_ecdsa_sign( + const secp256k1_context_t* ctx, + const unsigned char *msg32, + unsigned char *sig, + int *siglen, + const unsigned char *seckey, + secp256k1_nonce_function_t noncefp, + const void *ndata +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); + +/** Create a compact ECDSA signature (64 byte + recovery id). + * Returns: 1: signature created + * 0: the nonce generation function failed, or the secret key was invalid. + * In: ctx: pointer to a context object, initialized for signing (cannot be NULL) + * msg32: the 32-byte message hash being signed (cannot be NULL) + * seckey: pointer to a 32-byte secret key (cannot be NULL) + * noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used + * ndata: pointer to arbitrary data used by the nonce generation function (can be NULL) + * Out: sig: pointer to a 64-byte array where the signature will be placed (cannot be NULL) + * In case 0 is returned, the returned signature length will be zero. + * recid: pointer to an int, which will be updated to contain the recovery id (can be NULL) + */ +int secp256k1_ecdsa_sign_compact( + const secp256k1_context_t* ctx, + const unsigned char *msg32, + unsigned char *sig64, + const unsigned char *seckey, + secp256k1_nonce_function_t noncefp, + const void *ndata, + int *recid +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Recover an ECDSA public key from a compact signature. + * Returns: 1: public key successfully recovered (which guarantees a correct signature). + * 0: otherwise. + * In: ctx: pointer to a context object, initialized for verification (cannot be NULL) + * msg32: the 32-byte message hash assumed to be signed (cannot be NULL) + * sig64: signature as 64 byte array (cannot be NULL) + * compressed: whether to recover a compressed or uncompressed pubkey + * recid: the recovery id (0-3, as returned by ecdsa_sign_compact) + * Out: pubkey: pointer to a 33 or 65 byte array to put the pubkey (cannot be NULL) + * pubkeylen: pointer to an int that will contain the pubkey length (cannot be NULL) + */ +SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover_compact( + const secp256k1_context_t* ctx, + const unsigned char *msg32, + const unsigned char *sig64, + unsigned char *pubkey, + int *pubkeylen, + int compressed, + int recid +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); + +/** Verify an ECDSA secret key. + * Returns: 1: secret key is valid + * 0: secret key is invalid + * In: ctx: pointer to a context object (cannot be NULL) + * seckey: pointer to a 32-byte secret key (cannot be NULL) + */ +SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify( + const secp256k1_context_t* ctx, + const unsigned char *seckey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); + +/** Just validate a public key. + * Returns: 1: public key is valid + * 0: public key is invalid + * In: ctx: pointer to a context object (cannot be NULL) + * pubkey: pointer to a 33-byte or 65-byte public key (cannot be NULL). + * pubkeylen: length of pubkey + */ +SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_verify( + const secp256k1_context_t* ctx, + const unsigned char *pubkey, + int pubkeylen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); + +/** Compute the public key for a secret key. + * In: ctx: pointer to a context object, initialized for signing (cannot be NULL) + * compressed: whether the computed public key should be compressed + * seckey: pointer to a 32-byte private key (cannot be NULL) + * Out: pubkey: pointer to a 33-byte (if compressed) or 65-byte (if uncompressed) + * area to store the public key (cannot be NULL) + * pubkeylen: pointer to int that will be updated to contains the pubkey's + * length (cannot be NULL) + * Returns: 1: secret was valid, public key stores + * 0: secret was invalid, try again + */ +SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create( + const secp256k1_context_t* ctx, + unsigned char *pubkey, + int *pubkeylen, + const unsigned char *seckey, + int compressed +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Decompress a public key. + * In: ctx: pointer to a context object (cannot be NULL) + * In/Out: pubkey: pointer to a 65-byte array to put the decompressed public key. + * It must contain a 33-byte or 65-byte public key already (cannot be NULL) + * pubkeylen: pointer to the size of the public key pointed to by pubkey (cannot be NULL) + * It will be updated to reflect the new size. + * Returns: 0: pubkey was invalid + * 1: pubkey was valid, and was replaced with its decompressed version + */ +SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_decompress( + const secp256k1_context_t* ctx, + unsigned char *pubkey, + int *pubkeylen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Export a private key in DER format. + * In: ctx: pointer to a context object, initialized for signing (cannot be NULL) + */ +SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_export( + const secp256k1_context_t* ctx, + const unsigned char *seckey, + unsigned char *privkey, + int *privkeylen, + int compressed +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Import a private key in DER format. */ +SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_import( + const secp256k1_context_t* ctx, + unsigned char *seckey, + const unsigned char *privkey, + int privkeylen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Tweak a private key by adding tweak to it. */ +SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add( + const secp256k1_context_t* ctx, + unsigned char *seckey, + const unsigned char *tweak +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Tweak a public key by adding tweak times the generator to it. + * In: ctx: pointer to a context object, initialized for verification (cannot be NULL) + */ +SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add( + const secp256k1_context_t* ctx, + unsigned char *pubkey, + int pubkeylen, + const unsigned char *tweak +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); + +/** Tweak a private key by multiplying it with tweak. */ +SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul( + const secp256k1_context_t* ctx, + unsigned char *seckey, + const unsigned char *tweak +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Tweak a public key by multiplying it with tweak. + * In: ctx: pointer to a context object, initialized for verification (cannot be NULL) + */ +SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul( + const secp256k1_context_t* ctx, + unsigned char *pubkey, + int pubkeylen, + const unsigned char *tweak +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); + +/** Updates the context randomization. + * Returns: 1: randomization successfully updated + * 0: error + * In: ctx: pointer to a context object (cannot be NULL) + * seed32: pointer to a 32-byte random seed (NULL resets to initial state) + */ +SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize( + secp256k1_context_t* ctx, + const unsigned char *seed32 +) SECP256K1_ARG_NONNULL(1); + + +# ifdef __cplusplus +} +# endif + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/libsecp256k1.pc.in b/src/cryptoconditions/src/include/secp256k1/libsecp256k1.pc.in new file mode 100644 index 000000000..1c72dd000 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/libsecp256k1.pc.in @@ -0,0 +1,13 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libsecp256k1 +Description: Optimized C library for EC operations on curve secp256k1 +URL: https://github.com/bitcoin/secp256k1 +Version: @PACKAGE_VERSION@ +Cflags: -I${includedir} +Libs.private: @SECP_LIBS@ +Libs: -L${libdir} -lsecp256k1 + diff --git a/src/cryptoconditions/src/include/secp256k1/obj/.gitignore b/src/cryptoconditions/src/include/secp256k1/obj/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/src/cryptoconditions/src/include/secp256k1/src/bench.h b/src/cryptoconditions/src/include/secp256k1/src/bench.h new file mode 100644 index 000000000..db5f68cee --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/bench.h @@ -0,0 +1,56 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_BENCH_H_ +#define _SECP256K1_BENCH_H_ + +#include +#include +#include "sys/time.h" + +static double gettimedouble(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_usec * 0.000001 + tv.tv_sec; +} + +void print_number(double x) { + double y = x; + int c = 0; + if (y < 0.0) y = -y; + while (y < 100.0) { + y *= 10.0; + c++; + } + printf("%.*f", c, x); +} + +void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), void (*teardown)(void*), void* data, int count, int iter) { + int i; + double min = HUGE_VAL; + double sum = 0.0; + double max = 0.0; + for (i = 0; i < count; i++) { + double begin, total; + if (setup) setup(data); + begin = gettimedouble(); + benchmark(data); + total = gettimedouble() - begin; + if (teardown) teardown(data); + if (total < min) min = total; + if (total > max) max = total; + sum += total; + } + printf("%s: min ", name); + print_number(min * 1000000.0 / iter); + printf("us / avg "); + print_number((sum / count) * 1000000.0 / iter); + printf("us / max "); + print_number(max * 1000000.0 / iter); + printf("us\n"); +} + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/bench_internal.c b/src/cryptoconditions/src/include/secp256k1/src/bench_internal.c new file mode 100644 index 000000000..a960549b9 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/bench_internal.c @@ -0,0 +1,318 @@ +/********************************************************************** + * Copyright (c) 2014-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ +#include + +#include "include/secp256k1.h" + +#include "util.h" +#include "hash_impl.h" +#include "num_impl.h" +#include "field_impl.h" +#include "group_impl.h" +#include "scalar_impl.h" +#include "ecmult_impl.h" +#include "bench.h" + +typedef struct { + secp256k1_scalar_t scalar_x, scalar_y; + secp256k1_fe_t fe_x, fe_y; + secp256k1_ge_t ge_x, ge_y; + secp256k1_gej_t gej_x, gej_y; + unsigned char data[32]; + int wnaf[256]; +} bench_inv_t; + +void bench_setup(void* arg) { + bench_inv_t *data = (bench_inv_t*)arg; + + static const unsigned char init_x[32] = { + 0x02, 0x03, 0x05, 0x07, 0x0b, 0x0d, 0x11, 0x13, + 0x17, 0x1d, 0x1f, 0x25, 0x29, 0x2b, 0x2f, 0x35, + 0x3b, 0x3d, 0x43, 0x47, 0x49, 0x4f, 0x53, 0x59, + 0x61, 0x65, 0x67, 0x6b, 0x6d, 0x71, 0x7f, 0x83 + }; + + static const unsigned char init_y[32] = { + 0x82, 0x83, 0x85, 0x87, 0x8b, 0x8d, 0x81, 0x83, + 0x97, 0xad, 0xaf, 0xb5, 0xb9, 0xbb, 0xbf, 0xc5, + 0xdb, 0xdd, 0xe3, 0xe7, 0xe9, 0xef, 0xf3, 0xf9, + 0x11, 0x15, 0x17, 0x1b, 0x1d, 0xb1, 0xbf, 0xd3 + }; + + secp256k1_scalar_set_b32(&data->scalar_x, init_x, NULL); + secp256k1_scalar_set_b32(&data->scalar_y, init_y, NULL); + secp256k1_fe_set_b32(&data->fe_x, init_x); + secp256k1_fe_set_b32(&data->fe_y, init_y); + CHECK(secp256k1_ge_set_xo_var(&data->ge_x, &data->fe_x, 0)); + CHECK(secp256k1_ge_set_xo_var(&data->ge_y, &data->fe_y, 1)); + secp256k1_gej_set_ge(&data->gej_x, &data->ge_x); + secp256k1_gej_set_ge(&data->gej_y, &data->ge_y); + memcpy(data->data, init_x, 32); +} + +void bench_scalar_add(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 2000000; i++) { + secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + } +} + +void bench_scalar_negate(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 2000000; i++) { + secp256k1_scalar_negate(&data->scalar_x, &data->scalar_x); + } +} + +void bench_scalar_sqr(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_scalar_sqr(&data->scalar_x, &data->scalar_x); + } +} + +void bench_scalar_mul(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_scalar_mul(&data->scalar_x, &data->scalar_x, &data->scalar_y); + } +} + +#ifdef USE_ENDOMORPHISM +void bench_scalar_split(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_scalar_t l, r; + secp256k1_scalar_split_lambda_var(&l, &r, &data->scalar_x); + secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + } +} +#endif + +void bench_scalar_inverse(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 2000; i++) { + secp256k1_scalar_inverse(&data->scalar_x, &data->scalar_x); + secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + } +} + +void bench_scalar_inverse_var(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 2000; i++) { + secp256k1_scalar_inverse_var(&data->scalar_x, &data->scalar_x); + secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + } +} + +void bench_field_normalize(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 2000000; i++) { + secp256k1_fe_normalize(&data->fe_x); + } +} + +void bench_field_normalize_weak(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 2000000; i++) { + secp256k1_fe_normalize_weak(&data->fe_x); + } +} + +void bench_field_mul(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_fe_mul(&data->fe_x, &data->fe_x, &data->fe_y); + } +} + +void bench_field_sqr(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_fe_sqr(&data->fe_x, &data->fe_x); + } +} + +void bench_field_inverse(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_fe_inv(&data->fe_x, &data->fe_x); + secp256k1_fe_add(&data->fe_x, &data->fe_y); + } +} + +void bench_field_inverse_var(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_fe_inv_var(&data->fe_x, &data->fe_x); + secp256k1_fe_add(&data->fe_x, &data->fe_y); + } +} + +void bench_field_sqrt_var(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_fe_sqrt_var(&data->fe_x, &data->fe_x); + secp256k1_fe_add(&data->fe_x, &data->fe_y); + } +} + +void bench_group_double_var(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_gej_double_var(&data->gej_x, &data->gej_x); + } +} + +void bench_group_add_var(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_gej_add_var(&data->gej_x, &data->gej_x, &data->gej_y); + } +} + +void bench_group_add_affine(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_gej_add_ge(&data->gej_x, &data->gej_x, &data->ge_y); + } +} + +void bench_group_add_affine_var(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 200000; i++) { + secp256k1_gej_add_ge_var(&data->gej_x, &data->gej_x, &data->ge_y); + } +} + +void bench_ecmult_wnaf(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_ecmult_wnaf(data->wnaf, &data->scalar_x, WINDOW_A); + secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + } +} + + +void bench_sha256(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + secp256k1_sha256_t sha; + + for (i = 0; i < 20000; i++) { + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, data->data, 32); + secp256k1_sha256_finalize(&sha, data->data); + } +} + +void bench_hmac_sha256(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + secp256k1_hmac_sha256_t hmac; + + for (i = 0; i < 20000; i++) { + secp256k1_hmac_sha256_initialize(&hmac, data->data, 32); + secp256k1_hmac_sha256_write(&hmac, data->data, 32); + secp256k1_hmac_sha256_finalize(&hmac, data->data); + } +} + +void bench_rfc6979_hmac_sha256(void* arg) { + int i; + bench_inv_t *data = (bench_inv_t*)arg; + secp256k1_rfc6979_hmac_sha256_t rng; + + for (i = 0; i < 20000; i++) { + secp256k1_rfc6979_hmac_sha256_initialize(&rng, data->data, 32, data->data, 32, NULL, 0); + secp256k1_rfc6979_hmac_sha256_generate(&rng, data->data, 32); + } +} + + +int have_flag(int argc, char** argv, char *flag) { + char** argm = argv + argc; + argv++; + if (argv == argm) { + return 1; + } + while (argv != NULL && argv != argm) { + if (strcmp(*argv, flag) == 0) return 1; + argv++; + } + return 0; +} + +int main(int argc, char **argv) { + bench_inv_t data; + if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "add")) run_benchmark("scalar_add", bench_scalar_add, bench_setup, NULL, &data, 10, 2000000); + if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "negate")) run_benchmark("scalar_negate", bench_scalar_negate, bench_setup, NULL, &data, 10, 2000000); + if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "sqr")) run_benchmark("scalar_sqr", bench_scalar_sqr, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "mul")) run_benchmark("scalar_mul", bench_scalar_mul, bench_setup, NULL, &data, 10, 200000); +#ifdef USE_ENDOMORPHISM + if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "split")) run_benchmark("scalar_split", bench_scalar_split, bench_setup, NULL, &data, 10, 20000); +#endif + if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse", bench_scalar_inverse, bench_setup, NULL, &data, 10, 2000); + if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "inverse")) run_benchmark("scalar_inverse_var", bench_scalar_inverse_var, bench_setup, NULL, &data, 10, 2000); + + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize", bench_field_normalize, bench_setup, NULL, &data, 10, 2000000); + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "normalize")) run_benchmark("field_normalize_weak", bench_field_normalize_weak, bench_setup, NULL, &data, 10, 2000000); + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqr")) run_benchmark("field_sqr", bench_field_sqr, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, 20000); + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, 20000); + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt_var", bench_field_sqrt_var, bench_setup, NULL, &data, 10, 20000); + + if (have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_var", bench_group_add_var, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine", bench_group_add_affine, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine_var", bench_group_add_affine_var, bench_setup, NULL, &data, 10, 200000); + + if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, 20000); + + if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "sha256")) run_benchmark("hash_sha256", bench_sha256, bench_setup, NULL, &data, 10, 20000); + if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "hmac")) run_benchmark("hash_hmac_sha256", bench_hmac_sha256, bench_setup, NULL, &data, 10, 20000); + if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "rng6979")) run_benchmark("hash_rfc6979_hmac_sha256", bench_rfc6979_hmac_sha256, bench_setup, NULL, &data, 10, 20000); + return 0; +} diff --git a/src/cryptoconditions/src/include/secp256k1/src/bench_recover.c b/src/cryptoconditions/src/include/secp256k1/src/bench_recover.c new file mode 100644 index 000000000..56faed11a --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/bench_recover.c @@ -0,0 +1,51 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include "include/secp256k1.h" +#include "util.h" +#include "bench.h" + +typedef struct { + secp256k1_context_t *ctx; + unsigned char msg[32]; + unsigned char sig[64]; +} bench_recover_t; + +void bench_recover(void* arg) { + int i; + bench_recover_t *data = (bench_recover_t*)arg; + unsigned char pubkey[33]; + + for (i = 0; i < 20000; i++) { + int j; + int pubkeylen = 33; + CHECK(secp256k1_ecdsa_recover_compact(data->ctx, data->msg, data->sig, pubkey, &pubkeylen, 1, i % 2)); + for (j = 0; j < 32; j++) { + data->sig[j + 32] = data->msg[j]; /* Move former message to S. */ + data->msg[j] = data->sig[j]; /* Move former R to message. */ + data->sig[j] = pubkey[j + 1]; /* Move recovered pubkey X coordinate to R (which must be a valid X coordinate). */ + } + } +} + +void bench_recover_setup(void* arg) { + int i; + bench_recover_t *data = (bench_recover_t*)arg; + + for (i = 0; i < 32; i++) data->msg[i] = 1 + i; + for (i = 0; i < 64; i++) data->sig[i] = 65 + i; +} + +int main(void) { + bench_recover_t data; + + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + + run_benchmark("ecdsa_recover", bench_recover, bench_recover_setup, NULL, &data, 10, 20000); + + secp256k1_context_destroy(data.ctx); + return 0; +} diff --git a/src/cryptoconditions/src/include/secp256k1/src/bench_sign.c b/src/cryptoconditions/src/include/secp256k1/src/bench_sign.c new file mode 100644 index 000000000..072a37af5 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/bench_sign.c @@ -0,0 +1,50 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include "include/secp256k1.h" +#include "util.h" +#include "bench.h" + +typedef struct { + secp256k1_context_t* ctx; + unsigned char msg[32]; + unsigned char key[32]; +} bench_sign_t; + +static void bench_sign_setup(void* arg) { + int i; + bench_sign_t *data = (bench_sign_t*)arg; + + for (i = 0; i < 32; i++) data->msg[i] = i + 1; + for (i = 0; i < 32; i++) data->key[i] = i + 65; +} + +static void bench_sign(void* arg) { + int i; + bench_sign_t *data = (bench_sign_t*)arg; + + unsigned char sig[64]; + for (i = 0; i < 20000; i++) { + int j; + int recid = 0; + CHECK(secp256k1_ecdsa_sign_compact(data->ctx, data->msg, sig, data->key, NULL, NULL, &recid)); + for (j = 0; j < 32; j++) { + data->msg[j] = sig[j]; /* Move former R to message. */ + data->key[j] = sig[j + 32]; /* Move former S to key. */ + } + } +} + +int main(void) { + bench_sign_t data; + + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + + run_benchmark("ecdsa_sign", bench_sign, bench_sign_setup, NULL, &data, 10, 20000); + + secp256k1_context_destroy(data.ctx); + return 0; +} diff --git a/src/cryptoconditions/src/include/secp256k1/src/bench_verify.c b/src/cryptoconditions/src/include/secp256k1/src/bench_verify.c new file mode 100644 index 000000000..c8c82752c --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/bench_verify.c @@ -0,0 +1,56 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include + +#include "include/secp256k1.h" +#include "util.h" +#include "bench.h" + +typedef struct { + secp256k1_context_t *ctx; + unsigned char msg[32]; + unsigned char key[32]; + unsigned char sig[72]; + int siglen; + unsigned char pubkey[33]; + int pubkeylen; +} benchmark_verify_t; + +static void benchmark_verify(void* arg) { + int i; + benchmark_verify_t* data = (benchmark_verify_t*)arg; + + for (i = 0; i < 20000; i++) { + data->sig[data->siglen - 1] ^= (i & 0xFF); + data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); + data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); + CHECK(secp256k1_ecdsa_verify(data->ctx, data->msg, data->sig, data->siglen, data->pubkey, data->pubkeylen) == (i == 0)); + data->sig[data->siglen - 1] ^= (i & 0xFF); + data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); + data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); + } +} + +int main(void) { + int i; + benchmark_verify_t data; + + data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + + for (i = 0; i < 32; i++) data.msg[i] = 1 + i; + for (i = 0; i < 32; i++) data.key[i] = 33 + i; + data.siglen = 72; + secp256k1_ecdsa_sign(data.ctx, data.msg, data.sig, &data.siglen, data.key, NULL, NULL); + data.pubkeylen = 33; + CHECK(secp256k1_ec_pubkey_create(data.ctx, data.pubkey, &data.pubkeylen, data.key, 1)); + + run_benchmark("ecdsa_verify", benchmark_verify, NULL, NULL, &data, 10, 20000); + + secp256k1_context_destroy(data.ctx); + return 0; +} diff --git a/src/cryptoconditions/src/include/secp256k1/src/ecdsa.h b/src/cryptoconditions/src/include/secp256k1/src/ecdsa.h new file mode 100644 index 000000000..4ef78e8af --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/ecdsa.h @@ -0,0 +1,24 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_ECDSA_ +#define _SECP256K1_ECDSA_ + +#include "scalar.h" +#include "group.h" +#include "ecmult.h" + +typedef struct { + secp256k1_scalar_t r, s; +} secp256k1_ecdsa_sig_t; + +static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size); +static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a); +static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message); +static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *seckey, const secp256k1_scalar_t *message, const secp256k1_scalar_t *nonce, int *recid); +static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid); + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/ecdsa_impl.h b/src/cryptoconditions/src/include/secp256k1/src/ecdsa_impl.h new file mode 100644 index 000000000..8d97db946 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/ecdsa_impl.h @@ -0,0 +1,271 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + + +#ifndef _SECP256K1_ECDSA_IMPL_H_ +#define _SECP256K1_ECDSA_IMPL_H_ + +#include "scalar.h" +#include "field.h" +#include "group.h" +#include "ecmult.h" +#include "ecmult_gen.h" +#include "ecdsa.h" + +/** Group order for secp256k1 defined as 'n' in "Standards for Efficient Cryptography" (SEC2) 2.7.1 + * sage: for t in xrange(1023, -1, -1): + * .. p = 2**256 - 2**32 - t + * .. if p.is_prime(): + * .. print '%x'%p + * .. break + * 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f' + * sage: a = 0 + * sage: b = 7 + * sage: F = FiniteField (p) + * sage: '%x' % (EllipticCurve ([F (a), F (b)]).order()) + * 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141' + */ +static const secp256k1_fe_t secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, + 0xBAAEDCE6UL, 0xAF48A03BUL, 0xBFD25E8CUL, 0xD0364141UL +); + +/** Difference between field and order, values 'p' and 'n' values defined in + * "Standards for Efficient Cryptography" (SEC2) 2.7.1. + * sage: p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F + * sage: a = 0 + * sage: b = 7 + * sage: F = FiniteField (p) + * sage: '%x' % (p - EllipticCurve ([F (a), F (b)]).order()) + * '14551231950b75fc4402da1722fc9baee' + */ +static const secp256k1_fe_t secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_CONST( + 0, 0, 0, 1, 0x45512319UL, 0x50B75FC4UL, 0x402DA172UL, 0x2FC9BAEEUL +); + +static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size) { + + /* libscott had to add this to get this version of the library to read compact sigs */ + int overflow = 0; + if (size == 64) { + secp256k1_scalar_set_b32(&r->r, sig, &overflow); + secp256k1_scalar_set_b32(&r->s, sig+32, &overflow); + return 1; + } + + unsigned char ra[32] = {0}, sa[32] = {0}; + const unsigned char *rp; + const unsigned char *sp; + int lenr; + int lens; + if (sig[0] != 0x30) { + return 0; + } + lenr = sig[3]; + if (5+lenr >= size) { + return 0; + } + lens = sig[lenr+5]; + if (sig[1] != lenr+lens+4) { + return 0; + } + if (lenr+lens+6 > size) { + return 0; + } + if (sig[2] != 0x02) { + return 0; + } + if (lenr == 0) { + return 0; + } + if (sig[lenr+4] != 0x02) { + return 0; + } + if (lens == 0) { + return 0; + } + sp = sig + 6 + lenr; + while (lens > 0 && sp[0] == 0) { + lens--; + sp++; + } + if (lens > 32) { + return 0; + } + rp = sig + 4; + while (lenr > 0 && rp[0] == 0) { + lenr--; + rp++; + } + if (lenr > 32) { + return 0; + } + memcpy(ra + 32 - lenr, rp, lenr); + memcpy(sa + 32 - lens, sp, lens); + overflow = 0; + secp256k1_scalar_set_b32(&r->r, ra, &overflow); + if (overflow) { + return 0; + } + secp256k1_scalar_set_b32(&r->s, sa, &overflow); + if (overflow) { + return 0; + } + return 1; +} + +static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a) { + unsigned char r[33] = {0}, s[33] = {0}; + unsigned char *rp = r, *sp = s; + int lenR = 33, lenS = 33; + secp256k1_scalar_get_b32(&r[1], &a->r); + secp256k1_scalar_get_b32(&s[1], &a->s); + while (lenR > 1 && rp[0] == 0 && rp[1] < 0x80) { lenR--; rp++; } + while (lenS > 1 && sp[0] == 0 && sp[1] < 0x80) { lenS--; sp++; } + if (*size < 6+lenS+lenR) { + return 0; + } + *size = 6 + lenS + lenR; + sig[0] = 0x30; + sig[1] = 4 + lenS + lenR; + sig[2] = 0x02; + sig[3] = lenR; + memcpy(sig+4, rp, lenR); + sig[4+lenR] = 0x02; + sig[5+lenR] = lenS; + memcpy(sig+lenR+6, sp, lenS); + return 1; +} + +static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message) { + unsigned char c[32]; + secp256k1_scalar_t sn, u1, u2; + secp256k1_fe_t xr; + secp256k1_gej_t pubkeyj; + secp256k1_gej_t pr; + + if (secp256k1_scalar_is_zero(&sig->r) || secp256k1_scalar_is_zero(&sig->s)) { + return 0; + } + + secp256k1_scalar_inverse_var(&sn, &sig->s); + secp256k1_scalar_mul(&u1, &sn, message); + secp256k1_scalar_mul(&u2, &sn, &sig->r); + secp256k1_gej_set_ge(&pubkeyj, pubkey); + secp256k1_ecmult(ctx, &pr, &pubkeyj, &u2, &u1); + if (secp256k1_gej_is_infinity(&pr)) { + return 0; + } + secp256k1_scalar_get_b32(c, &sig->r); + secp256k1_fe_set_b32(&xr, c); + + /** We now have the recomputed R point in pr, and its claimed x coordinate (modulo n) + * in xr. Naively, we would extract the x coordinate from pr (requiring a inversion modulo p), + * compute the remainder modulo n, and compare it to xr. However: + * + * xr == X(pr) mod n + * <=> exists h. (xr + h * n < p && xr + h * n == X(pr)) + * [Since 2 * n > p, h can only be 0 or 1] + * <=> (xr == X(pr)) || (xr + n < p && xr + n == X(pr)) + * [In Jacobian coordinates, X(pr) is pr.x / pr.z^2 mod p] + * <=> (xr == pr.x / pr.z^2 mod p) || (xr + n < p && xr + n == pr.x / pr.z^2 mod p) + * [Multiplying both sides of the equations by pr.z^2 mod p] + * <=> (xr * pr.z^2 mod p == pr.x) || (xr + n < p && (xr + n) * pr.z^2 mod p == pr.x) + * + * Thus, we can avoid the inversion, but we have to check both cases separately. + * secp256k1_gej_eq_x implements the (xr * pr.z^2 mod p == pr.x) test. + */ + if (secp256k1_gej_eq_x_var(&xr, &pr)) { + /* xr.x == xr * xr.z^2 mod p, so the signature is valid. */ + return 1; + } + if (secp256k1_fe_cmp_var(&xr, &secp256k1_ecdsa_const_p_minus_order) >= 0) { + /* xr + p >= n, so we can skip testing the second case. */ + return 0; + } + secp256k1_fe_add(&xr, &secp256k1_ecdsa_const_order_as_fe); + if (secp256k1_gej_eq_x_var(&xr, &pr)) { + /* (xr + n) * pr.z^2 mod p == pr.x, so the signature is valid. */ + return 1; + } + return 0; +} + +static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid) { + unsigned char brx[32]; + secp256k1_fe_t fx; + secp256k1_ge_t x; + secp256k1_gej_t xj; + secp256k1_scalar_t rn, u1, u2; + secp256k1_gej_t qj; + + if (secp256k1_scalar_is_zero(&sig->r) || secp256k1_scalar_is_zero(&sig->s)) { + return 0; + } + + secp256k1_scalar_get_b32(brx, &sig->r); + VERIFY_CHECK(secp256k1_fe_set_b32(&fx, brx)); /* brx comes from a scalar, so is less than the order; certainly less than p */ + if (recid & 2) { + if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_const_p_minus_order) >= 0) { + return 0; + } + secp256k1_fe_add(&fx, &secp256k1_ecdsa_const_order_as_fe); + } + if (!secp256k1_ge_set_xo_var(&x, &fx, recid & 1)) { + return 0; + } + secp256k1_gej_set_ge(&xj, &x); + secp256k1_scalar_inverse_var(&rn, &sig->r); + secp256k1_scalar_mul(&u1, &rn, message); + secp256k1_scalar_negate(&u1, &u1); + secp256k1_scalar_mul(&u2, &rn, &sig->s); + secp256k1_ecmult(ctx, &qj, &xj, &u2, &u1); + secp256k1_ge_set_gej_var(pubkey, &qj); + return !secp256k1_gej_is_infinity(&qj); +} + +static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *seckey, const secp256k1_scalar_t *message, const secp256k1_scalar_t *nonce, int *recid) { + unsigned char b[32]; + secp256k1_gej_t rp; + secp256k1_ge_t r; + secp256k1_scalar_t n; + int overflow = 0; + + secp256k1_ecmult_gen(ctx, &rp, nonce); + secp256k1_ge_set_gej(&r, &rp); + secp256k1_fe_normalize(&r.x); + secp256k1_fe_normalize(&r.y); + secp256k1_fe_get_b32(b, &r.x); + secp256k1_scalar_set_b32(&sig->r, b, &overflow); + if (secp256k1_scalar_is_zero(&sig->r)) { + /* P.x = order is on the curve, so technically sig->r could end up zero, which would be an invalid signature. */ + secp256k1_gej_clear(&rp); + secp256k1_ge_clear(&r); + return 0; + } + if (recid) { + *recid = (overflow ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0); + } + secp256k1_scalar_mul(&n, &sig->r, seckey); + secp256k1_scalar_add(&n, &n, message); + secp256k1_scalar_inverse(&sig->s, nonce); + secp256k1_scalar_mul(&sig->s, &sig->s, &n); + secp256k1_scalar_clear(&n); + secp256k1_gej_clear(&rp); + secp256k1_ge_clear(&r); + if (secp256k1_scalar_is_zero(&sig->s)) { + return 0; + } + if (secp256k1_scalar_is_high(&sig->s)) { + secp256k1_scalar_negate(&sig->s, &sig->s); + if (recid) { + *recid ^= 1; + } + } + return 1; +} + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/eckey.h b/src/cryptoconditions/src/include/secp256k1/src/eckey.h new file mode 100644 index 000000000..53b818485 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/eckey.h @@ -0,0 +1,26 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_ECKEY_ +#define _SECP256K1_ECKEY_ + +#include "group.h" +#include "scalar.h" +#include "ecmult.h" +#include "ecmult_gen.h" + +static int secp256k1_eckey_pubkey_parse(secp256k1_ge_t *elem, const unsigned char *pub, int size); +static int secp256k1_eckey_pubkey_serialize(secp256k1_ge_t *elem, unsigned char *pub, int *size, int compressed); + +static int secp256k1_eckey_privkey_parse(secp256k1_scalar_t *key, const unsigned char *privkey, int privkeylen); +static int secp256k1_eckey_privkey_serialize(const secp256k1_ecmult_gen_context_t *ctx, unsigned char *privkey, int *privkeylen, const secp256k1_scalar_t *key, int compressed); + +static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak); +static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context_t *ctx, secp256k1_ge_t *key, const secp256k1_scalar_t *tweak); +static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak); +static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context_t *ctx, secp256k1_ge_t *key, const secp256k1_scalar_t *tweak); + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/eckey_impl.h b/src/cryptoconditions/src/include/secp256k1/src/eckey_impl.h new file mode 100644 index 000000000..a332bd34e --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/eckey_impl.h @@ -0,0 +1,202 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_ECKEY_IMPL_H_ +#define _SECP256K1_ECKEY_IMPL_H_ + +#include "eckey.h" + +#include "scalar.h" +#include "field.h" +#include "group.h" +#include "ecmult_gen.h" + +static int secp256k1_eckey_pubkey_parse(secp256k1_ge_t *elem, const unsigned char *pub, int size) { + if (size == 33 && (pub[0] == 0x02 || pub[0] == 0x03)) { + secp256k1_fe_t x; + return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == 0x03); + } else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) { + secp256k1_fe_t x, y; + if (!secp256k1_fe_set_b32(&x, pub+1) || !secp256k1_fe_set_b32(&y, pub+33)) { + return 0; + } + secp256k1_ge_set_xy(elem, &x, &y); + if ((pub[0] == 0x06 || pub[0] == 0x07) && secp256k1_fe_is_odd(&y) != (pub[0] == 0x07)) { + return 0; + } + return secp256k1_ge_is_valid_var(elem); + } else { + return 0; + } +} + +static int secp256k1_eckey_pubkey_serialize(secp256k1_ge_t *elem, unsigned char *pub, int *size, int compressed) { + if (secp256k1_ge_is_infinity(elem)) { + return 0; + } + secp256k1_fe_normalize_var(&elem->x); + secp256k1_fe_normalize_var(&elem->y); + secp256k1_fe_get_b32(&pub[1], &elem->x); + if (compressed) { + *size = 33; + pub[0] = 0x02 | (secp256k1_fe_is_odd(&elem->y) ? 0x01 : 0x00); + } else { + *size = 65; + pub[0] = 0x04; + secp256k1_fe_get_b32(&pub[33], &elem->y); + } + return 1; +} + +static int secp256k1_eckey_privkey_parse(secp256k1_scalar_t *key, const unsigned char *privkey, int privkeylen) { + unsigned char c[32] = {0}; + const unsigned char *end = privkey + privkeylen; + int lenb = 0; + int len = 0; + int overflow = 0; + /* sequence header */ + if (end < privkey+1 || *privkey != 0x30) { + return 0; + } + privkey++; + /* sequence length constructor */ + if (end < privkey+1 || !(*privkey & 0x80)) { + return 0; + } + lenb = *privkey & ~0x80; privkey++; + if (lenb < 1 || lenb > 2) { + return 0; + } + if (end < privkey+lenb) { + return 0; + } + /* sequence length */ + len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0); + privkey += lenb; + if (end < privkey+len) { + return 0; + } + /* sequence element 0: version number (=1) */ + if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01) { + return 0; + } + privkey += 3; + /* sequence element 1: octet string, up to 32 bytes */ + if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) { + return 0; + } + memcpy(c + 32 - privkey[1], privkey + 2, privkey[1]); + secp256k1_scalar_set_b32(key, c, &overflow); + memset(c, 0, 32); + return !overflow; +} + +static int secp256k1_eckey_privkey_serialize(const secp256k1_ecmult_gen_context_t *ctx, unsigned char *privkey, int *privkeylen, const secp256k1_scalar_t *key, int compressed) { + secp256k1_gej_t rp; + secp256k1_ge_t r; + int pubkeylen = 0; + secp256k1_ecmult_gen(ctx, &rp, key); + secp256k1_ge_set_gej(&r, &rp); + if (compressed) { + static const unsigned char begin[] = { + 0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20 + }; + static const unsigned char middle[] = { + 0xA0,0x81,0x85,0x30,0x81,0x82,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, + 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, + 0x21,0x02,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, + 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, + 0x17,0x98,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, + 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x24,0x03,0x22,0x00 + }; + unsigned char *ptr = privkey; + memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); + secp256k1_scalar_get_b32(ptr, key); ptr += 32; + memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); + if (!secp256k1_eckey_pubkey_serialize(&r, ptr, &pubkeylen, 1)) { + return 0; + } + ptr += pubkeylen; + *privkeylen = ptr - privkey; + } else { + static const unsigned char begin[] = { + 0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20 + }; + static const unsigned char middle[] = { + 0xA0,0x81,0xA5,0x30,0x81,0xA2,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, + 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, + 0x41,0x04,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, + 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, + 0x17,0x98,0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,0x5D,0xA4,0xFB,0xFC,0x0E,0x11, + 0x08,0xA8,0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,0x9C,0x47,0xD0,0x8F,0xFB,0x10, + 0xD4,0xB8,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, + 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x44,0x03,0x42,0x00 + }; + unsigned char *ptr = privkey; + memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); + secp256k1_scalar_get_b32(ptr, key); ptr += 32; + memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); + if (!secp256k1_eckey_pubkey_serialize(&r, ptr, &pubkeylen, 0)) { + return 0; + } + ptr += pubkeylen; + *privkeylen = ptr - privkey; + } + return 1; +} + +static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak) { + secp256k1_scalar_add(key, key, tweak); + if (secp256k1_scalar_is_zero(key)) { + return 0; + } + return 1; +} + +static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context_t *ctx, secp256k1_ge_t *key, const secp256k1_scalar_t *tweak) { + secp256k1_gej_t pt; + secp256k1_scalar_t one; + secp256k1_gej_set_ge(&pt, key); + secp256k1_scalar_set_int(&one, 1); + secp256k1_ecmult(ctx, &pt, &pt, &one, tweak); + + if (secp256k1_gej_is_infinity(&pt)) { + return 0; + } + secp256k1_ge_set_gej(key, &pt); + return 1; +} + +static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak) { + if (secp256k1_scalar_is_zero(tweak)) { + return 0; + } + + secp256k1_scalar_mul(key, key, tweak); + return 1; +} + +static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context_t *ctx, secp256k1_ge_t *key, const secp256k1_scalar_t *tweak) { + secp256k1_scalar_t zero; + secp256k1_gej_t pt; + if (secp256k1_scalar_is_zero(tweak)) { + return 0; + } + + secp256k1_scalar_set_int(&zero, 0); + secp256k1_gej_set_ge(&pt, key); + secp256k1_ecmult(ctx, &pt, &pt, tweak, &zero); + secp256k1_ge_set_gej(key, &pt); + return 1; +} + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/ecmult.h b/src/cryptoconditions/src/include/secp256k1/src/ecmult.h new file mode 100644 index 000000000..bab9e4ef5 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/ecmult.h @@ -0,0 +1,31 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_ECMULT_ +#define _SECP256K1_ECMULT_ + +#include "num.h" +#include "group.h" + +typedef struct { + /* For accelerating the computation of a*P + b*G: */ + secp256k1_ge_storage_t (*pre_g)[]; /* odd multiples of the generator */ +#ifdef USE_ENDOMORPHISM + secp256k1_ge_storage_t (*pre_g_128)[]; /* odd multiples of 2^128*generator */ +#endif +} secp256k1_ecmult_context_t; + +static void secp256k1_ecmult_context_init(secp256k1_ecmult_context_t *ctx); +static void secp256k1_ecmult_context_build(secp256k1_ecmult_context_t *ctx); +static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context_t *dst, + const secp256k1_ecmult_context_t *src); +static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context_t *ctx); +static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context_t *ctx); + +/** Double multiply: R = na*A + ng*G */ +static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_scalar_t *na, const secp256k1_scalar_t *ng); + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/ecmult_gen.h b/src/cryptoconditions/src/include/secp256k1/src/ecmult_gen.h new file mode 100644 index 000000000..3745633c4 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/ecmult_gen.h @@ -0,0 +1,43 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_ECMULT_GEN_ +#define _SECP256K1_ECMULT_GEN_ + +#include "scalar.h" +#include "group.h" + +typedef struct { + /* For accelerating the computation of a*G: + * To harden against timing attacks, use the following mechanism: + * * Break up the multiplicand into groups of 4 bits, called n_0, n_1, n_2, ..., n_63. + * * Compute sum(n_i * 16^i * G + U_i, i=0..63), where: + * * U_i = U * 2^i (for i=0..62) + * * U_i = U * (1-2^63) (for i=63) + * where U is a point with no known corresponding scalar. Note that sum(U_i, i=0..63) = 0. + * For each i, and each of the 16 possible values of n_i, (n_i * 16^i * G + U_i) is + * precomputed (call it prec(i, n_i)). The formula now becomes sum(prec(i, n_i), i=0..63). + * None of the resulting prec group elements have a known scalar, and neither do any of + * the intermediate sums while computing a*G. + */ + secp256k1_ge_storage_t (*prec)[64][16]; /* prec[j][i] = 16^j * i * G + U_i */ + secp256k1_scalar_t blind; + secp256k1_gej_t initial; +} secp256k1_ecmult_gen_context_t; + +static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context_t* ctx); +static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context_t* ctx); +static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context_t *dst, + const secp256k1_ecmult_gen_context_t* src); +static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context_t* ctx); +static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context_t* ctx); + +/** Multiply with the generator: R = a*G */ +static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context_t* ctx, secp256k1_gej_t *r, const secp256k1_scalar_t *a); + +static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context_t *ctx, const unsigned char *seed32); + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/ecmult_gen_impl.h b/src/cryptoconditions/src/include/secp256k1/src/ecmult_gen_impl.h new file mode 100644 index 000000000..4697753ac --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/ecmult_gen_impl.h @@ -0,0 +1,184 @@ +/********************************************************************** + * Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_ECMULT_GEN_IMPL_H_ +#define _SECP256K1_ECMULT_GEN_IMPL_H_ + +#include "scalar.h" +#include "group.h" +#include "ecmult_gen.h" +#include "hash_impl.h" + +static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context_t *ctx) { + ctx->prec = NULL; +} + +static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context_t *ctx) { + secp256k1_ge_t prec[1024]; + secp256k1_gej_t gj; + secp256k1_gej_t nums_gej; + int i, j; + + if (ctx->prec != NULL) { + return; + } + + ctx->prec = (secp256k1_ge_storage_t (*)[64][16])checked_malloc(sizeof(*ctx->prec)); + + /* get the generator */ + secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); + + /* Construct a group element with no known corresponding scalar (nothing up my sleeve). */ + { + static const unsigned char nums_b32[33] = "The scalar for this x is unknown"; + secp256k1_fe_t nums_x; + secp256k1_ge_t nums_ge; + VERIFY_CHECK(secp256k1_fe_set_b32(&nums_x, nums_b32)); + VERIFY_CHECK(secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0)); + secp256k1_gej_set_ge(&nums_gej, &nums_ge); + /* Add G to make the bits in x uniformly distributed. */ + secp256k1_gej_add_ge_var(&nums_gej, &nums_gej, &secp256k1_ge_const_g); + } + + /* compute prec. */ + { + secp256k1_gej_t precj[1024]; /* Jacobian versions of prec. */ + secp256k1_gej_t gbase; + secp256k1_gej_t numsbase; + gbase = gj; /* 16^j * G */ + numsbase = nums_gej; /* 2^j * nums. */ + for (j = 0; j < 64; j++) { + /* Set precj[j*16 .. j*16+15] to (numsbase, numsbase + gbase, ..., numsbase + 15*gbase). */ + precj[j*16] = numsbase; + for (i = 1; i < 16; i++) { + secp256k1_gej_add_var(&precj[j*16 + i], &precj[j*16 + i - 1], &gbase); + } + /* Multiply gbase by 16. */ + for (i = 0; i < 4; i++) { + secp256k1_gej_double_var(&gbase, &gbase); + } + /* Multiply numbase by 2. */ + secp256k1_gej_double_var(&numsbase, &numsbase); + if (j == 62) { + /* In the last iteration, numsbase is (1 - 2^j) * nums instead. */ + secp256k1_gej_neg(&numsbase, &numsbase); + secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej); + } + } + secp256k1_ge_set_all_gej_var(1024, prec, precj); + } + for (j = 0; j < 64; j++) { + for (i = 0; i < 16; i++) { + secp256k1_ge_to_storage(&(*ctx->prec)[j][i], &prec[j*16 + i]); + } + } + secp256k1_ecmult_gen_blind(ctx, NULL); +} + +static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context_t* ctx) { + return ctx->prec != NULL; +} + +static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context_t *dst, + const secp256k1_ecmult_gen_context_t *src) { + if (src->prec == NULL) { + dst->prec = NULL; + } else { + dst->prec = (secp256k1_ge_storage_t (*)[64][16])checked_malloc(sizeof(*dst->prec)); + memcpy(dst->prec, src->prec, sizeof(*dst->prec)); + dst->initial = src->initial; + dst->blind = src->blind; + } +} + +static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context_t *ctx) { + free(ctx->prec); + secp256k1_scalar_clear(&ctx->blind); + secp256k1_gej_clear(&ctx->initial); + ctx->prec = NULL; +} + +static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context_t *ctx, secp256k1_gej_t *r, const secp256k1_scalar_t *gn) { + secp256k1_ge_t add; + secp256k1_ge_storage_t adds; + secp256k1_scalar_t gnb; + int bits; + int i, j; + memset(&adds, 0, sizeof(adds)); + *r = ctx->initial; + /* Blind scalar/point multiplication by computing (n-b)G + bG instead of nG. */ + secp256k1_scalar_add(&gnb, gn, &ctx->blind); + add.infinity = 0; + for (j = 0; j < 64; j++) { + bits = secp256k1_scalar_get_bits(&gnb, j * 4, 4); + for (i = 0; i < 16; i++) { + /** This uses a conditional move to avoid any secret data in array indexes. + * _Any_ use of secret indexes has been demonstrated to result in timing + * sidechannels, even when the cache-line access patterns are uniform. + * See also: + * "A word of warning", CHES 2013 Rump Session, by Daniel J. Bernstein and Peter Schwabe + * (https://cryptojedi.org/peter/data/chesrump-20130822.pdf) and + * "Cache Attacks and Countermeasures: the Case of AES", RSA 2006, + * by Dag Arne Osvik, Adi Shamir, and Eran Tromer + * (http://www.tau.ac.il/~tromer/papers/cache.pdf) + */ + secp256k1_ge_storage_cmov(&adds, &(*ctx->prec)[j][i], i == bits); + } + secp256k1_ge_from_storage(&add, &adds); + secp256k1_gej_add_ge(r, r, &add); + } + bits = 0; + secp256k1_ge_clear(&add); + secp256k1_scalar_clear(&gnb); +} + +/* Setup blinding values for secp256k1_ecmult_gen. */ +static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context_t *ctx, const unsigned char *seed32) { + secp256k1_scalar_t b; + secp256k1_gej_t gb; + secp256k1_fe_t s; + unsigned char nonce32[32]; + secp256k1_rfc6979_hmac_sha256_t rng; + int retry; + if (!seed32) { + /* When seed is NULL, reset the initial point and blinding value. */ + secp256k1_gej_set_ge(&ctx->initial, &secp256k1_ge_const_g); + secp256k1_gej_neg(&ctx->initial, &ctx->initial); + secp256k1_scalar_set_int(&ctx->blind, 1); + } + /* The prior blinding value (if not reset) is chained forward by including it in the hash. */ + secp256k1_scalar_get_b32(nonce32, &ctx->blind); + /** Using a CSPRNG allows a failure free interface, avoids needing large amounts of random data, + * and guards against weak or adversarial seeds. This is a simpler and safer interface than + * asking the caller for blinding values directly and expecting them to retry on failure. + */ + secp256k1_rfc6979_hmac_sha256_initialize(&rng, seed32 ? seed32 : nonce32, 32, nonce32, 32, NULL, 0); + /* Retry for out of range results to achieve uniformity. */ + do { + secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); + retry = !secp256k1_fe_set_b32(&s, nonce32); + retry |= secp256k1_fe_is_zero(&s); + } while (retry); + /* Randomize the projection to defend against multiplier sidechannels. */ + secp256k1_gej_rescale(&ctx->initial, &s); + secp256k1_fe_clear(&s); + do { + secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); + secp256k1_scalar_set_b32(&b, nonce32, &retry); + /* A blinding value of 0 works, but would undermine the projection hardening. */ + retry |= secp256k1_scalar_is_zero(&b); + } while (retry); + secp256k1_rfc6979_hmac_sha256_finalize(&rng); + memset(nonce32, 0, 32); + secp256k1_ecmult_gen(ctx, &gb, &b); + secp256k1_scalar_negate(&b, &b); + ctx->blind = b; + ctx->initial = gb; + secp256k1_scalar_clear(&b); + secp256k1_gej_clear(&gb); +} + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/ecmult_impl.h b/src/cryptoconditions/src/include/secp256k1/src/ecmult_impl.h new file mode 100644 index 000000000..1b2856f83 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/ecmult_impl.h @@ -0,0 +1,317 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_ECMULT_IMPL_H_ +#define _SECP256K1_ECMULT_IMPL_H_ + +#include "group.h" +#include "scalar.h" +#include "ecmult.h" + +/* optimal for 128-bit and 256-bit exponents. */ +#define WINDOW_A 5 + +/** larger numbers may result in slightly better performance, at the cost of + exponentially larger precomputed tables. */ +#ifdef USE_ENDOMORPHISM +/** Two tables for window size 15: 1.375 MiB. */ +#define WINDOW_G 15 +#else +/** One table for window size 16: 1.375 MiB. */ +#define WINDOW_G 16 +#endif + +/** Fill a table 'pre' with precomputed odd multiples of a. W determines the size of the table. + * pre will contains the values [1*a,3*a,5*a,...,(2^(w-1)-1)*a], so it needs place for + * 2^(w-2) entries. + * + * There are two versions of this function: + * - secp256k1_ecmult_precomp_wnaf_gej, which operates on group elements in jacobian notation, + * fast to precompute, but slower to use in later additions. + * - secp256k1_ecmult_precomp_wnaf_ge, which operates on group elements in affine notations, + * (much) slower to precompute, but a bit faster to use in later additions. + * To compute a*P + b*G, we use the jacobian version for P, and the affine version for G, as + * G is constant, so it only needs to be done once in advance. + */ +static void secp256k1_ecmult_table_precomp_gej_var(secp256k1_gej_t *pre, const secp256k1_gej_t *a, int w) { + secp256k1_gej_t d; + int i; + pre[0] = *a; + secp256k1_gej_double_var(&d, &pre[0]); + for (i = 1; i < (1 << (w-2)); i++) { + secp256k1_gej_add_var(&pre[i], &d, &pre[i-1]); + } +} + +static void secp256k1_ecmult_table_precomp_ge_storage_var(secp256k1_ge_storage_t *pre, const secp256k1_gej_t *a, int w) { + secp256k1_gej_t d; + int i; + const int table_size = 1 << (w-2); + secp256k1_gej_t *prej = (secp256k1_gej_t *)checked_malloc(sizeof(secp256k1_gej_t) * table_size); + secp256k1_ge_t *prea = (secp256k1_ge_t *)checked_malloc(sizeof(secp256k1_ge_t) * table_size); + prej[0] = *a; + secp256k1_gej_double_var(&d, a); + for (i = 1; i < table_size; i++) { + secp256k1_gej_add_var(&prej[i], &d, &prej[i-1]); + } + secp256k1_ge_set_all_gej_var(table_size, prea, prej); + for (i = 0; i < table_size; i++) { + secp256k1_ge_to_storage(&pre[i], &prea[i]); + } + free(prej); + free(prea); +} + +/** The number of entries a table with precomputed multiples needs to have. */ +#define ECMULT_TABLE_SIZE(w) (1 << ((w)-2)) + +/** The following two macro retrieves a particular odd multiple from a table + * of precomputed multiples. */ +#define ECMULT_TABLE_GET_GEJ(r,pre,n,w) do { \ + VERIFY_CHECK(((n) & 1) == 1); \ + VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \ + VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \ + if ((n) > 0) { \ + *(r) = (pre)[((n)-1)/2]; \ + } else { \ + secp256k1_gej_neg((r), &(pre)[(-(n)-1)/2]); \ + } \ +} while(0) +#define ECMULT_TABLE_GET_GE_STORAGE(r,pre,n,w) do { \ + VERIFY_CHECK(((n) & 1) == 1); \ + VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \ + VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \ + if ((n) > 0) { \ + secp256k1_ge_from_storage((r), &(pre)[((n)-1)/2]); \ + } else { \ + secp256k1_ge_from_storage((r), &(pre)[(-(n)-1)/2]); \ + secp256k1_ge_neg((r), (r)); \ + } \ +} while(0) + +static void secp256k1_ecmult_context_init(secp256k1_ecmult_context_t *ctx) { + ctx->pre_g = NULL; +#ifdef USE_ENDOMORPHISM + ctx->pre_g_128 = NULL; +#endif +} + +static void secp256k1_ecmult_context_build(secp256k1_ecmult_context_t *ctx) { + secp256k1_gej_t gj; + + if (ctx->pre_g != NULL) { + return; + } + + /* get the generator */ + secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); + + ctx->pre_g = (secp256k1_ge_storage_t (*)[])checked_malloc(sizeof((*ctx->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); + + /* precompute the tables with odd multiples */ + secp256k1_ecmult_table_precomp_ge_storage_var(*ctx->pre_g, &gj, WINDOW_G); + +#ifdef USE_ENDOMORPHISM + { + secp256k1_gej_t g_128j; + int i; + + ctx->pre_g_128 = (secp256k1_ge_storage_t (*)[])checked_malloc(sizeof((*ctx->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); + + /* calculate 2^128*generator */ + g_128j = gj; + for (i = 0; i < 128; i++) { + secp256k1_gej_double_var(&g_128j, &g_128j); + } + secp256k1_ecmult_table_precomp_ge_storage_var(*ctx->pre_g_128, &g_128j, WINDOW_G); + } +#endif +} + +static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context_t *dst, + const secp256k1_ecmult_context_t *src) { + if (src->pre_g == NULL) { + dst->pre_g = NULL; + } else { + size_t size = sizeof((*dst->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G); + dst->pre_g = (secp256k1_ge_storage_t (*)[])checked_malloc(size); + memcpy(dst->pre_g, src->pre_g, size); + } +#ifdef USE_ENDOMORPHISM + if (src->pre_g_128 == NULL) { + dst->pre_g_128 = NULL; + } else { + size_t size = sizeof((*dst->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G); + dst->pre_g_128 = (secp256k1_ge_storage_t (*)[])checked_malloc(size); + memcpy(dst->pre_g_128, src->pre_g_128, size); + } +#endif +} + +static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context_t *ctx) { + return ctx->pre_g != NULL; +} + +static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context_t *ctx) { + free(ctx->pre_g); +#ifdef USE_ENDOMORPHISM + free(ctx->pre_g_128); +#endif + secp256k1_ecmult_context_init(ctx); +} + +/** Convert a number to WNAF notation. The number becomes represented by sum(2^i * wnaf[i], i=0..bits), + * with the following guarantees: + * - each wnaf[i] is either 0, or an odd integer between -(1<<(w-1) - 1) and (1<<(w-1) - 1) + * - two non-zero entries in wnaf are separated by at least w-1 zeroes. + * - the number of set values in wnaf is returned. This number is at most 256, and at most one more + * - than the number of bits in the (absolute value) of the input. + */ +static int secp256k1_ecmult_wnaf(int *wnaf, const secp256k1_scalar_t *a, int w) { + secp256k1_scalar_t s = *a; + int set_bits = 0; + int bit = 0; + int sign = 1; + + if (secp256k1_scalar_get_bits(&s, 255, 1)) { + secp256k1_scalar_negate(&s, &s); + sign = -1; + } + + while (bit < 256) { + int now; + int word; + if (secp256k1_scalar_get_bits(&s, bit, 1) == 0) { + bit++; + continue; + } + while (set_bits < bit) { + wnaf[set_bits++] = 0; + } + now = w; + if (bit + now > 256) { + now = 256 - bit; + } + word = secp256k1_scalar_get_bits_var(&s, bit, now); + if (word & (1 << (w-1))) { + secp256k1_scalar_add_bit(&s, bit + w); + wnaf[set_bits++] = sign * (word - (1 << w)); + } else { + wnaf[set_bits++] = sign * word; + } + bit += now; + } + return set_bits; +} + +static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_scalar_t *na, const secp256k1_scalar_t *ng) { + secp256k1_gej_t tmpj; + secp256k1_gej_t pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; + secp256k1_ge_t tmpa; +#ifdef USE_ENDOMORPHISM + secp256k1_gej_t pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; + secp256k1_scalar_t na_1, na_lam; + /* Splitted G factors. */ + secp256k1_scalar_t ng_1, ng_128; + int wnaf_na_1[130]; + int wnaf_na_lam[130]; + int bits_na_1; + int bits_na_lam; + int wnaf_ng_1[129]; + int bits_ng_1; + int wnaf_ng_128[129]; + int bits_ng_128; +#else + int wnaf_na[256]; + int bits_na; + int wnaf_ng[257]; + int bits_ng; +#endif + int i; + int bits; + +#ifdef USE_ENDOMORPHISM + /* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */ + secp256k1_scalar_split_lambda_var(&na_1, &na_lam, na); + + /* build wnaf representation for na_1 and na_lam. */ + bits_na_1 = secp256k1_ecmult_wnaf(wnaf_na_1, &na_1, WINDOW_A); + bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, &na_lam, WINDOW_A); + VERIFY_CHECK(bits_na_1 <= 130); + VERIFY_CHECK(bits_na_lam <= 130); + bits = bits_na_1; + if (bits_na_lam > bits) { + bits = bits_na_lam; + } +#else + /* build wnaf representation for na. */ + bits_na = secp256k1_ecmult_wnaf(wnaf_na, na, WINDOW_A); + bits = bits_na; +#endif + + /* calculate odd multiples of a */ + secp256k1_ecmult_table_precomp_gej_var(pre_a, a, WINDOW_A); + +#ifdef USE_ENDOMORPHISM + for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { + secp256k1_gej_mul_lambda(&pre_a_lam[i], &pre_a[i]); + } + + /* split ng into ng_1 and ng_128 (where gn = gn_1 + gn_128*2^128, and gn_1 and gn_128 are ~128 bit) */ + secp256k1_scalar_split_128(&ng_1, &ng_128, ng); + + /* Build wnaf representation for ng_1 and ng_128 */ + bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, &ng_1, WINDOW_G); + bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, &ng_128, WINDOW_G); + if (bits_ng_1 > bits) { + bits = bits_ng_1; + } + if (bits_ng_128 > bits) { + bits = bits_ng_128; + } +#else + bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, ng, WINDOW_G); + if (bits_ng > bits) { + bits = bits_ng; + } +#endif + + secp256k1_gej_set_infinity(r); + + for (i = bits-1; i >= 0; i--) { + int n; + secp256k1_gej_double_var(r, r); +#ifdef USE_ENDOMORPHISM + if (i < bits_na_1 && (n = wnaf_na_1[i])) { + ECMULT_TABLE_GET_GEJ(&tmpj, pre_a, n, WINDOW_A); + secp256k1_gej_add_var(r, r, &tmpj); + } + if (i < bits_na_lam && (n = wnaf_na_lam[i])) { + ECMULT_TABLE_GET_GEJ(&tmpj, pre_a_lam, n, WINDOW_A); + secp256k1_gej_add_var(r, r, &tmpj); + } + if (i < bits_ng_1 && (n = wnaf_ng_1[i])) { + ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G); + secp256k1_gej_add_ge_var(r, r, &tmpa); + } + if (i < bits_ng_128 && (n = wnaf_ng_128[i])) { + ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g_128, n, WINDOW_G); + secp256k1_gej_add_ge_var(r, r, &tmpa); + } +#else + if (i < bits_na && (n = wnaf_na[i])) { + ECMULT_TABLE_GET_GEJ(&tmpj, pre_a, n, WINDOW_A); + secp256k1_gej_add_var(r, r, &tmpj); + } + if (i < bits_ng && (n = wnaf_ng[i])) { + ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G); + secp256k1_gej_add_ge_var(r, r, &tmpa); + } +#endif + } +} + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/field.h b/src/cryptoconditions/src/include/secp256k1/src/field.h new file mode 100644 index 000000000..41b280892 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/field.h @@ -0,0 +1,119 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_FIELD_ +#define _SECP256K1_FIELD_ + +/** Field element module. + * + * Field elements can be represented in several ways, but code accessing + * it (and implementations) need to take certain properaties into account: + * - Each field element can be normalized or not. + * - Each field element has a magnitude, which represents how far away + * its representation is away from normalization. Normalized elements + * always have a magnitude of 1, but a magnitude of 1 doesn't imply + * normality. + */ + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#if defined(USE_FIELD_10X26) +#include "field_10x26.h" +#elif defined(USE_FIELD_5X52) +#include "field_5x52.h" +#else +#error "Please select field implementation" +#endif + +/** Normalize a field element. */ +static void secp256k1_fe_normalize(secp256k1_fe_t *r); + +/** Weakly normalize a field element: reduce it magnitude to 1, but don't fully normalize. */ +static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r); + +/** Normalize a field element, without constant-time guarantee. */ +static void secp256k1_fe_normalize_var(secp256k1_fe_t *r); + +/** Verify whether a field element represents zero i.e. would normalize to a zero value. The field + * implementation may optionally normalize the input, but this should not be relied upon. */ +static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r); + +/** Verify whether a field element represents zero i.e. would normalize to a zero value. The field + * implementation may optionally normalize the input, but this should not be relied upon. */ +static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r); + +/** Set a field element equal to a small integer. Resulting field element is normalized. */ +static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a); + +/** Verify whether a field element is zero. Requires the input to be normalized. */ +static int secp256k1_fe_is_zero(const secp256k1_fe_t *a); + +/** Check the "oddness" of a field element. Requires the input to be normalized. */ +static int secp256k1_fe_is_odd(const secp256k1_fe_t *a); + +/** Compare two field elements. Requires magnitude-1 inputs. */ +static int secp256k1_fe_equal_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b); + +/** Compare two field elements. Requires both inputs to be normalized */ +static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b); + +/** Set a field element equal to 32-byte big endian value. If succesful, the resulting field element is normalized. */ +static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a); + +/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ +static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a); + +/** Set a field element equal to the additive inverse of another. Takes a maximum magnitude of the input + * as an argument. The magnitude of the output is one higher. */ +static void secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m); + +/** Multiplies the passed field element with a small integer constant. Multiplies the magnitude by that + * small integer. */ +static void secp256k1_fe_mul_int(secp256k1_fe_t *r, int a); + +/** Adds a field element to another. The result has the sum of the inputs' magnitudes as magnitude. */ +static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a); + +/** Sets a field element to be the product of two others. Requires the inputs' magnitudes to be at most 8. + * The output magnitude is 1 (but not guaranteed to be normalized). */ +static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t * SECP256K1_RESTRICT b); + +/** Sets a field element to be the square of another. Requires the input's magnitude to be at most 8. + * The output magnitude is 1 (but not guaranteed to be normalized). */ +static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a); + +/** Sets a field element to be the (modular) square root (if any exist) of another. Requires the + * input's magnitude to be at most 8. The output magnitude is 1 (but not guaranteed to be + * normalized). Return value indicates whether a square root was found. */ +static int secp256k1_fe_sqrt_var(secp256k1_fe_t *r, const secp256k1_fe_t *a); + +/** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be + * at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */ +static void secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a); + +/** Potentially faster version of secp256k1_fe_inv, without constant-time guarantee. */ +static void secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a); + +/** Calculate the (modular) inverses of a batch of field elements. Requires the inputs' magnitudes to be + * at most 8. The output magnitudes are 1 (but not guaranteed to be normalized). The inputs and + * outputs must not overlap in memory. */ +static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe_t *r, const secp256k1_fe_t *a); + +/** Convert a field element to the storage type. */ +static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_fe_t*); + +/** Convert a field element back from the storage type. */ +static void secp256k1_fe_from_storage(secp256k1_fe_t *r, const secp256k1_fe_storage_t*); + +/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */ +static void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r, const secp256k1_fe_storage_t *a, int flag); + +/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */ +static void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag); + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/field_10x26.h b/src/cryptoconditions/src/include/secp256k1/src/field_10x26.h new file mode 100644 index 000000000..44bce6525 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/field_10x26.h @@ -0,0 +1,47 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_FIELD_REPR_ +#define _SECP256K1_FIELD_REPR_ + +#include + +typedef struct { + /* X = sum(i=0..9, elem[i]*2^26) mod n */ + uint32_t n[10]; +#ifdef VERIFY + int magnitude; + int normalized; +#endif +} secp256k1_fe_t; + +/* Unpacks a constant into a overlapping multi-limbed FE element. */ +#define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \ + (d0) & 0x3FFFFFFUL, \ + ((d0) >> 26) | ((d1) & 0xFFFFFUL) << 6, \ + ((d1) >> 20) | ((d2) & 0x3FFFUL) << 12, \ + ((d2) >> 14) | ((d3) & 0xFFUL) << 18, \ + ((d3) >> 8) | ((d4) & 0x3) << 24, \ + ((d4) >> 2) & 0x3FFFFFFUL, \ + ((d4) >> 28) | ((d5) & 0x3FFFFFUL) << 4, \ + ((d5) >> 22) | ((d6) & 0xFFFF) << 10, \ + ((d6) >> 16) | ((d7) & 0x3FF) << 16, \ + ((d7) >> 10) \ +} + +#ifdef VERIFY +#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1} +#else +#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))} +#endif + +typedef struct { + uint32_t n[8]; +} secp256k1_fe_storage_t; + +#define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }} + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/field_10x26_impl.h b/src/cryptoconditions/src/include/secp256k1/src/field_10x26_impl.h new file mode 100644 index 000000000..871b91f91 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/field_10x26_impl.h @@ -0,0 +1,1136 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_FIELD_REPR_IMPL_H_ +#define _SECP256K1_FIELD_REPR_IMPL_H_ + +#include +#include +#include "util.h" +#include "num.h" +#include "field.h" + +#ifdef VERIFY +static void secp256k1_fe_verify(const secp256k1_fe_t *a) { + const uint32_t *d = a->n; + int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; + r &= (d[0] <= 0x3FFFFFFUL * m); + r &= (d[1] <= 0x3FFFFFFUL * m); + r &= (d[2] <= 0x3FFFFFFUL * m); + r &= (d[3] <= 0x3FFFFFFUL * m); + r &= (d[4] <= 0x3FFFFFFUL * m); + r &= (d[5] <= 0x3FFFFFFUL * m); + r &= (d[6] <= 0x3FFFFFFUL * m); + r &= (d[7] <= 0x3FFFFFFUL * m); + r &= (d[8] <= 0x3FFFFFFUL * m); + r &= (d[9] <= 0x03FFFFFUL * m); + r &= (a->magnitude >= 0); + r &= (a->magnitude <= 32); + if (a->normalized) { + r &= (a->magnitude <= 1); + if (r && (d[9] == 0x03FFFFFUL)) { + uint32_t mid = d[8] & d[7] & d[6] & d[5] & d[4] & d[3] & d[2]; + if (mid == 0x3FFFFFFUL) { + r &= ((d[1] + 0x40UL + ((d[0] + 0x3D1UL) >> 26)) <= 0x3FFFFFFUL); + } + } + } + VERIFY_CHECK(r == 1); +} +#else +static void secp256k1_fe_verify(const secp256k1_fe_t *a) { + (void)a; +} +#endif + +static void secp256k1_fe_normalize(secp256k1_fe_t *r) { + uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], + t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; + + /* Reduce t9 at the start so there will be at most a single carry from the first pass */ + uint32_t m; + uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x3D1UL; t1 += (x << 6); + t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; + t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; + t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; m = t2; + t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; m &= t3; + t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; m &= t4; + t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; m &= t5; + t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; m &= t6; + t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; m &= t7; + t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; m &= t8; + + /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t9 >> 23 == 0); + + /* At most a single final reduction is needed; check if the value is >= the field characteristic */ + x = (t9 >> 22) | ((t9 == 0x03FFFFFUL) & (m == 0x3FFFFFFUL) + & ((t1 + 0x40UL + ((t0 + 0x3D1UL) >> 26)) > 0x3FFFFFFUL)); + + /* Apply the final reduction (for constant-time behaviour, we do it always) */ + t0 += x * 0x3D1UL; t1 += (x << 6); + t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; + t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; + t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; + t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; + t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; + t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; + t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; + t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; + t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; + + /* If t9 didn't carry to bit 22 already, then it should have after any final reduction */ + VERIFY_CHECK(t9 >> 22 == x); + + /* Mask off the possible multiple of 2^256 from the final reduction */ + t9 &= 0x03FFFFFUL; + + r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; + r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; + +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; + secp256k1_fe_verify(r); +#endif +} + +static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r) { + uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], + t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; + + /* Reduce t9 at the start so there will be at most a single carry from the first pass */ + uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x3D1UL; t1 += (x << 6); + t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; + t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; + t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; + t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; + t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; + t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; + t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; + t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; + t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; + + /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t9 >> 23 == 0); + + r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; + r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; + +#ifdef VERIFY + r->magnitude = 1; + secp256k1_fe_verify(r); +#endif +} + +static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) { + uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], + t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; + + /* Reduce t9 at the start so there will be at most a single carry from the first pass */ + uint32_t m; + uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x3D1UL; t1 += (x << 6); + t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; + t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; + t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; m = t2; + t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; m &= t3; + t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; m &= t4; + t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; m &= t5; + t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; m &= t6; + t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; m &= t7; + t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; m &= t8; + + /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t9 >> 23 == 0); + + /* At most a single final reduction is needed; check if the value is >= the field characteristic */ + x = (t9 >> 22) | ((t9 == 0x03FFFFFUL) & (m == 0x3FFFFFFUL) + & ((t1 + 0x40UL + ((t0 + 0x3D1UL) >> 26)) > 0x3FFFFFFUL)); + + if (x) { + t0 += 0x3D1UL; t1 += (x << 6); + t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; + t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; + t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; + t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; + t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; + t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; + t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; + t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; + t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; + + /* If t9 didn't carry to bit 22 already, then it should have after any final reduction */ + VERIFY_CHECK(t9 >> 22 == x); + + /* Mask off the possible multiple of 2^256 from the final reduction */ + t9 &= 0x03FFFFFUL; + } + + r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; + r->n[5] = t5; r->n[6] = t6; r->n[7] = t7; r->n[8] = t8; r->n[9] = t9; + +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; + secp256k1_fe_verify(r); +#endif +} + +static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r) { + uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], + t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; + + /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ + uint32_t z0, z1; + + /* Reduce t9 at the start so there will be at most a single carry from the first pass */ + uint32_t x = t9 >> 22; t9 &= 0x03FFFFFUL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x3D1UL; t1 += (x << 6); + t1 += (t0 >> 26); t0 &= 0x3FFFFFFUL; z0 = t0; z1 = t0 ^ 0x3D0UL; + t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; z0 |= t1; z1 &= t1 ^ 0x40UL; + t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; z0 |= t2; z1 &= t2; + t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; z0 |= t3; z1 &= t3; + t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; z0 |= t4; z1 &= t4; + t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; z0 |= t5; z1 &= t5; + t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; z0 |= t6; z1 &= t6; + t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; z0 |= t7; z1 &= t7; + t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; z0 |= t8; z1 &= t8; + z0 |= t9; z1 &= t9 ^ 0x3C00000UL; + + /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t9 >> 23 == 0); + + return (z0 == 0) | (z1 == 0x3FFFFFFUL); +} + +static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) { + uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; + uint32_t z0, z1; + uint32_t x; + + t0 = r->n[0]; + t9 = r->n[9]; + + /* Reduce t9 at the start so there will be at most a single carry from the first pass */ + x = t9 >> 22; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x3D1UL; + + /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ + z0 = t0 & 0x3FFFFFFUL; + z1 = z0 ^ 0x3D0UL; + + /* Fast return path should catch the majority of cases */ + if ((z0 != 0UL) & (z1 != 0x3FFFFFFUL)) { + return 0; + } + + t1 = r->n[1]; + t2 = r->n[2]; + t3 = r->n[3]; + t4 = r->n[4]; + t5 = r->n[5]; + t6 = r->n[6]; + t7 = r->n[7]; + t8 = r->n[8]; + + t9 &= 0x03FFFFFUL; + t1 += (x << 6); + + t1 += (t0 >> 26); t0 = z0; + t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; z0 |= t1; z1 &= t1 ^ 0x40UL; + t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; z0 |= t2; z1 &= t2; + t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; z0 |= t3; z1 &= t3; + t5 += (t4 >> 26); t4 &= 0x3FFFFFFUL; z0 |= t4; z1 &= t4; + t6 += (t5 >> 26); t5 &= 0x3FFFFFFUL; z0 |= t5; z1 &= t5; + t7 += (t6 >> 26); t6 &= 0x3FFFFFFUL; z0 |= t6; z1 &= t6; + t8 += (t7 >> 26); t7 &= 0x3FFFFFFUL; z0 |= t7; z1 &= t7; + t9 += (t8 >> 26); t8 &= 0x3FFFFFFUL; z0 |= t8; z1 &= t8; + z0 |= t9; z1 &= t9 ^ 0x3C00000UL; + + /* ... except for a possible carry at bit 22 of t9 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t9 >> 23 == 0); + + return (z0 == 0) | (z1 == 0x3FFFFFFUL); +} + +SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) { + r->n[0] = a; + r->n[1] = r->n[2] = r->n[3] = r->n[4] = r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0; +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; + secp256k1_fe_verify(r); +#endif +} + +SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe_t *a) { + const uint32_t *t = a->n; +#ifdef VERIFY + VERIFY_CHECK(a->normalized); + secp256k1_fe_verify(a); +#endif + return (t[0] | t[1] | t[2] | t[3] | t[4] | t[5] | t[6] | t[7] | t[8] | t[9]) == 0; +} + +SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe_t *a) { +#ifdef VERIFY + VERIFY_CHECK(a->normalized); + secp256k1_fe_verify(a); +#endif + return a->n[0] & 1; +} + +SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe_t *a) { + int i; +#ifdef VERIFY + a->magnitude = 0; + a->normalized = 1; +#endif + for (i=0; i<10; i++) { + a->n[i] = 0; + } +} + +static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { + int i; +#ifdef VERIFY + VERIFY_CHECK(a->normalized); + VERIFY_CHECK(b->normalized); + secp256k1_fe_verify(a); + secp256k1_fe_verify(b); +#endif + for (i = 9; i >= 0; i--) { + if (a->n[i] > b->n[i]) { + return 1; + } + if (a->n[i] < b->n[i]) { + return -1; + } + } + return 0; +} + +static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) { + int i; + r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; + r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0; + for (i=0; i<32; i++) { + int j; + for (j=0; j<4; j++) { + int limb = (8*i+2*j)/26; + int shift = (8*i+2*j)%26; + r->n[limb] |= (uint32_t)((a[31-i] >> (2*j)) & 0x3) << shift; + } + } + if (r->n[9] == 0x3FFFFFUL && (r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL && (r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL) { + return 0; + } +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; + secp256k1_fe_verify(r); +#endif + return 1; +} + +/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ +static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) { + int i; +#ifdef VERIFY + VERIFY_CHECK(a->normalized); + secp256k1_fe_verify(a); +#endif + for (i=0; i<32; i++) { + int j; + int c = 0; + for (j=0; j<4; j++) { + int limb = (8*i+2*j)/26; + int shift = (8*i+2*j)%26; + c |= ((a->n[limb] >> shift) & 0x3) << (2 * j); + } + r[31-i] = c; + } +} + +SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m) { +#ifdef VERIFY + VERIFY_CHECK(a->magnitude <= m); + secp256k1_fe_verify(a); +#endif + r->n[0] = 0x3FFFC2FUL * 2 * (m + 1) - a->n[0]; + r->n[1] = 0x3FFFFBFUL * 2 * (m + 1) - a->n[1]; + r->n[2] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[2]; + r->n[3] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[3]; + r->n[4] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[4]; + r->n[5] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[5]; + r->n[6] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[6]; + r->n[7] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[7]; + r->n[8] = 0x3FFFFFFUL * 2 * (m + 1) - a->n[8]; + r->n[9] = 0x03FFFFFUL * 2 * (m + 1) - a->n[9]; +#ifdef VERIFY + r->magnitude = m + 1; + r->normalized = 0; + secp256k1_fe_verify(r); +#endif +} + +SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) { + r->n[0] *= a; + r->n[1] *= a; + r->n[2] *= a; + r->n[3] *= a; + r->n[4] *= a; + r->n[5] *= a; + r->n[6] *= a; + r->n[7] *= a; + r->n[8] *= a; + r->n[9] *= a; +#ifdef VERIFY + r->magnitude *= a; + r->normalized = 0; + secp256k1_fe_verify(r); +#endif +} + +SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a) { +#ifdef VERIFY + secp256k1_fe_verify(a); +#endif + r->n[0] += a->n[0]; + r->n[1] += a->n[1]; + r->n[2] += a->n[2]; + r->n[3] += a->n[3]; + r->n[4] += a->n[4]; + r->n[5] += a->n[5]; + r->n[6] += a->n[6]; + r->n[7] += a->n[7]; + r->n[8] += a->n[8]; + r->n[9] += a->n[9]; +#ifdef VERIFY + r->magnitude += a->magnitude; + r->normalized = 0; + secp256k1_fe_verify(r); +#endif +} + +#ifdef VERIFY +#define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0) +#else +#define VERIFY_BITS(x, n) do { } while(0) +#endif + +SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b) { + uint64_t c, d; + uint64_t u0, u1, u2, u3, u4, u5, u6, u7, u8; + uint32_t t9, t1, t0, t2, t3, t4, t5, t6, t7; + const uint32_t M = 0x3FFFFFFUL, R0 = 0x3D10UL, R1 = 0x400UL; + + VERIFY_BITS(a[0], 30); + VERIFY_BITS(a[1], 30); + VERIFY_BITS(a[2], 30); + VERIFY_BITS(a[3], 30); + VERIFY_BITS(a[4], 30); + VERIFY_BITS(a[5], 30); + VERIFY_BITS(a[6], 30); + VERIFY_BITS(a[7], 30); + VERIFY_BITS(a[8], 30); + VERIFY_BITS(a[9], 26); + VERIFY_BITS(b[0], 30); + VERIFY_BITS(b[1], 30); + VERIFY_BITS(b[2], 30); + VERIFY_BITS(b[3], 30); + VERIFY_BITS(b[4], 30); + VERIFY_BITS(b[5], 30); + VERIFY_BITS(b[6], 30); + VERIFY_BITS(b[7], 30); + VERIFY_BITS(b[8], 30); + VERIFY_BITS(b[9], 26); + + /** [... a b c] is a shorthand for ... + a<<52 + b<<26 + c<<0 mod n. + * px is a shorthand for sum(a[i]*b[x-i], i=0..x). + * Note that [x 0 0 0 0 0 0 0 0 0 0] = [x*R1 x*R0]. + */ + + d = (uint64_t)a[0] * b[9] + + (uint64_t)a[1] * b[8] + + (uint64_t)a[2] * b[7] + + (uint64_t)a[3] * b[6] + + (uint64_t)a[4] * b[5] + + (uint64_t)a[5] * b[4] + + (uint64_t)a[6] * b[3] + + (uint64_t)a[7] * b[2] + + (uint64_t)a[8] * b[1] + + (uint64_t)a[9] * b[0]; + /* VERIFY_BITS(d, 64); */ + /* [d 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */ + t9 = d & M; d >>= 26; + VERIFY_BITS(t9, 26); + VERIFY_BITS(d, 38); + /* [d t9 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */ + + c = (uint64_t)a[0] * b[0]; + VERIFY_BITS(c, 60); + /* [d t9 0 0 0 0 0 0 0 0 c] = [p9 0 0 0 0 0 0 0 0 p0] */ + d += (uint64_t)a[1] * b[9] + + (uint64_t)a[2] * b[8] + + (uint64_t)a[3] * b[7] + + (uint64_t)a[4] * b[6] + + (uint64_t)a[5] * b[5] + + (uint64_t)a[6] * b[4] + + (uint64_t)a[7] * b[3] + + (uint64_t)a[8] * b[2] + + (uint64_t)a[9] * b[1]; + VERIFY_BITS(d, 63); + /* [d t9 0 0 0 0 0 0 0 0 c] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ + u0 = d & M; d >>= 26; c += u0 * R0; + VERIFY_BITS(u0, 26); + VERIFY_BITS(d, 37); + VERIFY_BITS(c, 61); + /* [d u0 t9 0 0 0 0 0 0 0 0 c-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ + t0 = c & M; c >>= 26; c += u0 * R1; + VERIFY_BITS(t0, 26); + VERIFY_BITS(c, 37); + /* [d u0 t9 0 0 0 0 0 0 0 c-u0*R1 t0-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ + /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ + + c += (uint64_t)a[0] * b[1] + + (uint64_t)a[1] * b[0]; + VERIFY_BITS(c, 62); + /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p10 p9 0 0 0 0 0 0 0 p1 p0] */ + d += (uint64_t)a[2] * b[9] + + (uint64_t)a[3] * b[8] + + (uint64_t)a[4] * b[7] + + (uint64_t)a[5] * b[6] + + (uint64_t)a[6] * b[5] + + (uint64_t)a[7] * b[4] + + (uint64_t)a[8] * b[3] + + (uint64_t)a[9] * b[2]; + VERIFY_BITS(d, 63); + /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ + u1 = d & M; d >>= 26; c += u1 * R0; + VERIFY_BITS(u1, 26); + VERIFY_BITS(d, 37); + VERIFY_BITS(c, 63); + /* [d u1 0 t9 0 0 0 0 0 0 0 c-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ + t1 = c & M; c >>= 26; c += u1 * R1; + VERIFY_BITS(t1, 26); + VERIFY_BITS(c, 38); + /* [d u1 0 t9 0 0 0 0 0 0 c-u1*R1 t1-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ + /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ + + c += (uint64_t)a[0] * b[2] + + (uint64_t)a[1] * b[1] + + (uint64_t)a[2] * b[0]; + VERIFY_BITS(c, 62); + /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ + d += (uint64_t)a[3] * b[9] + + (uint64_t)a[4] * b[8] + + (uint64_t)a[5] * b[7] + + (uint64_t)a[6] * b[6] + + (uint64_t)a[7] * b[5] + + (uint64_t)a[8] * b[4] + + (uint64_t)a[9] * b[3]; + VERIFY_BITS(d, 63); + /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ + u2 = d & M; d >>= 26; c += u2 * R0; + VERIFY_BITS(u2, 26); + VERIFY_BITS(d, 37); + VERIFY_BITS(c, 63); + /* [d u2 0 0 t9 0 0 0 0 0 0 c-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ + t2 = c & M; c >>= 26; c += u2 * R1; + VERIFY_BITS(t2, 26); + VERIFY_BITS(c, 38); + /* [d u2 0 0 t9 0 0 0 0 0 c-u2*R1 t2-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ + /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ + + c += (uint64_t)a[0] * b[3] + + (uint64_t)a[1] * b[2] + + (uint64_t)a[2] * b[1] + + (uint64_t)a[3] * b[0]; + VERIFY_BITS(c, 63); + /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ + d += (uint64_t)a[4] * b[9] + + (uint64_t)a[5] * b[8] + + (uint64_t)a[6] * b[7] + + (uint64_t)a[7] * b[6] + + (uint64_t)a[8] * b[5] + + (uint64_t)a[9] * b[4]; + VERIFY_BITS(d, 63); + /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ + u3 = d & M; d >>= 26; c += u3 * R0; + VERIFY_BITS(u3, 26); + VERIFY_BITS(d, 37); + /* VERIFY_BITS(c, 64); */ + /* [d u3 0 0 0 t9 0 0 0 0 0 c-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ + t3 = c & M; c >>= 26; c += u3 * R1; + VERIFY_BITS(t3, 26); + VERIFY_BITS(c, 39); + /* [d u3 0 0 0 t9 0 0 0 0 c-u3*R1 t3-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ + /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ + + c += (uint64_t)a[0] * b[4] + + (uint64_t)a[1] * b[3] + + (uint64_t)a[2] * b[2] + + (uint64_t)a[3] * b[1] + + (uint64_t)a[4] * b[0]; + VERIFY_BITS(c, 63); + /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ + d += (uint64_t)a[5] * b[9] + + (uint64_t)a[6] * b[8] + + (uint64_t)a[7] * b[7] + + (uint64_t)a[8] * b[6] + + (uint64_t)a[9] * b[5]; + VERIFY_BITS(d, 62); + /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ + u4 = d & M; d >>= 26; c += u4 * R0; + VERIFY_BITS(u4, 26); + VERIFY_BITS(d, 36); + /* VERIFY_BITS(c, 64); */ + /* [d u4 0 0 0 0 t9 0 0 0 0 c-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ + t4 = c & M; c >>= 26; c += u4 * R1; + VERIFY_BITS(t4, 26); + VERIFY_BITS(c, 39); + /* [d u4 0 0 0 0 t9 0 0 0 c-u4*R1 t4-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ + + c += (uint64_t)a[0] * b[5] + + (uint64_t)a[1] * b[4] + + (uint64_t)a[2] * b[3] + + (uint64_t)a[3] * b[2] + + (uint64_t)a[4] * b[1] + + (uint64_t)a[5] * b[0]; + VERIFY_BITS(c, 63); + /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ + d += (uint64_t)a[6] * b[9] + + (uint64_t)a[7] * b[8] + + (uint64_t)a[8] * b[7] + + (uint64_t)a[9] * b[6]; + VERIFY_BITS(d, 62); + /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ + u5 = d & M; d >>= 26; c += u5 * R0; + VERIFY_BITS(u5, 26); + VERIFY_BITS(d, 36); + /* VERIFY_BITS(c, 64); */ + /* [d u5 0 0 0 0 0 t9 0 0 0 c-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ + t5 = c & M; c >>= 26; c += u5 * R1; + VERIFY_BITS(t5, 26); + VERIFY_BITS(c, 39); + /* [d u5 0 0 0 0 0 t9 0 0 c-u5*R1 t5-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ + + c += (uint64_t)a[0] * b[6] + + (uint64_t)a[1] * b[5] + + (uint64_t)a[2] * b[4] + + (uint64_t)a[3] * b[3] + + (uint64_t)a[4] * b[2] + + (uint64_t)a[5] * b[1] + + (uint64_t)a[6] * b[0]; + VERIFY_BITS(c, 63); + /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ + d += (uint64_t)a[7] * b[9] + + (uint64_t)a[8] * b[8] + + (uint64_t)a[9] * b[7]; + VERIFY_BITS(d, 61); + /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ + u6 = d & M; d >>= 26; c += u6 * R0; + VERIFY_BITS(u6, 26); + VERIFY_BITS(d, 35); + /* VERIFY_BITS(c, 64); */ + /* [d u6 0 0 0 0 0 0 t9 0 0 c-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ + t6 = c & M; c >>= 26; c += u6 * R1; + VERIFY_BITS(t6, 26); + VERIFY_BITS(c, 39); + /* [d u6 0 0 0 0 0 0 t9 0 c-u6*R1 t6-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ + + c += (uint64_t)a[0] * b[7] + + (uint64_t)a[1] * b[6] + + (uint64_t)a[2] * b[5] + + (uint64_t)a[3] * b[4] + + (uint64_t)a[4] * b[3] + + (uint64_t)a[5] * b[2] + + (uint64_t)a[6] * b[1] + + (uint64_t)a[7] * b[0]; + /* VERIFY_BITS(c, 64); */ + VERIFY_CHECK(c <= 0x8000007C00000007ULL); + /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ + d += (uint64_t)a[8] * b[9] + + (uint64_t)a[9] * b[8]; + VERIFY_BITS(d, 58); + /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ + u7 = d & M; d >>= 26; c += u7 * R0; + VERIFY_BITS(u7, 26); + VERIFY_BITS(d, 32); + /* VERIFY_BITS(c, 64); */ + VERIFY_CHECK(c <= 0x800001703FFFC2F7ULL); + /* [d u7 0 0 0 0 0 0 0 t9 0 c-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ + t7 = c & M; c >>= 26; c += u7 * R1; + VERIFY_BITS(t7, 26); + VERIFY_BITS(c, 38); + /* [d u7 0 0 0 0 0 0 0 t9 c-u7*R1 t7-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ + + c += (uint64_t)a[0] * b[8] + + (uint64_t)a[1] * b[7] + + (uint64_t)a[2] * b[6] + + (uint64_t)a[3] * b[5] + + (uint64_t)a[4] * b[4] + + (uint64_t)a[5] * b[3] + + (uint64_t)a[6] * b[2] + + (uint64_t)a[7] * b[1] + + (uint64_t)a[8] * b[0]; + /* VERIFY_BITS(c, 64); */ + VERIFY_CHECK(c <= 0x9000007B80000008ULL); + /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + d += (uint64_t)a[9] * b[9]; + VERIFY_BITS(d, 57); + /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + u8 = d & M; d >>= 26; c += u8 * R0; + VERIFY_BITS(u8, 26); + VERIFY_BITS(d, 31); + /* VERIFY_BITS(c, 64); */ + VERIFY_CHECK(c <= 0x9000016FBFFFC2F8ULL); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + + r[3] = t3; + VERIFY_BITS(r[3], 26); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 t4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[4] = t4; + VERIFY_BITS(r[4], 26); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[5] = t5; + VERIFY_BITS(r[5], 26); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[6] = t6; + VERIFY_BITS(r[6], 26); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[7] = t7; + VERIFY_BITS(r[7], 26); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + + r[8] = c & M; c >>= 26; c += u8 * R1; + VERIFY_BITS(r[8], 26); + VERIFY_BITS(c, 39); + /* [d u8 0 0 0 0 0 0 0 0 t9+c-u8*R1 r8-u8*R0 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 0 0 0 0 t9+c r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + c += d * R0 + t9; + VERIFY_BITS(c, 45); + /* [d 0 0 0 0 0 0 0 0 0 c-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[9] = c & (M >> 4); c >>= 22; c += d * (R1 << 4); + VERIFY_BITS(r[9], 22); + VERIFY_BITS(c, 46); + /* [d 0 0 0 0 0 0 0 0 r9+((c-d*R1<<4)<<22)-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 0 0 -d*R1 r9+(c<<22)-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + + d = c * (R0 >> 4) + t0; + VERIFY_BITS(d, 56); + /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1 d-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[0] = d & M; d >>= 26; + VERIFY_BITS(r[0], 26); + VERIFY_BITS(d, 30); + /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1+d r0-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + d += c * (R1 >> 4) + t1; + VERIFY_BITS(d, 53); + VERIFY_CHECK(d <= 0x10000003FFFFBFULL); + /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 d-c*R1>>4 r0-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + /* [r9 r8 r7 r6 r5 r4 r3 t2 d r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[1] = d & M; d >>= 26; + VERIFY_BITS(r[1], 26); + VERIFY_BITS(d, 27); + VERIFY_CHECK(d <= 0x4000000ULL); + /* [r9 r8 r7 r6 r5 r4 r3 t2+d r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + d += t2; + VERIFY_BITS(d, 27); + /* [r9 r8 r7 r6 r5 r4 r3 d r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[2] = d; + VERIFY_BITS(r[2], 27); + /* [r9 r8 r7 r6 r5 r4 r3 r2 r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ +} + +SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t *a) { + uint64_t c, d; + uint64_t u0, u1, u2, u3, u4, u5, u6, u7, u8; + uint32_t t9, t0, t1, t2, t3, t4, t5, t6, t7; + const uint32_t M = 0x3FFFFFFUL, R0 = 0x3D10UL, R1 = 0x400UL; + + VERIFY_BITS(a[0], 30); + VERIFY_BITS(a[1], 30); + VERIFY_BITS(a[2], 30); + VERIFY_BITS(a[3], 30); + VERIFY_BITS(a[4], 30); + VERIFY_BITS(a[5], 30); + VERIFY_BITS(a[6], 30); + VERIFY_BITS(a[7], 30); + VERIFY_BITS(a[8], 30); + VERIFY_BITS(a[9], 26); + + /** [... a b c] is a shorthand for ... + a<<52 + b<<26 + c<<0 mod n. + * px is a shorthand for sum(a[i]*a[x-i], i=0..x). + * Note that [x 0 0 0 0 0 0 0 0 0 0] = [x*R1 x*R0]. + */ + + d = (uint64_t)(a[0]*2) * a[9] + + (uint64_t)(a[1]*2) * a[8] + + (uint64_t)(a[2]*2) * a[7] + + (uint64_t)(a[3]*2) * a[6] + + (uint64_t)(a[4]*2) * a[5]; + /* VERIFY_BITS(d, 64); */ + /* [d 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */ + t9 = d & M; d >>= 26; + VERIFY_BITS(t9, 26); + VERIFY_BITS(d, 38); + /* [d t9 0 0 0 0 0 0 0 0 0] = [p9 0 0 0 0 0 0 0 0 0] */ + + c = (uint64_t)a[0] * a[0]; + VERIFY_BITS(c, 60); + /* [d t9 0 0 0 0 0 0 0 0 c] = [p9 0 0 0 0 0 0 0 0 p0] */ + d += (uint64_t)(a[1]*2) * a[9] + + (uint64_t)(a[2]*2) * a[8] + + (uint64_t)(a[3]*2) * a[7] + + (uint64_t)(a[4]*2) * a[6] + + (uint64_t)a[5] * a[5]; + VERIFY_BITS(d, 63); + /* [d t9 0 0 0 0 0 0 0 0 c] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ + u0 = d & M; d >>= 26; c += u0 * R0; + VERIFY_BITS(u0, 26); + VERIFY_BITS(d, 37); + VERIFY_BITS(c, 61); + /* [d u0 t9 0 0 0 0 0 0 0 0 c-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ + t0 = c & M; c >>= 26; c += u0 * R1; + VERIFY_BITS(t0, 26); + VERIFY_BITS(c, 37); + /* [d u0 t9 0 0 0 0 0 0 0 c-u0*R1 t0-u0*R0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ + /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p10 p9 0 0 0 0 0 0 0 0 p0] */ + + c += (uint64_t)(a[0]*2) * a[1]; + VERIFY_BITS(c, 62); + /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p10 p9 0 0 0 0 0 0 0 p1 p0] */ + d += (uint64_t)(a[2]*2) * a[9] + + (uint64_t)(a[3]*2) * a[8] + + (uint64_t)(a[4]*2) * a[7] + + (uint64_t)(a[5]*2) * a[6]; + VERIFY_BITS(d, 63); + /* [d 0 t9 0 0 0 0 0 0 0 c t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ + u1 = d & M; d >>= 26; c += u1 * R0; + VERIFY_BITS(u1, 26); + VERIFY_BITS(d, 37); + VERIFY_BITS(c, 63); + /* [d u1 0 t9 0 0 0 0 0 0 0 c-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ + t1 = c & M; c >>= 26; c += u1 * R1; + VERIFY_BITS(t1, 26); + VERIFY_BITS(c, 38); + /* [d u1 0 t9 0 0 0 0 0 0 c-u1*R1 t1-u1*R0 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ + /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p11 p10 p9 0 0 0 0 0 0 0 p1 p0] */ + + c += (uint64_t)(a[0]*2) * a[2] + + (uint64_t)a[1] * a[1]; + VERIFY_BITS(c, 62); + /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ + d += (uint64_t)(a[3]*2) * a[9] + + (uint64_t)(a[4]*2) * a[8] + + (uint64_t)(a[5]*2) * a[7] + + (uint64_t)a[6] * a[6]; + VERIFY_BITS(d, 63); + /* [d 0 0 t9 0 0 0 0 0 0 c t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ + u2 = d & M; d >>= 26; c += u2 * R0; + VERIFY_BITS(u2, 26); + VERIFY_BITS(d, 37); + VERIFY_BITS(c, 63); + /* [d u2 0 0 t9 0 0 0 0 0 0 c-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ + t2 = c & M; c >>= 26; c += u2 * R1; + VERIFY_BITS(t2, 26); + VERIFY_BITS(c, 38); + /* [d u2 0 0 t9 0 0 0 0 0 c-u2*R1 t2-u2*R0 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ + /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 0 p2 p1 p0] */ + + c += (uint64_t)(a[0]*2) * a[3] + + (uint64_t)(a[1]*2) * a[2]; + VERIFY_BITS(c, 63); + /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ + d += (uint64_t)(a[4]*2) * a[9] + + (uint64_t)(a[5]*2) * a[8] + + (uint64_t)(a[6]*2) * a[7]; + VERIFY_BITS(d, 63); + /* [d 0 0 0 t9 0 0 0 0 0 c t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ + u3 = d & M; d >>= 26; c += u3 * R0; + VERIFY_BITS(u3, 26); + VERIFY_BITS(d, 37); + /* VERIFY_BITS(c, 64); */ + /* [d u3 0 0 0 t9 0 0 0 0 0 c-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ + t3 = c & M; c >>= 26; c += u3 * R1; + VERIFY_BITS(t3, 26); + VERIFY_BITS(c, 39); + /* [d u3 0 0 0 t9 0 0 0 0 c-u3*R1 t3-u3*R0 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ + /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 0 p3 p2 p1 p0] */ + + c += (uint64_t)(a[0]*2) * a[4] + + (uint64_t)(a[1]*2) * a[3] + + (uint64_t)a[2] * a[2]; + VERIFY_BITS(c, 63); + /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ + d += (uint64_t)(a[5]*2) * a[9] + + (uint64_t)(a[6]*2) * a[8] + + (uint64_t)a[7] * a[7]; + VERIFY_BITS(d, 62); + /* [d 0 0 0 0 t9 0 0 0 0 c t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ + u4 = d & M; d >>= 26; c += u4 * R0; + VERIFY_BITS(u4, 26); + VERIFY_BITS(d, 36); + /* VERIFY_BITS(c, 64); */ + /* [d u4 0 0 0 0 t9 0 0 0 0 c-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ + t4 = c & M; c >>= 26; c += u4 * R1; + VERIFY_BITS(t4, 26); + VERIFY_BITS(c, 39); + /* [d u4 0 0 0 0 t9 0 0 0 c-u4*R1 t4-u4*R0 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 0 p4 p3 p2 p1 p0] */ + + c += (uint64_t)(a[0]*2) * a[5] + + (uint64_t)(a[1]*2) * a[4] + + (uint64_t)(a[2]*2) * a[3]; + VERIFY_BITS(c, 63); + /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ + d += (uint64_t)(a[6]*2) * a[9] + + (uint64_t)(a[7]*2) * a[8]; + VERIFY_BITS(d, 62); + /* [d 0 0 0 0 0 t9 0 0 0 c t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ + u5 = d & M; d >>= 26; c += u5 * R0; + VERIFY_BITS(u5, 26); + VERIFY_BITS(d, 36); + /* VERIFY_BITS(c, 64); */ + /* [d u5 0 0 0 0 0 t9 0 0 0 c-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ + t5 = c & M; c >>= 26; c += u5 * R1; + VERIFY_BITS(t5, 26); + VERIFY_BITS(c, 39); + /* [d u5 0 0 0 0 0 t9 0 0 c-u5*R1 t5-u5*R0 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 0 p5 p4 p3 p2 p1 p0] */ + + c += (uint64_t)(a[0]*2) * a[6] + + (uint64_t)(a[1]*2) * a[5] + + (uint64_t)(a[2]*2) * a[4] + + (uint64_t)a[3] * a[3]; + VERIFY_BITS(c, 63); + /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ + d += (uint64_t)(a[7]*2) * a[9] + + (uint64_t)a[8] * a[8]; + VERIFY_BITS(d, 61); + /* [d 0 0 0 0 0 0 t9 0 0 c t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ + u6 = d & M; d >>= 26; c += u6 * R0; + VERIFY_BITS(u6, 26); + VERIFY_BITS(d, 35); + /* VERIFY_BITS(c, 64); */ + /* [d u6 0 0 0 0 0 0 t9 0 0 c-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ + t6 = c & M; c >>= 26; c += u6 * R1; + VERIFY_BITS(t6, 26); + VERIFY_BITS(c, 39); + /* [d u6 0 0 0 0 0 0 t9 0 c-u6*R1 t6-u6*R0 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 0 p6 p5 p4 p3 p2 p1 p0] */ + + c += (uint64_t)(a[0]*2) * a[7] + + (uint64_t)(a[1]*2) * a[6] + + (uint64_t)(a[2]*2) * a[5] + + (uint64_t)(a[3]*2) * a[4]; + /* VERIFY_BITS(c, 64); */ + VERIFY_CHECK(c <= 0x8000007C00000007ULL); + /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ + d += (uint64_t)(a[8]*2) * a[9]; + VERIFY_BITS(d, 58); + /* [d 0 0 0 0 0 0 0 t9 0 c t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ + u7 = d & M; d >>= 26; c += u7 * R0; + VERIFY_BITS(u7, 26); + VERIFY_BITS(d, 32); + /* VERIFY_BITS(c, 64); */ + VERIFY_CHECK(c <= 0x800001703FFFC2F7ULL); + /* [d u7 0 0 0 0 0 0 0 t9 0 c-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ + t7 = c & M; c >>= 26; c += u7 * R1; + VERIFY_BITS(t7, 26); + VERIFY_BITS(c, 38); + /* [d u7 0 0 0 0 0 0 0 t9 c-u7*R1 t7-u7*R0 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 0 p7 p6 p5 p4 p3 p2 p1 p0] */ + + c += (uint64_t)(a[0]*2) * a[8] + + (uint64_t)(a[1]*2) * a[7] + + (uint64_t)(a[2]*2) * a[6] + + (uint64_t)(a[3]*2) * a[5] + + (uint64_t)a[4] * a[4]; + /* VERIFY_BITS(c, 64); */ + VERIFY_CHECK(c <= 0x9000007B80000008ULL); + /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + d += (uint64_t)a[9] * a[9]; + VERIFY_BITS(d, 57); + /* [d 0 0 0 0 0 0 0 0 t9 c t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + u8 = d & M; d >>= 26; c += u8 * R0; + VERIFY_BITS(u8, 26); + VERIFY_BITS(d, 31); + /* VERIFY_BITS(c, 64); */ + VERIFY_CHECK(c <= 0x9000016FBFFFC2F8ULL); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 t4 t3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + + r[3] = t3; + VERIFY_BITS(r[3], 26); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 t4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[4] = t4; + VERIFY_BITS(r[4], 26); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 t5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[5] = t5; + VERIFY_BITS(r[5], 26); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 t6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[6] = t6; + VERIFY_BITS(r[6], 26); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 t7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[7] = t7; + VERIFY_BITS(r[7], 26); + /* [d u8 0 0 0 0 0 0 0 0 t9 c-u8*R0 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + + r[8] = c & M; c >>= 26; c += u8 * R1; + VERIFY_BITS(r[8], 26); + VERIFY_BITS(c, 39); + /* [d u8 0 0 0 0 0 0 0 0 t9+c-u8*R1 r8-u8*R0 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 0 0 0 0 t9+c r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + c += d * R0 + t9; + VERIFY_BITS(c, 45); + /* [d 0 0 0 0 0 0 0 0 0 c-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[9] = c & (M >> 4); c >>= 22; c += d * (R1 << 4); + VERIFY_BITS(r[9], 22); + VERIFY_BITS(c, 46); + /* [d 0 0 0 0 0 0 0 0 r9+((c-d*R1<<4)<<22)-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + /* [d 0 0 0 0 0 0 0 -d*R1 r9+(c<<22)-d*R0 r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1 t0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + + d = c * (R0 >> 4) + t0; + VERIFY_BITS(d, 56); + /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1 d-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[0] = d & M; d >>= 26; + VERIFY_BITS(r[0], 26); + VERIFY_BITS(d, 30); + /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 t1+d r0-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + d += c * (R1 >> 4) + t1; + VERIFY_BITS(d, 53); + VERIFY_CHECK(d <= 0x10000003FFFFBFULL); + /* [r9+(c<<22) r8 r7 r6 r5 r4 r3 t2 d-c*R1>>4 r0-c*R0>>4] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + /* [r9 r8 r7 r6 r5 r4 r3 t2 d r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[1] = d & M; d >>= 26; + VERIFY_BITS(r[1], 26); + VERIFY_BITS(d, 27); + VERIFY_CHECK(d <= 0x4000000ULL); + /* [r9 r8 r7 r6 r5 r4 r3 t2+d r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + d += t2; + VERIFY_BITS(d, 27); + /* [r9 r8 r7 r6 r5 r4 r3 d r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[2] = d; + VERIFY_BITS(r[2], 27); + /* [r9 r8 r7 r6 r5 r4 r3 r2 r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ +} + + +static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t * SECP256K1_RESTRICT b) { +#ifdef VERIFY + VERIFY_CHECK(a->magnitude <= 8); + VERIFY_CHECK(b->magnitude <= 8); + secp256k1_fe_verify(a); + secp256k1_fe_verify(b); + VERIFY_CHECK(r != b); +#endif + secp256k1_fe_mul_inner(r->n, a->n, b->n); +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 0; + secp256k1_fe_verify(r); +#endif +} + +static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) { +#ifdef VERIFY + VERIFY_CHECK(a->magnitude <= 8); + secp256k1_fe_verify(a); +#endif + secp256k1_fe_sqr_inner(r->n, a->n); +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 0; + secp256k1_fe_verify(r); +#endif +} + +static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag) { + uint32_t mask0, mask1; + mask0 = flag + ~((uint32_t)0); + mask1 = ~mask0; + r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); + r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); + r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); + r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); + r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1); + r->n[5] = (r->n[5] & mask0) | (a->n[5] & mask1); + r->n[6] = (r->n[6] & mask0) | (a->n[6] & mask1); + r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1); + r->n[8] = (r->n[8] & mask0) | (a->n[8] & mask1); + r->n[9] = (r->n[9] & mask0) | (a->n[9] & mask1); +#ifdef VERIFY + r->magnitude = (r->magnitude & mask0) | (a->magnitude & mask1); + r->normalized = (r->normalized & mask0) | (a->normalized & mask1); +#endif +} + +static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r, const secp256k1_fe_storage_t *a, int flag) { + uint32_t mask0, mask1; + mask0 = flag + ~((uint32_t)0); + mask1 = ~mask0; + r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); + r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); + r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); + r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); + r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1); + r->n[5] = (r->n[5] & mask0) | (a->n[5] & mask1); + r->n[6] = (r->n[6] & mask0) | (a->n[6] & mask1); + r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1); +} + +static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_fe_t *a) { +#ifdef VERIFY + VERIFY_CHECK(a->normalized); +#endif + r->n[0] = a->n[0] | a->n[1] << 26; + r->n[1] = a->n[1] >> 6 | a->n[2] << 20; + r->n[2] = a->n[2] >> 12 | a->n[3] << 14; + r->n[3] = a->n[3] >> 18 | a->n[4] << 8; + r->n[4] = a->n[4] >> 24 | a->n[5] << 2 | a->n[6] << 28; + r->n[5] = a->n[6] >> 4 | a->n[7] << 22; + r->n[6] = a->n[7] >> 10 | a->n[8] << 16; + r->n[7] = a->n[8] >> 16 | a->n[9] << 10; +} + +static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe_t *r, const secp256k1_fe_storage_t *a) { + r->n[0] = a->n[0] & 0x3FFFFFFUL; + r->n[1] = a->n[0] >> 26 | ((a->n[1] << 6) & 0x3FFFFFFUL); + r->n[2] = a->n[1] >> 20 | ((a->n[2] << 12) & 0x3FFFFFFUL); + r->n[3] = a->n[2] >> 14 | ((a->n[3] << 18) & 0x3FFFFFFUL); + r->n[4] = a->n[3] >> 8 | ((a->n[4] << 24) & 0x3FFFFFFUL); + r->n[5] = (a->n[4] >> 2) & 0x3FFFFFFUL; + r->n[6] = a->n[4] >> 28 | ((a->n[5] << 4) & 0x3FFFFFFUL); + r->n[7] = a->n[5] >> 22 | ((a->n[6] << 10) & 0x3FFFFFFUL); + r->n[8] = a->n[6] >> 16 | ((a->n[7] << 16) & 0x3FFFFFFUL); + r->n[9] = a->n[7] >> 10; +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; +#endif +} + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/field_5x52.h b/src/cryptoconditions/src/include/secp256k1/src/field_5x52.h new file mode 100644 index 000000000..4513d36f4 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/field_5x52.h @@ -0,0 +1,47 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_FIELD_REPR_ +#define _SECP256K1_FIELD_REPR_ + +#include + +typedef struct { + /* X = sum(i=0..4, elem[i]*2^52) mod n */ + uint64_t n[5]; +#ifdef VERIFY + int magnitude; + int normalized; +#endif +} secp256k1_fe_t; + +/* Unpacks a constant into a overlapping multi-limbed FE element. */ +#define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \ + (d0) | ((uint64_t)(d1) & 0xFFFFFUL) << 32, \ + ((d1) >> 20) | ((uint64_t)(d2)) << 12 | ((uint64_t)(d3) & 0xFFUL) << 44, \ + ((d3) >> 8) | ((uint64_t)(d4) & 0xFFFFFFFUL) << 24, \ + ((d4) >> 28) | ((uint64_t)(d5)) << 4 | ((uint64_t)(d6) & 0xFFFFUL) << 36, \ + ((d6) >> 16) | ((uint64_t)(d7)) << 16 \ +} + +#ifdef VERIFY +#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0)), 1, 1} +#else +#define SECP256K1_FE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {SECP256K1_FE_CONST_INNER((d7), (d6), (d5), (d4), (d3), (d2), (d1), (d0))} +#endif + +typedef struct { + uint64_t n[4]; +} secp256k1_fe_storage_t; + +#define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ \ + (d0) | ((uint64_t)(d1)) << 32, \ + (d2) | ((uint64_t)(d3)) << 32, \ + (d4) | ((uint64_t)(d5)) << 32, \ + (d6) | ((uint64_t)(d7)) << 32 \ +}} + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/field_5x52_asm_impl.h b/src/cryptoconditions/src/include/secp256k1/src/field_5x52_asm_impl.h new file mode 100644 index 000000000..98cc004bf --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/field_5x52_asm_impl.h @@ -0,0 +1,502 @@ +/********************************************************************** + * Copyright (c) 2013-2014 Diederik Huys, Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +/** + * Changelog: + * - March 2013, Diederik Huys: original version + * - November 2014, Pieter Wuille: updated to use Peter Dettman's parallel multiplication algorithm + * - December 2014, Pieter Wuille: converted from YASM to GCC inline assembly + */ + +#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_ +#define _SECP256K1_FIELD_INNER5X52_IMPL_H_ + +SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) { +/** + * Registers: rdx:rax = multiplication accumulator + * r9:r8 = c + * r15:rcx = d + * r10-r14 = a0-a4 + * rbx = b + * rdi = r + * rsi = a / t? + */ + uint64_t tmp1, tmp2, tmp3; +__asm__ __volatile__( + "movq 0(%%rsi),%%r10\n" + "movq 8(%%rsi),%%r11\n" + "movq 16(%%rsi),%%r12\n" + "movq 24(%%rsi),%%r13\n" + "movq 32(%%rsi),%%r14\n" + + /* d += a3 * b0 */ + "movq 0(%%rbx),%%rax\n" + "mulq %%r13\n" + "movq %%rax,%%rcx\n" + "movq %%rdx,%%r15\n" + /* d += a2 * b1 */ + "movq 8(%%rbx),%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a1 * b2 */ + "movq 16(%%rbx),%%rax\n" + "mulq %%r11\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d = a0 * b3 */ + "movq 24(%%rbx),%%rax\n" + "mulq %%r10\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* c = a4 * b4 */ + "movq 32(%%rbx),%%rax\n" + "mulq %%r14\n" + "movq %%rax,%%r8\n" + "movq %%rdx,%%r9\n" + /* d += (c & M) * R */ + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* c >>= 52 (%%r8 only) */ + "shrdq $52,%%r9,%%r8\n" + /* t3 (tmp1) = d & M */ + "movq %%rcx,%%rsi\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rsi\n" + "movq %%rsi,%q1\n" + /* d >>= 52 */ + "shrdq $52,%%r15,%%rcx\n" + "xorq %%r15,%%r15\n" + /* d += a4 * b0 */ + "movq 0(%%rbx),%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a3 * b1 */ + "movq 8(%%rbx),%%rax\n" + "mulq %%r13\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a2 * b2 */ + "movq 16(%%rbx),%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a1 * b3 */ + "movq 24(%%rbx),%%rax\n" + "mulq %%r11\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a0 * b4 */ + "movq 32(%%rbx),%%rax\n" + "mulq %%r10\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += c * R */ + "movq %%r8,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* t4 = d & M (%%rsi) */ + "movq %%rcx,%%rsi\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rsi\n" + /* d >>= 52 */ + "shrdq $52,%%r15,%%rcx\n" + "xorq %%r15,%%r15\n" + /* tx = t4 >> 48 (tmp3) */ + "movq %%rsi,%%rax\n" + "shrq $48,%%rax\n" + "movq %%rax,%q3\n" + /* t4 &= (M >> 4) (tmp2) */ + "movq $0xffffffffffff,%%rax\n" + "andq %%rax,%%rsi\n" + "movq %%rsi,%q2\n" + /* c = a0 * b0 */ + "movq 0(%%rbx),%%rax\n" + "mulq %%r10\n" + "movq %%rax,%%r8\n" + "movq %%rdx,%%r9\n" + /* d += a4 * b1 */ + "movq 8(%%rbx),%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a3 * b2 */ + "movq 16(%%rbx),%%rax\n" + "mulq %%r13\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a2 * b3 */ + "movq 24(%%rbx),%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a1 * b4 */ + "movq 32(%%rbx),%%rax\n" + "mulq %%r11\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* u0 = d & M (%%rsi) */ + "movq %%rcx,%%rsi\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rsi\n" + /* d >>= 52 */ + "shrdq $52,%%r15,%%rcx\n" + "xorq %%r15,%%r15\n" + /* u0 = (u0 << 4) | tx (%%rsi) */ + "shlq $4,%%rsi\n" + "movq %q3,%%rax\n" + "orq %%rax,%%rsi\n" + /* c += u0 * (R >> 4) */ + "movq $0x1000003d1,%%rax\n" + "mulq %%rsi\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* r[0] = c & M */ + "movq %%r8,%%rax\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rax\n" + "movq %%rax,0(%%rdi)\n" + /* c >>= 52 */ + "shrdq $52,%%r9,%%r8\n" + "xorq %%r9,%%r9\n" + /* c += a1 * b0 */ + "movq 0(%%rbx),%%rax\n" + "mulq %%r11\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* c += a0 * b1 */ + "movq 8(%%rbx),%%rax\n" + "mulq %%r10\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* d += a4 * b2 */ + "movq 16(%%rbx),%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a3 * b3 */ + "movq 24(%%rbx),%%rax\n" + "mulq %%r13\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a2 * b4 */ + "movq 32(%%rbx),%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* c += (d & M) * R */ + "movq %%rcx,%%rax\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* d >>= 52 */ + "shrdq $52,%%r15,%%rcx\n" + "xorq %%r15,%%r15\n" + /* r[1] = c & M */ + "movq %%r8,%%rax\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rax\n" + "movq %%rax,8(%%rdi)\n" + /* c >>= 52 */ + "shrdq $52,%%r9,%%r8\n" + "xorq %%r9,%%r9\n" + /* c += a2 * b0 */ + "movq 0(%%rbx),%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* c += a1 * b1 */ + "movq 8(%%rbx),%%rax\n" + "mulq %%r11\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* c += a0 * b2 (last use of %%r10 = a0) */ + "movq 16(%%rbx),%%rax\n" + "mulq %%r10\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* fetch t3 (%%r10, overwrites a0), t4 (%%rsi) */ + "movq %q2,%%rsi\n" + "movq %q1,%%r10\n" + /* d += a4 * b3 */ + "movq 24(%%rbx),%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* d += a3 * b4 */ + "movq 32(%%rbx),%%rax\n" + "mulq %%r13\n" + "addq %%rax,%%rcx\n" + "adcq %%rdx,%%r15\n" + /* c += (d & M) * R */ + "movq %%rcx,%%rax\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* d >>= 52 (%%rcx only) */ + "shrdq $52,%%r15,%%rcx\n" + /* r[2] = c & M */ + "movq %%r8,%%rax\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rax\n" + "movq %%rax,16(%%rdi)\n" + /* c >>= 52 */ + "shrdq $52,%%r9,%%r8\n" + "xorq %%r9,%%r9\n" + /* c += t3 */ + "addq %%r10,%%r8\n" + /* c += d * R */ + "movq %%rcx,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* r[3] = c & M */ + "movq %%r8,%%rax\n" + "movq $0xfffffffffffff,%%rdx\n" + "andq %%rdx,%%rax\n" + "movq %%rax,24(%%rdi)\n" + /* c >>= 52 (%%r8 only) */ + "shrdq $52,%%r9,%%r8\n" + /* c += t4 (%%r8 only) */ + "addq %%rsi,%%r8\n" + /* r[4] = c */ + "movq %%r8,32(%%rdi)\n" +: "+S"(a), "=m"(tmp1), "=m"(tmp2), "=m"(tmp3) +: "b"(b), "D"(r) +: "%rax", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory" +); +} + +SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) { +/** + * Registers: rdx:rax = multiplication accumulator + * r9:r8 = c + * rcx:rbx = d + * r10-r14 = a0-a4 + * r15 = M (0xfffffffffffff) + * rdi = r + * rsi = a / t? + */ + uint64_t tmp1, tmp2, tmp3; +__asm__ __volatile__( + "movq 0(%%rsi),%%r10\n" + "movq 8(%%rsi),%%r11\n" + "movq 16(%%rsi),%%r12\n" + "movq 24(%%rsi),%%r13\n" + "movq 32(%%rsi),%%r14\n" + "movq $0xfffffffffffff,%%r15\n" + + /* d = (a0*2) * a3 */ + "leaq (%%r10,%%r10,1),%%rax\n" + "mulq %%r13\n" + "movq %%rax,%%rbx\n" + "movq %%rdx,%%rcx\n" + /* d += (a1*2) * a2 */ + "leaq (%%r11,%%r11,1),%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* c = a4 * a4 */ + "movq %%r14,%%rax\n" + "mulq %%r14\n" + "movq %%rax,%%r8\n" + "movq %%rdx,%%r9\n" + /* d += (c & M) * R */ + "andq %%r15,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* c >>= 52 (%%r8 only) */ + "shrdq $52,%%r9,%%r8\n" + /* t3 (tmp1) = d & M */ + "movq %%rbx,%%rsi\n" + "andq %%r15,%%rsi\n" + "movq %%rsi,%q1\n" + /* d >>= 52 */ + "shrdq $52,%%rcx,%%rbx\n" + "xorq %%rcx,%%rcx\n" + /* a4 *= 2 */ + "addq %%r14,%%r14\n" + /* d += a0 * a4 */ + "movq %%r10,%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* d+= (a1*2) * a3 */ + "leaq (%%r11,%%r11,1),%%rax\n" + "mulq %%r13\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* d += a2 * a2 */ + "movq %%r12,%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* d += c * R */ + "movq %%r8,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* t4 = d & M (%%rsi) */ + "movq %%rbx,%%rsi\n" + "andq %%r15,%%rsi\n" + /* d >>= 52 */ + "shrdq $52,%%rcx,%%rbx\n" + "xorq %%rcx,%%rcx\n" + /* tx = t4 >> 48 (tmp3) */ + "movq %%rsi,%%rax\n" + "shrq $48,%%rax\n" + "movq %%rax,%q3\n" + /* t4 &= (M >> 4) (tmp2) */ + "movq $0xffffffffffff,%%rax\n" + "andq %%rax,%%rsi\n" + "movq %%rsi,%q2\n" + /* c = a0 * a0 */ + "movq %%r10,%%rax\n" + "mulq %%r10\n" + "movq %%rax,%%r8\n" + "movq %%rdx,%%r9\n" + /* d += a1 * a4 */ + "movq %%r11,%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* d += (a2*2) * a3 */ + "leaq (%%r12,%%r12,1),%%rax\n" + "mulq %%r13\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* u0 = d & M (%%rsi) */ + "movq %%rbx,%%rsi\n" + "andq %%r15,%%rsi\n" + /* d >>= 52 */ + "shrdq $52,%%rcx,%%rbx\n" + "xorq %%rcx,%%rcx\n" + /* u0 = (u0 << 4) | tx (%%rsi) */ + "shlq $4,%%rsi\n" + "movq %q3,%%rax\n" + "orq %%rax,%%rsi\n" + /* c += u0 * (R >> 4) */ + "movq $0x1000003d1,%%rax\n" + "mulq %%rsi\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* r[0] = c & M */ + "movq %%r8,%%rax\n" + "andq %%r15,%%rax\n" + "movq %%rax,0(%%rdi)\n" + /* c >>= 52 */ + "shrdq $52,%%r9,%%r8\n" + "xorq %%r9,%%r9\n" + /* a0 *= 2 */ + "addq %%r10,%%r10\n" + /* c += a0 * a1 */ + "movq %%r10,%%rax\n" + "mulq %%r11\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* d += a2 * a4 */ + "movq %%r12,%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* d += a3 * a3 */ + "movq %%r13,%%rax\n" + "mulq %%r13\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* c += (d & M) * R */ + "movq %%rbx,%%rax\n" + "andq %%r15,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* d >>= 52 */ + "shrdq $52,%%rcx,%%rbx\n" + "xorq %%rcx,%%rcx\n" + /* r[1] = c & M */ + "movq %%r8,%%rax\n" + "andq %%r15,%%rax\n" + "movq %%rax,8(%%rdi)\n" + /* c >>= 52 */ + "shrdq $52,%%r9,%%r8\n" + "xorq %%r9,%%r9\n" + /* c += a0 * a2 (last use of %%r10) */ + "movq %%r10,%%rax\n" + "mulq %%r12\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* fetch t3 (%%r10, overwrites a0),t4 (%%rsi) */ + "movq %q2,%%rsi\n" + "movq %q1,%%r10\n" + /* c += a1 * a1 */ + "movq %%r11,%%rax\n" + "mulq %%r11\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* d += a3 * a4 */ + "movq %%r13,%%rax\n" + "mulq %%r14\n" + "addq %%rax,%%rbx\n" + "adcq %%rdx,%%rcx\n" + /* c += (d & M) * R */ + "movq %%rbx,%%rax\n" + "andq %%r15,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* d >>= 52 (%%rbx only) */ + "shrdq $52,%%rcx,%%rbx\n" + /* r[2] = c & M */ + "movq %%r8,%%rax\n" + "andq %%r15,%%rax\n" + "movq %%rax,16(%%rdi)\n" + /* c >>= 52 */ + "shrdq $52,%%r9,%%r8\n" + "xorq %%r9,%%r9\n" + /* c += t3 */ + "addq %%r10,%%r8\n" + /* c += d * R */ + "movq %%rbx,%%rax\n" + "movq $0x1000003d10,%%rdx\n" + "mulq %%rdx\n" + "addq %%rax,%%r8\n" + "adcq %%rdx,%%r9\n" + /* r[3] = c & M */ + "movq %%r8,%%rax\n" + "andq %%r15,%%rax\n" + "movq %%rax,24(%%rdi)\n" + /* c >>= 52 (%%r8 only) */ + "shrdq $52,%%r9,%%r8\n" + /* c += t4 (%%r8 only) */ + "addq %%rsi,%%r8\n" + /* r[4] = c */ + "movq %%r8,32(%%rdi)\n" +: "+S"(a), "=m"(tmp1), "=m"(tmp2), "=m"(tmp3) +: "D"(r) +: "%rax", "%rbx", "%rcx", "%rdx", "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "cc", "memory" +); +} + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/field_5x52_impl.h b/src/cryptoconditions/src/include/secp256k1/src/field_5x52_impl.h new file mode 100644 index 000000000..bda4c3dfc --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/field_5x52_impl.h @@ -0,0 +1,454 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_FIELD_REPR_IMPL_H_ +#define _SECP256K1_FIELD_REPR_IMPL_H_ + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#include +#include "util.h" +#include "num.h" +#include "field.h" + +#if defined(USE_ASM_X86_64) +#include "field_5x52_asm_impl.h" +#else +#include "field_5x52_int128_impl.h" +#endif + +/** Implements arithmetic modulo FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE FFFFFC2F, + * represented as 5 uint64_t's in base 2^52. The values are allowed to contain >52 each. In particular, + * each FieldElem has a 'magnitude' associated with it. Internally, a magnitude M means each element + * is at most M*(2^53-1), except the most significant one, which is limited to M*(2^49-1). All operations + * accept any input with magnitude at most M, and have different rules for propagating magnitude to their + * output. + */ + +#ifdef VERIFY +static void secp256k1_fe_verify(const secp256k1_fe_t *a) { + const uint64_t *d = a->n; + int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; + /* secp256k1 'p' value defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ + r &= (d[0] <= 0xFFFFFFFFFFFFFULL * m); + r &= (d[1] <= 0xFFFFFFFFFFFFFULL * m); + r &= (d[2] <= 0xFFFFFFFFFFFFFULL * m); + r &= (d[3] <= 0xFFFFFFFFFFFFFULL * m); + r &= (d[4] <= 0x0FFFFFFFFFFFFULL * m); + r &= (a->magnitude >= 0); + r &= (a->magnitude <= 2048); + if (a->normalized) { + r &= (a->magnitude <= 1); + if (r && (d[4] == 0x0FFFFFFFFFFFFULL) && ((d[3] & d[2] & d[1]) == 0xFFFFFFFFFFFFFULL)) { + r &= (d[0] < 0xFFFFEFFFFFC2FULL); + } + } + VERIFY_CHECK(r == 1); +} +#else +static void secp256k1_fe_verify(const secp256k1_fe_t *a) { + (void)a; +} +#endif + +static void secp256k1_fe_normalize(secp256k1_fe_t *r) { + uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; + + /* Reduce t4 at the start so there will be at most a single carry from the first pass */ + uint64_t m; + uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; m = t1; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; m &= t2; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; m &= t3; + + /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t4 >> 49 == 0); + + /* At most a single final reduction is needed; check if the value is >= the field characteristic */ + x = (t4 >> 48) | ((t4 == 0x0FFFFFFFFFFFFULL) & (m == 0xFFFFFFFFFFFFFULL) + & (t0 >= 0xFFFFEFFFFFC2FULL)); + + /* Apply the final reduction (for constant-time behaviour, we do it always) */ + t0 += x * 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; + + /* If t4 didn't carry to bit 48 already, then it should have after any final reduction */ + VERIFY_CHECK(t4 >> 48 == x); + + /* Mask off the possible multiple of 2^256 from the final reduction */ + t4 &= 0x0FFFFFFFFFFFFULL; + + r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; + +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; + secp256k1_fe_verify(r); +#endif +} + +static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r) { + uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; + + /* Reduce t4 at the start so there will be at most a single carry from the first pass */ + uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; + + /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t4 >> 49 == 0); + + r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; + +#ifdef VERIFY + r->magnitude = 1; + secp256k1_fe_verify(r); +#endif +} + +static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) { + uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; + + /* Reduce t4 at the start so there will be at most a single carry from the first pass */ + uint64_t m; + uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; m = t1; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; m &= t2; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; m &= t3; + + /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t4 >> 49 == 0); + + /* At most a single final reduction is needed; check if the value is >= the field characteristic */ + x = (t4 >> 48) | ((t4 == 0x0FFFFFFFFFFFFULL) & (m == 0xFFFFFFFFFFFFFULL) + & (t0 >= 0xFFFFEFFFFFC2FULL)); + + if (x) { + t0 += 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; + + /* If t4 didn't carry to bit 48 already, then it should have after any final reduction */ + VERIFY_CHECK(t4 >> 48 == x); + + /* Mask off the possible multiple of 2^256 from the final reduction */ + t4 &= 0x0FFFFFFFFFFFFULL; + } + + r->n[0] = t0; r->n[1] = t1; r->n[2] = t2; r->n[3] = t3; r->n[4] = t4; + +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; + secp256k1_fe_verify(r); +#endif +} + +static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r) { + uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; + + /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ + uint64_t z0, z1; + + /* Reduce t4 at the start so there will be at most a single carry from the first pass */ + uint64_t x = t4 >> 48; t4 &= 0x0FFFFFFFFFFFFULL; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x1000003D1ULL; + t1 += (t0 >> 52); t0 &= 0xFFFFFFFFFFFFFULL; z0 = t0; z1 = t0 ^ 0x1000003D0ULL; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; z0 |= t1; z1 &= t1; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; z0 |= t2; z1 &= t2; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; z0 |= t3; z1 &= t3; + z0 |= t4; z1 &= t4 ^ 0xF000000000000ULL; + + /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t4 >> 49 == 0); + + return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); +} + +static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) { + uint64_t t0, t1, t2, t3, t4; + uint64_t z0, z1; + uint64_t x; + + t0 = r->n[0]; + t4 = r->n[4]; + + /* Reduce t4 at the start so there will be at most a single carry from the first pass */ + x = t4 >> 48; + + /* The first pass ensures the magnitude is 1, ... */ + t0 += x * 0x1000003D1ULL; + + /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ + z0 = t0 & 0xFFFFFFFFFFFFFULL; + z1 = z0 ^ 0x1000003D0ULL; + + /* Fast return path should catch the majority of cases */ + if ((z0 != 0ULL) & (z1 != 0xFFFFFFFFFFFFFULL)) { + return 0; + } + + t1 = r->n[1]; + t2 = r->n[2]; + t3 = r->n[3]; + + t4 &= 0x0FFFFFFFFFFFFULL; + + t1 += (t0 >> 52); t0 = z0; + t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; z0 |= t1; z1 &= t1; + t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; z0 |= t2; z1 &= t2; + t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; z0 |= t3; z1 &= t3; + z0 |= t4; z1 &= t4 ^ 0xF000000000000ULL; + + /* ... except for a possible carry at bit 48 of t4 (i.e. bit 256 of the field element) */ + VERIFY_CHECK(t4 >> 49 == 0); + + return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); +} + +SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) { + r->n[0] = a; + r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; + secp256k1_fe_verify(r); +#endif +} + +SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe_t *a) { + const uint64_t *t = a->n; +#ifdef VERIFY + VERIFY_CHECK(a->normalized); + secp256k1_fe_verify(a); +#endif + return (t[0] | t[1] | t[2] | t[3] | t[4]) == 0; +} + +SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe_t *a) { +#ifdef VERIFY + VERIFY_CHECK(a->normalized); + secp256k1_fe_verify(a); +#endif + return a->n[0] & 1; +} + +SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe_t *a) { + int i; +#ifdef VERIFY + a->magnitude = 0; + a->normalized = 1; +#endif + for (i=0; i<5; i++) { + a->n[i] = 0; + } +} + +static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { + int i; +#ifdef VERIFY + VERIFY_CHECK(a->normalized); + VERIFY_CHECK(b->normalized); + secp256k1_fe_verify(a); + secp256k1_fe_verify(b); +#endif + for (i = 4; i >= 0; i--) { + if (a->n[i] > b->n[i]) { + return 1; + } + if (a->n[i] < b->n[i]) { + return -1; + } + } + return 0; +} + +static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) { + int i; + r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; + for (i=0; i<32; i++) { + int j; + for (j=0; j<2; j++) { + int limb = (8*i+4*j)/52; + int shift = (8*i+4*j)%52; + r->n[limb] |= (uint64_t)((a[31-i] >> (4*j)) & 0xF) << shift; + } + } + if (r->n[4] == 0x0FFFFFFFFFFFFULL && (r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL && r->n[0] >= 0xFFFFEFFFFFC2FULL) { + return 0; + } +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; + secp256k1_fe_verify(r); +#endif + return 1; +} + +/** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ +static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) { + int i; +#ifdef VERIFY + VERIFY_CHECK(a->normalized); + secp256k1_fe_verify(a); +#endif + for (i=0; i<32; i++) { + int j; + int c = 0; + for (j=0; j<2; j++) { + int limb = (8*i+4*j)/52; + int shift = (8*i+4*j)%52; + c |= ((a->n[limb] >> shift) & 0xF) << (4 * j); + } + r[31-i] = c; + } +} + +SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m) { +#ifdef VERIFY + VERIFY_CHECK(a->magnitude <= m); + secp256k1_fe_verify(a); +#endif + r->n[0] = 0xFFFFEFFFFFC2FULL * 2 * (m + 1) - a->n[0]; + r->n[1] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[1]; + r->n[2] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[2]; + r->n[3] = 0xFFFFFFFFFFFFFULL * 2 * (m + 1) - a->n[3]; + r->n[4] = 0x0FFFFFFFFFFFFULL * 2 * (m + 1) - a->n[4]; +#ifdef VERIFY + r->magnitude = m + 1; + r->normalized = 0; + secp256k1_fe_verify(r); +#endif +} + +SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) { + r->n[0] *= a; + r->n[1] *= a; + r->n[2] *= a; + r->n[3] *= a; + r->n[4] *= a; +#ifdef VERIFY + r->magnitude *= a; + r->normalized = 0; + secp256k1_fe_verify(r); +#endif +} + +SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a) { +#ifdef VERIFY + secp256k1_fe_verify(a); +#endif + r->n[0] += a->n[0]; + r->n[1] += a->n[1]; + r->n[2] += a->n[2]; + r->n[3] += a->n[3]; + r->n[4] += a->n[4]; +#ifdef VERIFY + r->magnitude += a->magnitude; + r->normalized = 0; + secp256k1_fe_verify(r); +#endif +} + +static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t * SECP256K1_RESTRICT b) { +#ifdef VERIFY + VERIFY_CHECK(a->magnitude <= 8); + VERIFY_CHECK(b->magnitude <= 8); + secp256k1_fe_verify(a); + secp256k1_fe_verify(b); + VERIFY_CHECK(r != b); +#endif + secp256k1_fe_mul_inner(r->n, a->n, b->n); +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 0; + secp256k1_fe_verify(r); +#endif +} + +static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) { +#ifdef VERIFY + VERIFY_CHECK(a->magnitude <= 8); + secp256k1_fe_verify(a); +#endif + secp256k1_fe_sqr_inner(r->n, a->n); +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 0; + secp256k1_fe_verify(r); +#endif +} + +static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag) { + uint64_t mask0, mask1; + mask0 = flag + ~((uint64_t)0); + mask1 = ~mask0; + r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); + r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); + r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); + r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); + r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1); +#ifdef VERIFY + r->magnitude = (r->magnitude & mask0) | (a->magnitude & mask1); + r->normalized = (r->normalized & mask0) | (a->normalized & mask1); +#endif +} + +static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r, const secp256k1_fe_storage_t *a, int flag) { + uint64_t mask0, mask1; + mask0 = flag + ~((uint64_t)0); + mask1 = ~mask0; + r->n[0] = (r->n[0] & mask0) | (a->n[0] & mask1); + r->n[1] = (r->n[1] & mask0) | (a->n[1] & mask1); + r->n[2] = (r->n[2] & mask0) | (a->n[2] & mask1); + r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); +} + +static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_fe_t *a) { +#ifdef VERIFY + VERIFY_CHECK(a->normalized); +#endif + r->n[0] = a->n[0] | a->n[1] << 52; + r->n[1] = a->n[1] >> 12 | a->n[2] << 40; + r->n[2] = a->n[2] >> 24 | a->n[3] << 28; + r->n[3] = a->n[3] >> 36 | a->n[4] << 16; +} + +static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe_t *r, const secp256k1_fe_storage_t *a) { + r->n[0] = a->n[0] & 0xFFFFFFFFFFFFFULL; + r->n[1] = a->n[0] >> 52 | ((a->n[1] << 12) & 0xFFFFFFFFFFFFFULL); + r->n[2] = a->n[1] >> 40 | ((a->n[2] << 24) & 0xFFFFFFFFFFFFFULL); + r->n[3] = a->n[2] >> 28 | ((a->n[3] << 36) & 0xFFFFFFFFFFFFFULL); + r->n[4] = a->n[3] >> 16; +#ifdef VERIFY + r->magnitude = 1; + r->normalized = 1; +#endif +} + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/field_5x52_int128_impl.h b/src/cryptoconditions/src/include/secp256k1/src/field_5x52_int128_impl.h new file mode 100644 index 000000000..9280bb5ea --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/field_5x52_int128_impl.h @@ -0,0 +1,277 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_ +#define _SECP256K1_FIELD_INNER5X52_IMPL_H_ + +#include + +#ifdef VERIFY +#define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0) +#else +#define VERIFY_BITS(x, n) do { } while(0) +#endif + +SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) { + uint128_t c, d; + uint64_t t3, t4, tx, u0; + uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4]; + const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL; + + VERIFY_BITS(a[0], 56); + VERIFY_BITS(a[1], 56); + VERIFY_BITS(a[2], 56); + VERIFY_BITS(a[3], 56); + VERIFY_BITS(a[4], 52); + VERIFY_BITS(b[0], 56); + VERIFY_BITS(b[1], 56); + VERIFY_BITS(b[2], 56); + VERIFY_BITS(b[3], 56); + VERIFY_BITS(b[4], 52); + VERIFY_CHECK(r != b); + + /* [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n. + * px is a shorthand for sum(a[i]*b[x-i], i=0..x). + * Note that [x 0 0 0 0 0] = [x*R]. + */ + + d = (uint128_t)a0 * b[3] + + (uint128_t)a1 * b[2] + + (uint128_t)a2 * b[1] + + (uint128_t)a3 * b[0]; + VERIFY_BITS(d, 114); + /* [d 0 0 0] = [p3 0 0 0] */ + c = (uint128_t)a4 * b[4]; + VERIFY_BITS(c, 112); + /* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + d += (c & M) * R; c >>= 52; + VERIFY_BITS(d, 115); + VERIFY_BITS(c, 60); + /* [c 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + t3 = d & M; d >>= 52; + VERIFY_BITS(t3, 52); + VERIFY_BITS(d, 63); + /* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + + d += (uint128_t)a0 * b[4] + + (uint128_t)a1 * b[3] + + (uint128_t)a2 * b[2] + + (uint128_t)a3 * b[1] + + (uint128_t)a4 * b[0]; + VERIFY_BITS(d, 115); + /* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + d += c * R; + VERIFY_BITS(d, 116); + /* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + t4 = d & M; d >>= 52; + VERIFY_BITS(t4, 52); + VERIFY_BITS(d, 64); + /* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + tx = (t4 >> 48); t4 &= (M >> 4); + VERIFY_BITS(tx, 4); + VERIFY_BITS(t4, 48); + /* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + + c = (uint128_t)a0 * b[0]; + VERIFY_BITS(c, 112); + /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */ + d += (uint128_t)a1 * b[4] + + (uint128_t)a2 * b[3] + + (uint128_t)a3 * b[2] + + (uint128_t)a4 * b[1]; + VERIFY_BITS(d, 115); + /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + u0 = d & M; d >>= 52; + VERIFY_BITS(u0, 52); + VERIFY_BITS(d, 63); + /* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + /* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + u0 = (u0 << 4) | tx; + VERIFY_BITS(u0, 56); + /* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + c += (uint128_t)u0 * (R >> 4); + VERIFY_BITS(c, 115); + /* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + r[0] = c & M; c >>= 52; + VERIFY_BITS(r[0], 52); + VERIFY_BITS(c, 61); + /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */ + + c += (uint128_t)a0 * b[1] + + (uint128_t)a1 * b[0]; + VERIFY_BITS(c, 114); + /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */ + d += (uint128_t)a2 * b[4] + + (uint128_t)a3 * b[3] + + (uint128_t)a4 * b[2]; + VERIFY_BITS(d, 114); + /* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ + c += (d & M) * R; d >>= 52; + VERIFY_BITS(c, 115); + VERIFY_BITS(d, 62); + /* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ + r[1] = c & M; c >>= 52; + VERIFY_BITS(r[1], 52); + VERIFY_BITS(c, 63); + /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ + + c += (uint128_t)a0 * b[2] + + (uint128_t)a1 * b[1] + + (uint128_t)a2 * b[0]; + VERIFY_BITS(c, 114); + /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */ + d += (uint128_t)a3 * b[4] + + (uint128_t)a4 * b[3]; + VERIFY_BITS(d, 114); + /* [d 0 0 t4 t3 c t1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + c += (d & M) * R; d >>= 52; + VERIFY_BITS(c, 115); + VERIFY_BITS(d, 62); + /* [d 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + + /* [d 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[2] = c & M; c >>= 52; + VERIFY_BITS(r[2], 52); + VERIFY_BITS(c, 63); + /* [d 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + c += d * R + t3;; + VERIFY_BITS(c, 100); + /* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[3] = c & M; c >>= 52; + VERIFY_BITS(r[3], 52); + VERIFY_BITS(c, 48); + /* [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + c += t4; + VERIFY_BITS(c, 49); + /* [c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[4] = c; + VERIFY_BITS(r[4], 49); + /* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ +} + +SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t *a) { + uint128_t c, d; + uint64_t a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4]; + int64_t t3, t4, tx, u0; + const uint64_t M = 0xFFFFFFFFFFFFFULL, R = 0x1000003D10ULL; + + VERIFY_BITS(a[0], 56); + VERIFY_BITS(a[1], 56); + VERIFY_BITS(a[2], 56); + VERIFY_BITS(a[3], 56); + VERIFY_BITS(a[4], 52); + + /** [... a b c] is a shorthand for ... + a<<104 + b<<52 + c<<0 mod n. + * px is a shorthand for sum(a[i]*a[x-i], i=0..x). + * Note that [x 0 0 0 0 0] = [x*R]. + */ + + d = (uint128_t)(a0*2) * a3 + + (uint128_t)(a1*2) * a2; + VERIFY_BITS(d, 114); + /* [d 0 0 0] = [p3 0 0 0] */ + c = (uint128_t)a4 * a4; + VERIFY_BITS(c, 112); + /* [c 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + d += (c & M) * R; c >>= 52; + VERIFY_BITS(d, 115); + VERIFY_BITS(c, 60); + /* [c 0 0 0 0 0 d 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + t3 = d & M; d >>= 52; + VERIFY_BITS(t3, 52); + VERIFY_BITS(d, 63); + /* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 0 p3 0 0 0] */ + + a4 *= 2; + d += (uint128_t)a0 * a4 + + (uint128_t)(a1*2) * a3 + + (uint128_t)a2 * a2; + VERIFY_BITS(d, 115); + /* [c 0 0 0 0 d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + d += c * R; + VERIFY_BITS(d, 116); + /* [d t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + t4 = d & M; d >>= 52; + VERIFY_BITS(t4, 52); + VERIFY_BITS(d, 64); + /* [d t4 t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + tx = (t4 >> 48); t4 &= (M >> 4); + VERIFY_BITS(tx, 4); + VERIFY_BITS(t4, 48); + /* [d t4+(tx<<48) t3 0 0 0] = [p8 0 0 0 p4 p3 0 0 0] */ + + c = (uint128_t)a0 * a0; + VERIFY_BITS(c, 112); + /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 0 p4 p3 0 0 p0] */ + d += (uint128_t)a1 * a4 + + (uint128_t)(a2*2) * a3; + VERIFY_BITS(d, 114); + /* [d t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + u0 = d & M; d >>= 52; + VERIFY_BITS(u0, 52); + VERIFY_BITS(d, 62); + /* [d u0 t4+(tx<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + /* [d 0 t4+(tx<<48)+(u0<<52) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + u0 = (u0 << 4) | tx; + VERIFY_BITS(u0, 56); + /* [d 0 t4+(u0<<48) t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + c += (uint128_t)u0 * (R >> 4); + VERIFY_BITS(c, 113); + /* [d 0 t4 t3 0 0 c] = [p8 0 0 p5 p4 p3 0 0 p0] */ + r[0] = c & M; c >>= 52; + VERIFY_BITS(r[0], 52); + VERIFY_BITS(c, 61); + /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 0 p0] */ + + a0 *= 2; + c += (uint128_t)a0 * a1; + VERIFY_BITS(c, 114); + /* [d 0 t4 t3 0 c r0] = [p8 0 0 p5 p4 p3 0 p1 p0] */ + d += (uint128_t)a2 * a4 + + (uint128_t)a3 * a3; + VERIFY_BITS(d, 114); + /* [d 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ + c += (d & M) * R; d >>= 52; + VERIFY_BITS(c, 115); + VERIFY_BITS(d, 62); + /* [d 0 0 t4 t3 0 c r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ + r[1] = c & M; c >>= 52; + VERIFY_BITS(r[1], 52); + VERIFY_BITS(c, 63); + /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 0 p1 p0] */ + + c += (uint128_t)a0 * a2 + + (uint128_t)a1 * a1; + VERIFY_BITS(c, 114); + /* [d 0 0 t4 t3 c r1 r0] = [p8 0 p6 p5 p4 p3 p2 p1 p0] */ + d += (uint128_t)a3 * a4; + VERIFY_BITS(d, 114); + /* [d 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + c += (d & M) * R; d >>= 52; + VERIFY_BITS(c, 115); + VERIFY_BITS(d, 62); + /* [d 0 0 0 t4 t3 c r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[2] = c & M; c >>= 52; + VERIFY_BITS(r[2], 52); + VERIFY_BITS(c, 63); + /* [d 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + + c += d * R + t3;; + VERIFY_BITS(c, 100); + /* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[3] = c & M; c >>= 52; + VERIFY_BITS(r[3], 52); + VERIFY_BITS(c, 48); + /* [t4+c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + c += t4; + VERIFY_BITS(c, 49); + /* [c r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ + r[4] = c; + VERIFY_BITS(r[4], 49); + /* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ +} + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/field_impl.h b/src/cryptoconditions/src/include/secp256k1/src/field_impl.h new file mode 100644 index 000000000..e6ec11e8f --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/field_impl.h @@ -0,0 +1,263 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_FIELD_IMPL_H_ +#define _SECP256K1_FIELD_IMPL_H_ + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#include "util.h" + +#if defined(USE_FIELD_10X26) +#include "field_10x26_impl.h" +#elif defined(USE_FIELD_5X52) +#include "field_5x52_impl.h" +#else +#error "Please select field implementation" +#endif + +SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { + secp256k1_fe_t na; + secp256k1_fe_negate(&na, a, 1); + secp256k1_fe_add(&na, b); + return secp256k1_fe_normalizes_to_zero_var(&na); +} + +static int secp256k1_fe_sqrt_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) { + secp256k1_fe_t x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; + int j; + + /** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in + * { 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block: + * 1, [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223] + */ + + secp256k1_fe_sqr(&x2, a); + secp256k1_fe_mul(&x2, &x2, a); + + secp256k1_fe_sqr(&x3, &x2); + secp256k1_fe_mul(&x3, &x3, a); + + x6 = x3; + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&x6, &x6); + } + secp256k1_fe_mul(&x6, &x6, &x3); + + x9 = x6; + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&x9, &x9); + } + secp256k1_fe_mul(&x9, &x9, &x3); + + x11 = x9; + for (j=0; j<2; j++) { + secp256k1_fe_sqr(&x11, &x11); + } + secp256k1_fe_mul(&x11, &x11, &x2); + + x22 = x11; + for (j=0; j<11; j++) { + secp256k1_fe_sqr(&x22, &x22); + } + secp256k1_fe_mul(&x22, &x22, &x11); + + x44 = x22; + for (j=0; j<22; j++) { + secp256k1_fe_sqr(&x44, &x44); + } + secp256k1_fe_mul(&x44, &x44, &x22); + + x88 = x44; + for (j=0; j<44; j++) { + secp256k1_fe_sqr(&x88, &x88); + } + secp256k1_fe_mul(&x88, &x88, &x44); + + x176 = x88; + for (j=0; j<88; j++) { + secp256k1_fe_sqr(&x176, &x176); + } + secp256k1_fe_mul(&x176, &x176, &x88); + + x220 = x176; + for (j=0; j<44; j++) { + secp256k1_fe_sqr(&x220, &x220); + } + secp256k1_fe_mul(&x220, &x220, &x44); + + x223 = x220; + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&x223, &x223); + } + secp256k1_fe_mul(&x223, &x223, &x3); + + /* The final result is then assembled using a sliding window over the blocks. */ + + t1 = x223; + for (j=0; j<23; j++) { + secp256k1_fe_sqr(&t1, &t1); + } + secp256k1_fe_mul(&t1, &t1, &x22); + for (j=0; j<6; j++) { + secp256k1_fe_sqr(&t1, &t1); + } + secp256k1_fe_mul(&t1, &t1, &x2); + secp256k1_fe_sqr(&t1, &t1); + secp256k1_fe_sqr(r, &t1); + + /* Check that a square root was actually calculated */ + + secp256k1_fe_sqr(&t1, r); + return secp256k1_fe_equal_var(&t1, a); +} + +static void secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a) { + secp256k1_fe_t x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; + int j; + + /** The binary representation of (p - 2) has 5 blocks of 1s, with lengths in + * { 1, 2, 22, 223 }. Use an addition chain to calculate 2^n - 1 for each block: + * [1], [2], 3, 6, 9, 11, [22], 44, 88, 176, 220, [223] + */ + + secp256k1_fe_sqr(&x2, a); + secp256k1_fe_mul(&x2, &x2, a); + + secp256k1_fe_sqr(&x3, &x2); + secp256k1_fe_mul(&x3, &x3, a); + + x6 = x3; + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&x6, &x6); + } + secp256k1_fe_mul(&x6, &x6, &x3); + + x9 = x6; + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&x9, &x9); + } + secp256k1_fe_mul(&x9, &x9, &x3); + + x11 = x9; + for (j=0; j<2; j++) { + secp256k1_fe_sqr(&x11, &x11); + } + secp256k1_fe_mul(&x11, &x11, &x2); + + x22 = x11; + for (j=0; j<11; j++) { + secp256k1_fe_sqr(&x22, &x22); + } + secp256k1_fe_mul(&x22, &x22, &x11); + + x44 = x22; + for (j=0; j<22; j++) { + secp256k1_fe_sqr(&x44, &x44); + } + secp256k1_fe_mul(&x44, &x44, &x22); + + x88 = x44; + for (j=0; j<44; j++) { + secp256k1_fe_sqr(&x88, &x88); + } + secp256k1_fe_mul(&x88, &x88, &x44); + + x176 = x88; + for (j=0; j<88; j++) { + secp256k1_fe_sqr(&x176, &x176); + } + secp256k1_fe_mul(&x176, &x176, &x88); + + x220 = x176; + for (j=0; j<44; j++) { + secp256k1_fe_sqr(&x220, &x220); + } + secp256k1_fe_mul(&x220, &x220, &x44); + + x223 = x220; + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&x223, &x223); + } + secp256k1_fe_mul(&x223, &x223, &x3); + + /* The final result is then assembled using a sliding window over the blocks. */ + + t1 = x223; + for (j=0; j<23; j++) { + secp256k1_fe_sqr(&t1, &t1); + } + secp256k1_fe_mul(&t1, &t1, &x22); + for (j=0; j<5; j++) { + secp256k1_fe_sqr(&t1, &t1); + } + secp256k1_fe_mul(&t1, &t1, a); + for (j=0; j<3; j++) { + secp256k1_fe_sqr(&t1, &t1); + } + secp256k1_fe_mul(&t1, &t1, &x2); + for (j=0; j<2; j++) { + secp256k1_fe_sqr(&t1, &t1); + } + secp256k1_fe_mul(r, a, &t1); +} + +static void secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) { +#if defined(USE_FIELD_INV_BUILTIN) + secp256k1_fe_inv(r, a); +#elif defined(USE_FIELD_INV_NUM) + secp256k1_num_t n, m; + /* secp256k1 field prime, value p defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ + static const unsigned char prime[32] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F + }; + unsigned char b[32]; + secp256k1_fe_t c = *a; + secp256k1_fe_normalize_var(&c); + secp256k1_fe_get_b32(b, &c); + secp256k1_num_set_bin(&n, b, 32); + secp256k1_num_set_bin(&m, prime, 32); + secp256k1_num_mod_inverse(&n, &n, &m); + secp256k1_num_get_bin(b, 32, &n); + VERIFY_CHECK(secp256k1_fe_set_b32(r, b)); +#else +#error "Please select field inverse implementation" +#endif +} + +static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe_t *r, const secp256k1_fe_t *a) { + secp256k1_fe_t u; + size_t i; + if (len < 1) { + return; + } + + VERIFY_CHECK((r + len <= a) || (a + len <= r)); + + r[0] = a[0]; + + i = 0; + while (++i < len) { + secp256k1_fe_mul(&r[i], &r[i - 1], &a[i]); + } + + secp256k1_fe_inv_var(&u, &r[--i]); + + while (i > 0) { + int j = i--; + secp256k1_fe_mul(&r[j], &r[i], &u); + secp256k1_fe_mul(&u, &u, &a[j]); + } + + r[0] = u; +} + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/group.h b/src/cryptoconditions/src/include/secp256k1/src/group.h new file mode 100644 index 000000000..0b08b3b99 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/group.h @@ -0,0 +1,121 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_GROUP_ +#define _SECP256K1_GROUP_ + +#include "num.h" +#include "field.h" + +/** A group element of the secp256k1 curve, in affine coordinates. */ +typedef struct { + secp256k1_fe_t x; + secp256k1_fe_t y; + int infinity; /* whether this represents the point at infinity */ +} secp256k1_ge_t; + +#define SECP256K1_GE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), 0} +#define SECP256K1_GE_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1} + +/** A group element of the secp256k1 curve, in jacobian coordinates. */ +typedef struct { + secp256k1_fe_t x; /* actual X: x/z^2 */ + secp256k1_fe_t y; /* actual Y: y/z^3 */ + secp256k1_fe_t z; + int infinity; /* whether this represents the point at infinity */ +} secp256k1_gej_t; + +#define SECP256K1_GEJ_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1), 0} +#define SECP256K1_GEJ_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1} + +typedef struct { + secp256k1_fe_storage_t x; + secp256k1_fe_storage_t y; +} secp256k1_ge_storage_t; + +#define SECP256K1_GE_STORAGE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_STORAGE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_STORAGE_CONST((i),(j),(k),(l),(m),(n),(o),(p))} + +/** Set a group element equal to the point at infinity */ +static void secp256k1_ge_set_infinity(secp256k1_ge_t *r); + +/** Set a group element equal to the point with given X and Y coordinates */ +static void secp256k1_ge_set_xy(secp256k1_ge_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y); + +/** Set a group element (affine) equal to the point with the given X coordinate, and given oddness + * for Y. Return value indicates whether the result is valid. */ +static int secp256k1_ge_set_xo_var(secp256k1_ge_t *r, const secp256k1_fe_t *x, int odd); + +/** Check whether a group element is the point at infinity. */ +static int secp256k1_ge_is_infinity(const secp256k1_ge_t *a); + +/** Check whether a group element is valid (i.e., on the curve). */ +static int secp256k1_ge_is_valid_var(const secp256k1_ge_t *a); + +static void secp256k1_ge_neg(secp256k1_ge_t *r, const secp256k1_ge_t *a); + +/** Set a group element equal to another which is given in jacobian coordinates */ +static void secp256k1_ge_set_gej(secp256k1_ge_t *r, secp256k1_gej_t *a); + +/** Set a batch of group elements equal to the inputs given in jacobian coordinates */ +static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge_t *r, const secp256k1_gej_t *a); + + +/** Set a group element (jacobian) equal to the point at infinity. */ +static void secp256k1_gej_set_infinity(secp256k1_gej_t *r); + +/** Set a group element (jacobian) equal to the point with given X and Y coordinates. */ +static void secp256k1_gej_set_xy(secp256k1_gej_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y); + +/** Set a group element (jacobian) equal to another which is given in affine coordinates. */ +static void secp256k1_gej_set_ge(secp256k1_gej_t *r, const secp256k1_ge_t *a); + +/** Compare the X coordinate of a group element (jacobian). */ +static int secp256k1_gej_eq_x_var(const secp256k1_fe_t *x, const secp256k1_gej_t *a); + +/** Set r equal to the inverse of a (i.e., mirrored around the X axis) */ +static void secp256k1_gej_neg(secp256k1_gej_t *r, const secp256k1_gej_t *a); + +/** Check whether a group element is the point at infinity. */ +static int secp256k1_gej_is_infinity(const secp256k1_gej_t *a); + +/** Set r equal to the double of a. */ +static void secp256k1_gej_double_var(secp256k1_gej_t *r, const secp256k1_gej_t *a); + +/** Set r equal to the sum of a and b. */ +static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_gej_t *b); + +/** Set r equal to the sum of a and b (with b given in affine coordinates, and not infinity). */ +static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b); + +/** Set r equal to the sum of a and b (with b given in affine coordinates). This is more efficient + than secp256k1_gej_add_var. It is identical to secp256k1_gej_add_ge but without constant-time + guarantee, and b is allowed to be infinity. */ +static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b); + +#ifdef USE_ENDOMORPHISM +/** Set r to be equal to lambda times a, where lambda is chosen in a way such that this is very fast. */ +static void secp256k1_gej_mul_lambda(secp256k1_gej_t *r, const secp256k1_gej_t *a); +#endif + +/** Clear a secp256k1_gej_t to prevent leaking sensitive information. */ +static void secp256k1_gej_clear(secp256k1_gej_t *r); + +/** Clear a secp256k1_ge_t to prevent leaking sensitive information. */ +static void secp256k1_ge_clear(secp256k1_ge_t *r); + +/** Convert a group element to the storage type. */ +static void secp256k1_ge_to_storage(secp256k1_ge_storage_t *r, const secp256k1_ge_t*); + +/** Convert a group element back from the storage type. */ +static void secp256k1_ge_from_storage(secp256k1_ge_t *r, const secp256k1_ge_storage_t*); + +/** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */ +static void secp256k1_ge_storage_cmov(secp256k1_ge_storage_t *r, const secp256k1_ge_storage_t *a, int flag); + +/** Rescale a jacobian point by b which must be non-zero. Constant-time. */ +static void secp256k1_gej_rescale(secp256k1_gej_t *r, const secp256k1_fe_t *b); + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/group_impl.h b/src/cryptoconditions/src/include/secp256k1/src/group_impl.h new file mode 100644 index 000000000..0f64576fb --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/group_impl.h @@ -0,0 +1,443 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_GROUP_IMPL_H_ +#define _SECP256K1_GROUP_IMPL_H_ + +#include + +#include "num.h" +#include "field.h" +#include "group.h" + +/** Generator for secp256k1, value 'g' defined in + * "Standards for Efficient Cryptography" (SEC2) 2.7.1. + */ +static const secp256k1_ge_t secp256k1_ge_const_g = SECP256K1_GE_CONST( + 0x79BE667EUL, 0xF9DCBBACUL, 0x55A06295UL, 0xCE870B07UL, + 0x029BFCDBUL, 0x2DCE28D9UL, 0x59F2815BUL, 0x16F81798UL, + 0x483ADA77UL, 0x26A3C465UL, 0x5DA4FBFCUL, 0x0E1108A8UL, + 0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL +); + +static void secp256k1_ge_set_infinity(secp256k1_ge_t *r) { + r->infinity = 1; +} + +static void secp256k1_ge_set_xy(secp256k1_ge_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y) { + r->infinity = 0; + r->x = *x; + r->y = *y; +} + +static int secp256k1_ge_is_infinity(const secp256k1_ge_t *a) { + return a->infinity; +} + +static void secp256k1_ge_neg(secp256k1_ge_t *r, const secp256k1_ge_t *a) { + *r = *a; + secp256k1_fe_normalize_weak(&r->y); + secp256k1_fe_negate(&r->y, &r->y, 1); +} + +static void secp256k1_ge_set_gej(secp256k1_ge_t *r, secp256k1_gej_t *a) { + secp256k1_fe_t z2, z3; + r->infinity = a->infinity; + secp256k1_fe_inv(&a->z, &a->z); + secp256k1_fe_sqr(&z2, &a->z); + secp256k1_fe_mul(&z3, &a->z, &z2); + secp256k1_fe_mul(&a->x, &a->x, &z2); + secp256k1_fe_mul(&a->y, &a->y, &z3); + secp256k1_fe_set_int(&a->z, 1); + r->x = a->x; + r->y = a->y; +} + +static void secp256k1_ge_set_gej_var(secp256k1_ge_t *r, secp256k1_gej_t *a) { + secp256k1_fe_t z2, z3; + r->infinity = a->infinity; + if (a->infinity) { + return; + } + secp256k1_fe_inv_var(&a->z, &a->z); + secp256k1_fe_sqr(&z2, &a->z); + secp256k1_fe_mul(&z3, &a->z, &z2); + secp256k1_fe_mul(&a->x, &a->x, &z2); + secp256k1_fe_mul(&a->y, &a->y, &z3); + secp256k1_fe_set_int(&a->z, 1); + r->x = a->x; + r->y = a->y; +} + +static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge_t *r, const secp256k1_gej_t *a) { + secp256k1_fe_t *az; + secp256k1_fe_t *azi; + size_t i; + size_t count = 0; + az = (secp256k1_fe_t *)checked_malloc(sizeof(secp256k1_fe_t) * len); + for (i = 0; i < len; i++) { + if (!a[i].infinity) { + az[count++] = a[i].z; + } + } + + azi = (secp256k1_fe_t *)checked_malloc(sizeof(secp256k1_fe_t) * count); + secp256k1_fe_inv_all_var(count, azi, az); + free(az); + + count = 0; + for (i = 0; i < len; i++) { + r[i].infinity = a[i].infinity; + if (!a[i].infinity) { + secp256k1_fe_t zi2, zi3; + secp256k1_fe_t *zi = &azi[count++]; + secp256k1_fe_sqr(&zi2, zi); + secp256k1_fe_mul(&zi3, &zi2, zi); + secp256k1_fe_mul(&r[i].x, &a[i].x, &zi2); + secp256k1_fe_mul(&r[i].y, &a[i].y, &zi3); + } + } + free(azi); +} + +static void secp256k1_gej_set_infinity(secp256k1_gej_t *r) { + r->infinity = 1; + secp256k1_fe_set_int(&r->x, 0); + secp256k1_fe_set_int(&r->y, 0); + secp256k1_fe_set_int(&r->z, 0); +} + +static void secp256k1_gej_set_xy(secp256k1_gej_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y) { + r->infinity = 0; + r->x = *x; + r->y = *y; + secp256k1_fe_set_int(&r->z, 1); +} + +static void secp256k1_gej_clear(secp256k1_gej_t *r) { + r->infinity = 0; + secp256k1_fe_clear(&r->x); + secp256k1_fe_clear(&r->y); + secp256k1_fe_clear(&r->z); +} + +static void secp256k1_ge_clear(secp256k1_ge_t *r) { + r->infinity = 0; + secp256k1_fe_clear(&r->x); + secp256k1_fe_clear(&r->y); +} + +static int secp256k1_ge_set_xo_var(secp256k1_ge_t *r, const secp256k1_fe_t *x, int odd) { + secp256k1_fe_t x2, x3, c; + r->x = *x; + secp256k1_fe_sqr(&x2, x); + secp256k1_fe_mul(&x3, x, &x2); + r->infinity = 0; + secp256k1_fe_set_int(&c, 7); + secp256k1_fe_add(&c, &x3); + if (!secp256k1_fe_sqrt_var(&r->y, &c)) { + return 0; + } + secp256k1_fe_normalize_var(&r->y); + if (secp256k1_fe_is_odd(&r->y) != odd) { + secp256k1_fe_negate(&r->y, &r->y, 1); + } + return 1; +} + +static void secp256k1_gej_set_ge(secp256k1_gej_t *r, const secp256k1_ge_t *a) { + r->infinity = a->infinity; + r->x = a->x; + r->y = a->y; + secp256k1_fe_set_int(&r->z, 1); +} + +static int secp256k1_gej_eq_x_var(const secp256k1_fe_t *x, const secp256k1_gej_t *a) { + secp256k1_fe_t r, r2; + VERIFY_CHECK(!a->infinity); + secp256k1_fe_sqr(&r, &a->z); secp256k1_fe_mul(&r, &r, x); + r2 = a->x; secp256k1_fe_normalize_weak(&r2); + return secp256k1_fe_equal_var(&r, &r2); +} + +static void secp256k1_gej_neg(secp256k1_gej_t *r, const secp256k1_gej_t *a) { + r->infinity = a->infinity; + r->x = a->x; + r->y = a->y; + r->z = a->z; + secp256k1_fe_normalize_weak(&r->y); + secp256k1_fe_negate(&r->y, &r->y, 1); +} + +static int secp256k1_gej_is_infinity(const secp256k1_gej_t *a) { + return a->infinity; +} + +static int secp256k1_gej_is_valid_var(const secp256k1_gej_t *a) { + secp256k1_fe_t y2, x3, z2, z6; + if (a->infinity) { + return 0; + } + /** y^2 = x^3 + 7 + * (Y/Z^3)^2 = (X/Z^2)^3 + 7 + * Y^2 / Z^6 = X^3 / Z^6 + 7 + * Y^2 = X^3 + 7*Z^6 + */ + secp256k1_fe_sqr(&y2, &a->y); + secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x); + secp256k1_fe_sqr(&z2, &a->z); + secp256k1_fe_sqr(&z6, &z2); secp256k1_fe_mul(&z6, &z6, &z2); + secp256k1_fe_mul_int(&z6, 7); + secp256k1_fe_add(&x3, &z6); + secp256k1_fe_normalize_weak(&x3); + return secp256k1_fe_equal_var(&y2, &x3); +} + +static int secp256k1_ge_is_valid_var(const secp256k1_ge_t *a) { + secp256k1_fe_t y2, x3, c; + if (a->infinity) { + return 0; + } + /* y^2 = x^3 + 7 */ + secp256k1_fe_sqr(&y2, &a->y); + secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x); + secp256k1_fe_set_int(&c, 7); + secp256k1_fe_add(&x3, &c); + secp256k1_fe_normalize_weak(&x3); + return secp256k1_fe_equal_var(&y2, &x3); +} + +static void secp256k1_gej_double_var(secp256k1_gej_t *r, const secp256k1_gej_t *a) { + /* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate */ + secp256k1_fe_t t1,t2,t3,t4; + /** For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity, + * Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have + * y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p. + */ + r->infinity = a->infinity; + if (r->infinity) { + return; + } + + secp256k1_fe_mul(&r->z, &a->z, &a->y); + secp256k1_fe_mul_int(&r->z, 2); /* Z' = 2*Y*Z (2) */ + secp256k1_fe_sqr(&t1, &a->x); + secp256k1_fe_mul_int(&t1, 3); /* T1 = 3*X^2 (3) */ + secp256k1_fe_sqr(&t2, &t1); /* T2 = 9*X^4 (1) */ + secp256k1_fe_sqr(&t3, &a->y); + secp256k1_fe_mul_int(&t3, 2); /* T3 = 2*Y^2 (2) */ + secp256k1_fe_sqr(&t4, &t3); + secp256k1_fe_mul_int(&t4, 2); /* T4 = 8*Y^4 (2) */ + secp256k1_fe_mul(&t3, &t3, &a->x); /* T3 = 2*X*Y^2 (1) */ + r->x = t3; + secp256k1_fe_mul_int(&r->x, 4); /* X' = 8*X*Y^2 (4) */ + secp256k1_fe_negate(&r->x, &r->x, 4); /* X' = -8*X*Y^2 (5) */ + secp256k1_fe_add(&r->x, &t2); /* X' = 9*X^4 - 8*X*Y^2 (6) */ + secp256k1_fe_negate(&t2, &t2, 1); /* T2 = -9*X^4 (2) */ + secp256k1_fe_mul_int(&t3, 6); /* T3 = 12*X*Y^2 (6) */ + secp256k1_fe_add(&t3, &t2); /* T3 = 12*X*Y^2 - 9*X^4 (8) */ + secp256k1_fe_mul(&r->y, &t1, &t3); /* Y' = 36*X^3*Y^2 - 27*X^6 (1) */ + secp256k1_fe_negate(&t2, &t4, 2); /* T2 = -8*Y^4 (3) */ + secp256k1_fe_add(&r->y, &t2); /* Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4) */ +} + +static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_gej_t *b) { + /* Operations: 12 mul, 4 sqr, 2 normalize, 12 mul_int/add/negate */ + secp256k1_fe_t z22, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; + if (a->infinity) { + *r = *b; + return; + } + if (b->infinity) { + *r = *a; + return; + } + r->infinity = 0; + secp256k1_fe_sqr(&z22, &b->z); + secp256k1_fe_sqr(&z12, &a->z); + secp256k1_fe_mul(&u1, &a->x, &z22); + secp256k1_fe_mul(&u2, &b->x, &z12); + secp256k1_fe_mul(&s1, &a->y, &z22); secp256k1_fe_mul(&s1, &s1, &b->z); + secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z); + secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); + secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2); + if (secp256k1_fe_normalizes_to_zero_var(&h)) { + if (secp256k1_fe_normalizes_to_zero_var(&i)) { + secp256k1_gej_double_var(r, a); + } else { + r->infinity = 1; + } + return; + } + secp256k1_fe_sqr(&i2, &i); + secp256k1_fe_sqr(&h2, &h); + secp256k1_fe_mul(&h3, &h, &h2); + secp256k1_fe_mul(&r->z, &a->z, &b->z); secp256k1_fe_mul(&r->z, &r->z, &h); + secp256k1_fe_mul(&t, &u1, &h2); + r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2); + secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i); + secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1); + secp256k1_fe_add(&r->y, &h3); +} + +static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b) { + /* 8 mul, 3 sqr, 4 normalize, 12 mul_int/add/negate */ + secp256k1_fe_t z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; + if (a->infinity) { + r->infinity = b->infinity; + r->x = b->x; + r->y = b->y; + secp256k1_fe_set_int(&r->z, 1); + return; + } + if (b->infinity) { + *r = *a; + return; + } + r->infinity = 0; + secp256k1_fe_sqr(&z12, &a->z); + u1 = a->x; secp256k1_fe_normalize_weak(&u1); + secp256k1_fe_mul(&u2, &b->x, &z12); + s1 = a->y; secp256k1_fe_normalize_weak(&s1); + secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &a->z); + secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); + secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2); + if (secp256k1_fe_normalizes_to_zero_var(&h)) { + if (secp256k1_fe_normalizes_to_zero_var(&i)) { + secp256k1_gej_double_var(r, a); + } else { + r->infinity = 1; + } + return; + } + secp256k1_fe_sqr(&i2, &i); + secp256k1_fe_sqr(&h2, &h); + secp256k1_fe_mul(&h3, &h, &h2); + r->z = a->z; secp256k1_fe_mul(&r->z, &r->z, &h); + secp256k1_fe_mul(&t, &u1, &h2); + r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2); + secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i); + secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1); + secp256k1_fe_add(&r->y, &h3); +} + +static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b) { + /* Operations: 7 mul, 5 sqr, 5 normalize, 17 mul_int/add/negate/cmov */ + static const secp256k1_fe_t fe_1 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); + secp256k1_fe_t zz, u1, u2, s1, s2, z, t, m, n, q, rr; + int infinity; + VERIFY_CHECK(!b->infinity); + VERIFY_CHECK(a->infinity == 0 || a->infinity == 1); + + /** In: + * Eric Brier and Marc Joye, Weierstrass Elliptic Curves and Side-Channel Attacks. + * In D. Naccache and P. Paillier, Eds., Public Key Cryptography, vol. 2274 of Lecture Notes in Computer Science, pages 335-345. Springer-Verlag, 2002. + * we find as solution for a unified addition/doubling formula: + * lambda = ((x1 + x2)^2 - x1 * x2 + a) / (y1 + y2), with a = 0 for secp256k1's curve equation. + * x3 = lambda^2 - (x1 + x2) + * 2*y3 = lambda * (x1 + x2 - 2 * x3) - (y1 + y2). + * + * Substituting x_i = Xi / Zi^2 and yi = Yi / Zi^3, for i=1,2,3, gives: + * U1 = X1*Z2^2, U2 = X2*Z1^2 + * S1 = Y1*Z2^3, S2 = Y2*Z1^3 + * Z = Z1*Z2 + * T = U1+U2 + * M = S1+S2 + * Q = T*M^2 + * R = T^2-U1*U2 + * X3 = 4*(R^2-Q) + * Y3 = 4*(R*(3*Q-2*R^2)-M^4) + * Z3 = 2*M*Z + * (Note that the paper uses xi = Xi / Zi and yi = Yi / Zi instead.) + */ + + secp256k1_fe_sqr(&zz, &a->z); /* z = Z1^2 */ + u1 = a->x; secp256k1_fe_normalize_weak(&u1); /* u1 = U1 = X1*Z2^2 (1) */ + secp256k1_fe_mul(&u2, &b->x, &zz); /* u2 = U2 = X2*Z1^2 (1) */ + s1 = a->y; secp256k1_fe_normalize_weak(&s1); /* s1 = S1 = Y1*Z2^3 (1) */ + secp256k1_fe_mul(&s2, &b->y, &zz); /* s2 = Y2*Z2^2 (1) */ + secp256k1_fe_mul(&s2, &s2, &a->z); /* s2 = S2 = Y2*Z1^3 (1) */ + z = a->z; /* z = Z = Z1*Z2 (8) */ + t = u1; secp256k1_fe_add(&t, &u2); /* t = T = U1+U2 (2) */ + m = s1; secp256k1_fe_add(&m, &s2); /* m = M = S1+S2 (2) */ + secp256k1_fe_sqr(&n, &m); /* n = M^2 (1) */ + secp256k1_fe_mul(&q, &n, &t); /* q = Q = T*M^2 (1) */ + secp256k1_fe_sqr(&n, &n); /* n = M^4 (1) */ + secp256k1_fe_sqr(&rr, &t); /* rr = T^2 (1) */ + secp256k1_fe_mul(&t, &u1, &u2); secp256k1_fe_negate(&t, &t, 1); /* t = -U1*U2 (2) */ + secp256k1_fe_add(&rr, &t); /* rr = R = T^2-U1*U2 (3) */ + secp256k1_fe_sqr(&t, &rr); /* t = R^2 (1) */ + secp256k1_fe_mul(&r->z, &m, &z); /* r->z = M*Z (1) */ + infinity = secp256k1_fe_normalizes_to_zero(&r->z) * (1 - a->infinity); + secp256k1_fe_mul_int(&r->z, 2 * (1 - a->infinity)); /* r->z = Z3 = 2*M*Z (2) */ + r->x = t; /* r->x = R^2 (1) */ + secp256k1_fe_negate(&q, &q, 1); /* q = -Q (2) */ + secp256k1_fe_add(&r->x, &q); /* r->x = R^2-Q (3) */ + secp256k1_fe_normalize(&r->x); + secp256k1_fe_mul_int(&q, 3); /* q = -3*Q (6) */ + secp256k1_fe_mul_int(&t, 2); /* t = 2*R^2 (2) */ + secp256k1_fe_add(&t, &q); /* t = 2*R^2-3*Q (8) */ + secp256k1_fe_mul(&t, &t, &rr); /* t = R*(2*R^2-3*Q) (1) */ + secp256k1_fe_add(&t, &n); /* t = R*(2*R^2-3*Q)+M^4 (2) */ + secp256k1_fe_negate(&r->y, &t, 2); /* r->y = R*(3*Q-2*R^2)-M^4 (3) */ + secp256k1_fe_normalize_weak(&r->y); + secp256k1_fe_mul_int(&r->x, 4 * (1 - a->infinity)); /* r->x = X3 = 4*(R^2-Q) */ + secp256k1_fe_mul_int(&r->y, 4 * (1 - a->infinity)); /* r->y = Y3 = 4*R*(3*Q-2*R^2)-4*M^4 (4) */ + + /** In case a->infinity == 1, the above code results in r->x, r->y, and r->z all equal to 0. + * Replace r with b->x, b->y, 1 in that case. + */ + secp256k1_fe_cmov(&r->x, &b->x, a->infinity); + secp256k1_fe_cmov(&r->y, &b->y, a->infinity); + secp256k1_fe_cmov(&r->z, &fe_1, a->infinity); + r->infinity = infinity; +} + +static void secp256k1_gej_rescale(secp256k1_gej_t *r, const secp256k1_fe_t *s) { + /* Operations: 4 mul, 1 sqr */ + secp256k1_fe_t zz; + VERIFY_CHECK(!secp256k1_fe_is_zero(s)); + secp256k1_fe_sqr(&zz, s); + secp256k1_fe_mul(&r->x, &r->x, &zz); /* r->x *= s^2 */ + secp256k1_fe_mul(&r->y, &r->y, &zz); + secp256k1_fe_mul(&r->y, &r->y, s); /* r->y *= s^3 */ + secp256k1_fe_mul(&r->z, &r->z, s); /* r->z *= s */ +} + +static void secp256k1_ge_to_storage(secp256k1_ge_storage_t *r, const secp256k1_ge_t *a) { + secp256k1_fe_t x, y; + VERIFY_CHECK(!a->infinity); + x = a->x; + secp256k1_fe_normalize(&x); + y = a->y; + secp256k1_fe_normalize(&y); + secp256k1_fe_to_storage(&r->x, &x); + secp256k1_fe_to_storage(&r->y, &y); +} + +static void secp256k1_ge_from_storage(secp256k1_ge_t *r, const secp256k1_ge_storage_t *a) { + secp256k1_fe_from_storage(&r->x, &a->x); + secp256k1_fe_from_storage(&r->y, &a->y); + r->infinity = 0; +} + +static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage_t *r, const secp256k1_ge_storage_t *a, int flag) { + secp256k1_fe_storage_cmov(&r->x, &a->x, flag); + secp256k1_fe_storage_cmov(&r->y, &a->y, flag); +} + +#ifdef USE_ENDOMORPHISM +static void secp256k1_gej_mul_lambda(secp256k1_gej_t *r, const secp256k1_gej_t *a) { + static const secp256k1_fe_t beta = SECP256K1_FE_CONST( + 0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul, + 0x9cf04975ul, 0x12f58995ul, 0xc1396c28ul, 0x719501eeul + ); + *r = *a; + secp256k1_fe_mul(&r->x, &r->x, &beta); +} +#endif + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/hash.h b/src/cryptoconditions/src/include/secp256k1/src/hash.h new file mode 100644 index 000000000..843423d7f --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/hash.h @@ -0,0 +1,41 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_HASH_ +#define _SECP256K1_HASH_ + +#include +#include + +typedef struct { + uint32_t s[32]; + uint32_t buf[16]; /* In big endian */ + size_t bytes; +} secp256k1_sha256_t; + +static void secp256k1_sha256_initialize(secp256k1_sha256_t *hash); +static void secp256k1_sha256_write(secp256k1_sha256_t *hash, const unsigned char *data, size_t size); +static void secp256k1_sha256_finalize(secp256k1_sha256_t *hash, unsigned char *out32); + +typedef struct { + secp256k1_sha256_t inner, outer; +} secp256k1_hmac_sha256_t; + +static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, const unsigned char *key, size_t size); +static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256_t *hash, const unsigned char *data, size_t size); +static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsigned char *out32); + +typedef struct { + unsigned char v[32]; + unsigned char k[32]; + int retry; +} secp256k1_rfc6979_hmac_sha256_t; + +static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen, const unsigned char *msg, size_t msglen, const unsigned char *rnd, size_t rndlen); +static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256_t *rng, unsigned char *out, size_t outlen); +static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256_t *rng); + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/hash_impl.h b/src/cryptoconditions/src/include/secp256k1/src/hash_impl.h new file mode 100644 index 000000000..9828827bc --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/hash_impl.h @@ -0,0 +1,293 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_HASH_IMPL_H_ +#define _SECP256K1_HASH_IMPL_H_ + +#include "hash.h" + +#include +#include +#include + +#define Ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) +#define Maj(x,y,z) (((x) & (y)) | ((z) & ((x) | (y)))) +#define Sigma0(x) (((x) >> 2 | (x) << 30) ^ ((x) >> 13 | (x) << 19) ^ ((x) >> 22 | (x) << 10)) +#define Sigma1(x) (((x) >> 6 | (x) << 26) ^ ((x) >> 11 | (x) << 21) ^ ((x) >> 25 | (x) << 7)) +#define sigma0(x) (((x) >> 7 | (x) << 25) ^ ((x) >> 18 | (x) << 14) ^ ((x) >> 3)) +#define sigma1(x) (((x) >> 17 | (x) << 15) ^ ((x) >> 19 | (x) << 13) ^ ((x) >> 10)) + +#define Round(a,b,c,d,e,f,g,h,k,w) do { \ + uint32_t t1 = (h) + Sigma1(e) + Ch((e), (f), (g)) + (k) + (w); \ + uint32_t t2 = Sigma0(a) + Maj((a), (b), (c)); \ + (d) += t1; \ + (h) = t1 + t2; \ +} while(0) + +#ifdef WORDS_BIGENDIAN +#define BE32(x) (x) +#else +#define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24)) +#endif + +static void secp256k1_sha256_initialize(secp256k1_sha256_t *hash) { + hash->s[0] = 0x6a09e667ul; + hash->s[1] = 0xbb67ae85ul; + hash->s[2] = 0x3c6ef372ul; + hash->s[3] = 0xa54ff53aul; + hash->s[4] = 0x510e527ful; + hash->s[5] = 0x9b05688cul; + hash->s[6] = 0x1f83d9abul; + hash->s[7] = 0x5be0cd19ul; + hash->bytes = 0; +} + +/** Perform one SHA-256 transformation, processing 16 big endian 32-bit words. */ +static void secp256k1_sha256_transform(uint32_t* s, const uint32_t* chunk) { + uint32_t a = s[0], b = s[1], c = s[2], d = s[3], e = s[4], f = s[5], g = s[6], h = s[7]; + uint32_t w0, w1, w2, w3, w4, w5, w6, w7, w8, w9, w10, w11, w12, w13, w14, w15; + + Round(a, b, c, d, e, f, g, h, 0x428a2f98, w0 = BE32(chunk[0])); + Round(h, a, b, c, d, e, f, g, 0x71374491, w1 = BE32(chunk[1])); + Round(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w2 = BE32(chunk[2])); + Round(f, g, h, a, b, c, d, e, 0xe9b5dba5, w3 = BE32(chunk[3])); + Round(e, f, g, h, a, b, c, d, 0x3956c25b, w4 = BE32(chunk[4])); + Round(d, e, f, g, h, a, b, c, 0x59f111f1, w5 = BE32(chunk[5])); + Round(c, d, e, f, g, h, a, b, 0x923f82a4, w6 = BE32(chunk[6])); + Round(b, c, d, e, f, g, h, a, 0xab1c5ed5, w7 = BE32(chunk[7])); + Round(a, b, c, d, e, f, g, h, 0xd807aa98, w8 = BE32(chunk[8])); + Round(h, a, b, c, d, e, f, g, 0x12835b01, w9 = BE32(chunk[9])); + Round(g, h, a, b, c, d, e, f, 0x243185be, w10 = BE32(chunk[10])); + Round(f, g, h, a, b, c, d, e, 0x550c7dc3, w11 = BE32(chunk[11])); + Round(e, f, g, h, a, b, c, d, 0x72be5d74, w12 = BE32(chunk[12])); + Round(d, e, f, g, h, a, b, c, 0x80deb1fe, w13 = BE32(chunk[13])); + Round(c, d, e, f, g, h, a, b, 0x9bdc06a7, w14 = BE32(chunk[14])); + Round(b, c, d, e, f, g, h, a, 0xc19bf174, w15 = BE32(chunk[15])); + + Round(a, b, c, d, e, f, g, h, 0xe49b69c1, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0xefbe4786, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0x0fc19dc6, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0x240ca1cc, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x2de92c6f, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x4a7484aa, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x5cb0a9dc, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x76f988da, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0x983e5152, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0xa831c66d, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0xb00327c8, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0xbf597fc7, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0xc6e00bf3, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0xd5a79147, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0x06ca6351, w14 += sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0x14292967, w15 += sigma1(w13) + w8 + sigma0(w0)); + + Round(a, b, c, d, e, f, g, h, 0x27b70a85, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0x2e1b2138, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0x4d2c6dfc, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0x53380d13, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x650a7354, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x766a0abb, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x81c2c92e, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x92722c85, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0xa2bfe8a1, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0xa81a664b, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0xc24b8b70, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0xc76c51a3, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0xd192e819, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0xd6990624, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0xf40e3585, w14 += sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0x106aa070, w15 += sigma1(w13) + w8 + sigma0(w0)); + + Round(a, b, c, d, e, f, g, h, 0x19a4c116, w0 += sigma1(w14) + w9 + sigma0(w1)); + Round(h, a, b, c, d, e, f, g, 0x1e376c08, w1 += sigma1(w15) + w10 + sigma0(w2)); + Round(g, h, a, b, c, d, e, f, 0x2748774c, w2 += sigma1(w0) + w11 + sigma0(w3)); + Round(f, g, h, a, b, c, d, e, 0x34b0bcb5, w3 += sigma1(w1) + w12 + sigma0(w4)); + Round(e, f, g, h, a, b, c, d, 0x391c0cb3, w4 += sigma1(w2) + w13 + sigma0(w5)); + Round(d, e, f, g, h, a, b, c, 0x4ed8aa4a, w5 += sigma1(w3) + w14 + sigma0(w6)); + Round(c, d, e, f, g, h, a, b, 0x5b9cca4f, w6 += sigma1(w4) + w15 + sigma0(w7)); + Round(b, c, d, e, f, g, h, a, 0x682e6ff3, w7 += sigma1(w5) + w0 + sigma0(w8)); + Round(a, b, c, d, e, f, g, h, 0x748f82ee, w8 += sigma1(w6) + w1 + sigma0(w9)); + Round(h, a, b, c, d, e, f, g, 0x78a5636f, w9 += sigma1(w7) + w2 + sigma0(w10)); + Round(g, h, a, b, c, d, e, f, 0x84c87814, w10 += sigma1(w8) + w3 + sigma0(w11)); + Round(f, g, h, a, b, c, d, e, 0x8cc70208, w11 += sigma1(w9) + w4 + sigma0(w12)); + Round(e, f, g, h, a, b, c, d, 0x90befffa, w12 += sigma1(w10) + w5 + sigma0(w13)); + Round(d, e, f, g, h, a, b, c, 0xa4506ceb, w13 += sigma1(w11) + w6 + sigma0(w14)); + Round(c, d, e, f, g, h, a, b, 0xbef9a3f7, w14 + sigma1(w12) + w7 + sigma0(w15)); + Round(b, c, d, e, f, g, h, a, 0xc67178f2, w15 + sigma1(w13) + w8 + sigma0(w0)); + + s[0] += a; + s[1] += b; + s[2] += c; + s[3] += d; + s[4] += e; + s[5] += f; + s[6] += g; + s[7] += h; +} + +static void secp256k1_sha256_write(secp256k1_sha256_t *hash, const unsigned char *data, size_t len) { + size_t bufsize = hash->bytes & 0x3F; + hash->bytes += len; + while (bufsize + len >= 64) { + /* Fill the buffer, and process it. */ + memcpy(((unsigned char*)hash->buf) + bufsize, data, 64 - bufsize); + data += 64 - bufsize; + len -= 64 - bufsize; + secp256k1_sha256_transform(hash->s, hash->buf); + bufsize = 0; + } + if (len) { + /* Fill the buffer with what remains. */ + memcpy(((unsigned char*)hash->buf) + bufsize, data, len); + } +} + +static void secp256k1_sha256_finalize(secp256k1_sha256_t *hash, unsigned char *out32) { + static const unsigned char pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + uint32_t sizedesc[2]; + uint32_t out[8]; + int i = 0; + sizedesc[0] = BE32(hash->bytes >> 29); + sizedesc[1] = BE32(hash->bytes << 3); + secp256k1_sha256_write(hash, pad, 1 + ((119 - (hash->bytes % 64)) % 64)); + secp256k1_sha256_write(hash, (const unsigned char*)sizedesc, 8); + for (i = 0; i < 8; i++) { + out[i] = BE32(hash->s[i]); + hash->s[i] = 0; + } + memcpy(out32, (const unsigned char*)out, 32); +} + +static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, const unsigned char *key, size_t keylen) { + int n; + unsigned char rkey[64]; + if (keylen <= 64) { + memcpy(rkey, key, keylen); + memset(rkey + keylen, 0, 64 - keylen); + } else { + secp256k1_sha256_t sha256; + secp256k1_sha256_initialize(&sha256); + secp256k1_sha256_write(&sha256, key, keylen); + secp256k1_sha256_finalize(&sha256, rkey); + memset(rkey + 32, 0, 32); + } + + secp256k1_sha256_initialize(&hash->outer); + for (n = 0; n < 64; n++) { + rkey[n] ^= 0x5c; + } + secp256k1_sha256_write(&hash->outer, rkey, 64); + + secp256k1_sha256_initialize(&hash->inner); + for (n = 0; n < 64; n++) { + rkey[n] ^= 0x5c ^ 0x36; + } + secp256k1_sha256_write(&hash->inner, rkey, 64); + memset(rkey, 0, 64); +} + +static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256_t *hash, const unsigned char *data, size_t size) { + secp256k1_sha256_write(&hash->inner, data, size); +} + +static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsigned char *out32) { + unsigned char temp[32]; + secp256k1_sha256_finalize(&hash->inner, temp); + secp256k1_sha256_write(&hash->outer, temp, 32); + memset(temp, 0, 32); + secp256k1_sha256_finalize(&hash->outer, out32); +} + + +static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen, const unsigned char *msg, size_t msglen, const unsigned char *rnd, size_t rndlen) { + secp256k1_hmac_sha256_t hmac; + static const unsigned char zero[1] = {0x00}; + static const unsigned char one[1] = {0x01}; + + memset(rng->v, 0x01, 32); /* RFC6979 3.2.b. */ + memset(rng->k, 0x00, 32); /* RFC6979 3.2.c. */ + + /* RFC6979 3.2.d. */ + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_write(&hmac, zero, 1); + secp256k1_hmac_sha256_write(&hmac, key, keylen); + secp256k1_hmac_sha256_write(&hmac, msg, msglen); + if (rnd && rndlen) { + /* RFC6979 3.6 "Additional data". */ + secp256k1_hmac_sha256_write(&hmac, rnd, rndlen); + } + secp256k1_hmac_sha256_finalize(&hmac, rng->k); + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_finalize(&hmac, rng->v); + + /* RFC6979 3.2.f. */ + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_write(&hmac, one, 1); + secp256k1_hmac_sha256_write(&hmac, key, keylen); + secp256k1_hmac_sha256_write(&hmac, msg, msglen); + if (rnd && rndlen) { + /* RFC6979 3.6 "Additional data". */ + secp256k1_hmac_sha256_write(&hmac, rnd, rndlen); + } + secp256k1_hmac_sha256_finalize(&hmac, rng->k); + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_finalize(&hmac, rng->v); + rng->retry = 0; +} + +static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256_t *rng, unsigned char *out, size_t outlen) { + /* RFC6979 3.2.h. */ + static const unsigned char zero[1] = {0x00}; + if (rng->retry) { + secp256k1_hmac_sha256_t hmac; + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_write(&hmac, zero, 1); + secp256k1_hmac_sha256_finalize(&hmac, rng->k); + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_finalize(&hmac, rng->v); + } + + while (outlen > 0) { + secp256k1_hmac_sha256_t hmac; + int now = outlen; + secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); + secp256k1_hmac_sha256_write(&hmac, rng->v, 32); + secp256k1_hmac_sha256_finalize(&hmac, rng->v); + if (now > 32) { + now = 32; + } + memcpy(out, rng->v, now); + out += now; + outlen -= now; + } + + rng->retry = 1; +} + +static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256_t *rng) { + memset(rng->k, 0, 32); + memset(rng->v, 0, 32); + rng->retry = 0; +} + + +#undef Round +#undef sigma0 +#undef sigma1 +#undef Sigma0 +#undef Sigma1 +#undef Ch +#undef Maj +#undef ReadBE32 +#undef WriteBE32 + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java b/src/cryptoconditions/src/include/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java new file mode 100644 index 000000000..90a498eaa --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java @@ -0,0 +1,60 @@ +package org.bitcoin; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +import com.google.common.base.Preconditions; + + +/** + * This class holds native methods to handle ECDSA verification. + * You can find an example library that can be used for this at + * https://github.com/sipa/secp256k1 + */ +public class NativeSecp256k1 { + public static final boolean enabled; + static { + boolean isEnabled = true; + try { + System.loadLibrary("javasecp256k1"); + } catch (UnsatisfiedLinkError e) { + isEnabled = false; + } + enabled = isEnabled; + } + + private static ThreadLocal nativeECDSABuffer = new ThreadLocal(); + /** + * Verifies the given secp256k1 signature in native code. + * Calling when enabled == false is undefined (probably library not loaded) + * + * @param data The data which was signed, must be exactly 32 bytes + * @param signature The signature + * @param pub The public key which did the signing + */ + public static boolean verify(byte[] data, byte[] signature, byte[] pub) { + Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null) { + byteBuff = ByteBuffer.allocateDirect(32 + 8 + 520 + 520); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(data); + byteBuff.putInt(signature.length); + byteBuff.putInt(pub.length); + byteBuff.put(signature); + byteBuff.put(pub); + return secp256k1_ecdsa_verify(byteBuff) == 1; + } + + /** + * @param byteBuff signature format is byte[32] data, + * native-endian int signatureLength, native-endian int pubkeyLength, + * byte[signatureLength] signature, byte[pubkeyLength] pub + * @returns 1 for valid signature, anything else for invalid + */ + private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff); +} diff --git a/src/cryptoconditions/src/include/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c b/src/cryptoconditions/src/include/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c new file mode 100644 index 000000000..bb4cd7072 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c @@ -0,0 +1,23 @@ +#include "org_bitcoin_NativeSecp256k1.h" +#include "include/secp256k1.h" + +JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify + (JNIEnv* env, jclass classObject, jobject byteBufferObject) +{ + unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + int sigLen = *((int*)(data + 32)); + int pubLen = *((int*)(data + 32 + 4)); + + return secp256k1_ecdsa_verify(data, 32, data+32+8, sigLen, data+32+8+sigLen, pubLen); +} + +static void __javasecp256k1_attach(void) __attribute__((constructor)); +static void __javasecp256k1_detach(void) __attribute__((destructor)); + +static void __javasecp256k1_attach(void) { + secp256k1_start(SECP256K1_START_VERIFY); +} + +static void __javasecp256k1_detach(void) { + secp256k1_stop(); +} diff --git a/src/cryptoconditions/src/include/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h b/src/cryptoconditions/src/include/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h new file mode 100644 index 000000000..d7fb004fa --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h @@ -0,0 +1,21 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class org_bitcoin_NativeSecp256k1 */ + +#ifndef _Included_org_bitcoin_NativeSecp256k1 +#define _Included_org_bitcoin_NativeSecp256k1 +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ecdsa_verify + * Signature: (Ljava/nio/ByteBuffer;)I + */ +JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify + (JNIEnv *, jclass, jobject); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/num.h b/src/cryptoconditions/src/include/secp256k1/src/num.h new file mode 100644 index 000000000..339b6bb6e --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/num.h @@ -0,0 +1,68 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_NUM_ +#define _SECP256K1_NUM_ + +#ifndef USE_NUM_NONE + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#if defined(USE_NUM_GMP) +#include "num_gmp.h" +#else +#error "Please select num implementation" +#endif + +/** Copy a number. */ +static void secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a); + +/** Convert a number's absolute value to a binary big-endian string. + * There must be enough place. */ +static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a); + +/** Set a number to the value of a binary big-endian string. */ +static void secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen); + +/** Compute a modular inverse. The input must be less than the modulus. */ +static void secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m); + +/** Compare the absolute value of two numbers. */ +static int secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b); + +/** Test whether two number are equal (including sign). */ +static int secp256k1_num_eq(const secp256k1_num_t *a, const secp256k1_num_t *b); + +/** Add two (signed) numbers. */ +static void secp256k1_num_add(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b); + +/** Subtract two (signed) numbers. */ +static void secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b); + +/** Multiply two (signed) numbers. */ +static void secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b); + +/** Replace a number by its remainder modulo m. M's sign is ignored. The result is a number between 0 and m-1, + even if r was negative. */ +static void secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m); + +/** Right-shift the passed number by bits bits. */ +static void secp256k1_num_shift(secp256k1_num_t *r, int bits); + +/** Check whether a number is zero. */ +static int secp256k1_num_is_zero(const secp256k1_num_t *a); + +/** Check whether a number is strictly negative. */ +static int secp256k1_num_is_neg(const secp256k1_num_t *a); + +/** Change a number's sign. */ +static void secp256k1_num_negate(secp256k1_num_t *r); + +#endif + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/num_gmp.h b/src/cryptoconditions/src/include/secp256k1/src/num_gmp.h new file mode 100644 index 000000000..baa1f2bf2 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/num_gmp.h @@ -0,0 +1,20 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_NUM_REPR_ +#define _SECP256K1_NUM_REPR_ + +#include + +#define NUM_LIMBS ((256+GMP_NUMB_BITS-1)/GMP_NUMB_BITS) + +typedef struct { + mp_limb_t data[2*NUM_LIMBS]; + int neg; + int limbs; +} secp256k1_num_t; + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/num_gmp_impl.h b/src/cryptoconditions/src/include/secp256k1/src/num_gmp_impl.h new file mode 100644 index 000000000..dbbc458d5 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/num_gmp_impl.h @@ -0,0 +1,260 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_NUM_REPR_IMPL_H_ +#define _SECP256K1_NUM_REPR_IMPL_H_ + +#include +#include +#include + +#include "util.h" +#include "num.h" + +#ifdef VERIFY +static void secp256k1_num_sanity(const secp256k1_num_t *a) { + VERIFY_CHECK(a->limbs == 1 || (a->limbs > 1 && a->data[a->limbs-1] != 0)); +} +#else +#define secp256k1_num_sanity(a) do { } while(0) +#endif + +static void secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a) { + *r = *a; +} + +static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a) { + unsigned char tmp[65]; + int len = 0; + int shift = 0; + if (a->limbs>1 || a->data[0] != 0) { + len = mpn_get_str(tmp, 256, (mp_limb_t*)a->data, a->limbs); + } + while (shift < len && tmp[shift] == 0) shift++; + VERIFY_CHECK(len-shift <= (int)rlen); + memset(r, 0, rlen - len + shift); + if (len > shift) { + memcpy(r + rlen - len + shift, tmp + shift, len - shift); + } + memset(tmp, 0, sizeof(tmp)); +} + +static void secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen) { + int len; + VERIFY_CHECK(alen > 0); + VERIFY_CHECK(alen <= 64); + len = mpn_set_str(r->data, a, alen, 256); + if (len == 0) { + r->data[0] = 0; + len = 1; + } + VERIFY_CHECK(len <= NUM_LIMBS*2); + r->limbs = len; + r->neg = 0; + while (r->limbs > 1 && r->data[r->limbs-1]==0) { + r->limbs--; + } +} + +static void secp256k1_num_add_abs(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { + mp_limb_t c = mpn_add(r->data, a->data, a->limbs, b->data, b->limbs); + r->limbs = a->limbs; + if (c != 0) { + VERIFY_CHECK(r->limbs < 2*NUM_LIMBS); + r->data[r->limbs++] = c; + } +} + +static void secp256k1_num_sub_abs(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { + mp_limb_t c = mpn_sub(r->data, a->data, a->limbs, b->data, b->limbs); + VERIFY_CHECK(c == 0); + r->limbs = a->limbs; + while (r->limbs > 1 && r->data[r->limbs-1]==0) { + r->limbs--; + } +} + +static void secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m) { + secp256k1_num_sanity(r); + secp256k1_num_sanity(m); + + if (r->limbs >= m->limbs) { + mp_limb_t t[2*NUM_LIMBS]; + mpn_tdiv_qr(t, r->data, 0, r->data, r->limbs, m->data, m->limbs); + memset(t, 0, sizeof(t)); + r->limbs = m->limbs; + while (r->limbs > 1 && r->data[r->limbs-1]==0) { + r->limbs--; + } + } + + if (r->neg && (r->limbs > 1 || r->data[0] != 0)) { + secp256k1_num_sub_abs(r, m, r); + r->neg = 0; + } +} + +static void secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m) { + int i; + mp_limb_t g[NUM_LIMBS+1]; + mp_limb_t u[NUM_LIMBS+1]; + mp_limb_t v[NUM_LIMBS+1]; + mp_size_t sn; + mp_size_t gn; + secp256k1_num_sanity(a); + secp256k1_num_sanity(m); + + /** mpn_gcdext computes: (G,S) = gcdext(U,V), where + * * G = gcd(U,V) + * * G = U*S + V*T + * * U has equal or more limbs than V, and V has no padding + * If we set U to be (a padded version of) a, and V = m: + * G = a*S + m*T + * G = a*S mod m + * Assuming G=1: + * S = 1/a mod m + */ + VERIFY_CHECK(m->limbs <= NUM_LIMBS); + VERIFY_CHECK(m->data[m->limbs-1] != 0); + for (i = 0; i < m->limbs; i++) { + u[i] = (i < a->limbs) ? a->data[i] : 0; + v[i] = m->data[i]; + } + sn = NUM_LIMBS+1; + gn = mpn_gcdext(g, r->data, &sn, u, m->limbs, v, m->limbs); + VERIFY_CHECK(gn == 1); + VERIFY_CHECK(g[0] == 1); + r->neg = a->neg ^ m->neg; + if (sn < 0) { + mpn_sub(r->data, m->data, m->limbs, r->data, -sn); + r->limbs = m->limbs; + while (r->limbs > 1 && r->data[r->limbs-1]==0) { + r->limbs--; + } + } else { + r->limbs = sn; + } + memset(g, 0, sizeof(g)); + memset(u, 0, sizeof(u)); + memset(v, 0, sizeof(v)); +} + +static int secp256k1_num_is_zero(const secp256k1_num_t *a) { + return (a->limbs == 1 && a->data[0] == 0); +} + +static int secp256k1_num_is_neg(const secp256k1_num_t *a) { + return (a->limbs > 1 || a->data[0] != 0) && a->neg; +} + +static int secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b) { + if (a->limbs > b->limbs) { + return 1; + } + if (a->limbs < b->limbs) { + return -1; + } + return mpn_cmp(a->data, b->data, a->limbs); +} + +static int secp256k1_num_eq(const secp256k1_num_t *a, const secp256k1_num_t *b) { + if (a->limbs > b->limbs) { + return 0; + } + if (a->limbs < b->limbs) { + return 0; + } + if ((a->neg && !secp256k1_num_is_zero(a)) != (b->neg && !secp256k1_num_is_zero(b))) { + return 0; + } + return mpn_cmp(a->data, b->data, a->limbs) == 0; +} + +static void secp256k1_num_subadd(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, int bneg) { + if (!(b->neg ^ bneg ^ a->neg)) { /* a and b have the same sign */ + r->neg = a->neg; + if (a->limbs >= b->limbs) { + secp256k1_num_add_abs(r, a, b); + } else { + secp256k1_num_add_abs(r, b, a); + } + } else { + if (secp256k1_num_cmp(a, b) > 0) { + r->neg = a->neg; + secp256k1_num_sub_abs(r, a, b); + } else { + r->neg = b->neg ^ bneg; + secp256k1_num_sub_abs(r, b, a); + } + } +} + +static void secp256k1_num_add(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { + secp256k1_num_sanity(a); + secp256k1_num_sanity(b); + secp256k1_num_subadd(r, a, b, 0); +} + +static void secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { + secp256k1_num_sanity(a); + secp256k1_num_sanity(b); + secp256k1_num_subadd(r, a, b, 1); +} + +static void secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { + mp_limb_t tmp[2*NUM_LIMBS+1]; + secp256k1_num_sanity(a); + secp256k1_num_sanity(b); + + VERIFY_CHECK(a->limbs + b->limbs <= 2*NUM_LIMBS+1); + if ((a->limbs==1 && a->data[0]==0) || (b->limbs==1 && b->data[0]==0)) { + r->limbs = 1; + r->neg = 0; + r->data[0] = 0; + return; + } + if (a->limbs >= b->limbs) { + mpn_mul(tmp, a->data, a->limbs, b->data, b->limbs); + } else { + mpn_mul(tmp, b->data, b->limbs, a->data, a->limbs); + } + r->limbs = a->limbs + b->limbs; + if (r->limbs > 1 && tmp[r->limbs - 1]==0) { + r->limbs--; + } + VERIFY_CHECK(r->limbs <= 2*NUM_LIMBS); + mpn_copyi(r->data, tmp, r->limbs); + r->neg = a->neg ^ b->neg; + memset(tmp, 0, sizeof(tmp)); +} + +static void secp256k1_num_shift(secp256k1_num_t *r, int bits) { + int i; + if (bits % GMP_NUMB_BITS) { + /* Shift within limbs. */ + mpn_rshift(r->data, r->data, r->limbs, bits % GMP_NUMB_BITS); + } + if (bits >= GMP_NUMB_BITS) { + /* Shift full limbs. */ + for (i = 0; i < r->limbs; i++) { + int index = i + (bits / GMP_NUMB_BITS); + if (index < r->limbs && index < 2*NUM_LIMBS) { + r->data[i] = r->data[index]; + } else { + r->data[i] = 0; + } + } + } + while (r->limbs>1 && r->data[r->limbs-1]==0) { + r->limbs--; + } +} + +static void secp256k1_num_negate(secp256k1_num_t *r) { + r->neg ^= 1; +} + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/num_impl.h b/src/cryptoconditions/src/include/secp256k1/src/num_impl.h new file mode 100644 index 000000000..0b0e3a072 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/num_impl.h @@ -0,0 +1,24 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_NUM_IMPL_H_ +#define _SECP256K1_NUM_IMPL_H_ + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#include "num.h" + +#if defined(USE_NUM_GMP) +#include "num_gmp_impl.h" +#elif defined(USE_NUM_NONE) +/* Nothing. */ +#else +#error "Please select num implementation" +#endif + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/scalar.h b/src/cryptoconditions/src/include/secp256k1/src/scalar.h new file mode 100644 index 000000000..f5d09f8d4 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/scalar.h @@ -0,0 +1,93 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_SCALAR_ +#define _SECP256K1_SCALAR_ + +#include "num.h" + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#if defined(USE_SCALAR_4X64) +#include "scalar_4x64.h" +#elif defined(USE_SCALAR_8X32) +#include "scalar_8x32.h" +#else +#error "Please select scalar implementation" +#endif + +/** Clear a scalar to prevent the leak of sensitive data. */ +static void secp256k1_scalar_clear(secp256k1_scalar_t *r); + +/** Access bits from a scalar. All requested bits must belong to the same 32-bit limb. */ +static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count); + +/** Access bits from a scalar. Not constant time. */ +static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count); + +/** Set a scalar from a big endian byte array. */ +static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *bin, int *overflow); + +/** Set a scalar to an unsigned integer. */ +static void secp256k1_scalar_set_int(secp256k1_scalar_t *r, unsigned int v); + +/** Convert a scalar to a byte array. */ +static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar_t* a); + +/** Add two scalars together (modulo the group order). Returns whether it overflowed. */ +static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b); + +/** Add a power of two to a scalar. The result is not allowed to overflow. */ +static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit); + +/** Multiply two scalars (modulo the group order). */ +static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b); + +/** Compute the square of a scalar (modulo the group order). */ +static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t *a); + +/** Compute the inverse of a scalar (modulo the group order). */ +static void secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scalar_t *a); + +/** Compute the inverse of a scalar (modulo the group order), without constant-time guarantee. */ +static void secp256k1_scalar_inverse_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *a); + +/** Compute the complement of a scalar (modulo the group order). */ +static void secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scalar_t *a); + +/** Check whether a scalar equals zero. */ +static int secp256k1_scalar_is_zero(const secp256k1_scalar_t *a); + +/** Check whether a scalar equals one. */ +static int secp256k1_scalar_is_one(const secp256k1_scalar_t *a); + +/** Check whether a scalar is higher than the group order divided by 2. */ +static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a); + +#ifndef USE_NUM_NONE +/** Convert a scalar to a number. */ +static void secp256k1_scalar_get_num(secp256k1_num_t *r, const secp256k1_scalar_t *a); + +/** Get the order of the group as a number. */ +static void secp256k1_scalar_order_get_num(secp256k1_num_t *r); +#endif + +/** Compare two scalars. */ +static int secp256k1_scalar_eq(const secp256k1_scalar_t *a, const secp256k1_scalar_t *b); + +#ifdef USE_ENDOMORPHISM +/** Find r1 and r2 such that r1+r2*2^128 = a. */ +static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a); +/** Find r1 and r2 such that r1+r2*lambda = a, and r1 and r2 are maximum 128 bits long (see secp256k1_gej_mul_lambda). */ +static void secp256k1_scalar_split_lambda_var(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a); +#endif + +/** Multiply a and b (without taking the modulus!), divide by 2**shift, and round to the nearest integer. Shift must be at least 256. */ +static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b, unsigned int shift); + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/scalar_4x64.h b/src/cryptoconditions/src/include/secp256k1/src/scalar_4x64.h new file mode 100644 index 000000000..82899aa7b --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/scalar_4x64.h @@ -0,0 +1,19 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_SCALAR_REPR_ +#define _SECP256K1_SCALAR_REPR_ + +#include + +/** A scalar modulo the group order of the secp256k1 curve. */ +typedef struct { + uint64_t d[4]; +} secp256k1_scalar_t; + +#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{((uint64_t)(d1)) << 32 | (d0), ((uint64_t)(d3)) << 32 | (d2), ((uint64_t)(d5)) << 32 | (d4), ((uint64_t)(d7)) << 32 | (d6)}} + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/scalar_4x64_impl.h b/src/cryptoconditions/src/include/secp256k1/src/scalar_4x64_impl.h new file mode 100644 index 000000000..ff365292f --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/scalar_4x64_impl.h @@ -0,0 +1,920 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_ +#define _SECP256K1_SCALAR_REPR_IMPL_H_ + +/* Limbs of the secp256k1 order. */ +#define SECP256K1_N_0 ((uint64_t)0xBFD25E8CD0364141ULL) +#define SECP256K1_N_1 ((uint64_t)0xBAAEDCE6AF48A03BULL) +#define SECP256K1_N_2 ((uint64_t)0xFFFFFFFFFFFFFFFEULL) +#define SECP256K1_N_3 ((uint64_t)0xFFFFFFFFFFFFFFFFULL) + +/* Limbs of 2^256 minus the secp256k1 order. */ +#define SECP256K1_N_C_0 (~SECP256K1_N_0 + 1) +#define SECP256K1_N_C_1 (~SECP256K1_N_1) +#define SECP256K1_N_C_2 (1) + +/* Limbs of half the secp256k1 order. */ +#define SECP256K1_N_H_0 ((uint64_t)0xDFE92F46681B20A0ULL) +#define SECP256K1_N_H_1 ((uint64_t)0x5D576E7357A4501DULL) +#define SECP256K1_N_H_2 ((uint64_t)0xFFFFFFFFFFFFFFFFULL) +#define SECP256K1_N_H_3 ((uint64_t)0x7FFFFFFFFFFFFFFFULL) + +SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar_t *r) { + r->d[0] = 0; + r->d[1] = 0; + r->d[2] = 0; + r->d[3] = 0; +} + +SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar_t *r, unsigned int v) { + r->d[0] = v; + r->d[1] = 0; + r->d[2] = 0; + r->d[3] = 0; +} + +SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count) { + VERIFY_CHECK((offset + count - 1) >> 6 == offset >> 6); + return (a->d[offset >> 6] >> (offset & 0x3F)) & ((((uint64_t)1) << count) - 1); +} + +SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count) { + VERIFY_CHECK(count < 32); + VERIFY_CHECK(offset + count <= 256); + if ((offset + count - 1) >> 6 == offset >> 6) { + return secp256k1_scalar_get_bits(a, offset, count); + } else { + VERIFY_CHECK((offset >> 6) + 1 < 4); + return ((a->d[offset >> 6] >> (offset & 0x3F)) | (a->d[(offset >> 6) + 1] << (64 - (offset & 0x3F)))) & ((((uint64_t)1) << count) - 1); + } +} + +SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar_t *a) { + int yes = 0; + int no = 0; + no |= (a->d[3] < SECP256K1_N_3); /* No need for a > check. */ + no |= (a->d[2] < SECP256K1_N_2); + yes |= (a->d[2] > SECP256K1_N_2) & ~no; + no |= (a->d[1] < SECP256K1_N_1); + yes |= (a->d[1] > SECP256K1_N_1) & ~no; + yes |= (a->d[0] >= SECP256K1_N_0) & ~no; + return yes; +} + +SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar_t *r, unsigned int overflow) { + uint128_t t; + VERIFY_CHECK(overflow <= 1); + t = (uint128_t)r->d[0] + overflow * SECP256K1_N_C_0; + r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint128_t)r->d[1] + overflow * SECP256K1_N_C_1; + r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint128_t)r->d[2] + overflow * SECP256K1_N_C_2; + r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint64_t)r->d[3]; + r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; + return overflow; +} + +static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { + int overflow; + uint128_t t = (uint128_t)a->d[0] + b->d[0]; + r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint128_t)a->d[1] + b->d[1]; + r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint128_t)a->d[2] + b->d[2]; + r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint128_t)a->d[3] + b->d[3]; + r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + overflow = t + secp256k1_scalar_check_overflow(r); + VERIFY_CHECK(overflow == 0 || overflow == 1); + secp256k1_scalar_reduce(r, overflow); + return overflow; +} + +static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit) { + uint128_t t; + VERIFY_CHECK(bit < 256); + t = (uint128_t)r->d[0] + (((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F)); + r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint128_t)r->d[1] + (((uint64_t)((bit >> 6) == 1)) << (bit & 0x3F)); + r->d[1] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint128_t)r->d[2] + (((uint64_t)((bit >> 6) == 2)) << (bit & 0x3F)); + r->d[2] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; + t += (uint128_t)r->d[3] + (((uint64_t)((bit >> 6) == 3)) << (bit & 0x3F)); + r->d[3] = t & 0xFFFFFFFFFFFFFFFFULL; +#ifdef VERIFY + VERIFY_CHECK((t >> 64) == 0); + VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0); +#endif +} + +static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *b32, int *overflow) { + int over; + r->d[0] = (uint64_t)b32[31] | (uint64_t)b32[30] << 8 | (uint64_t)b32[29] << 16 | (uint64_t)b32[28] << 24 | (uint64_t)b32[27] << 32 | (uint64_t)b32[26] << 40 | (uint64_t)b32[25] << 48 | (uint64_t)b32[24] << 56; + r->d[1] = (uint64_t)b32[23] | (uint64_t)b32[22] << 8 | (uint64_t)b32[21] << 16 | (uint64_t)b32[20] << 24 | (uint64_t)b32[19] << 32 | (uint64_t)b32[18] << 40 | (uint64_t)b32[17] << 48 | (uint64_t)b32[16] << 56; + r->d[2] = (uint64_t)b32[15] | (uint64_t)b32[14] << 8 | (uint64_t)b32[13] << 16 | (uint64_t)b32[12] << 24 | (uint64_t)b32[11] << 32 | (uint64_t)b32[10] << 40 | (uint64_t)b32[9] << 48 | (uint64_t)b32[8] << 56; + r->d[3] = (uint64_t)b32[7] | (uint64_t)b32[6] << 8 | (uint64_t)b32[5] << 16 | (uint64_t)b32[4] << 24 | (uint64_t)b32[3] << 32 | (uint64_t)b32[2] << 40 | (uint64_t)b32[1] << 48 | (uint64_t)b32[0] << 56; + over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r)); + if (overflow) { + *overflow = over; + } +} + +static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar_t* a) { + bin[0] = a->d[3] >> 56; bin[1] = a->d[3] >> 48; bin[2] = a->d[3] >> 40; bin[3] = a->d[3] >> 32; bin[4] = a->d[3] >> 24; bin[5] = a->d[3] >> 16; bin[6] = a->d[3] >> 8; bin[7] = a->d[3]; + bin[8] = a->d[2] >> 56; bin[9] = a->d[2] >> 48; bin[10] = a->d[2] >> 40; bin[11] = a->d[2] >> 32; bin[12] = a->d[2] >> 24; bin[13] = a->d[2] >> 16; bin[14] = a->d[2] >> 8; bin[15] = a->d[2]; + bin[16] = a->d[1] >> 56; bin[17] = a->d[1] >> 48; bin[18] = a->d[1] >> 40; bin[19] = a->d[1] >> 32; bin[20] = a->d[1] >> 24; bin[21] = a->d[1] >> 16; bin[22] = a->d[1] >> 8; bin[23] = a->d[1]; + bin[24] = a->d[0] >> 56; bin[25] = a->d[0] >> 48; bin[26] = a->d[0] >> 40; bin[27] = a->d[0] >> 32; bin[28] = a->d[0] >> 24; bin[29] = a->d[0] >> 16; bin[30] = a->d[0] >> 8; bin[31] = a->d[0]; +} + +SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar_t *a) { + return (a->d[0] | a->d[1] | a->d[2] | a->d[3]) == 0; +} + +static void secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) { + uint64_t nonzero = 0xFFFFFFFFFFFFFFFFULL * (secp256k1_scalar_is_zero(a) == 0); + uint128_t t = (uint128_t)(~a->d[0]) + SECP256K1_N_0 + 1; + r->d[0] = t & nonzero; t >>= 64; + t += (uint128_t)(~a->d[1]) + SECP256K1_N_1; + r->d[1] = t & nonzero; t >>= 64; + t += (uint128_t)(~a->d[2]) + SECP256K1_N_2; + r->d[2] = t & nonzero; t >>= 64; + t += (uint128_t)(~a->d[3]) + SECP256K1_N_3; + r->d[3] = t & nonzero; +} + +SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar_t *a) { + return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3]) == 0; +} + +static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) { + int yes = 0; + int no = 0; + no |= (a->d[3] < SECP256K1_N_H_3); + yes |= (a->d[3] > SECP256K1_N_H_3) & ~no; + no |= (a->d[2] < SECP256K1_N_H_2) & ~yes; /* No need for a > check. */ + no |= (a->d[1] < SECP256K1_N_H_1) & ~yes; + yes |= (a->d[1] > SECP256K1_N_H_1) & ~no; + yes |= (a->d[0] > SECP256K1_N_H_0) & ~no; + return yes; +} + +/* Inspired by the macros in OpenSSL's crypto/bn/asm/x86_64-gcc.c. */ + +/** Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define muladd(a,b) { \ + uint64_t tl, th; \ + { \ + uint128_t t = (uint128_t)a * b; \ + th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \ + tl = t; \ + } \ + c0 += tl; /* overflow is handled on the next line */ \ + th += (c0 < tl) ? 1 : 0; /* at most 0xFFFFFFFFFFFFFFFF */ \ + c1 += th; /* overflow is handled on the next line */ \ + c2 += (c1 < th) ? 1 : 0; /* never overflows by contract (verified in the next line) */ \ + VERIFY_CHECK((c1 >= th) || (c2 != 0)); \ +} + +/** Add a*b to the number defined by (c0,c1). c1 must never overflow. */ +#define muladd_fast(a,b) { \ + uint64_t tl, th; \ + { \ + uint128_t t = (uint128_t)a * b; \ + th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \ + tl = t; \ + } \ + c0 += tl; /* overflow is handled on the next line */ \ + th += (c0 < tl) ? 1 : 0; /* at most 0xFFFFFFFFFFFFFFFF */ \ + c1 += th; /* never overflows by contract (verified in the next line) */ \ + VERIFY_CHECK(c1 >= th); \ +} + +/** Add 2*a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define muladd2(a,b) { \ + uint64_t tl, th, th2, tl2; \ + { \ + uint128_t t = (uint128_t)a * b; \ + th = t >> 64; /* at most 0xFFFFFFFFFFFFFFFE */ \ + tl = t; \ + } \ + th2 = th + th; /* at most 0xFFFFFFFFFFFFFFFE (in case th was 0x7FFFFFFFFFFFFFFF) */ \ + c2 += (th2 < th) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((th2 >= th) || (c2 != 0)); \ + tl2 = tl + tl; /* at most 0xFFFFFFFFFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFFFFFFFFFF) */ \ + th2 += (tl2 < tl) ? 1 : 0; /* at most 0xFFFFFFFFFFFFFFFF */ \ + c0 += tl2; /* overflow is handled on the next line */ \ + th2 += (c0 < tl2) ? 1 : 0; /* second overflow is handled on the next line */ \ + c2 += (c0 < tl2) & (th2 == 0); /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c0 >= tl2) || (th2 != 0) || (c2 != 0)); \ + c1 += th2; /* overflow is handled on the next line */ \ + c2 += (c1 < th2) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c1 >= th2) || (c2 != 0)); \ +} + +/** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define sumadd(a) { \ + unsigned int over; \ + c0 += (a); /* overflow is handled on the next line */ \ + over = (c0 < (a)) ? 1 : 0; \ + c1 += over; /* overflow is handled on the next line */ \ + c2 += (c1 < over) ? 1 : 0; /* never overflows by contract */ \ +} + +/** Add a to the number defined by (c0,c1). c1 must never overflow, c2 must be zero. */ +#define sumadd_fast(a) { \ + c0 += (a); /* overflow is handled on the next line */ \ + c1 += (c0 < (a)) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c1 != 0) | (c0 >= (a))); \ + VERIFY_CHECK(c2 == 0); \ +} + +/** Extract the lowest 64 bits of (c0,c1,c2) into n, and left shift the number 64 bits. */ +#define extract(n) { \ + (n) = c0; \ + c0 = c1; \ + c1 = c2; \ + c2 = 0; \ +} + +/** Extract the lowest 64 bits of (c0,c1,c2) into n, and left shift the number 64 bits. c2 is required to be zero. */ +#define extract_fast(n) { \ + (n) = c0; \ + c0 = c1; \ + c1 = 0; \ + VERIFY_CHECK(c2 == 0); \ +} + +static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint64_t *l) { +#ifdef USE_ASM_X86_64 + /* Reduce 512 bits into 385. */ + uint64_t m0, m1, m2, m3, m4, m5, m6; + uint64_t p0, p1, p2, p3, p4; + uint64_t c; + + __asm__ __volatile__( + /* Preload. */ + "movq 32(%%rsi), %%r11\n" + "movq 40(%%rsi), %%r12\n" + "movq 48(%%rsi), %%r13\n" + "movq 56(%%rsi), %%r14\n" + /* Initialize r8,r9,r10 */ + "movq 0(%%rsi), %%r8\n" + "movq $0, %%r9\n" + "movq $0, %%r10\n" + /* (r8,r9) += n0 * c0 */ + "movq %8, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + /* extract m0 */ + "movq %%r8, %q0\n" + "movq $0, %%r8\n" + /* (r9,r10) += l1 */ + "addq 8(%%rsi), %%r9\n" + "adcq $0, %%r10\n" + /* (r9,r10,r8) += n1 * c0 */ + "movq %8, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += n0 * c1 */ + "movq %9, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* extract m1 */ + "movq %%r9, %q1\n" + "movq $0, %%r9\n" + /* (r10,r8,r9) += l2 */ + "addq 16(%%rsi), %%r10\n" + "adcq $0, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += n2 * c0 */ + "movq %8, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += n1 * c1 */ + "movq %9, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += n0 */ + "addq %%r11, %%r10\n" + "adcq $0, %%r8\n" + "adcq $0, %%r9\n" + /* extract m2 */ + "movq %%r10, %q2\n" + "movq $0, %%r10\n" + /* (r8,r9,r10) += l3 */ + "addq 24(%%rsi), %%r8\n" + "adcq $0, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += n3 * c0 */ + "movq %8, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += n2 * c1 */ + "movq %9, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += n1 */ + "addq %%r12, %%r8\n" + "adcq $0, %%r9\n" + "adcq $0, %%r10\n" + /* extract m3 */ + "movq %%r8, %q3\n" + "movq $0, %%r8\n" + /* (r9,r10,r8) += n3 * c1 */ + "movq %9, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += n2 */ + "addq %%r13, %%r9\n" + "adcq $0, %%r10\n" + "adcq $0, %%r8\n" + /* extract m4 */ + "movq %%r9, %q4\n" + /* (r10,r8) += n3 */ + "addq %%r14, %%r10\n" + "adcq $0, %%r8\n" + /* extract m5 */ + "movq %%r10, %q5\n" + /* extract m6 */ + "movq %%r8, %q6\n" + : "=g"(m0), "=g"(m1), "=g"(m2), "=g"(m3), "=g"(m4), "=g"(m5), "=g"(m6) + : "S"(l), "n"(SECP256K1_N_C_0), "n"(SECP256K1_N_C_1) + : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "cc"); + + /* Reduce 385 bits into 258. */ + __asm__ __volatile__( + /* Preload */ + "movq %q9, %%r11\n" + "movq %q10, %%r12\n" + "movq %q11, %%r13\n" + /* Initialize (r8,r9,r10) */ + "movq %q5, %%r8\n" + "movq $0, %%r9\n" + "movq $0, %%r10\n" + /* (r8,r9) += m4 * c0 */ + "movq %12, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + /* extract p0 */ + "movq %%r8, %q0\n" + "movq $0, %%r8\n" + /* (r9,r10) += m1 */ + "addq %q6, %%r9\n" + "adcq $0, %%r10\n" + /* (r9,r10,r8) += m5 * c0 */ + "movq %12, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += m4 * c1 */ + "movq %13, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* extract p1 */ + "movq %%r9, %q1\n" + "movq $0, %%r9\n" + /* (r10,r8,r9) += m2 */ + "addq %q7, %%r10\n" + "adcq $0, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += m6 * c0 */ + "movq %12, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += m5 * c1 */ + "movq %13, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += m4 */ + "addq %%r11, %%r10\n" + "adcq $0, %%r8\n" + "adcq $0, %%r9\n" + /* extract p2 */ + "movq %%r10, %q2\n" + /* (r8,r9) += m3 */ + "addq %q8, %%r8\n" + "adcq $0, %%r9\n" + /* (r8,r9) += m6 * c1 */ + "movq %13, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + /* (r8,r9) += m5 */ + "addq %%r12, %%r8\n" + "adcq $0, %%r9\n" + /* extract p3 */ + "movq %%r8, %q3\n" + /* (r9) += m6 */ + "addq %%r13, %%r9\n" + /* extract p4 */ + "movq %%r9, %q4\n" + : "=&g"(p0), "=&g"(p1), "=&g"(p2), "=g"(p3), "=g"(p4) + : "g"(m0), "g"(m1), "g"(m2), "g"(m3), "g"(m4), "g"(m5), "g"(m6), "n"(SECP256K1_N_C_0), "n"(SECP256K1_N_C_1) + : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "cc"); + + /* Reduce 258 bits into 256. */ + __asm__ __volatile__( + /* Preload */ + "movq %q5, %%r10\n" + /* (rax,rdx) = p4 * c0 */ + "movq %7, %%rax\n" + "mulq %%r10\n" + /* (rax,rdx) += p0 */ + "addq %q1, %%rax\n" + "adcq $0, %%rdx\n" + /* extract r0 */ + "movq %%rax, 0(%q6)\n" + /* Move to (r8,r9) */ + "movq %%rdx, %%r8\n" + "movq $0, %%r9\n" + /* (r8,r9) += p1 */ + "addq %q2, %%r8\n" + "adcq $0, %%r9\n" + /* (r8,r9) += p4 * c1 */ + "movq %8, %%rax\n" + "mulq %%r10\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + /* Extract r1 */ + "movq %%r8, 8(%q6)\n" + "movq $0, %%r8\n" + /* (r9,r8) += p4 */ + "addq %%r10, %%r9\n" + "adcq $0, %%r8\n" + /* (r9,r8) += p2 */ + "addq %q3, %%r9\n" + "adcq $0, %%r8\n" + /* Extract r2 */ + "movq %%r9, 16(%q6)\n" + "movq $0, %%r9\n" + /* (r8,r9) += p3 */ + "addq %q4, %%r8\n" + "adcq $0, %%r9\n" + /* Extract r3 */ + "movq %%r8, 24(%q6)\n" + /* Extract c */ + "movq %%r9, %q0\n" + : "=g"(c) + : "g"(p0), "g"(p1), "g"(p2), "g"(p3), "g"(p4), "D"(r), "n"(SECP256K1_N_C_0), "n"(SECP256K1_N_C_1) + : "rax", "rdx", "r8", "r9", "r10", "cc", "memory"); +#else + uint128_t c; + uint64_t c0, c1, c2; + uint64_t n0 = l[4], n1 = l[5], n2 = l[6], n3 = l[7]; + uint64_t m0, m1, m2, m3, m4, m5; + uint32_t m6; + uint64_t p0, p1, p2, p3; + uint32_t p4; + + /* Reduce 512 bits into 385. */ + /* m[0..6] = l[0..3] + n[0..3] * SECP256K1_N_C. */ + c0 = l[0]; c1 = 0; c2 = 0; + muladd_fast(n0, SECP256K1_N_C_0); + extract_fast(m0); + sumadd_fast(l[1]); + muladd(n1, SECP256K1_N_C_0); + muladd(n0, SECP256K1_N_C_1); + extract(m1); + sumadd(l[2]); + muladd(n2, SECP256K1_N_C_0); + muladd(n1, SECP256K1_N_C_1); + sumadd(n0); + extract(m2); + sumadd(l[3]); + muladd(n3, SECP256K1_N_C_0); + muladd(n2, SECP256K1_N_C_1); + sumadd(n1); + extract(m3); + muladd(n3, SECP256K1_N_C_1); + sumadd(n2); + extract(m4); + sumadd_fast(n3); + extract_fast(m5); + VERIFY_CHECK(c0 <= 1); + m6 = c0; + + /* Reduce 385 bits into 258. */ + /* p[0..4] = m[0..3] + m[4..6] * SECP256K1_N_C. */ + c0 = m0; c1 = 0; c2 = 0; + muladd_fast(m4, SECP256K1_N_C_0); + extract_fast(p0); + sumadd_fast(m1); + muladd(m5, SECP256K1_N_C_0); + muladd(m4, SECP256K1_N_C_1); + extract(p1); + sumadd(m2); + muladd(m6, SECP256K1_N_C_0); + muladd(m5, SECP256K1_N_C_1); + sumadd(m4); + extract(p2); + sumadd_fast(m3); + muladd_fast(m6, SECP256K1_N_C_1); + sumadd_fast(m5); + extract_fast(p3); + p4 = c0 + m6; + VERIFY_CHECK(p4 <= 2); + + /* Reduce 258 bits into 256. */ + /* r[0..3] = p[0..3] + p[4] * SECP256K1_N_C. */ + c = p0 + (uint128_t)SECP256K1_N_C_0 * p4; + r->d[0] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; + c += p1 + (uint128_t)SECP256K1_N_C_1 * p4; + r->d[1] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; + c += p2 + (uint128_t)p4; + r->d[2] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; + c += p3; + r->d[3] = c & 0xFFFFFFFFFFFFFFFFULL; c >>= 64; +#endif + + /* Final reduction of r. */ + secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r)); +} + +static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { +#ifdef USE_ASM_X86_64 + const uint64_t *pb = b->d; + __asm__ __volatile__( + /* Preload */ + "movq 0(%%rdi), %%r15\n" + "movq 8(%%rdi), %%rbx\n" + "movq 16(%%rdi), %%rcx\n" + "movq 0(%%rdx), %%r11\n" + "movq 8(%%rdx), %%r12\n" + "movq 16(%%rdx), %%r13\n" + "movq 24(%%rdx), %%r14\n" + /* (rax,rdx) = a0 * b0 */ + "movq %%r15, %%rax\n" + "mulq %%r11\n" + /* Extract l0 */ + "movq %%rax, 0(%%rsi)\n" + /* (r8,r9,r10) = (rdx) */ + "movq %%rdx, %%r8\n" + "xorq %%r9, %%r9\n" + "xorq %%r10, %%r10\n" + /* (r8,r9,r10) += a0 * b1 */ + "movq %%r15, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += a1 * b0 */ + "movq %%rbx, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* Extract l1 */ + "movq %%r8, 8(%%rsi)\n" + "xorq %%r8, %%r8\n" + /* (r9,r10,r8) += a0 * b2 */ + "movq %%r15, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += a1 * b1 */ + "movq %%rbx, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += a2 * b0 */ + "movq %%rcx, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* Extract l2 */ + "movq %%r9, 16(%%rsi)\n" + "xorq %%r9, %%r9\n" + /* (r10,r8,r9) += a0 * b3 */ + "movq %%r15, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* Preload a3 */ + "movq 24(%%rdi), %%r15\n" + /* (r10,r8,r9) += a1 * b2 */ + "movq %%rbx, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += a2 * b1 */ + "movq %%rcx, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += a3 * b0 */ + "movq %%r15, %%rax\n" + "mulq %%r11\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* Extract l3 */ + "movq %%r10, 24(%%rsi)\n" + "xorq %%r10, %%r10\n" + /* (r8,r9,r10) += a1 * b3 */ + "movq %%rbx, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += a2 * b2 */ + "movq %%rcx, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += a3 * b1 */ + "movq %%r15, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* Extract l4 */ + "movq %%r8, 32(%%rsi)\n" + "xorq %%r8, %%r8\n" + /* (r9,r10,r8) += a2 * b3 */ + "movq %%rcx, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += a3 * b2 */ + "movq %%r15, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* Extract l5 */ + "movq %%r9, 40(%%rsi)\n" + /* (r10,r8) += a3 * b3 */ + "movq %%r15, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + /* Extract l6 */ + "movq %%r10, 48(%%rsi)\n" + /* Extract l7 */ + "movq %%r8, 56(%%rsi)\n" + : "+d"(pb) + : "S"(l), "D"(a->d) + : "rax", "rbx", "rcx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "cc", "memory"); +#else + /* 160 bit accumulator. */ + uint64_t c0 = 0, c1 = 0; + uint32_t c2 = 0; + + /* l[0..7] = a[0..3] * b[0..3]. */ + muladd_fast(a->d[0], b->d[0]); + extract_fast(l[0]); + muladd(a->d[0], b->d[1]); + muladd(a->d[1], b->d[0]); + extract(l[1]); + muladd(a->d[0], b->d[2]); + muladd(a->d[1], b->d[1]); + muladd(a->d[2], b->d[0]); + extract(l[2]); + muladd(a->d[0], b->d[3]); + muladd(a->d[1], b->d[2]); + muladd(a->d[2], b->d[1]); + muladd(a->d[3], b->d[0]); + extract(l[3]); + muladd(a->d[1], b->d[3]); + muladd(a->d[2], b->d[2]); + muladd(a->d[3], b->d[1]); + extract(l[4]); + muladd(a->d[2], b->d[3]); + muladd(a->d[3], b->d[2]); + extract(l[5]); + muladd_fast(a->d[3], b->d[3]); + extract_fast(l[6]); + VERIFY_CHECK(c1 <= 0); + l[7] = c0; +#endif +} + +static void secp256k1_scalar_sqr_512(uint64_t l[8], const secp256k1_scalar_t *a) { +#ifdef USE_ASM_X86_64 + __asm__ __volatile__( + /* Preload */ + "movq 0(%%rdi), %%r11\n" + "movq 8(%%rdi), %%r12\n" + "movq 16(%%rdi), %%r13\n" + "movq 24(%%rdi), %%r14\n" + /* (rax,rdx) = a0 * a0 */ + "movq %%r11, %%rax\n" + "mulq %%r11\n" + /* Extract l0 */ + "movq %%rax, 0(%%rsi)\n" + /* (r8,r9,r10) = (rdx,0) */ + "movq %%rdx, %%r8\n" + "xorq %%r9, %%r9\n" + "xorq %%r10, %%r10\n" + /* (r8,r9,r10) += 2 * a0 * a1 */ + "movq %%r11, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* Extract l1 */ + "movq %%r8, 8(%%rsi)\n" + "xorq %%r8, %%r8\n" + /* (r9,r10,r8) += 2 * a0 * a2 */ + "movq %%r11, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* (r9,r10,r8) += a1 * a1 */ + "movq %%r12, %%rax\n" + "mulq %%r12\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* Extract l2 */ + "movq %%r9, 16(%%rsi)\n" + "xorq %%r9, %%r9\n" + /* (r10,r8,r9) += 2 * a0 * a3 */ + "movq %%r11, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* (r10,r8,r9) += 2 * a1 * a2 */ + "movq %%r12, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + "adcq $0, %%r9\n" + /* Extract l3 */ + "movq %%r10, 24(%%rsi)\n" + "xorq %%r10, %%r10\n" + /* (r8,r9,r10) += 2 * a1 * a3 */ + "movq %%r12, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* (r8,r9,r10) += a2 * a2 */ + "movq %%r13, %%rax\n" + "mulq %%r13\n" + "addq %%rax, %%r8\n" + "adcq %%rdx, %%r9\n" + "adcq $0, %%r10\n" + /* Extract l4 */ + "movq %%r8, 32(%%rsi)\n" + "xorq %%r8, %%r8\n" + /* (r9,r10,r8) += 2 * a2 * a3 */ + "movq %%r13, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + "addq %%rax, %%r9\n" + "adcq %%rdx, %%r10\n" + "adcq $0, %%r8\n" + /* Extract l5 */ + "movq %%r9, 40(%%rsi)\n" + /* (r10,r8) += a3 * a3 */ + "movq %%r14, %%rax\n" + "mulq %%r14\n" + "addq %%rax, %%r10\n" + "adcq %%rdx, %%r8\n" + /* Extract l6 */ + "movq %%r10, 48(%%rsi)\n" + /* Extract l7 */ + "movq %%r8, 56(%%rsi)\n" + : + : "S"(l), "D"(a->d) + : "rax", "rdx", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "cc", "memory"); +#else + /* 160 bit accumulator. */ + uint64_t c0 = 0, c1 = 0; + uint32_t c2 = 0; + + /* l[0..7] = a[0..3] * b[0..3]. */ + muladd_fast(a->d[0], a->d[0]); + extract_fast(l[0]); + muladd2(a->d[0], a->d[1]); + extract(l[1]); + muladd2(a->d[0], a->d[2]); + muladd(a->d[1], a->d[1]); + extract(l[2]); + muladd2(a->d[0], a->d[3]); + muladd2(a->d[1], a->d[2]); + extract(l[3]); + muladd2(a->d[1], a->d[3]); + muladd(a->d[2], a->d[2]); + extract(l[4]); + muladd2(a->d[2], a->d[3]); + extract(l[5]); + muladd_fast(a->d[3], a->d[3]); + extract_fast(l[6]); + VERIFY_CHECK(c1 == 0); + l[7] = c0; +#endif +} + +#undef sumadd +#undef sumadd_fast +#undef muladd +#undef muladd_fast +#undef muladd2 +#undef extract +#undef extract_fast + +static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { + uint64_t l[8]; + secp256k1_scalar_mul_512(l, a, b); + secp256k1_scalar_reduce_512(r, l); +} + +static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) { + uint64_t l[8]; + secp256k1_scalar_sqr_512(l, a); + secp256k1_scalar_reduce_512(r, l); +} + +static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a) { + r1->d[0] = a->d[0]; + r1->d[1] = a->d[1]; + r1->d[2] = 0; + r1->d[3] = 0; + r2->d[0] = a->d[2]; + r2->d[1] = a->d[3]; + r2->d[2] = 0; + r2->d[3] = 0; +} + +SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { + return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3])) == 0; +} + +SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b, unsigned int shift) { + uint64_t l[8]; + unsigned int shiftlimbs; + unsigned int shiftlow; + unsigned int shifthigh; + VERIFY_CHECK(shift >= 256); + secp256k1_scalar_mul_512(l, a, b); + shiftlimbs = shift >> 6; + shiftlow = shift & 0x3F; + shifthigh = 64 - shiftlow; + r->d[0] = shift < 512 ? (l[0 + shiftlimbs] >> shiftlow | (shift < 448 && shiftlow ? (l[1 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[1] = shift < 448 ? (l[1 + shiftlimbs] >> shiftlow | (shift < 384 && shiftlow ? (l[2 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[2] = shift < 384 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[3] = shift < 320 ? (l[3 + shiftlimbs] >> shiftlow) : 0; + if ((l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1) { + secp256k1_scalar_add_bit(r, 0); + } +} + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/scalar_8x32.h b/src/cryptoconditions/src/include/secp256k1/src/scalar_8x32.h new file mode 100644 index 000000000..f17017e24 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/scalar_8x32.h @@ -0,0 +1,19 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_SCALAR_REPR_ +#define _SECP256K1_SCALAR_REPR_ + +#include + +/** A scalar modulo the group order of the secp256k1 curve. */ +typedef struct { + uint32_t d[8]; +} secp256k1_scalar_t; + +#define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{(d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7)}} + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/scalar_8x32_impl.h b/src/cryptoconditions/src/include/secp256k1/src/scalar_8x32_impl.h new file mode 100644 index 000000000..22b31d411 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/scalar_8x32_impl.h @@ -0,0 +1,681 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_ +#define _SECP256K1_SCALAR_REPR_IMPL_H_ + +/* Limbs of the secp256k1 order. */ +#define SECP256K1_N_0 ((uint32_t)0xD0364141UL) +#define SECP256K1_N_1 ((uint32_t)0xBFD25E8CUL) +#define SECP256K1_N_2 ((uint32_t)0xAF48A03BUL) +#define SECP256K1_N_3 ((uint32_t)0xBAAEDCE6UL) +#define SECP256K1_N_4 ((uint32_t)0xFFFFFFFEUL) +#define SECP256K1_N_5 ((uint32_t)0xFFFFFFFFUL) +#define SECP256K1_N_6 ((uint32_t)0xFFFFFFFFUL) +#define SECP256K1_N_7 ((uint32_t)0xFFFFFFFFUL) + +/* Limbs of 2^256 minus the secp256k1 order. */ +#define SECP256K1_N_C_0 (~SECP256K1_N_0 + 1) +#define SECP256K1_N_C_1 (~SECP256K1_N_1) +#define SECP256K1_N_C_2 (~SECP256K1_N_2) +#define SECP256K1_N_C_3 (~SECP256K1_N_3) +#define SECP256K1_N_C_4 (1) + +/* Limbs of half the secp256k1 order. */ +#define SECP256K1_N_H_0 ((uint32_t)0x681B20A0UL) +#define SECP256K1_N_H_1 ((uint32_t)0xDFE92F46UL) +#define SECP256K1_N_H_2 ((uint32_t)0x57A4501DUL) +#define SECP256K1_N_H_3 ((uint32_t)0x5D576E73UL) +#define SECP256K1_N_H_4 ((uint32_t)0xFFFFFFFFUL) +#define SECP256K1_N_H_5 ((uint32_t)0xFFFFFFFFUL) +#define SECP256K1_N_H_6 ((uint32_t)0xFFFFFFFFUL) +#define SECP256K1_N_H_7 ((uint32_t)0x7FFFFFFFUL) + +SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar_t *r) { + r->d[0] = 0; + r->d[1] = 0; + r->d[2] = 0; + r->d[3] = 0; + r->d[4] = 0; + r->d[5] = 0; + r->d[6] = 0; + r->d[7] = 0; +} + +SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar_t *r, unsigned int v) { + r->d[0] = v; + r->d[1] = 0; + r->d[2] = 0; + r->d[3] = 0; + r->d[4] = 0; + r->d[5] = 0; + r->d[6] = 0; + r->d[7] = 0; +} + +SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count) { + VERIFY_CHECK((offset + count - 1) >> 5 == offset >> 5); + return (a->d[offset >> 5] >> (offset & 0x1F)) & ((1 << count) - 1); +} + +SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count) { + VERIFY_CHECK(count < 32); + VERIFY_CHECK(offset + count <= 256); + if ((offset + count - 1) >> 5 == offset >> 5) { + return secp256k1_scalar_get_bits(a, offset, count); + } else { + VERIFY_CHECK((offset >> 5) + 1 < 8); + return ((a->d[offset >> 5] >> (offset & 0x1F)) | (a->d[(offset >> 5) + 1] << (32 - (offset & 0x1F)))) & ((((uint32_t)1) << count) - 1); + } +} + +SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar_t *a) { + int yes = 0; + int no = 0; + no |= (a->d[7] < SECP256K1_N_7); /* No need for a > check. */ + no |= (a->d[6] < SECP256K1_N_6); /* No need for a > check. */ + no |= (a->d[5] < SECP256K1_N_5); /* No need for a > check. */ + no |= (a->d[4] < SECP256K1_N_4); + yes |= (a->d[4] > SECP256K1_N_4) & ~no; + no |= (a->d[3] < SECP256K1_N_3) & ~yes; + yes |= (a->d[3] > SECP256K1_N_3) & ~no; + no |= (a->d[2] < SECP256K1_N_2) & ~yes; + yes |= (a->d[2] > SECP256K1_N_2) & ~no; + no |= (a->d[1] < SECP256K1_N_1) & ~yes; + yes |= (a->d[1] > SECP256K1_N_1) & ~no; + yes |= (a->d[0] >= SECP256K1_N_0) & ~no; + return yes; +} + +SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar_t *r, uint32_t overflow) { + uint64_t t; + VERIFY_CHECK(overflow <= 1); + t = (uint64_t)r->d[0] + overflow * SECP256K1_N_C_0; + r->d[0] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[1] + overflow * SECP256K1_N_C_1; + r->d[1] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[2] + overflow * SECP256K1_N_C_2; + r->d[2] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[3] + overflow * SECP256K1_N_C_3; + r->d[3] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[4] + overflow * SECP256K1_N_C_4; + r->d[4] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[5]; + r->d[5] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[6]; + r->d[6] = t & 0xFFFFFFFFUL; t >>= 32; + t += (uint64_t)r->d[7]; + r->d[7] = t & 0xFFFFFFFFUL; + return overflow; +} + +static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { + int overflow; + uint64_t t = (uint64_t)a->d[0] + b->d[0]; + r->d[0] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[1] + b->d[1]; + r->d[1] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[2] + b->d[2]; + r->d[2] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[3] + b->d[3]; + r->d[3] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[4] + b->d[4]; + r->d[4] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[5] + b->d[5]; + r->d[5] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[6] + b->d[6]; + r->d[6] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)a->d[7] + b->d[7]; + r->d[7] = t & 0xFFFFFFFFULL; t >>= 32; + overflow = t + secp256k1_scalar_check_overflow(r); + VERIFY_CHECK(overflow == 0 || overflow == 1); + secp256k1_scalar_reduce(r, overflow); + return overflow; +} + +static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit) { + uint64_t t; + VERIFY_CHECK(bit < 256); + t = (uint64_t)r->d[0] + (((uint32_t)((bit >> 5) == 0)) << (bit & 0x1F)); + r->d[0] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)r->d[1] + (((uint32_t)((bit >> 5) == 1)) << (bit & 0x1F)); + r->d[1] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)r->d[2] + (((uint32_t)((bit >> 5) == 2)) << (bit & 0x1F)); + r->d[2] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)r->d[3] + (((uint32_t)((bit >> 5) == 3)) << (bit & 0x1F)); + r->d[3] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)r->d[4] + (((uint32_t)((bit >> 5) == 4)) << (bit & 0x1F)); + r->d[4] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)r->d[5] + (((uint32_t)((bit >> 5) == 5)) << (bit & 0x1F)); + r->d[5] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)r->d[6] + (((uint32_t)((bit >> 5) == 6)) << (bit & 0x1F)); + r->d[6] = t & 0xFFFFFFFFULL; t >>= 32; + t += (uint64_t)r->d[7] + (((uint32_t)((bit >> 5) == 7)) << (bit & 0x1F)); + r->d[7] = t & 0xFFFFFFFFULL; +#ifdef VERIFY + VERIFY_CHECK((t >> 32) == 0); + VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0); +#endif +} + +static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *b32, int *overflow) { + int over; + r->d[0] = (uint32_t)b32[31] | (uint32_t)b32[30] << 8 | (uint32_t)b32[29] << 16 | (uint32_t)b32[28] << 24; + r->d[1] = (uint32_t)b32[27] | (uint32_t)b32[26] << 8 | (uint32_t)b32[25] << 16 | (uint32_t)b32[24] << 24; + r->d[2] = (uint32_t)b32[23] | (uint32_t)b32[22] << 8 | (uint32_t)b32[21] << 16 | (uint32_t)b32[20] << 24; + r->d[3] = (uint32_t)b32[19] | (uint32_t)b32[18] << 8 | (uint32_t)b32[17] << 16 | (uint32_t)b32[16] << 24; + r->d[4] = (uint32_t)b32[15] | (uint32_t)b32[14] << 8 | (uint32_t)b32[13] << 16 | (uint32_t)b32[12] << 24; + r->d[5] = (uint32_t)b32[11] | (uint32_t)b32[10] << 8 | (uint32_t)b32[9] << 16 | (uint32_t)b32[8] << 24; + r->d[6] = (uint32_t)b32[7] | (uint32_t)b32[6] << 8 | (uint32_t)b32[5] << 16 | (uint32_t)b32[4] << 24; + r->d[7] = (uint32_t)b32[3] | (uint32_t)b32[2] << 8 | (uint32_t)b32[1] << 16 | (uint32_t)b32[0] << 24; + over = secp256k1_scalar_reduce(r, secp256k1_scalar_check_overflow(r)); + if (overflow) { + *overflow = over; + } +} + +static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar_t* a) { + bin[0] = a->d[7] >> 24; bin[1] = a->d[7] >> 16; bin[2] = a->d[7] >> 8; bin[3] = a->d[7]; + bin[4] = a->d[6] >> 24; bin[5] = a->d[6] >> 16; bin[6] = a->d[6] >> 8; bin[7] = a->d[6]; + bin[8] = a->d[5] >> 24; bin[9] = a->d[5] >> 16; bin[10] = a->d[5] >> 8; bin[11] = a->d[5]; + bin[12] = a->d[4] >> 24; bin[13] = a->d[4] >> 16; bin[14] = a->d[4] >> 8; bin[15] = a->d[4]; + bin[16] = a->d[3] >> 24; bin[17] = a->d[3] >> 16; bin[18] = a->d[3] >> 8; bin[19] = a->d[3]; + bin[20] = a->d[2] >> 24; bin[21] = a->d[2] >> 16; bin[22] = a->d[2] >> 8; bin[23] = a->d[2]; + bin[24] = a->d[1] >> 24; bin[25] = a->d[1] >> 16; bin[26] = a->d[1] >> 8; bin[27] = a->d[1]; + bin[28] = a->d[0] >> 24; bin[29] = a->d[0] >> 16; bin[30] = a->d[0] >> 8; bin[31] = a->d[0]; +} + +SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar_t *a) { + return (a->d[0] | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0; +} + +static void secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) { + uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(a) == 0); + uint64_t t = (uint64_t)(~a->d[0]) + SECP256K1_N_0 + 1; + r->d[0] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[1]) + SECP256K1_N_1; + r->d[1] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[2]) + SECP256K1_N_2; + r->d[2] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[3]) + SECP256K1_N_3; + r->d[3] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[4]) + SECP256K1_N_4; + r->d[4] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[5]) + SECP256K1_N_5; + r->d[5] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[6]) + SECP256K1_N_6; + r->d[6] = t & nonzero; t >>= 32; + t += (uint64_t)(~a->d[7]) + SECP256K1_N_7; + r->d[7] = t & nonzero; +} + +SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar_t *a) { + return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0; +} + +static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) { + int yes = 0; + int no = 0; + no |= (a->d[7] < SECP256K1_N_H_7); + yes |= (a->d[7] > SECP256K1_N_H_7) & ~no; + no |= (a->d[6] < SECP256K1_N_H_6) & ~yes; /* No need for a > check. */ + no |= (a->d[5] < SECP256K1_N_H_5) & ~yes; /* No need for a > check. */ + no |= (a->d[4] < SECP256K1_N_H_4) & ~yes; /* No need for a > check. */ + no |= (a->d[3] < SECP256K1_N_H_3) & ~yes; + yes |= (a->d[3] > SECP256K1_N_H_3) & ~no; + no |= (a->d[2] < SECP256K1_N_H_2) & ~yes; + yes |= (a->d[2] > SECP256K1_N_H_2) & ~no; + no |= (a->d[1] < SECP256K1_N_H_1) & ~yes; + yes |= (a->d[1] > SECP256K1_N_H_1) & ~no; + yes |= (a->d[0] > SECP256K1_N_H_0) & ~no; + return yes; +} + +/* Inspired by the macros in OpenSSL's crypto/bn/asm/x86_64-gcc.c. */ + +/** Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define muladd(a,b) { \ + uint32_t tl, th; \ + { \ + uint64_t t = (uint64_t)a * b; \ + th = t >> 32; /* at most 0xFFFFFFFE */ \ + tl = t; \ + } \ + c0 += tl; /* overflow is handled on the next line */ \ + th += (c0 < tl) ? 1 : 0; /* at most 0xFFFFFFFF */ \ + c1 += th; /* overflow is handled on the next line */ \ + c2 += (c1 < th) ? 1 : 0; /* never overflows by contract (verified in the next line) */ \ + VERIFY_CHECK((c1 >= th) || (c2 != 0)); \ +} + +/** Add a*b to the number defined by (c0,c1). c1 must never overflow. */ +#define muladd_fast(a,b) { \ + uint32_t tl, th; \ + { \ + uint64_t t = (uint64_t)a * b; \ + th = t >> 32; /* at most 0xFFFFFFFE */ \ + tl = t; \ + } \ + c0 += tl; /* overflow is handled on the next line */ \ + th += (c0 < tl) ? 1 : 0; /* at most 0xFFFFFFFF */ \ + c1 += th; /* never overflows by contract (verified in the next line) */ \ + VERIFY_CHECK(c1 >= th); \ +} + +/** Add 2*a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define muladd2(a,b) { \ + uint32_t tl, th, th2, tl2; \ + { \ + uint64_t t = (uint64_t)a * b; \ + th = t >> 32; /* at most 0xFFFFFFFE */ \ + tl = t; \ + } \ + th2 = th + th; /* at most 0xFFFFFFFE (in case th was 0x7FFFFFFF) */ \ + c2 += (th2 < th) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((th2 >= th) || (c2 != 0)); \ + tl2 = tl + tl; /* at most 0xFFFFFFFE (in case the lowest 63 bits of tl were 0x7FFFFFFF) */ \ + th2 += (tl2 < tl) ? 1 : 0; /* at most 0xFFFFFFFF */ \ + c0 += tl2; /* overflow is handled on the next line */ \ + th2 += (c0 < tl2) ? 1 : 0; /* second overflow is handled on the next line */ \ + c2 += (c0 < tl2) & (th2 == 0); /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c0 >= tl2) || (th2 != 0) || (c2 != 0)); \ + c1 += th2; /* overflow is handled on the next line */ \ + c2 += (c1 < th2) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c1 >= th2) || (c2 != 0)); \ +} + +/** Add a to the number defined by (c0,c1,c2). c2 must never overflow. */ +#define sumadd(a) { \ + unsigned int over; \ + c0 += (a); /* overflow is handled on the next line */ \ + over = (c0 < (a)) ? 1 : 0; \ + c1 += over; /* overflow is handled on the next line */ \ + c2 += (c1 < over) ? 1 : 0; /* never overflows by contract */ \ +} + +/** Add a to the number defined by (c0,c1). c1 must never overflow, c2 must be zero. */ +#define sumadd_fast(a) { \ + c0 += (a); /* overflow is handled on the next line */ \ + c1 += (c0 < (a)) ? 1 : 0; /* never overflows by contract (verified the next line) */ \ + VERIFY_CHECK((c1 != 0) | (c0 >= (a))); \ + VERIFY_CHECK(c2 == 0); \ +} + +/** Extract the lowest 32 bits of (c0,c1,c2) into n, and left shift the number 32 bits. */ +#define extract(n) { \ + (n) = c0; \ + c0 = c1; \ + c1 = c2; \ + c2 = 0; \ +} + +/** Extract the lowest 32 bits of (c0,c1,c2) into n, and left shift the number 32 bits. c2 is required to be zero. */ +#define extract_fast(n) { \ + (n) = c0; \ + c0 = c1; \ + c1 = 0; \ + VERIFY_CHECK(c2 == 0); \ +} + +static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint32_t *l) { + uint64_t c; + uint32_t n0 = l[8], n1 = l[9], n2 = l[10], n3 = l[11], n4 = l[12], n5 = l[13], n6 = l[14], n7 = l[15]; + uint32_t m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12; + uint32_t p0, p1, p2, p3, p4, p5, p6, p7, p8; + + /* 96 bit accumulator. */ + uint32_t c0, c1, c2; + + /* Reduce 512 bits into 385. */ + /* m[0..12] = l[0..7] + n[0..7] * SECP256K1_N_C. */ + c0 = l[0]; c1 = 0; c2 = 0; + muladd_fast(n0, SECP256K1_N_C_0); + extract_fast(m0); + sumadd_fast(l[1]); + muladd(n1, SECP256K1_N_C_0); + muladd(n0, SECP256K1_N_C_1); + extract(m1); + sumadd(l[2]); + muladd(n2, SECP256K1_N_C_0); + muladd(n1, SECP256K1_N_C_1); + muladd(n0, SECP256K1_N_C_2); + extract(m2); + sumadd(l[3]); + muladd(n3, SECP256K1_N_C_0); + muladd(n2, SECP256K1_N_C_1); + muladd(n1, SECP256K1_N_C_2); + muladd(n0, SECP256K1_N_C_3); + extract(m3); + sumadd(l[4]); + muladd(n4, SECP256K1_N_C_0); + muladd(n3, SECP256K1_N_C_1); + muladd(n2, SECP256K1_N_C_2); + muladd(n1, SECP256K1_N_C_3); + sumadd(n0); + extract(m4); + sumadd(l[5]); + muladd(n5, SECP256K1_N_C_0); + muladd(n4, SECP256K1_N_C_1); + muladd(n3, SECP256K1_N_C_2); + muladd(n2, SECP256K1_N_C_3); + sumadd(n1); + extract(m5); + sumadd(l[6]); + muladd(n6, SECP256K1_N_C_0); + muladd(n5, SECP256K1_N_C_1); + muladd(n4, SECP256K1_N_C_2); + muladd(n3, SECP256K1_N_C_3); + sumadd(n2); + extract(m6); + sumadd(l[7]); + muladd(n7, SECP256K1_N_C_0); + muladd(n6, SECP256K1_N_C_1); + muladd(n5, SECP256K1_N_C_2); + muladd(n4, SECP256K1_N_C_3); + sumadd(n3); + extract(m7); + muladd(n7, SECP256K1_N_C_1); + muladd(n6, SECP256K1_N_C_2); + muladd(n5, SECP256K1_N_C_3); + sumadd(n4); + extract(m8); + muladd(n7, SECP256K1_N_C_2); + muladd(n6, SECP256K1_N_C_3); + sumadd(n5); + extract(m9); + muladd(n7, SECP256K1_N_C_3); + sumadd(n6); + extract(m10); + sumadd_fast(n7); + extract_fast(m11); + VERIFY_CHECK(c0 <= 1); + m12 = c0; + + /* Reduce 385 bits into 258. */ + /* p[0..8] = m[0..7] + m[8..12] * SECP256K1_N_C. */ + c0 = m0; c1 = 0; c2 = 0; + muladd_fast(m8, SECP256K1_N_C_0); + extract_fast(p0); + sumadd_fast(m1); + muladd(m9, SECP256K1_N_C_0); + muladd(m8, SECP256K1_N_C_1); + extract(p1); + sumadd(m2); + muladd(m10, SECP256K1_N_C_0); + muladd(m9, SECP256K1_N_C_1); + muladd(m8, SECP256K1_N_C_2); + extract(p2); + sumadd(m3); + muladd(m11, SECP256K1_N_C_0); + muladd(m10, SECP256K1_N_C_1); + muladd(m9, SECP256K1_N_C_2); + muladd(m8, SECP256K1_N_C_3); + extract(p3); + sumadd(m4); + muladd(m12, SECP256K1_N_C_0); + muladd(m11, SECP256K1_N_C_1); + muladd(m10, SECP256K1_N_C_2); + muladd(m9, SECP256K1_N_C_3); + sumadd(m8); + extract(p4); + sumadd(m5); + muladd(m12, SECP256K1_N_C_1); + muladd(m11, SECP256K1_N_C_2); + muladd(m10, SECP256K1_N_C_3); + sumadd(m9); + extract(p5); + sumadd(m6); + muladd(m12, SECP256K1_N_C_2); + muladd(m11, SECP256K1_N_C_3); + sumadd(m10); + extract(p6); + sumadd_fast(m7); + muladd_fast(m12, SECP256K1_N_C_3); + sumadd_fast(m11); + extract_fast(p7); + p8 = c0 + m12; + VERIFY_CHECK(p8 <= 2); + + /* Reduce 258 bits into 256. */ + /* r[0..7] = p[0..7] + p[8] * SECP256K1_N_C. */ + c = p0 + (uint64_t)SECP256K1_N_C_0 * p8; + r->d[0] = c & 0xFFFFFFFFUL; c >>= 32; + c += p1 + (uint64_t)SECP256K1_N_C_1 * p8; + r->d[1] = c & 0xFFFFFFFFUL; c >>= 32; + c += p2 + (uint64_t)SECP256K1_N_C_2 * p8; + r->d[2] = c & 0xFFFFFFFFUL; c >>= 32; + c += p3 + (uint64_t)SECP256K1_N_C_3 * p8; + r->d[3] = c & 0xFFFFFFFFUL; c >>= 32; + c += p4 + (uint64_t)p8; + r->d[4] = c & 0xFFFFFFFFUL; c >>= 32; + c += p5; + r->d[5] = c & 0xFFFFFFFFUL; c >>= 32; + c += p6; + r->d[6] = c & 0xFFFFFFFFUL; c >>= 32; + c += p7; + r->d[7] = c & 0xFFFFFFFFUL; c >>= 32; + + /* Final reduction of r. */ + secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r)); +} + +static void secp256k1_scalar_mul_512(uint32_t *l, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { + /* 96 bit accumulator. */ + uint32_t c0 = 0, c1 = 0, c2 = 0; + + /* l[0..15] = a[0..7] * b[0..7]. */ + muladd_fast(a->d[0], b->d[0]); + extract_fast(l[0]); + muladd(a->d[0], b->d[1]); + muladd(a->d[1], b->d[0]); + extract(l[1]); + muladd(a->d[0], b->d[2]); + muladd(a->d[1], b->d[1]); + muladd(a->d[2], b->d[0]); + extract(l[2]); + muladd(a->d[0], b->d[3]); + muladd(a->d[1], b->d[2]); + muladd(a->d[2], b->d[1]); + muladd(a->d[3], b->d[0]); + extract(l[3]); + muladd(a->d[0], b->d[4]); + muladd(a->d[1], b->d[3]); + muladd(a->d[2], b->d[2]); + muladd(a->d[3], b->d[1]); + muladd(a->d[4], b->d[0]); + extract(l[4]); + muladd(a->d[0], b->d[5]); + muladd(a->d[1], b->d[4]); + muladd(a->d[2], b->d[3]); + muladd(a->d[3], b->d[2]); + muladd(a->d[4], b->d[1]); + muladd(a->d[5], b->d[0]); + extract(l[5]); + muladd(a->d[0], b->d[6]); + muladd(a->d[1], b->d[5]); + muladd(a->d[2], b->d[4]); + muladd(a->d[3], b->d[3]); + muladd(a->d[4], b->d[2]); + muladd(a->d[5], b->d[1]); + muladd(a->d[6], b->d[0]); + extract(l[6]); + muladd(a->d[0], b->d[7]); + muladd(a->d[1], b->d[6]); + muladd(a->d[2], b->d[5]); + muladd(a->d[3], b->d[4]); + muladd(a->d[4], b->d[3]); + muladd(a->d[5], b->d[2]); + muladd(a->d[6], b->d[1]); + muladd(a->d[7], b->d[0]); + extract(l[7]); + muladd(a->d[1], b->d[7]); + muladd(a->d[2], b->d[6]); + muladd(a->d[3], b->d[5]); + muladd(a->d[4], b->d[4]); + muladd(a->d[5], b->d[3]); + muladd(a->d[6], b->d[2]); + muladd(a->d[7], b->d[1]); + extract(l[8]); + muladd(a->d[2], b->d[7]); + muladd(a->d[3], b->d[6]); + muladd(a->d[4], b->d[5]); + muladd(a->d[5], b->d[4]); + muladd(a->d[6], b->d[3]); + muladd(a->d[7], b->d[2]); + extract(l[9]); + muladd(a->d[3], b->d[7]); + muladd(a->d[4], b->d[6]); + muladd(a->d[5], b->d[5]); + muladd(a->d[6], b->d[4]); + muladd(a->d[7], b->d[3]); + extract(l[10]); + muladd(a->d[4], b->d[7]); + muladd(a->d[5], b->d[6]); + muladd(a->d[6], b->d[5]); + muladd(a->d[7], b->d[4]); + extract(l[11]); + muladd(a->d[5], b->d[7]); + muladd(a->d[6], b->d[6]); + muladd(a->d[7], b->d[5]); + extract(l[12]); + muladd(a->d[6], b->d[7]); + muladd(a->d[7], b->d[6]); + extract(l[13]); + muladd_fast(a->d[7], b->d[7]); + extract_fast(l[14]); + VERIFY_CHECK(c1 == 0); + l[15] = c0; +} + +static void secp256k1_scalar_sqr_512(uint32_t *l, const secp256k1_scalar_t *a) { + /* 96 bit accumulator. */ + uint32_t c0 = 0, c1 = 0, c2 = 0; + + /* l[0..15] = a[0..7]^2. */ + muladd_fast(a->d[0], a->d[0]); + extract_fast(l[0]); + muladd2(a->d[0], a->d[1]); + extract(l[1]); + muladd2(a->d[0], a->d[2]); + muladd(a->d[1], a->d[1]); + extract(l[2]); + muladd2(a->d[0], a->d[3]); + muladd2(a->d[1], a->d[2]); + extract(l[3]); + muladd2(a->d[0], a->d[4]); + muladd2(a->d[1], a->d[3]); + muladd(a->d[2], a->d[2]); + extract(l[4]); + muladd2(a->d[0], a->d[5]); + muladd2(a->d[1], a->d[4]); + muladd2(a->d[2], a->d[3]); + extract(l[5]); + muladd2(a->d[0], a->d[6]); + muladd2(a->d[1], a->d[5]); + muladd2(a->d[2], a->d[4]); + muladd(a->d[3], a->d[3]); + extract(l[6]); + muladd2(a->d[0], a->d[7]); + muladd2(a->d[1], a->d[6]); + muladd2(a->d[2], a->d[5]); + muladd2(a->d[3], a->d[4]); + extract(l[7]); + muladd2(a->d[1], a->d[7]); + muladd2(a->d[2], a->d[6]); + muladd2(a->d[3], a->d[5]); + muladd(a->d[4], a->d[4]); + extract(l[8]); + muladd2(a->d[2], a->d[7]); + muladd2(a->d[3], a->d[6]); + muladd2(a->d[4], a->d[5]); + extract(l[9]); + muladd2(a->d[3], a->d[7]); + muladd2(a->d[4], a->d[6]); + muladd(a->d[5], a->d[5]); + extract(l[10]); + muladd2(a->d[4], a->d[7]); + muladd2(a->d[5], a->d[6]); + extract(l[11]); + muladd2(a->d[5], a->d[7]); + muladd(a->d[6], a->d[6]); + extract(l[12]); + muladd2(a->d[6], a->d[7]); + extract(l[13]); + muladd_fast(a->d[7], a->d[7]); + extract_fast(l[14]); + VERIFY_CHECK(c1 == 0); + l[15] = c0; +} + +#undef sumadd +#undef sumadd_fast +#undef muladd +#undef muladd_fast +#undef muladd2 +#undef extract +#undef extract_fast + +static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { + uint32_t l[16]; + secp256k1_scalar_mul_512(l, a, b); + secp256k1_scalar_reduce_512(r, l); +} + +static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) { + uint32_t l[16]; + secp256k1_scalar_sqr_512(l, a); + secp256k1_scalar_reduce_512(r, l); +} + +#ifdef USE_ENDOMORPHISM +static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a) { + r1->d[0] = a->d[0]; + r1->d[1] = a->d[1]; + r1->d[2] = a->d[2]; + r1->d[3] = a->d[3]; + r1->d[4] = 0; + r1->d[5] = 0; + r1->d[6] = 0; + r1->d[7] = 0; + r2->d[0] = a->d[4]; + r2->d[1] = a->d[5]; + r2->d[2] = a->d[6]; + r2->d[3] = a->d[7]; + r2->d[4] = 0; + r2->d[5] = 0; + r2->d[6] = 0; + r2->d[7] = 0; +} +#endif + +SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { + return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3]) | (a->d[4] ^ b->d[4]) | (a->d[5] ^ b->d[5]) | (a->d[6] ^ b->d[6]) | (a->d[7] ^ b->d[7])) == 0; +} + +SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b, unsigned int shift) { + uint32_t l[16]; + unsigned int shiftlimbs; + unsigned int shiftlow; + unsigned int shifthigh; + VERIFY_CHECK(shift >= 256); + secp256k1_scalar_mul_512(l, a, b); + shiftlimbs = shift >> 5; + shiftlow = shift & 0x1F; + shifthigh = 32 - shiftlow; + r->d[0] = shift < 512 ? (l[0 + shiftlimbs] >> shiftlow | (shift < 480 && shiftlow ? (l[1 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[1] = shift < 480 ? (l[1 + shiftlimbs] >> shiftlow | (shift < 448 && shiftlow ? (l[2 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[2] = shift < 448 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 416 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[3] = shift < 416 ? (l[3 + shiftlimbs] >> shiftlow | (shift < 384 && shiftlow ? (l[4 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[4] = shift < 384 ? (l[4 + shiftlimbs] >> shiftlow | (shift < 352 && shiftlow ? (l[5 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[5] = shift < 352 ? (l[5 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[6 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[6] = shift < 320 ? (l[6 + shiftlimbs] >> shiftlow | (shift < 288 && shiftlow ? (l[7 + shiftlimbs] << shifthigh) : 0)) : 0; + r->d[7] = shift < 288 ? (l[7 + shiftlimbs] >> shiftlow) : 0; + if ((l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1) { + secp256k1_scalar_add_bit(r, 0); + } +} + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/scalar_impl.h b/src/cryptoconditions/src/include/secp256k1/src/scalar_impl.h new file mode 100644 index 000000000..33824983e --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/scalar_impl.h @@ -0,0 +1,327 @@ +/********************************************************************** + * Copyright (c) 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_SCALAR_IMPL_H_ +#define _SECP256K1_SCALAR_IMPL_H_ + +#include + +#include "group.h" +#include "scalar.h" + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#if defined(USE_SCALAR_4X64) +#include "scalar_4x64_impl.h" +#elif defined(USE_SCALAR_8X32) +#include "scalar_8x32_impl.h" +#else +#error "Please select scalar implementation" +#endif + +#ifndef USE_NUM_NONE +static void secp256k1_scalar_get_num(secp256k1_num_t *r, const secp256k1_scalar_t *a) { + unsigned char c[32]; + secp256k1_scalar_get_b32(c, a); + secp256k1_num_set_bin(r, c, 32); +} + +/** secp256k1 curve order, see secp256k1_ecdsa_const_order_as_fe in ecdsa_impl.h */ +static void secp256k1_scalar_order_get_num(secp256k1_num_t *r) { + static const unsigned char order[32] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, + 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B, + 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41 + }; + secp256k1_num_set_bin(r, order, 32); +} +#endif + +static void secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scalar_t *x) { + secp256k1_scalar_t *t; + int i; + /* First compute x ^ (2^N - 1) for some values of N. */ + secp256k1_scalar_t x2, x3, x4, x6, x7, x8, x15, x30, x60, x120, x127; + + secp256k1_scalar_sqr(&x2, x); + secp256k1_scalar_mul(&x2, &x2, x); + + secp256k1_scalar_sqr(&x3, &x2); + secp256k1_scalar_mul(&x3, &x3, x); + + secp256k1_scalar_sqr(&x4, &x3); + secp256k1_scalar_mul(&x4, &x4, x); + + secp256k1_scalar_sqr(&x6, &x4); + secp256k1_scalar_sqr(&x6, &x6); + secp256k1_scalar_mul(&x6, &x6, &x2); + + secp256k1_scalar_sqr(&x7, &x6); + secp256k1_scalar_mul(&x7, &x7, x); + + secp256k1_scalar_sqr(&x8, &x7); + secp256k1_scalar_mul(&x8, &x8, x); + + secp256k1_scalar_sqr(&x15, &x8); + for (i = 0; i < 6; i++) { + secp256k1_scalar_sqr(&x15, &x15); + } + secp256k1_scalar_mul(&x15, &x15, &x7); + + secp256k1_scalar_sqr(&x30, &x15); + for (i = 0; i < 14; i++) { + secp256k1_scalar_sqr(&x30, &x30); + } + secp256k1_scalar_mul(&x30, &x30, &x15); + + secp256k1_scalar_sqr(&x60, &x30); + for (i = 0; i < 29; i++) { + secp256k1_scalar_sqr(&x60, &x60); + } + secp256k1_scalar_mul(&x60, &x60, &x30); + + secp256k1_scalar_sqr(&x120, &x60); + for (i = 0; i < 59; i++) { + secp256k1_scalar_sqr(&x120, &x120); + } + secp256k1_scalar_mul(&x120, &x120, &x60); + + secp256k1_scalar_sqr(&x127, &x120); + for (i = 0; i < 6; i++) { + secp256k1_scalar_sqr(&x127, &x127); + } + secp256k1_scalar_mul(&x127, &x127, &x7); + + /* Then accumulate the final result (t starts at x127). */ + t = &x127; + for (i = 0; i < 2; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 4; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x3); /* 111 */ + for (i = 0; i < 2; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 2; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 2; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 4; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x3); /* 111 */ + for (i = 0; i < 3; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x2); /* 11 */ + for (i = 0; i < 4; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x3); /* 111 */ + for (i = 0; i < 5; i++) { /* 00 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x3); /* 111 */ + for (i = 0; i < 4; i++) { /* 00 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x2); /* 11 */ + for (i = 0; i < 2; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 2; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 5; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x4); /* 1111 */ + for (i = 0; i < 2; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 3; i++) { /* 00 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 4; i++) { /* 000 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 2; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 10; i++) { /* 0000000 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x3); /* 111 */ + for (i = 0; i < 4; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x3); /* 111 */ + for (i = 0; i < 9; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x8); /* 11111111 */ + for (i = 0; i < 2; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 3; i++) { /* 00 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 3; i++) { /* 00 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 5; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x4); /* 1111 */ + for (i = 0; i < 2; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 5; i++) { /* 000 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x2); /* 11 */ + for (i = 0; i < 4; i++) { /* 00 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x2); /* 11 */ + for (i = 0; i < 2; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 8; i++) { /* 000000 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x2); /* 11 */ + for (i = 0; i < 3; i++) { /* 0 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &x2); /* 11 */ + for (i = 0; i < 3; i++) { /* 00 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 6; i++) { /* 00000 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, x); /* 1 */ + for (i = 0; i < 8; i++) { /* 00 */ + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(r, t, &x6); /* 111111 */ +} + +static void secp256k1_scalar_inverse_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *x) { +#if defined(USE_SCALAR_INV_BUILTIN) + secp256k1_scalar_inverse(r, x); +#elif defined(USE_SCALAR_INV_NUM) + unsigned char b[32]; + secp256k1_num_t n, m; + secp256k1_scalar_get_b32(b, x); + secp256k1_num_set_bin(&n, b, 32); + secp256k1_scalar_order_get_num(&m); + secp256k1_num_mod_inverse(&n, &n, &m); + secp256k1_num_get_bin(b, 32, &n); + secp256k1_scalar_set_b32(r, b, NULL); +#else +#error "Please select scalar inverse implementation" +#endif +} + +#ifdef USE_ENDOMORPHISM +/** + * The Secp256k1 curve has an endomorphism, where lambda * (x, y) = (beta * x, y), where + * lambda is {0x53,0x63,0xad,0x4c,0xc0,0x5c,0x30,0xe0,0xa5,0x26,0x1c,0x02,0x88,0x12,0x64,0x5a, + * 0x12,0x2e,0x22,0xea,0x20,0x81,0x66,0x78,0xdf,0x02,0x96,0x7c,0x1b,0x23,0xbd,0x72} + * + * "Guide to Elliptic Curve Cryptography" (Hankerson, Menezes, Vanstone) gives an algorithm + * (algorithm 3.74) to find k1 and k2 given k, such that k1 + k2 * lambda == k mod n, and k1 + * and k2 have a small size. + * It relies on constants a1, b1, a2, b2. These constants for the value of lambda above are: + * + * - a1 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15} + * - b1 = -{0xe4,0x43,0x7e,0xd6,0x01,0x0e,0x88,0x28,0x6f,0x54,0x7f,0xa9,0x0a,0xbf,0xe4,0xc3} + * - a2 = {0x01,0x14,0xca,0x50,0xf7,0xa8,0xe2,0xf3,0xf6,0x57,0xc1,0x10,0x8d,0x9d,0x44,0xcf,0xd8} + * - b2 = {0x30,0x86,0xd2,0x21,0xa7,0xd4,0x6b,0xcd,0xe8,0x6c,0x90,0xe4,0x92,0x84,0xeb,0x15} + * + * The algorithm then computes c1 = round(b1 * k / n) and c2 = round(b2 * k / n), and gives + * k1 = k - (c1*a1 + c2*a2) and k2 = -(c1*b1 + c2*b2). Instead, we use modular arithmetic, and + * compute k1 as k - k2 * lambda, avoiding the need for constants a1 and a2. + * + * g1, g2 are precomputed constants used to replace division with a rounded multiplication + * when decomposing the scalar for an endomorphism-based point multiplication. + * + * The possibility of using precomputed estimates is mentioned in "Guide to Elliptic Curve + * Cryptography" (Hankerson, Menezes, Vanstone) in section 3.5. + * + * The derivation is described in the paper "Efficient Software Implementation of Public-Key + * Cryptography on Sensor Networks Using the MSP430X Microcontroller" (Gouvea, Oliveira, Lopez), + * Section 4.3 (here we use a somewhat higher-precision estimate): + * d = a1*b2 - b1*a2 + * g1 = round((2^272)*b2/d) + * g2 = round((2^272)*b1/d) + * + * (Note that 'd' is also equal to the curve order here because [a1,b1] and [a2,b2] are found + * as outputs of the Extended Euclidean Algorithm on inputs 'order' and 'lambda'). + * + * The function below splits a in r1 and r2, such that r1 + lambda * r2 == a (mod order). + */ + +static void secp256k1_scalar_split_lambda_var(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a) { + secp256k1_scalar_t c1, c2; + static const secp256k1_scalar_t minus_lambda = SECP256K1_SCALAR_CONST( + 0xAC9C52B3UL, 0x3FA3CF1FUL, 0x5AD9E3FDUL, 0x77ED9BA4UL, + 0xA880B9FCUL, 0x8EC739C2UL, 0xE0CFC810UL, 0xB51283CFUL + ); + static const secp256k1_scalar_t minus_b1 = SECP256K1_SCALAR_CONST( + 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL, + 0xE4437ED6UL, 0x010E8828UL, 0x6F547FA9UL, 0x0ABFE4C3UL + ); + static const secp256k1_scalar_t minus_b2 = SECP256K1_SCALAR_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, + 0x8A280AC5UL, 0x0774346DUL, 0xD765CDA8UL, 0x3DB1562CUL + ); + static const secp256k1_scalar_t g1 = SECP256K1_SCALAR_CONST( + 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00003086UL, + 0xD221A7D4UL, 0x6BCDE86CUL, 0x90E49284UL, 0xEB153DABUL + ); + static const secp256k1_scalar_t g2 = SECP256K1_SCALAR_CONST( + 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x0000E443UL, + 0x7ED6010EUL, 0x88286F54UL, 0x7FA90ABFUL, 0xE4C42212UL + ); + VERIFY_CHECK(r1 != a); + VERIFY_CHECK(r2 != a); + secp256k1_scalar_mul_shift_var(&c1, a, &g1, 272); + secp256k1_scalar_mul_shift_var(&c2, a, &g2, 272); + secp256k1_scalar_mul(&c1, &c1, &minus_b1); + secp256k1_scalar_mul(&c2, &c2, &minus_b2); + secp256k1_scalar_add(r2, &c1, &c2); + secp256k1_scalar_mul(r1, r2, &minus_lambda); + secp256k1_scalar_add(r1, r1, a); +} +#endif + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/secp256k1.c b/src/cryptoconditions/src/include/secp256k1/src/secp256k1.c new file mode 100644 index 000000000..d6192dc4e --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/secp256k1.c @@ -0,0 +1,419 @@ +/********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#define SECP256K1_BUILD (1) + +#include "include/secp256k1.h" + +#include "util.h" +#include "num_impl.h" +#include "field_impl.h" +#include "scalar_impl.h" +#include "group_impl.h" +#include "ecmult_impl.h" +#include "ecmult_gen_impl.h" +#include "ecdsa_impl.h" +#include "eckey_impl.h" +#include "hash_impl.h" + +struct secp256k1_context_struct { + secp256k1_ecmult_context_t ecmult_ctx; + secp256k1_ecmult_gen_context_t ecmult_gen_ctx; +}; + +secp256k1_context_t* secp256k1_context_create(int flags) { + secp256k1_context_t* ret = (secp256k1_context_t*)checked_malloc(sizeof(secp256k1_context_t)); + + secp256k1_ecmult_context_init(&ret->ecmult_ctx); + secp256k1_ecmult_gen_context_init(&ret->ecmult_gen_ctx); + + if (flags & SECP256K1_CONTEXT_SIGN) { + secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx); + } + if (flags & SECP256K1_CONTEXT_VERIFY) { + secp256k1_ecmult_context_build(&ret->ecmult_ctx); + } + + return ret; +} + +secp256k1_context_t* secp256k1_context_clone(const secp256k1_context_t* ctx) { + secp256k1_context_t* ret = (secp256k1_context_t*)checked_malloc(sizeof(secp256k1_context_t)); + secp256k1_ecmult_context_clone(&ret->ecmult_ctx, &ctx->ecmult_ctx); + secp256k1_ecmult_gen_context_clone(&ret->ecmult_gen_ctx, &ctx->ecmult_gen_ctx); + return ret; +} + +void secp256k1_context_destroy(secp256k1_context_t* ctx) { + secp256k1_ecmult_context_clear(&ctx->ecmult_ctx); + secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx); + + free(ctx); +} + +int secp256k1_ecdsa_verify(const secp256k1_context_t* ctx, const unsigned char *msg32, const unsigned char *sig, int siglen, const unsigned char *pubkey, int pubkeylen) { + secp256k1_ge_t q; + secp256k1_ecdsa_sig_t s; + secp256k1_scalar_t m; + int ret = -3; + DEBUG_CHECK(ctx != NULL); + DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + DEBUG_CHECK(msg32 != NULL); + DEBUG_CHECK(sig != NULL); + DEBUG_CHECK(pubkey != NULL); + + secp256k1_scalar_set_b32(&m, msg32, NULL); + + if (secp256k1_eckey_pubkey_parse(&q, pubkey, pubkeylen)) { + if (secp256k1_ecdsa_sig_parse(&s, sig, siglen)) { + if (secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &s, &q, &m)) { + /* success is 1, all other values are fail */ + ret = 1; + } else { + ret = 0; + } + } else { + ret = -2; + } + } else { + ret = -1; + } + + return ret; +} + +static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) { + secp256k1_rfc6979_hmac_sha256_t rng; + unsigned int i; + secp256k1_rfc6979_hmac_sha256_initialize(&rng, key32, 32, msg32, 32, (const unsigned char*)data, data != NULL ? 32 : 0); + for (i = 0; i <= counter; i++) { + secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); + } + secp256k1_rfc6979_hmac_sha256_finalize(&rng); + return 1; +} + +const secp256k1_nonce_function_t secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979; +const secp256k1_nonce_function_t secp256k1_nonce_function_default = nonce_function_rfc6979; + +int secp256k1_ecdsa_sign(const secp256k1_context_t* ctx, const unsigned char *msg32, unsigned char *signature, int *signaturelen, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata) { + secp256k1_ecdsa_sig_t sig; + secp256k1_scalar_t sec, non, msg; + int ret = 0; + int overflow = 0; + unsigned int count = 0; + DEBUG_CHECK(ctx != NULL); + DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + DEBUG_CHECK(msg32 != NULL); + DEBUG_CHECK(signature != NULL); + DEBUG_CHECK(signaturelen != NULL); + DEBUG_CHECK(seckey != NULL); + if (noncefp == NULL) { + noncefp = secp256k1_nonce_function_default; + } + + secp256k1_scalar_set_b32(&sec, seckey, &overflow); + /* Fail if the secret key is invalid. */ + if (!overflow && !secp256k1_scalar_is_zero(&sec)) { + secp256k1_scalar_set_b32(&msg, msg32, NULL); + while (1) { + unsigned char nonce32[32]; + ret = noncefp(nonce32, msg32, seckey, count, noncedata); + if (!ret) { + break; + } + secp256k1_scalar_set_b32(&non, nonce32, &overflow); + memset(nonce32, 0, 32); + if (!secp256k1_scalar_is_zero(&non) && !overflow) { + if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &sig, &sec, &msg, &non, NULL)) { + break; + } + } + count++; + } + if (ret) { + ret = secp256k1_ecdsa_sig_serialize(signature, signaturelen, &sig); + } + secp256k1_scalar_clear(&msg); + secp256k1_scalar_clear(&non); + secp256k1_scalar_clear(&sec); + } + if (!ret) { + *signaturelen = 0; + } + return ret; +} + +int secp256k1_ecdsa_sign_compact(const secp256k1_context_t* ctx, const unsigned char *msg32, unsigned char *sig64, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata, int *recid) { + secp256k1_ecdsa_sig_t sig; + secp256k1_scalar_t sec, non, msg; + int ret = 0; + int overflow = 0; + unsigned int count = 0; + DEBUG_CHECK(ctx != NULL); + DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + DEBUG_CHECK(msg32 != NULL); + DEBUG_CHECK(sig64 != NULL); + DEBUG_CHECK(seckey != NULL); + if (noncefp == NULL) { + noncefp = secp256k1_nonce_function_default; + } + + secp256k1_scalar_set_b32(&sec, seckey, &overflow); + /* Fail if the secret key is invalid. */ + if (!overflow && !secp256k1_scalar_is_zero(&sec)) { + secp256k1_scalar_set_b32(&msg, msg32, NULL); + while (1) { + unsigned char nonce32[32]; + ret = noncefp(nonce32, msg32, seckey, count, noncedata); + if (!ret) { + break; + } + secp256k1_scalar_set_b32(&non, nonce32, &overflow); + memset(nonce32, 0, 32); + if (!secp256k1_scalar_is_zero(&non) && !overflow) { + if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &sig, &sec, &msg, &non, recid)) { + break; + } + } + count++; + } + if (ret) { + secp256k1_scalar_get_b32(sig64, &sig.r); + secp256k1_scalar_get_b32(sig64 + 32, &sig.s); + } + secp256k1_scalar_clear(&msg); + secp256k1_scalar_clear(&non); + secp256k1_scalar_clear(&sec); + } + if (!ret) { + memset(sig64, 0, 64); + } + return ret; +} + +int secp256k1_ecdsa_recover_compact(const secp256k1_context_t* ctx, const unsigned char *msg32, const unsigned char *sig64, unsigned char *pubkey, int *pubkeylen, int compressed, int recid) { + secp256k1_ge_t q; + secp256k1_ecdsa_sig_t sig; + secp256k1_scalar_t m; + int ret = 0; + int overflow = 0; + DEBUG_CHECK(ctx != NULL); + DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + DEBUG_CHECK(msg32 != NULL); + DEBUG_CHECK(sig64 != NULL); + DEBUG_CHECK(pubkey != NULL); + DEBUG_CHECK(pubkeylen != NULL); + DEBUG_CHECK(recid >= 0 && recid <= 3); + + secp256k1_scalar_set_b32(&sig.r, sig64, &overflow); + if (!overflow) { + secp256k1_scalar_set_b32(&sig.s, sig64 + 32, &overflow); + if (!overflow) { + secp256k1_scalar_set_b32(&m, msg32, NULL); + + if (secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &sig, &q, &m, recid)) { + ret = secp256k1_eckey_pubkey_serialize(&q, pubkey, pubkeylen, compressed); + } + } + } + return ret; +} + +int secp256k1_ec_seckey_verify(const secp256k1_context_t* ctx, const unsigned char *seckey) { + secp256k1_scalar_t sec; + int ret; + int overflow; + DEBUG_CHECK(ctx != NULL); + DEBUG_CHECK(seckey != NULL); + (void)ctx; + + secp256k1_scalar_set_b32(&sec, seckey, &overflow); + ret = !secp256k1_scalar_is_zero(&sec) && !overflow; + secp256k1_scalar_clear(&sec); + return ret; +} + +int secp256k1_ec_pubkey_verify(const secp256k1_context_t* ctx, const unsigned char *pubkey, int pubkeylen) { + secp256k1_ge_t q; + DEBUG_CHECK(ctx != NULL); + DEBUG_CHECK(pubkey != NULL); + (void)ctx; + + return secp256k1_eckey_pubkey_parse(&q, pubkey, pubkeylen); +} + +int secp256k1_ec_pubkey_create(const secp256k1_context_t* ctx, unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed) { + secp256k1_gej_t pj; + secp256k1_ge_t p; + secp256k1_scalar_t sec; + int overflow; + int ret = 0; + DEBUG_CHECK(ctx != NULL); + DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + DEBUG_CHECK(pubkey != NULL); + DEBUG_CHECK(pubkeylen != NULL); + DEBUG_CHECK(seckey != NULL); + + secp256k1_scalar_set_b32(&sec, seckey, &overflow); + if (!overflow) { + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec); + secp256k1_scalar_clear(&sec); + secp256k1_ge_set_gej(&p, &pj); + ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, pubkeylen, compressed); + } + if (!ret) { + *pubkeylen = 0; + } + return ret; +} + +int secp256k1_ec_pubkey_decompress(const secp256k1_context_t* ctx, unsigned char *pubkey, int *pubkeylen) { + secp256k1_ge_t p; + int ret = 0; + DEBUG_CHECK(pubkey != NULL); + DEBUG_CHECK(pubkeylen != NULL); + (void)ctx; + + if (secp256k1_eckey_pubkey_parse(&p, pubkey, *pubkeylen)) { + ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, pubkeylen, 0); + } + return ret; +} + +int secp256k1_ec_privkey_tweak_add(const secp256k1_context_t* ctx, unsigned char *seckey, const unsigned char *tweak) { + secp256k1_scalar_t term; + secp256k1_scalar_t sec; + int ret = 0; + int overflow = 0; + DEBUG_CHECK(ctx != NULL); + DEBUG_CHECK(seckey != NULL); + DEBUG_CHECK(tweak != NULL); + (void)ctx; + + secp256k1_scalar_set_b32(&term, tweak, &overflow); + secp256k1_scalar_set_b32(&sec, seckey, NULL); + + ret = secp256k1_eckey_privkey_tweak_add(&sec, &term) && !overflow; + if (ret) { + secp256k1_scalar_get_b32(seckey, &sec); + } + + secp256k1_scalar_clear(&sec); + secp256k1_scalar_clear(&term); + return ret; +} + +int secp256k1_ec_pubkey_tweak_add(const secp256k1_context_t* ctx, unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) { + secp256k1_ge_t p; + secp256k1_scalar_t term; + int ret = 0; + int overflow = 0; + DEBUG_CHECK(ctx != NULL); + DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + DEBUG_CHECK(pubkey != NULL); + DEBUG_CHECK(tweak != NULL); + + secp256k1_scalar_set_b32(&term, tweak, &overflow); + if (!overflow) { + ret = secp256k1_eckey_pubkey_parse(&p, pubkey, pubkeylen); + if (ret) { + ret = secp256k1_eckey_pubkey_tweak_add(&ctx->ecmult_ctx, &p, &term); + } + if (ret) { + int oldlen = pubkeylen; + ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33); + VERIFY_CHECK(pubkeylen == oldlen); + } + } + + return ret; +} + +int secp256k1_ec_privkey_tweak_mul(const secp256k1_context_t* ctx, unsigned char *seckey, const unsigned char *tweak) { + secp256k1_scalar_t factor; + secp256k1_scalar_t sec; + int ret = 0; + int overflow = 0; + DEBUG_CHECK(ctx != NULL); + DEBUG_CHECK(seckey != NULL); + DEBUG_CHECK(tweak != NULL); + (void)ctx; + + secp256k1_scalar_set_b32(&factor, tweak, &overflow); + secp256k1_scalar_set_b32(&sec, seckey, NULL); + ret = secp256k1_eckey_privkey_tweak_mul(&sec, &factor) && !overflow; + if (ret) { + secp256k1_scalar_get_b32(seckey, &sec); + } + + secp256k1_scalar_clear(&sec); + secp256k1_scalar_clear(&factor); + return ret; +} + +int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context_t* ctx, unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) { + secp256k1_ge_t p; + secp256k1_scalar_t factor; + int ret = 0; + int overflow = 0; + DEBUG_CHECK(ctx != NULL); + DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + DEBUG_CHECK(pubkey != NULL); + DEBUG_CHECK(tweak != NULL); + + secp256k1_scalar_set_b32(&factor, tweak, &overflow); + if (!overflow) { + ret = secp256k1_eckey_pubkey_parse(&p, pubkey, pubkeylen); + if (ret) { + ret = secp256k1_eckey_pubkey_tweak_mul(&ctx->ecmult_ctx, &p, &factor); + } + if (ret) { + int oldlen = pubkeylen; + ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33); + VERIFY_CHECK(pubkeylen == oldlen); + } + } + + return ret; +} + +int secp256k1_ec_privkey_export(const secp256k1_context_t* ctx, const unsigned char *seckey, unsigned char *privkey, int *privkeylen, int compressed) { + secp256k1_scalar_t key; + int ret = 0; + DEBUG_CHECK(seckey != NULL); + DEBUG_CHECK(privkey != NULL); + DEBUG_CHECK(privkeylen != NULL); + DEBUG_CHECK(ctx != NULL); + DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + + secp256k1_scalar_set_b32(&key, seckey, NULL); + ret = secp256k1_eckey_privkey_serialize(&ctx->ecmult_gen_ctx, privkey, privkeylen, &key, compressed); + secp256k1_scalar_clear(&key); + return ret; +} + +int secp256k1_ec_privkey_import(const secp256k1_context_t* ctx, unsigned char *seckey, const unsigned char *privkey, int privkeylen) { + secp256k1_scalar_t key; + int ret = 0; + DEBUG_CHECK(seckey != NULL); + DEBUG_CHECK(privkey != NULL); + (void)ctx; + + ret = secp256k1_eckey_privkey_parse(&key, privkey, privkeylen); + if (ret) { + secp256k1_scalar_get_b32(seckey, &key); + } + secp256k1_scalar_clear(&key); + return ret; +} + +int secp256k1_context_randomize(secp256k1_context_t* ctx, const unsigned char *seed32) { + DEBUG_CHECK(ctx != NULL); + DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); + return 1; +} diff --git a/src/cryptoconditions/src/include/secp256k1/src/testrand.h b/src/cryptoconditions/src/include/secp256k1/src/testrand.h new file mode 100644 index 000000000..041bb92c4 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/testrand.h @@ -0,0 +1,28 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_TESTRAND_H_ +#define _SECP256K1_TESTRAND_H_ + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +/* A non-cryptographic RNG used only for test infrastructure. */ + +/** Seed the pseudorandom number generator for testing. */ +SECP256K1_INLINE static void secp256k1_rand_seed(const unsigned char *seed16); + +/** Generate a pseudorandom 32-bit number. */ +static uint32_t secp256k1_rand32(void); + +/** Generate a pseudorandom 32-byte array. */ +static void secp256k1_rand256(unsigned char *b32); + +/** Generate a pseudorandom 32-byte array with long sequences of zero and one bits. */ +static void secp256k1_rand256_test(unsigned char *b32); + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/testrand_impl.h b/src/cryptoconditions/src/include/secp256k1/src/testrand_impl.h new file mode 100644 index 000000000..21c69f1c5 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/testrand_impl.h @@ -0,0 +1,60 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_TESTRAND_IMPL_H_ +#define _SECP256K1_TESTRAND_IMPL_H_ + +#include +#include + +#include "testrand.h" +#include "hash.h" + +static secp256k1_rfc6979_hmac_sha256_t secp256k1_test_rng; +static uint32_t secp256k1_test_rng_precomputed[8]; +static int secp256k1_test_rng_precomputed_used = 8; + +SECP256K1_INLINE static void secp256k1_rand_seed(const unsigned char *seed16) { + secp256k1_rfc6979_hmac_sha256_initialize(&secp256k1_test_rng, (const unsigned char*)"TestRNG", 7, seed16, 16, NULL, 0); +} + +SECP256K1_INLINE static uint32_t secp256k1_rand32(void) { + if (secp256k1_test_rng_precomputed_used == 8) { + secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, (unsigned char*)(&secp256k1_test_rng_precomputed[0]), sizeof(secp256k1_test_rng_precomputed)); + secp256k1_test_rng_precomputed_used = 0; + } + return secp256k1_test_rng_precomputed[secp256k1_test_rng_precomputed_used++]; +} + +static void secp256k1_rand256(unsigned char *b32) { + secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, b32, 32); +} + +static void secp256k1_rand256_test(unsigned char *b32) { + int bits=0; + uint64_t ent = 0; + int entleft = 0; + memset(b32, 0, 32); + while (bits < 256) { + int now; + uint32_t val; + if (entleft < 12) { + ent |= ((uint64_t)secp256k1_rand32()) << entleft; + entleft += 32; + } + now = 1 + ((ent % 64)*((ent >> 6) % 32)+16)/31; + val = 1 & (ent >> 11); + ent >>= 12; + entleft -= 12; + while (now > 0 && bits < 256) { + b32[bits / 8] |= val << (bits % 8); + now--; + bits++; + } + } +} + +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/tests.c b/src/cryptoconditions/src/include/secp256k1/src/tests.c new file mode 100644 index 000000000..d0e05057f --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/tests.c @@ -0,0 +1,2083 @@ +/********************************************************************** + * Copyright (c) 2013, 2014, 2015 Pieter Wuille, Gregory Maxwell * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#include +#include + +#include + +#include "secp256k1.c" +#include "testrand_impl.h" + +#ifdef ENABLE_OPENSSL_TESTS +#include "openssl/bn.h" +#include "openssl/ec.h" +#include "openssl/ecdsa.h" +#include "openssl/obj_mac.h" +#endif + +static int count = 64; +static secp256k1_context_t *ctx = NULL; + +void random_field_element_test(secp256k1_fe_t *fe) { + do { + unsigned char b32[32]; + secp256k1_rand256_test(b32); + if (secp256k1_fe_set_b32(fe, b32)) { + break; + } + } while(1); +} + +void random_field_element_magnitude(secp256k1_fe_t *fe) { + secp256k1_fe_t zero; + int n = secp256k1_rand32() % 9; + secp256k1_fe_normalize(fe); + if (n == 0) { + return; + } + secp256k1_fe_clear(&zero); + secp256k1_fe_negate(&zero, &zero, 0); + secp256k1_fe_mul_int(&zero, n - 1); + secp256k1_fe_add(fe, &zero); +#ifdef VERIFY + CHECK(fe->magnitude == n); +#endif +} + +void random_group_element_test(secp256k1_ge_t *ge) { + secp256k1_fe_t fe; + do { + random_field_element_test(&fe); + if (secp256k1_ge_set_xo_var(ge, &fe, secp256k1_rand32() & 1)) { + break; + } + } while(1); +} + +void random_group_element_jacobian_test(secp256k1_gej_t *gej, const secp256k1_ge_t *ge) { + secp256k1_fe_t z2, z3; + do { + random_field_element_test(&gej->z); + if (!secp256k1_fe_is_zero(&gej->z)) { + break; + } + } while(1); + secp256k1_fe_sqr(&z2, &gej->z); + secp256k1_fe_mul(&z3, &z2, &gej->z); + secp256k1_fe_mul(&gej->x, &ge->x, &z2); + secp256k1_fe_mul(&gej->y, &ge->y, &z3); + gej->infinity = ge->infinity; +} + +void random_scalar_order_test(secp256k1_scalar_t *num) { + do { + unsigned char b32[32]; + int overflow = 0; + secp256k1_rand256_test(b32); + secp256k1_scalar_set_b32(num, b32, &overflow); + if (overflow || secp256k1_scalar_is_zero(num)) { + continue; + } + break; + } while(1); +} + +void random_scalar_order(secp256k1_scalar_t *num) { + do { + unsigned char b32[32]; + int overflow = 0; + secp256k1_rand256(b32); + secp256k1_scalar_set_b32(num, b32, &overflow); + if (overflow || secp256k1_scalar_is_zero(num)) { + continue; + } + break; + } while(1); +} + +void run_context_tests(void) { + secp256k1_context_t *none = secp256k1_context_create(0); + secp256k1_context_t *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_context_t *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + secp256k1_context_t *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + + secp256k1_gej_t pubj; + secp256k1_ge_t pub; + secp256k1_scalar_t msg, key, nonce; + secp256k1_ecdsa_sig_t sig; + + /*** clone and destroy all of them to make sure cloning was complete ***/ + { + secp256k1_context_t *ctx_tmp; + + ctx_tmp = none; none = secp256k1_context_clone(none); secp256k1_context_destroy(ctx_tmp); + ctx_tmp = sign; sign = secp256k1_context_clone(sign); secp256k1_context_destroy(ctx_tmp); + ctx_tmp = vrfy; vrfy = secp256k1_context_clone(vrfy); secp256k1_context_destroy(ctx_tmp); + ctx_tmp = both; both = secp256k1_context_clone(both); secp256k1_context_destroy(ctx_tmp); + } + + /*** attempt to use them ***/ + random_scalar_order_test(&msg); + random_scalar_order_test(&key); + secp256k1_ecmult_gen(&both->ecmult_gen_ctx, &pubj, &key); + secp256k1_ge_set_gej(&pub, &pubj); + + /* obtain a working nonce */ + do { + random_scalar_order_test(&nonce); + } while(!secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sig, &key, &msg, &nonce, NULL)); + + /* try signing */ + CHECK(secp256k1_ecdsa_sig_sign(&sign->ecmult_gen_ctx, &sig, &key, &msg, &nonce, NULL)); + CHECK(secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sig, &key, &msg, &nonce, NULL)); + + /* try verifying */ + CHECK(secp256k1_ecdsa_sig_verify(&vrfy->ecmult_ctx, &sig, &pub, &msg)); + CHECK(secp256k1_ecdsa_sig_verify(&both->ecmult_ctx, &sig, &pub, &msg)); + + /* cleanup */ + secp256k1_context_destroy(none); + secp256k1_context_destroy(sign); + secp256k1_context_destroy(vrfy); + secp256k1_context_destroy(both); +} + +/***** HASH TESTS *****/ + +void run_sha256_tests(void) { + static const char *inputs[8] = { + "", "abc", "message digest", "secure hash algorithm", "SHA256 is considered to be safe", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "For this sample, this 63-byte string will be used as input data", + "This is exactly 64 bytes long, not counting the terminating byte" + }; + static const unsigned char outputs[8][32] = { + {0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}, + {0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c, 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad}, + {0xf7, 0x84, 0x6f, 0x55, 0xcf, 0x23, 0xe1, 0x4e, 0xeb, 0xea, 0xb5, 0xb4, 0xe1, 0x55, 0x0c, 0xad, 0x5b, 0x50, 0x9e, 0x33, 0x48, 0xfb, 0xc4, 0xef, 0xa3, 0xa1, 0x41, 0x3d, 0x39, 0x3c, 0xb6, 0x50}, + {0xf3, 0x0c, 0xeb, 0x2b, 0xb2, 0x82, 0x9e, 0x79, 0xe4, 0xca, 0x97, 0x53, 0xd3, 0x5a, 0x8e, 0xcc, 0x00, 0x26, 0x2d, 0x16, 0x4c, 0xc0, 0x77, 0x08, 0x02, 0x95, 0x38, 0x1c, 0xbd, 0x64, 0x3f, 0x0d}, + {0x68, 0x19, 0xd9, 0x15, 0xc7, 0x3f, 0x4d, 0x1e, 0x77, 0xe4, 0xe1, 0xb5, 0x2d, 0x1f, 0xa0, 0xf9, 0xcf, 0x9b, 0xea, 0xea, 0xd3, 0x93, 0x9f, 0x15, 0x87, 0x4b, 0xd9, 0x88, 0xe2, 0xa2, 0x36, 0x30}, + {0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67, 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1}, + {0xf0, 0x8a, 0x78, 0xcb, 0xba, 0xee, 0x08, 0x2b, 0x05, 0x2a, 0xe0, 0x70, 0x8f, 0x32, 0xfa, 0x1e, 0x50, 0xc5, 0xc4, 0x21, 0xaa, 0x77, 0x2b, 0xa5, 0xdb, 0xb4, 0x06, 0xa2, 0xea, 0x6b, 0xe3, 0x42}, + {0xab, 0x64, 0xef, 0xf7, 0xe8, 0x8e, 0x2e, 0x46, 0x16, 0x5e, 0x29, 0xf2, 0xbc, 0xe4, 0x18, 0x26, 0xbd, 0x4c, 0x7b, 0x35, 0x52, 0xf6, 0xb3, 0x82, 0xa9, 0xe7, 0xd3, 0xaf, 0x47, 0xc2, 0x45, 0xf8} + }; + int i; + for (i = 0; i < 8; i++) { + unsigned char out[32]; + secp256k1_sha256_t hasher; + secp256k1_sha256_initialize(&hasher); + secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); + secp256k1_sha256_finalize(&hasher, out); + CHECK(memcmp(out, outputs[i], 32) == 0); + if (strlen(inputs[i]) > 0) { + int split = secp256k1_rand32() % strlen(inputs[i]); + secp256k1_sha256_initialize(&hasher); + secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); + secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); + secp256k1_sha256_finalize(&hasher, out); + CHECK(memcmp(out, outputs[i], 32) == 0); + } + } +} + +void run_hmac_sha256_tests(void) { + static const char *keys[6] = { + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", + "\x4a\x65\x66\x65", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", + "\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", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa" + }; + static const char *inputs[6] = { + "\x48\x69\x20\x54\x68\x65\x72\x65", + "\x77\x68\x61\x74\x20\x64\x6f\x20\x79\x61\x20\x77\x61\x6e\x74\x20\x66\x6f\x72\x20\x6e\x6f\x74\x68\x69\x6e\x67\x3f", + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd", + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd", + "\x54\x65\x73\x74\x20\x55\x73\x69\x6e\x67\x20\x4c\x61\x72\x67\x65\x72\x20\x54\x68\x61\x6e\x20\x42\x6c\x6f\x63\x6b\x2d\x53\x69\x7a\x65\x20\x4b\x65\x79\x20\x2d\x20\x48\x61\x73\x68\x20\x4b\x65\x79\x20\x46\x69\x72\x73\x74", + "\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20\x74\x65\x73\x74\x20\x75\x73\x69\x6e\x67\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x6b\x65\x79\x20\x61\x6e\x64\x20\x61\x20\x6c\x61\x72\x67\x65\x72\x20\x74\x68\x61\x6e\x20\x62\x6c\x6f\x63\x6b\x2d\x73\x69\x7a\x65\x20\x64\x61\x74\x61\x2e\x20\x54\x68\x65\x20\x6b\x65\x79\x20\x6e\x65\x65\x64\x73\x20\x74\x6f\x20\x62\x65\x20\x68\x61\x73\x68\x65\x64\x20\x62\x65\x66\x6f\x72\x65\x20\x62\x65\x69\x6e\x67\x20\x75\x73\x65\x64\x20\x62\x79\x20\x74\x68\x65\x20\x48\x4d\x41\x43\x20\x61\x6c\x67\x6f\x72\x69\x74\x68\x6d\x2e" + }; + static const unsigned char outputs[6][32] = { + {0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b, 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7, 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7}, + {0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e, 0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7, 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83, 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43}, + {0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, 0x85, 0x4d, 0xb8, 0xeb, 0xd0, 0x91, 0x81, 0xa7, 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22, 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe}, + {0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e, 0xa4, 0xcc, 0x81, 0x98, 0x99, 0xf2, 0x08, 0x3a, 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07, 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b}, + {0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, 0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f, 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14, 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54}, + {0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, 0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44, 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93, 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2} + }; + int i; + for (i = 0; i < 6; i++) { + secp256k1_hmac_sha256_t hasher; + unsigned char out[32]; + secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); + secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); + secp256k1_hmac_sha256_finalize(&hasher, out); + CHECK(memcmp(out, outputs[i], 32) == 0); + if (strlen(inputs[i]) > 0) { + int split = secp256k1_rand32() % strlen(inputs[i]); + secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); + secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); + secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); + secp256k1_hmac_sha256_finalize(&hasher, out); + CHECK(memcmp(out, outputs[i], 32) == 0); + } + } +} + +void run_rfc6979_hmac_sha256_tests(void) { + static const unsigned char key1[32] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00}; + static const unsigned char msg1[32] = {0x4b, 0xf5, 0x12, 0x2f, 0x34, 0x45, 0x54, 0xc5, 0x3b, 0xde, 0x2e, 0xbb, 0x8c, 0xd2, 0xb7, 0xe3, 0xd1, 0x60, 0x0a, 0xd6, 0x31, 0xc3, 0x85, 0xa5, 0xd7, 0xcc, 0xe2, 0x3c, 0x77, 0x85, 0x45, 0x9a}; + static const unsigned char out1[3][32] = { + {0x4f, 0xe2, 0x95, 0x25, 0xb2, 0x08, 0x68, 0x09, 0x15, 0x9a, 0xcd, 0xf0, 0x50, 0x6e, 0xfb, 0x86, 0xb0, 0xec, 0x93, 0x2c, 0x7b, 0xa4, 0x42, 0x56, 0xab, 0x32, 0x1e, 0x42, 0x1e, 0x67, 0xe9, 0xfb}, + {0x2b, 0xf0, 0xff, 0xf1, 0xd3, 0xc3, 0x78, 0xa2, 0x2d, 0xc5, 0xde, 0x1d, 0x85, 0x65, 0x22, 0x32, 0x5c, 0x65, 0xb5, 0x04, 0x49, 0x1a, 0x0c, 0xbd, 0x01, 0xcb, 0x8f, 0x3a, 0xa6, 0x7f, 0xfd, 0x4a}, + {0xf5, 0x28, 0xb4, 0x10, 0xcb, 0x54, 0x1f, 0x77, 0x00, 0x0d, 0x7a, 0xfb, 0x6c, 0x5b, 0x53, 0xc5, 0xc4, 0x71, 0xea, 0xb4, 0x3e, 0x46, 0x6d, 0x9a, 0xc5, 0x19, 0x0c, 0x39, 0xc8, 0x2f, 0xd8, 0x2e} + }; + + static const unsigned char key2[32] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + static const unsigned char msg2[32] = {0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}; + static const unsigned char out2[3][32] = { + {0x9c, 0x23, 0x6c, 0x16, 0x5b, 0x82, 0xae, 0x0c, 0xd5, 0x90, 0x65, 0x9e, 0x10, 0x0b, 0x6b, 0xab, 0x30, 0x36, 0xe7, 0xba, 0x8b, 0x06, 0x74, 0x9b, 0xaf, 0x69, 0x81, 0xe1, 0x6f, 0x1a, 0x2b, 0x95}, + {0xdf, 0x47, 0x10, 0x61, 0x62, 0x5b, 0xc0, 0xea, 0x14, 0xb6, 0x82, 0xfe, 0xee, 0x2c, 0x9c, 0x02, 0xf2, 0x35, 0xda, 0x04, 0x20, 0x4c, 0x1d, 0x62, 0xa1, 0x53, 0x6c, 0x6e, 0x17, 0xae, 0xd7, 0xa9}, + {0x75, 0x97, 0x88, 0x7c, 0xbd, 0x76, 0x32, 0x1f, 0x32, 0xe3, 0x04, 0x40, 0x67, 0x9a, 0x22, 0xcf, 0x7f, 0x8d, 0x9d, 0x2e, 0xac, 0x39, 0x0e, 0x58, 0x1f, 0xea, 0x09, 0x1c, 0xe2, 0x02, 0xba, 0x94} + }; + + secp256k1_rfc6979_hmac_sha256_t rng; + unsigned char out[32]; + unsigned char zero[1] = {0}; + int i; + + secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 32, msg1, 32, NULL, 1); + for (i = 0; i < 3; i++) { + secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); + CHECK(memcmp(out, out1[i], 32) == 0); + } + secp256k1_rfc6979_hmac_sha256_finalize(&rng); + + secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 32, msg1, 32, zero, 1); + for (i = 0; i < 3; i++) { + secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); + CHECK(memcmp(out, out1[i], 32) != 0); + } + secp256k1_rfc6979_hmac_sha256_finalize(&rng); + + secp256k1_rfc6979_hmac_sha256_initialize(&rng, key2, 32, msg2, 32, zero, 0); + for (i = 0; i < 3; i++) { + secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); + CHECK(memcmp(out, out2[i], 32) == 0); + } + secp256k1_rfc6979_hmac_sha256_finalize(&rng); +} + +/***** NUM TESTS *****/ + +#ifndef USE_NUM_NONE +void random_num_negate(secp256k1_num_t *num) { + if (secp256k1_rand32() & 1) { + secp256k1_num_negate(num); + } +} + +void random_num_order_test(secp256k1_num_t *num) { + secp256k1_scalar_t sc; + random_scalar_order_test(&sc); + secp256k1_scalar_get_num(num, &sc); +} + +void random_num_order(secp256k1_num_t *num) { + secp256k1_scalar_t sc; + random_scalar_order(&sc); + secp256k1_scalar_get_num(num, &sc); +} + +void test_num_negate(void) { + secp256k1_num_t n1; + secp256k1_num_t n2; + random_num_order_test(&n1); /* n1 = R */ + random_num_negate(&n1); + secp256k1_num_copy(&n2, &n1); /* n2 = R */ + secp256k1_num_sub(&n1, &n2, &n1); /* n1 = n2-n1 = 0 */ + CHECK(secp256k1_num_is_zero(&n1)); + secp256k1_num_copy(&n1, &n2); /* n1 = R */ + secp256k1_num_negate(&n1); /* n1 = -R */ + CHECK(!secp256k1_num_is_zero(&n1)); + secp256k1_num_add(&n1, &n2, &n1); /* n1 = n2+n1 = 0 */ + CHECK(secp256k1_num_is_zero(&n1)); + secp256k1_num_copy(&n1, &n2); /* n1 = R */ + secp256k1_num_negate(&n1); /* n1 = -R */ + CHECK(secp256k1_num_is_neg(&n1) != secp256k1_num_is_neg(&n2)); + secp256k1_num_negate(&n1); /* n1 = R */ + CHECK(secp256k1_num_eq(&n1, &n2)); +} + +void test_num_add_sub(void) { + secp256k1_num_t n1; + secp256k1_num_t n2; + secp256k1_num_t n1p2, n2p1, n1m2, n2m1; + int r = secp256k1_rand32(); + random_num_order_test(&n1); /* n1 = R1 */ + if (r & 1) { + random_num_negate(&n1); + } + random_num_order_test(&n2); /* n2 = R2 */ + if (r & 2) { + random_num_negate(&n2); + } + secp256k1_num_add(&n1p2, &n1, &n2); /* n1p2 = R1 + R2 */ + secp256k1_num_add(&n2p1, &n2, &n1); /* n2p1 = R2 + R1 */ + secp256k1_num_sub(&n1m2, &n1, &n2); /* n1m2 = R1 - R2 */ + secp256k1_num_sub(&n2m1, &n2, &n1); /* n2m1 = R2 - R1 */ + CHECK(secp256k1_num_eq(&n1p2, &n2p1)); + CHECK(!secp256k1_num_eq(&n1p2, &n1m2)); + secp256k1_num_negate(&n2m1); /* n2m1 = -R2 + R1 */ + CHECK(secp256k1_num_eq(&n2m1, &n1m2)); + CHECK(!secp256k1_num_eq(&n2m1, &n1)); + secp256k1_num_add(&n2m1, &n2m1, &n2); /* n2m1 = -R2 + R1 + R2 = R1 */ + CHECK(secp256k1_num_eq(&n2m1, &n1)); + CHECK(!secp256k1_num_eq(&n2p1, &n1)); + secp256k1_num_sub(&n2p1, &n2p1, &n2); /* n2p1 = R2 + R1 - R2 = R1 */ + CHECK(secp256k1_num_eq(&n2p1, &n1)); +} + +void run_num_smalltests(void) { + int i; + for (i = 0; i < 100*count; i++) { + test_num_negate(); + test_num_add_sub(); + } +} +#endif + +/***** SCALAR TESTS *****/ + +void scalar_test(void) { + secp256k1_scalar_t s; + secp256k1_scalar_t s1; + secp256k1_scalar_t s2; +#ifndef USE_NUM_NONE + secp256k1_num_t snum, s1num, s2num; + secp256k1_num_t order, half_order; +#endif + unsigned char c[32]; + + /* Set 's' to a random scalar, with value 'snum'. */ + random_scalar_order_test(&s); + + /* Set 's1' to a random scalar, with value 's1num'. */ + random_scalar_order_test(&s1); + + /* Set 's2' to a random scalar, with value 'snum2', and byte array representation 'c'. */ + random_scalar_order_test(&s2); + secp256k1_scalar_get_b32(c, &s2); + +#ifndef USE_NUM_NONE + secp256k1_scalar_get_num(&snum, &s); + secp256k1_scalar_get_num(&s1num, &s1); + secp256k1_scalar_get_num(&s2num, &s2); + + secp256k1_scalar_order_get_num(&order); + half_order = order; + secp256k1_num_shift(&half_order, 1); +#endif + + { + int i; + /* Test that fetching groups of 4 bits from a scalar and recursing n(i)=16*n(i-1)+p(i) reconstructs it. */ + secp256k1_scalar_t n; + secp256k1_scalar_set_int(&n, 0); + for (i = 0; i < 256; i += 4) { + secp256k1_scalar_t t; + int j; + secp256k1_scalar_set_int(&t, secp256k1_scalar_get_bits(&s, 256 - 4 - i, 4)); + for (j = 0; j < 4; j++) { + secp256k1_scalar_add(&n, &n, &n); + } + secp256k1_scalar_add(&n, &n, &t); + } + CHECK(secp256k1_scalar_eq(&n, &s)); + } + + { + /* Test that fetching groups of randomly-sized bits from a scalar and recursing n(i)=b*n(i-1)+p(i) reconstructs it. */ + secp256k1_scalar_t n; + int i = 0; + secp256k1_scalar_set_int(&n, 0); + while (i < 256) { + secp256k1_scalar_t t; + int j; + int now = (secp256k1_rand32() % 15) + 1; + if (now + i > 256) { + now = 256 - i; + } + secp256k1_scalar_set_int(&t, secp256k1_scalar_get_bits_var(&s, 256 - now - i, now)); + for (j = 0; j < now; j++) { + secp256k1_scalar_add(&n, &n, &n); + } + secp256k1_scalar_add(&n, &n, &t); + i += now; + } + CHECK(secp256k1_scalar_eq(&n, &s)); + } + +#ifndef USE_NUM_NONE + { + /* Test that adding the scalars together is equal to adding their numbers together modulo the order. */ + secp256k1_num_t rnum; + secp256k1_num_t r2num; + secp256k1_scalar_t r; + secp256k1_num_add(&rnum, &snum, &s2num); + secp256k1_num_mod(&rnum, &order); + secp256k1_scalar_add(&r, &s, &s2); + secp256k1_scalar_get_num(&r2num, &r); + CHECK(secp256k1_num_eq(&rnum, &r2num)); + } + + { + /* Test that multipying the scalars is equal to multiplying their numbers modulo the order. */ + secp256k1_scalar_t r; + secp256k1_num_t r2num; + secp256k1_num_t rnum; + secp256k1_num_mul(&rnum, &snum, &s2num); + secp256k1_num_mod(&rnum, &order); + secp256k1_scalar_mul(&r, &s, &s2); + secp256k1_scalar_get_num(&r2num, &r); + CHECK(secp256k1_num_eq(&rnum, &r2num)); + /* The result can only be zero if at least one of the factors was zero. */ + CHECK(secp256k1_scalar_is_zero(&r) == (secp256k1_scalar_is_zero(&s) || secp256k1_scalar_is_zero(&s2))); + /* The results can only be equal to one of the factors if that factor was zero, or the other factor was one. */ + CHECK(secp256k1_num_eq(&rnum, &snum) == (secp256k1_scalar_is_zero(&s) || secp256k1_scalar_is_one(&s2))); + CHECK(secp256k1_num_eq(&rnum, &s2num) == (secp256k1_scalar_is_zero(&s2) || secp256k1_scalar_is_one(&s))); + } + + { + secp256k1_scalar_t neg; + secp256k1_num_t negnum; + secp256k1_num_t negnum2; + /* Check that comparison with zero matches comparison with zero on the number. */ + CHECK(secp256k1_num_is_zero(&snum) == secp256k1_scalar_is_zero(&s)); + /* Check that comparison with the half order is equal to testing for high scalar. */ + CHECK(secp256k1_scalar_is_high(&s) == (secp256k1_num_cmp(&snum, &half_order) > 0)); + secp256k1_scalar_negate(&neg, &s); + secp256k1_num_sub(&negnum, &order, &snum); + secp256k1_num_mod(&negnum, &order); + /* Check that comparison with the half order is equal to testing for high scalar after negation. */ + CHECK(secp256k1_scalar_is_high(&neg) == (secp256k1_num_cmp(&negnum, &half_order) > 0)); + /* Negating should change the high property, unless the value was already zero. */ + CHECK((secp256k1_scalar_is_high(&s) == secp256k1_scalar_is_high(&neg)) == secp256k1_scalar_is_zero(&s)); + secp256k1_scalar_get_num(&negnum2, &neg); + /* Negating a scalar should be equal to (order - n) mod order on the number. */ + CHECK(secp256k1_num_eq(&negnum, &negnum2)); + secp256k1_scalar_add(&neg, &neg, &s); + /* Adding a number to its negation should result in zero. */ + CHECK(secp256k1_scalar_is_zero(&neg)); + secp256k1_scalar_negate(&neg, &neg); + /* Negating zero should still result in zero. */ + CHECK(secp256k1_scalar_is_zero(&neg)); + } + + { + /* Test secp256k1_scalar_mul_shift_var. */ + secp256k1_scalar_t r; + secp256k1_num_t one; + secp256k1_num_t rnum; + secp256k1_num_t rnum2; + unsigned char cone[1] = {0x01}; + unsigned int shift = 256 + (secp256k1_rand32() % 257); + secp256k1_scalar_mul_shift_var(&r, &s1, &s2, shift); + secp256k1_num_mul(&rnum, &s1num, &s2num); + secp256k1_num_shift(&rnum, shift - 1); + secp256k1_num_set_bin(&one, cone, 1); + secp256k1_num_add(&rnum, &rnum, &one); + secp256k1_num_shift(&rnum, 1); + secp256k1_scalar_get_num(&rnum2, &r); + CHECK(secp256k1_num_eq(&rnum, &rnum2)); + } +#endif + + { + /* Test that scalar inverses are equal to the inverse of their number modulo the order. */ + if (!secp256k1_scalar_is_zero(&s)) { + secp256k1_scalar_t inv; +#ifndef USE_NUM_NONE + secp256k1_num_t invnum; + secp256k1_num_t invnum2; +#endif + secp256k1_scalar_inverse(&inv, &s); +#ifndef USE_NUM_NONE + secp256k1_num_mod_inverse(&invnum, &snum, &order); + secp256k1_scalar_get_num(&invnum2, &inv); + CHECK(secp256k1_num_eq(&invnum, &invnum2)); +#endif + secp256k1_scalar_mul(&inv, &inv, &s); + /* Multiplying a scalar with its inverse must result in one. */ + CHECK(secp256k1_scalar_is_one(&inv)); + secp256k1_scalar_inverse(&inv, &inv); + /* Inverting one must result in one. */ + CHECK(secp256k1_scalar_is_one(&inv)); + } + } + + { + /* Test commutativity of add. */ + secp256k1_scalar_t r1, r2; + secp256k1_scalar_add(&r1, &s1, &s2); + secp256k1_scalar_add(&r2, &s2, &s1); + CHECK(secp256k1_scalar_eq(&r1, &r2)); + } + + { + secp256k1_scalar_t r1, r2; + secp256k1_scalar_t b; + int i; + /* Test add_bit. */ + int bit = secp256k1_rand32() % 256; + secp256k1_scalar_set_int(&b, 1); + CHECK(secp256k1_scalar_is_one(&b)); + for (i = 0; i < bit; i++) { + secp256k1_scalar_add(&b, &b, &b); + } + r1 = s1; + r2 = s1; + if (!secp256k1_scalar_add(&r1, &r1, &b)) { + /* No overflow happened. */ + secp256k1_scalar_add_bit(&r2, bit); + CHECK(secp256k1_scalar_eq(&r1, &r2)); + } + } + + { + /* Test commutativity of mul. */ + secp256k1_scalar_t r1, r2; + secp256k1_scalar_mul(&r1, &s1, &s2); + secp256k1_scalar_mul(&r2, &s2, &s1); + CHECK(secp256k1_scalar_eq(&r1, &r2)); + } + + { + /* Test associativity of add. */ + secp256k1_scalar_t r1, r2; + secp256k1_scalar_add(&r1, &s1, &s2); + secp256k1_scalar_add(&r1, &r1, &s); + secp256k1_scalar_add(&r2, &s2, &s); + secp256k1_scalar_add(&r2, &s1, &r2); + CHECK(secp256k1_scalar_eq(&r1, &r2)); + } + + { + /* Test associativity of mul. */ + secp256k1_scalar_t r1, r2; + secp256k1_scalar_mul(&r1, &s1, &s2); + secp256k1_scalar_mul(&r1, &r1, &s); + secp256k1_scalar_mul(&r2, &s2, &s); + secp256k1_scalar_mul(&r2, &s1, &r2); + CHECK(secp256k1_scalar_eq(&r1, &r2)); + } + + { + /* Test distributitivity of mul over add. */ + secp256k1_scalar_t r1, r2, t; + secp256k1_scalar_add(&r1, &s1, &s2); + secp256k1_scalar_mul(&r1, &r1, &s); + secp256k1_scalar_mul(&r2, &s1, &s); + secp256k1_scalar_mul(&t, &s2, &s); + secp256k1_scalar_add(&r2, &r2, &t); + CHECK(secp256k1_scalar_eq(&r1, &r2)); + } + + { + /* Test square. */ + secp256k1_scalar_t r1, r2; + secp256k1_scalar_sqr(&r1, &s1); + secp256k1_scalar_mul(&r2, &s1, &s1); + CHECK(secp256k1_scalar_eq(&r1, &r2)); + } + + { + /* Test multiplicative identity. */ + secp256k1_scalar_t r1, v1; + secp256k1_scalar_set_int(&v1,1); + secp256k1_scalar_mul(&r1, &s1, &v1); + CHECK(secp256k1_scalar_eq(&r1, &s1)); + } + + { + /* Test additive identity. */ + secp256k1_scalar_t r1, v0; + secp256k1_scalar_set_int(&v0,0); + secp256k1_scalar_add(&r1, &s1, &v0); + CHECK(secp256k1_scalar_eq(&r1, &s1)); + } + + { + /* Test zero product property. */ + secp256k1_scalar_t r1, v0; + secp256k1_scalar_set_int(&v0,0); + secp256k1_scalar_mul(&r1, &s1, &v0); + CHECK(secp256k1_scalar_eq(&r1, &v0)); + } + +} + +void run_scalar_tests(void) { + int i; + for (i = 0; i < 128 * count; i++) { + scalar_test(); + } + + { + /* (-1)+1 should be zero. */ + secp256k1_scalar_t s, o; + secp256k1_scalar_set_int(&s, 1); + CHECK(secp256k1_scalar_is_one(&s)); + secp256k1_scalar_negate(&o, &s); + secp256k1_scalar_add(&o, &o, &s); + CHECK(secp256k1_scalar_is_zero(&o)); + secp256k1_scalar_negate(&o, &o); + CHECK(secp256k1_scalar_is_zero(&o)); + } + +#ifndef USE_NUM_NONE + { + /* A scalar with value of the curve order should be 0. */ + secp256k1_num_t order; + secp256k1_scalar_t zero; + unsigned char bin[32]; + int overflow = 0; + secp256k1_scalar_order_get_num(&order); + secp256k1_num_get_bin(bin, 32, &order); + secp256k1_scalar_set_b32(&zero, bin, &overflow); + CHECK(overflow == 1); + CHECK(secp256k1_scalar_is_zero(&zero)); + } +#endif +} + +/***** FIELD TESTS *****/ + +void random_fe(secp256k1_fe_t *x) { + unsigned char bin[32]; + do { + secp256k1_rand256(bin); + if (secp256k1_fe_set_b32(x, bin)) { + return; + } + } while(1); +} + +void random_fe_non_zero(secp256k1_fe_t *nz) { + int tries = 10; + while (--tries >= 0) { + random_fe(nz); + secp256k1_fe_normalize(nz); + if (!secp256k1_fe_is_zero(nz)) { + break; + } + } + /* Infinitesimal probability of spurious failure here */ + CHECK(tries >= 0); +} + +void random_fe_non_square(secp256k1_fe_t *ns) { + secp256k1_fe_t r; + random_fe_non_zero(ns); + if (secp256k1_fe_sqrt_var(&r, ns)) { + secp256k1_fe_negate(ns, ns, 1); + } +} + +int check_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { + secp256k1_fe_t an = *a; + secp256k1_fe_t bn = *b; + secp256k1_fe_normalize_weak(&an); + secp256k1_fe_normalize_var(&bn); + return secp256k1_fe_equal_var(&an, &bn); +} + +int check_fe_inverse(const secp256k1_fe_t *a, const secp256k1_fe_t *ai) { + secp256k1_fe_t x; + secp256k1_fe_t one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); + secp256k1_fe_mul(&x, a, ai); + return check_fe_equal(&x, &one); +} + +void run_field_convert(void) { + static const unsigned char b32[32] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, + 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x40 + }; + static const secp256k1_fe_storage_t fes = SECP256K1_FE_STORAGE_CONST( + 0x00010203UL, 0x04050607UL, 0x11121314UL, 0x15161718UL, + 0x22232425UL, 0x26272829UL, 0x33343536UL, 0x37383940UL + ); + static const secp256k1_fe_t fe = SECP256K1_FE_CONST( + 0x00010203UL, 0x04050607UL, 0x11121314UL, 0x15161718UL, + 0x22232425UL, 0x26272829UL, 0x33343536UL, 0x37383940UL + ); + secp256k1_fe_t fe2; + unsigned char b322[32]; + secp256k1_fe_storage_t fes2; + /* Check conversions to fe. */ + CHECK(secp256k1_fe_set_b32(&fe2, b32)); + CHECK(secp256k1_fe_equal_var(&fe, &fe2)); + secp256k1_fe_from_storage(&fe2, &fes); + CHECK(secp256k1_fe_equal_var(&fe, &fe2)); + /* Check conversion from fe. */ + secp256k1_fe_get_b32(b322, &fe); + CHECK(memcmp(b322, b32, 32) == 0); + secp256k1_fe_to_storage(&fes2, &fe); + CHECK(memcmp(&fes2, &fes, sizeof(fes)) == 0); +} + +void run_field_misc(void) { + secp256k1_fe_t x; + secp256k1_fe_t y; + secp256k1_fe_t z; + secp256k1_fe_t q; + secp256k1_fe_t fe5 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 5); + int i; + for (i = 0; i < 5*count; i++) { + secp256k1_fe_storage_t xs, ys, zs; + random_fe(&x); + random_fe_non_zero(&y); + /* Test the fe equality and comparison operations. */ + CHECK(secp256k1_fe_cmp_var(&x, &x) == 0); + CHECK(secp256k1_fe_equal_var(&x, &x)); + z = x; + secp256k1_fe_add(&z,&y); + /* Test fe conditional move; z is not normalized here. */ + q = x; + secp256k1_fe_cmov(&x, &z, 0); + secp256k1_fe_cmov(&x, &x, 1); + CHECK(memcmp(&x, &z, sizeof(x)) != 0); + CHECK(memcmp(&x, &q, sizeof(x)) == 0); + secp256k1_fe_cmov(&q, &z, 1); + CHECK(memcmp(&q, &z, sizeof(q)) == 0); + /* Test storage conversion and conditional moves. */ + secp256k1_fe_normalize(&z); + CHECK(!secp256k1_fe_equal_var(&x, &z)); + secp256k1_fe_to_storage(&xs, &x); + secp256k1_fe_to_storage(&ys, &y); + secp256k1_fe_to_storage(&zs, &z); + secp256k1_fe_storage_cmov(&zs, &xs, 0); + secp256k1_fe_storage_cmov(&zs, &zs, 1); + CHECK(memcmp(&xs, &zs, sizeof(xs)) != 0); + secp256k1_fe_storage_cmov(&ys, &xs, 1); + CHECK(memcmp(&xs, &ys, sizeof(xs)) == 0); + secp256k1_fe_from_storage(&x, &xs); + secp256k1_fe_from_storage(&y, &ys); + secp256k1_fe_from_storage(&z, &zs); + /* Test that mul_int, mul, and add agree. */ + secp256k1_fe_add(&y, &x); + secp256k1_fe_add(&y, &x); + z = x; + secp256k1_fe_mul_int(&z, 3); + CHECK(check_fe_equal(&y, &z)); + secp256k1_fe_add(&y, &x); + secp256k1_fe_add(&z, &x); + CHECK(check_fe_equal(&z, &y)); + z = x; + secp256k1_fe_mul_int(&z, 5); + secp256k1_fe_mul(&q, &x, &fe5); + CHECK(check_fe_equal(&z, &q)); + secp256k1_fe_negate(&x, &x, 1); + secp256k1_fe_add(&z, &x); + secp256k1_fe_add(&q, &x); + CHECK(check_fe_equal(&y, &z)); + CHECK(check_fe_equal(&q, &y)); + } +} + +void run_field_inv(void) { + secp256k1_fe_t x, xi, xii; + int i; + for (i = 0; i < 10*count; i++) { + random_fe_non_zero(&x); + secp256k1_fe_inv(&xi, &x); + CHECK(check_fe_inverse(&x, &xi)); + secp256k1_fe_inv(&xii, &xi); + CHECK(check_fe_equal(&x, &xii)); + } +} + +void run_field_inv_var(void) { + secp256k1_fe_t x, xi, xii; + int i; + for (i = 0; i < 10*count; i++) { + random_fe_non_zero(&x); + secp256k1_fe_inv_var(&xi, &x); + CHECK(check_fe_inverse(&x, &xi)); + secp256k1_fe_inv_var(&xii, &xi); + CHECK(check_fe_equal(&x, &xii)); + } +} + +void run_field_inv_all_var(void) { + secp256k1_fe_t x[16], xi[16], xii[16]; + int i; + /* Check it's safe to call for 0 elements */ + secp256k1_fe_inv_all_var(0, xi, x); + for (i = 0; i < count; i++) { + size_t j; + size_t len = (secp256k1_rand32() & 15) + 1; + for (j = 0; j < len; j++) { + random_fe_non_zero(&x[j]); + } + secp256k1_fe_inv_all_var(len, xi, x); + for (j = 0; j < len; j++) { + CHECK(check_fe_inverse(&x[j], &xi[j])); + } + secp256k1_fe_inv_all_var(len, xii, xi); + for (j = 0; j < len; j++) { + CHECK(check_fe_equal(&x[j], &xii[j])); + } + } +} + +void run_sqr(void) { + secp256k1_fe_t x, s; + + { + int i; + secp256k1_fe_set_int(&x, 1); + secp256k1_fe_negate(&x, &x, 1); + + for (i = 1; i <= 512; ++i) { + secp256k1_fe_mul_int(&x, 2); + secp256k1_fe_normalize(&x); + secp256k1_fe_sqr(&s, &x); + } + } +} + +void test_sqrt(const secp256k1_fe_t *a, const secp256k1_fe_t *k) { + secp256k1_fe_t r1, r2; + int v = secp256k1_fe_sqrt_var(&r1, a); + CHECK((v == 0) == (k == NULL)); + + if (k != NULL) { + /* Check that the returned root is +/- the given known answer */ + secp256k1_fe_negate(&r2, &r1, 1); + secp256k1_fe_add(&r1, k); secp256k1_fe_add(&r2, k); + secp256k1_fe_normalize(&r1); secp256k1_fe_normalize(&r2); + CHECK(secp256k1_fe_is_zero(&r1) || secp256k1_fe_is_zero(&r2)); + } +} + +void run_sqrt(void) { + secp256k1_fe_t ns, x, s, t; + int i; + + /* Check sqrt(0) is 0 */ + secp256k1_fe_set_int(&x, 0); + secp256k1_fe_sqr(&s, &x); + test_sqrt(&s, &x); + + /* Check sqrt of small squares (and their negatives) */ + for (i = 1; i <= 100; i++) { + secp256k1_fe_set_int(&x, i); + secp256k1_fe_sqr(&s, &x); + test_sqrt(&s, &x); + secp256k1_fe_negate(&t, &s, 1); + test_sqrt(&t, NULL); + } + + /* Consistency checks for large random values */ + for (i = 0; i < 10; i++) { + int j; + random_fe_non_square(&ns); + for (j = 0; j < count; j++) { + random_fe(&x); + secp256k1_fe_sqr(&s, &x); + test_sqrt(&s, &x); + secp256k1_fe_negate(&t, &s, 1); + test_sqrt(&t, NULL); + secp256k1_fe_mul(&t, &s, &ns); + test_sqrt(&t, NULL); + } + } +} + +/***** GROUP TESTS *****/ + +void ge_equals_ge(const secp256k1_ge_t *a, const secp256k1_ge_t *b) { + CHECK(a->infinity == b->infinity); + if (a->infinity) { + return; + } + CHECK(secp256k1_fe_equal_var(&a->x, &b->x)); + CHECK(secp256k1_fe_equal_var(&b->y, &b->y)); +} + +/* This compares jacobian points including their Z, not just their geometric meaning. */ +int gej_xyz_equals_gej(const secp256k1_gej_t *a, const secp256k1_gej_t *b) { + secp256k1_gej_t a2; + secp256k1_gej_t b2; + int ret = 1; + ret &= a->infinity == b->infinity; + if (ret && !a->infinity) { + a2 = *a; + b2 = *b; + secp256k1_fe_normalize(&a2.x); + secp256k1_fe_normalize(&a2.y); + secp256k1_fe_normalize(&a2.z); + secp256k1_fe_normalize(&b2.x); + secp256k1_fe_normalize(&b2.y); + secp256k1_fe_normalize(&b2.z); + ret &= secp256k1_fe_cmp_var(&a2.x, &b2.x) == 0; + ret &= secp256k1_fe_cmp_var(&a2.y, &b2.y) == 0; + ret &= secp256k1_fe_cmp_var(&a2.z, &b2.z) == 0; + } + return ret; +} + +void ge_equals_gej(const secp256k1_ge_t *a, const secp256k1_gej_t *b) { + secp256k1_fe_t z2s; + secp256k1_fe_t u1, u2, s1, s2; + CHECK(a->infinity == b->infinity); + if (a->infinity) { + return; + } + /* Check a.x * b.z^2 == b.x && a.y * b.z^3 == b.y, to avoid inverses. */ + secp256k1_fe_sqr(&z2s, &b->z); + secp256k1_fe_mul(&u1, &a->x, &z2s); + u2 = b->x; secp256k1_fe_normalize_weak(&u2); + secp256k1_fe_mul(&s1, &a->y, &z2s); secp256k1_fe_mul(&s1, &s1, &b->z); + s2 = b->y; secp256k1_fe_normalize_weak(&s2); + CHECK(secp256k1_fe_equal_var(&u1, &u2)); + CHECK(secp256k1_fe_equal_var(&s1, &s2)); +} + +void test_ge(void) { + int i, i1; + int runs = 4; + /* Points: (infinity, p1, p1, -p1, -p1, p2, p2, -p2, -p2, p3, p3, -p3, -p3, p4, p4, -p4, -p4). + * The second in each pair of identical points uses a random Z coordinate in the Jacobian form. + * All magnitudes are randomized. + * All 17*17 combinations of points are added to eachother, using all applicable methods. + */ + secp256k1_ge_t *ge = (secp256k1_ge_t *)malloc(sizeof(secp256k1_ge_t) * (1 + 4 * runs)); + secp256k1_gej_t *gej = (secp256k1_gej_t *)malloc(sizeof(secp256k1_gej_t) * (1 + 4 * runs)); + secp256k1_gej_set_infinity(&gej[0]); + secp256k1_ge_clear(&ge[0]); + secp256k1_ge_set_gej_var(&ge[0], &gej[0]); + for (i = 0; i < runs; i++) { + int j; + secp256k1_ge_t g; + random_group_element_test(&g); + ge[1 + 4 * i] = g; + ge[2 + 4 * i] = g; + secp256k1_ge_neg(&ge[3 + 4 * i], &g); + secp256k1_ge_neg(&ge[4 + 4 * i], &g); + secp256k1_gej_set_ge(&gej[1 + 4 * i], &ge[1 + 4 * i]); + random_group_element_jacobian_test(&gej[2 + 4 * i], &ge[2 + 4 * i]); + secp256k1_gej_set_ge(&gej[3 + 4 * i], &ge[3 + 4 * i]); + random_group_element_jacobian_test(&gej[4 + 4 * i], &ge[4 + 4 * i]); + for (j = 0; j < 4; j++) { + random_field_element_magnitude(&ge[1 + j + 4 * i].x); + random_field_element_magnitude(&ge[1 + j + 4 * i].y); + random_field_element_magnitude(&gej[1 + j + 4 * i].x); + random_field_element_magnitude(&gej[1 + j + 4 * i].y); + random_field_element_magnitude(&gej[1 + j + 4 * i].z); + } + } + + for (i1 = 0; i1 < 1 + 4 * runs; i1++) { + int i2; + for (i2 = 0; i2 < 1 + 4 * runs; i2++) { + /* Compute reference result using gej + gej (var). */ + secp256k1_gej_t refj, resj; + secp256k1_ge_t ref; + secp256k1_gej_add_var(&refj, &gej[i1], &gej[i2]); + secp256k1_ge_set_gej_var(&ref, &refj); + + /* Test gej + ge (var). */ + secp256k1_gej_add_ge_var(&resj, &gej[i1], &ge[i2]); + ge_equals_gej(&ref, &resj); + + /* Test gej + ge (const). */ + if (i2 != 0) { + /* secp256k1_gej_add_ge does not support its second argument being infinity. */ + secp256k1_gej_add_ge(&resj, &gej[i1], &ge[i2]); + ge_equals_gej(&ref, &resj); + } + + /* Test doubling (var). */ + if ((i1 == 0 && i2 == 0) || ((i1 + 3)/4 == (i2 + 3)/4 && ((i1 + 3)%4)/2 == ((i2 + 3)%4)/2)) { + /* Normal doubling. */ + secp256k1_gej_double_var(&resj, &gej[i1]); + ge_equals_gej(&ref, &resj); + secp256k1_gej_double_var(&resj, &gej[i2]); + ge_equals_gej(&ref, &resj); + } + + /* Test adding opposites. */ + if ((i1 == 0 && i2 == 0) || ((i1 + 3)/4 == (i2 + 3)/4 && ((i1 + 3)%4)/2 != ((i2 + 3)%4)/2)) { + CHECK(secp256k1_ge_is_infinity(&ref)); + } + + /* Test adding infinity. */ + if (i1 == 0) { + CHECK(secp256k1_ge_is_infinity(&ge[i1])); + CHECK(secp256k1_gej_is_infinity(&gej[i1])); + ge_equals_gej(&ref, &gej[i2]); + } + if (i2 == 0) { + CHECK(secp256k1_ge_is_infinity(&ge[i2])); + CHECK(secp256k1_gej_is_infinity(&gej[i2])); + ge_equals_gej(&ref, &gej[i1]); + } + } + } + + /* Test adding all points together in random order equals infinity. */ + { + secp256k1_gej_t sum = SECP256K1_GEJ_CONST_INFINITY; + secp256k1_gej_t *gej_shuffled = (secp256k1_gej_t *)malloc((4 * runs + 1) * sizeof(secp256k1_gej_t)); + for (i = 0; i < 4 * runs + 1; i++) { + gej_shuffled[i] = gej[i]; + } + for (i = 0; i < 4 * runs + 1; i++) { + int swap = i + secp256k1_rand32() % (4 * runs + 1 - i); + if (swap != i) { + secp256k1_gej_t t = gej_shuffled[i]; + gej_shuffled[i] = gej_shuffled[swap]; + gej_shuffled[swap] = t; + } + } + for (i = 0; i < 4 * runs + 1; i++) { + secp256k1_gej_add_var(&sum, &sum, &gej_shuffled[i]); + } + CHECK(secp256k1_gej_is_infinity(&sum)); + free(gej_shuffled); + } + + /* Test batch gej -> ge conversion. */ + { + secp256k1_ge_t *ge_set_all = (secp256k1_ge_t *)malloc((4 * runs + 1) * sizeof(secp256k1_ge_t)); + secp256k1_ge_set_all_gej_var(4 * runs + 1, ge_set_all, gej); + for (i = 0; i < 4 * runs + 1; i++) { + secp256k1_fe_t s; + random_fe_non_zero(&s); + secp256k1_gej_rescale(&gej[i], &s); + ge_equals_gej(&ge_set_all[i], &gej[i]); + } + free(ge_set_all); + } + + free(ge); + free(gej); +} + +void run_ge(void) { + int i; + for (i = 0; i < count * 32; i++) { + test_ge(); + } +} + +/***** ECMULT TESTS *****/ + +void run_ecmult_chain(void) { + /* random starting point A (on the curve) */ + secp256k1_gej_t a = SECP256K1_GEJ_CONST( + 0x8b30bbe9, 0xae2a9906, 0x96b22f67, 0x0709dff3, + 0x727fd8bc, 0x04d3362c, 0x6c7bf458, 0xe2846004, + 0xa357ae91, 0x5c4a6528, 0x1309edf2, 0x0504740f, + 0x0eb33439, 0x90216b4f, 0x81063cb6, 0x5f2f7e0f + ); + /* two random initial factors xn and gn */ + secp256k1_scalar_t xn = SECP256K1_SCALAR_CONST( + 0x84cc5452, 0xf7fde1ed, 0xb4d38a8c, 0xe9b1b84c, + 0xcef31f14, 0x6e569be9, 0x705d357a, 0x42985407 + ); + secp256k1_scalar_t gn = SECP256K1_SCALAR_CONST( + 0xa1e58d22, 0x553dcd42, 0xb2398062, 0x5d4c57a9, + 0x6e9323d4, 0x2b3152e5, 0xca2c3990, 0xedc7c9de + ); + /* two small multipliers to be applied to xn and gn in every iteration: */ + static const secp256k1_scalar_t xf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x1337); + static const secp256k1_scalar_t gf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x7113); + /* accumulators with the resulting coefficients to A and G */ + secp256k1_scalar_t ae = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); + secp256k1_scalar_t ge = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + /* actual points */ + secp256k1_gej_t x = a; + secp256k1_gej_t x2; + int i; + + /* the point being computed */ + x = a; + for (i = 0; i < 200*count; i++) { + /* in each iteration, compute X = xn*X + gn*G; */ + secp256k1_ecmult(&ctx->ecmult_ctx, &x, &x, &xn, &gn); + /* also compute ae and ge: the actual accumulated factors for A and G */ + /* if X was (ae*A+ge*G), xn*X + gn*G results in (xn*ae*A + (xn*ge+gn)*G) */ + secp256k1_scalar_mul(&ae, &ae, &xn); + secp256k1_scalar_mul(&ge, &ge, &xn); + secp256k1_scalar_add(&ge, &ge, &gn); + /* modify xn and gn */ + secp256k1_scalar_mul(&xn, &xn, &xf); + secp256k1_scalar_mul(&gn, &gn, &gf); + + /* verify */ + if (i == 19999) { + /* expected result after 19999 iterations */ + secp256k1_gej_t rp = SECP256K1_GEJ_CONST( + 0xD6E96687, 0xF9B10D09, 0x2A6F3543, 0x9D86CEBE, + 0xA4535D0D, 0x409F5358, 0x6440BD74, 0xB933E830, + 0xB95CBCA2, 0xC77DA786, 0x539BE8FD, 0x53354D2D, + 0x3B4F566A, 0xE6580454, 0x07ED6015, 0xEE1B2A88 + ); + + secp256k1_gej_neg(&rp, &rp); + secp256k1_gej_add_var(&rp, &rp, &x); + CHECK(secp256k1_gej_is_infinity(&rp)); + } + } + /* redo the computation, but directly with the resulting ae and ge coefficients: */ + secp256k1_ecmult(&ctx->ecmult_ctx, &x2, &a, &ae, &ge); + secp256k1_gej_neg(&x2, &x2); + secp256k1_gej_add_var(&x2, &x2, &x); + CHECK(secp256k1_gej_is_infinity(&x2)); +} + +void test_point_times_order(const secp256k1_gej_t *point) { + /* X * (point + G) + (order-X) * (pointer + G) = 0 */ + secp256k1_scalar_t x; + secp256k1_scalar_t nx; + secp256k1_gej_t res1, res2; + secp256k1_ge_t res3; + unsigned char pub[65]; + int psize = 65; + random_scalar_order_test(&x); + secp256k1_scalar_negate(&nx, &x); + secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &x, &x); /* calc res1 = x * point + x * G; */ + secp256k1_ecmult(&ctx->ecmult_ctx, &res2, point, &nx, &nx); /* calc res2 = (order - x) * point + (order - x) * G; */ + secp256k1_gej_add_var(&res1, &res1, &res2); + CHECK(secp256k1_gej_is_infinity(&res1)); + CHECK(secp256k1_gej_is_valid_var(&res1) == 0); + secp256k1_ge_set_gej(&res3, &res1); + CHECK(secp256k1_ge_is_infinity(&res3)); + CHECK(secp256k1_ge_is_valid_var(&res3) == 0); + CHECK(secp256k1_eckey_pubkey_serialize(&res3, pub, &psize, 0) == 0); + psize = 65; + CHECK(secp256k1_eckey_pubkey_serialize(&res3, pub, &psize, 1) == 0); +} + +void run_point_times_order(void) { + int i; + secp256k1_fe_t x = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 2); + static const secp256k1_fe_t xr = SECP256K1_FE_CONST( + 0x7603CB59, 0xB0EF6C63, 0xFE608479, 0x2A0C378C, + 0xDB3233A8, 0x0F8A9A09, 0xA877DEAD, 0x31B38C45 + ); + for (i = 0; i < 500; i++) { + secp256k1_ge_t p; + if (secp256k1_ge_set_xo_var(&p, &x, 1)) { + secp256k1_gej_t j; + CHECK(secp256k1_ge_is_valid_var(&p)); + secp256k1_gej_set_ge(&j, &p); + CHECK(secp256k1_gej_is_valid_var(&j)); + test_point_times_order(&j); + } + secp256k1_fe_sqr(&x, &x); + } + secp256k1_fe_normalize_var(&x); + CHECK(secp256k1_fe_equal_var(&x, &xr)); +} + +void test_wnaf(const secp256k1_scalar_t *number, int w) { + secp256k1_scalar_t x, two, t; + int wnaf[256]; + int zeroes = -1; + int i; + int bits; + secp256k1_scalar_set_int(&x, 0); + secp256k1_scalar_set_int(&two, 2); + bits = secp256k1_ecmult_wnaf(wnaf, number, w); + CHECK(bits <= 256); + for (i = bits-1; i >= 0; i--) { + int v = wnaf[i]; + secp256k1_scalar_mul(&x, &x, &two); + if (v) { + CHECK(zeroes == -1 || zeroes >= w-1); /* check that distance between non-zero elements is at least w-1 */ + zeroes=0; + CHECK((v & 1) == 1); /* check non-zero elements are odd */ + CHECK(v <= (1 << (w-1)) - 1); /* check range below */ + CHECK(v >= -(1 << (w-1)) - 1); /* check range above */ + } else { + CHECK(zeroes != -1); /* check that no unnecessary zero padding exists */ + zeroes++; + } + if (v >= 0) { + secp256k1_scalar_set_int(&t, v); + } else { + secp256k1_scalar_set_int(&t, -v); + secp256k1_scalar_negate(&t, &t); + } + secp256k1_scalar_add(&x, &x, &t); + } + CHECK(secp256k1_scalar_eq(&x, number)); /* check that wnaf represents number */ +} + +void run_wnaf(void) { + int i; + secp256k1_scalar_t n; + for (i = 0; i < count; i++) { + random_scalar_order(&n); + test_wnaf(&n, 4+(i%10)); + } +} + +void test_ecmult_constants(void) { + /* Test ecmult_gen() for [0..36) and [order-36..0). */ + secp256k1_scalar_t x; + secp256k1_gej_t r; + secp256k1_ge_t ng; + int i; + int j; + secp256k1_ge_neg(&ng, &secp256k1_ge_const_g); + for (i = 0; i < 36; i++ ) { + secp256k1_scalar_set_int(&x, i); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &r, &x); + for (j = 0; j < i; j++) { + if (j == i - 1) { + ge_equals_gej(&secp256k1_ge_const_g, &r); + } + secp256k1_gej_add_ge(&r, &r, &ng); + } + CHECK(secp256k1_gej_is_infinity(&r)); + } + for (i = 1; i <= 36; i++ ) { + secp256k1_scalar_set_int(&x, i); + secp256k1_scalar_negate(&x, &x); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &r, &x); + for (j = 0; j < i; j++) { + if (j == i - 1) { + ge_equals_gej(&ng, &r); + } + secp256k1_gej_add_ge(&r, &r, &secp256k1_ge_const_g); + } + CHECK(secp256k1_gej_is_infinity(&r)); + } +} + +void run_ecmult_constants(void) { + test_ecmult_constants(); +} + +void test_ecmult_gen_blind(void) { + /* Test ecmult_gen() blinding and confirm that the blinding changes, the affline points match, and the z's don't match. */ + secp256k1_scalar_t key; + secp256k1_scalar_t b; + unsigned char seed32[32]; + secp256k1_gej_t pgej; + secp256k1_gej_t pgej2; + secp256k1_gej_t i; + secp256k1_ge_t pge; + random_scalar_order_test(&key); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pgej, &key); + secp256k1_rand256(seed32); + b = ctx->ecmult_gen_ctx.blind; + i = ctx->ecmult_gen_ctx.initial; + secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); + CHECK(!secp256k1_scalar_eq(&b, &ctx->ecmult_gen_ctx.blind)); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pgej2, &key); + CHECK(!gej_xyz_equals_gej(&pgej, &pgej2)); + CHECK(!gej_xyz_equals_gej(&i, &ctx->ecmult_gen_ctx.initial)); + secp256k1_ge_set_gej(&pge, &pgej); + ge_equals_gej(&pge, &pgej2); +} + +void test_ecmult_gen_blind_reset(void) { + /* Test ecmult_gen() blinding reset and confirm that the blinding is consistent. */ + secp256k1_scalar_t b; + secp256k1_gej_t initial; + secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, 0); + b = ctx->ecmult_gen_ctx.blind; + initial = ctx->ecmult_gen_ctx.initial; + secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, 0); + CHECK(secp256k1_scalar_eq(&b, &ctx->ecmult_gen_ctx.blind)); + CHECK(gej_xyz_equals_gej(&initial, &ctx->ecmult_gen_ctx.initial)); +} + +void run_ecmult_gen_blind(void) { + int i; + test_ecmult_gen_blind_reset(); + for (i = 0; i < 10; i++) { + test_ecmult_gen_blind(); + } +} + + +void random_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *key, const secp256k1_scalar_t *msg, int *recid) { + secp256k1_scalar_t nonce; + do { + random_scalar_order_test(&nonce); + } while(!secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, sig, key, msg, &nonce, recid)); +} + +void test_ecdsa_sign_verify(void) { + secp256k1_gej_t pubj; + secp256k1_ge_t pub; + secp256k1_scalar_t one; + secp256k1_scalar_t msg, key; + secp256k1_ecdsa_sig_t sig; + int recid; + int getrec; + random_scalar_order_test(&msg); + random_scalar_order_test(&key); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubj, &key); + secp256k1_ge_set_gej(&pub, &pubj); + getrec = secp256k1_rand32()&1; + random_sign(&sig, &key, &msg, getrec?&recid:NULL); + if (getrec) { + CHECK(recid >= 0 && recid < 4); + } + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &pub, &msg)); + secp256k1_scalar_set_int(&one, 1); + secp256k1_scalar_add(&msg, &msg, &one); + CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &pub, &msg)); +} + +void run_ecdsa_sign_verify(void) { + int i; + for (i = 0; i < 10*count; i++) { + test_ecdsa_sign_verify(); + } +} + +/** Dummy nonce generation function that just uses a precomputed nonce, and fails if it is not accepted. Use only for testing. */ +static int precomputed_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) { + (void)msg32; + (void)key32; + memcpy(nonce32, data, 32); + return (counter == 0); +} + +static int nonce_function_test_fail(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) { + /* Dummy nonce generator that has a fatal error on the first counter value. */ + if (counter == 0) { + return 0; + } + return nonce_function_rfc6979(nonce32, msg32, key32, counter - 1, data); +} + +static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) { + /* Dummy nonce generator that produces unacceptable nonces for the first several counter values. */ + if (counter < 3) { + memset(nonce32, counter==0 ? 0 : 255, 32); + if (counter == 2) { + nonce32[31]--; + } + return 1; + } + if (counter < 5) { + static const unsigned char order[] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, + 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B, + 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41 + }; + memcpy(nonce32, order, 32); + if (counter == 4) { + nonce32[31]++; + } + return 1; + } + /* Retry rate of 6979 is negligible esp. as we only call this in determinstic tests. */ + /* If someone does fine a case where it retries for secp256k1, we'd like to know. */ + if (counter > 5) { + return 0; + } + return nonce_function_rfc6979(nonce32, msg32, key32, counter - 5, data); +} + +int is_empty_compact_signature(const unsigned char *sig64) { + static const unsigned char res[64] = {0}; + return memcmp(sig64, res, 64) == 0; +} + +void test_ecdsa_end_to_end(void) { + unsigned char extra[32] = {0x00}; + unsigned char privkey[32]; + unsigned char message[32]; + unsigned char privkey2[32]; + unsigned char csignature[64]; + unsigned char signature[72]; + unsigned char signature2[72]; + unsigned char signature3[72]; + unsigned char signature4[72]; + unsigned char pubkey[65]; + unsigned char recpubkey[65]; + unsigned char seckey[300]; + int signaturelen = 72; + int signaturelen2 = 72; + int signaturelen3 = 72; + int signaturelen4 = 72; + int recid = 0; + int recpubkeylen = 0; + int pubkeylen = 65; + int seckeylen = 300; + + /* Generate a random key and message. */ + { + secp256k1_scalar_t msg, key; + random_scalar_order_test(&msg); + random_scalar_order_test(&key); + secp256k1_scalar_get_b32(privkey, &key); + secp256k1_scalar_get_b32(message, &msg); + } + + /* Construct and verify corresponding public key. */ + CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, pubkey, &pubkeylen, privkey, (secp256k1_rand32() & 3) != 0) == 1); + if (secp256k1_rand32() & 1) { + CHECK(secp256k1_ec_pubkey_decompress(ctx, pubkey, &pubkeylen)); + } + CHECK(secp256k1_ec_pubkey_verify(ctx, pubkey, pubkeylen)); + + /* Verify private key import and export. */ + CHECK(secp256k1_ec_privkey_export(ctx, privkey, seckey, &seckeylen, secp256k1_rand32() % 2) == 1); + CHECK(secp256k1_ec_privkey_import(ctx, privkey2, seckey, seckeylen) == 1); + CHECK(memcmp(privkey, privkey2, 32) == 0); + + /* Optionally tweak the keys using addition. */ + if (secp256k1_rand32() % 3 == 0) { + int ret1; + int ret2; + unsigned char rnd[32]; + unsigned char pubkey2[65]; + int pubkeylen2 = 65; + secp256k1_rand256_test(rnd); + ret1 = secp256k1_ec_privkey_tweak_add(ctx, privkey, rnd); + ret2 = secp256k1_ec_pubkey_tweak_add(ctx, pubkey, pubkeylen, rnd); + CHECK(ret1 == ret2); + if (ret1 == 0) { + return; + } + CHECK(secp256k1_ec_pubkey_create(ctx, pubkey2, &pubkeylen2, privkey, pubkeylen == 33) == 1); + CHECK(memcmp(pubkey, pubkey2, pubkeylen) == 0); + } + + /* Optionally tweak the keys using multiplication. */ + if (secp256k1_rand32() % 3 == 0) { + int ret1; + int ret2; + unsigned char rnd[32]; + unsigned char pubkey2[65]; + int pubkeylen2 = 65; + secp256k1_rand256_test(rnd); + ret1 = secp256k1_ec_privkey_tweak_mul(ctx, privkey, rnd); + ret2 = secp256k1_ec_pubkey_tweak_mul(ctx, pubkey, pubkeylen, rnd); + CHECK(ret1 == ret2); + if (ret1 == 0) { + return; + } + CHECK(secp256k1_ec_pubkey_create(ctx, pubkey2, &pubkeylen2, privkey, pubkeylen == 33) == 1); + CHECK(memcmp(pubkey, pubkey2, pubkeylen) == 0); + } + + /* Sign. */ + CHECK(secp256k1_ecdsa_sign(ctx, message, signature, &signaturelen, privkey, NULL, NULL) == 1); + CHECK(signaturelen > 0); + CHECK(secp256k1_ecdsa_sign(ctx, message, signature2, &signaturelen2, privkey, NULL, extra) == 1); + CHECK(signaturelen2 > 0); + extra[31] = 1; + CHECK(secp256k1_ecdsa_sign(ctx, message, signature3, &signaturelen3, privkey, NULL, extra) == 1); + CHECK(signaturelen3 > 0); + extra[31] = 0; + extra[0] = 1; + CHECK(secp256k1_ecdsa_sign(ctx, message, signature4, &signaturelen4, privkey, NULL, extra) == 1); + CHECK(signaturelen3 > 0); + CHECK((signaturelen != signaturelen2) || (memcmp(signature, signature2, signaturelen) != 0)); + CHECK((signaturelen != signaturelen3) || (memcmp(signature, signature3, signaturelen) != 0)); + CHECK((signaturelen3 != signaturelen2) || (memcmp(signature3, signature2, signaturelen3) != 0)); + CHECK((signaturelen4 != signaturelen3) || (memcmp(signature4, signature3, signaturelen4) != 0)); + CHECK((signaturelen4 != signaturelen2) || (memcmp(signature4, signature2, signaturelen4) != 0)); + CHECK((signaturelen4 != signaturelen) || (memcmp(signature4, signature, signaturelen4) != 0)); + /* Verify. */ + CHECK(secp256k1_ecdsa_verify(ctx, message, signature, signaturelen, pubkey, pubkeylen) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, message, signature2, signaturelen2, pubkey, pubkeylen) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, message, signature3, signaturelen3, pubkey, pubkeylen) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, message, signature4, signaturelen4, pubkey, pubkeylen) == 1); + /* Destroy signature and verify again. */ + signature[signaturelen - 1 - secp256k1_rand32() % 20] += 1 + (secp256k1_rand32() % 255); + CHECK(secp256k1_ecdsa_verify(ctx, message, signature, signaturelen, pubkey, pubkeylen) != 1); + + /* Compact sign. */ + CHECK(secp256k1_ecdsa_sign_compact(ctx, message, csignature, privkey, NULL, NULL, &recid) == 1); + CHECK(!is_empty_compact_signature(csignature)); + /* Recover. */ + CHECK(secp256k1_ecdsa_recover_compact(ctx, message, csignature, recpubkey, &recpubkeylen, pubkeylen == 33, recid) == 1); + CHECK(recpubkeylen == pubkeylen); + CHECK(memcmp(pubkey, recpubkey, pubkeylen) == 0); + /* Destroy signature and verify again. */ + csignature[secp256k1_rand32() % 64] += 1 + (secp256k1_rand32() % 255); + CHECK(secp256k1_ecdsa_recover_compact(ctx, message, csignature, recpubkey, &recpubkeylen, pubkeylen == 33, recid) != 1 || + memcmp(pubkey, recpubkey, pubkeylen) != 0); + CHECK(recpubkeylen == pubkeylen); + +} + +void test_random_pubkeys(void) { + secp256k1_ge_t elem; + secp256k1_ge_t elem2; + unsigned char in[65]; + /* Generate some randomly sized pubkeys. */ + uint32_t r = secp256k1_rand32(); + int len = (r & 3) == 0 ? 65 : 33; + r>>=2; + if ((r & 3) == 0) { + len = (r & 252) >> 3; + } + r>>=8; + if (len == 65) { + in[0] = (r & 2) ? 4 : (r & 1? 6 : 7); + } else { + in[0] = (r & 1) ? 2 : 3; + } + r>>=2; + if ((r & 7) == 0) { + in[0] = (r & 2040) >> 3; + } + r>>=11; + if (len > 1) { + secp256k1_rand256(&in[1]); + } + if (len > 33) { + secp256k1_rand256(&in[33]); + } + if (secp256k1_eckey_pubkey_parse(&elem, in, len)) { + unsigned char out[65]; + unsigned char firstb; + int res; + int size = len; + firstb = in[0]; + /* If the pubkey can be parsed, it should round-trip... */ + CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, len == 33)); + CHECK(size == len); + CHECK(memcmp(&in[1], &out[1], len-1) == 0); + /* ... except for the type of hybrid inputs. */ + if ((in[0] != 6) && (in[0] != 7)) { + CHECK(in[0] == out[0]); + } + size = 65; + CHECK(secp256k1_eckey_pubkey_serialize(&elem, in, &size, 0)); + CHECK(size == 65); + CHECK(secp256k1_eckey_pubkey_parse(&elem2, in, size)); + ge_equals_ge(&elem,&elem2); + /* Check that the X9.62 hybrid type is checked. */ + in[0] = (r & 1) ? 6 : 7; + res = secp256k1_eckey_pubkey_parse(&elem2, in, size); + if (firstb == 2 || firstb == 3) { + if (in[0] == firstb + 4) { + CHECK(res); + } else { + CHECK(!res); + } + } + if (res) { + ge_equals_ge(&elem,&elem2); + CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, 0)); + CHECK(memcmp(&in[1], &out[1], 64) == 0); + } + } +} + +void run_random_pubkeys(void) { + int i; + for (i = 0; i < 10*count; i++) { + test_random_pubkeys(); + } +} + +void run_ecdsa_end_to_end(void) { + int i; + for (i = 0; i < 64*count; i++) { + test_ecdsa_end_to_end(); + } +} + +/* Tests several edge cases. */ +void test_ecdsa_edge_cases(void) { + const unsigned char msg32[32] = { + 'T', 'h', 'i', 's', ' ', 'i', 's', ' ', + 'a', ' ', 'v', 'e', 'r', 'y', ' ', 's', + 'e', 'c', 'r', 'e', 't', ' ', 'm', 'e', + 's', 's', 'a', 'g', 'e', '.', '.', '.' + }; + const unsigned char sig64[64] = { + /* Generated by signing the above message with nonce 'This is the nonce we will use...' + * and secret key 0 (which is not valid), resulting in recid 0. */ + 0x67, 0xCB, 0x28, 0x5F, 0x9C, 0xD1, 0x94, 0xE8, + 0x40, 0xD6, 0x29, 0x39, 0x7A, 0xF5, 0x56, 0x96, + 0x62, 0xFD, 0xE4, 0x46, 0x49, 0x99, 0x59, 0x63, + 0x17, 0x9A, 0x7D, 0xD1, 0x7B, 0xD2, 0x35, 0x32, + 0x4B, 0x1B, 0x7D, 0xF3, 0x4C, 0xE1, 0xF6, 0x8E, + 0x69, 0x4F, 0xF6, 0xF1, 0x1A, 0xC7, 0x51, 0xDD, + 0x7D, 0xD7, 0x3E, 0x38, 0x7E, 0xE4, 0xFC, 0x86, + 0x6E, 0x1B, 0xE8, 0xEC, 0xC7, 0xDD, 0x95, 0x57 + }; + unsigned char pubkey[65]; + int t; + int pubkeylen = 65; + /* signature (r,s) = (4,4), which can be recovered with all 4 recids. */ + const unsigned char sigb64[64] = { + 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, 0x04, + 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, 0x04, + }; + unsigned char pubkeyb[33]; + int pubkeyblen = 33; + int recid; + + CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 0)); + CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 1)); + CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 2)); + CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 3)); + + for (recid = 0; recid < 4; recid++) { + int i; + int recid2; + /* (4,4) encoded in DER. */ + unsigned char sigbder[8] = {0x30, 0x06, 0x02, 0x01, 0x04, 0x02, 0x01, 0x04}; + unsigned char sigcder_zr[7] = {0x30, 0x05, 0x02, 0x00, 0x02, 0x01, 0x01}; + unsigned char sigcder_zs[7] = {0x30, 0x05, 0x02, 0x01, 0x01, 0x02, 0x00}; + unsigned char sigbderalt1[39] = { + 0x30, 0x25, 0x02, 0x20, 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, 0x04, 0x02, 0x01, 0x04, + }; + unsigned char sigbderalt2[39] = { + 0x30, 0x25, 0x02, 0x01, 0x04, 0x02, 0x20, 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, 0x04, + }; + unsigned char sigbderalt3[40] = { + 0x30, 0x26, 0x02, 0x21, 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, 0x04, 0x02, 0x01, 0x04, + }; + unsigned char sigbderalt4[40] = { + 0x30, 0x26, 0x02, 0x01, 0x04, 0x02, 0x21, 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, 0x04, + }; + /* (order + r,4) encoded in DER. */ + unsigned char sigbderlong[40] = { + 0x30, 0x26, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, + 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, + 0x8C, 0xD0, 0x36, 0x41, 0x45, 0x02, 0x01, 0x04 + }; + CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigb64, pubkeyb, &pubkeyblen, 1, recid)); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == 1); + for (recid2 = 0; recid2 < 4; recid2++) { + unsigned char pubkey2b[33]; + int pubkey2blen = 33; + CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigb64, pubkey2b, &pubkey2blen, 1, recid2)); + /* Verifying with (order + r,4) should always fail. */ + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderlong, sizeof(sigbderlong), pubkey2b, pubkey2blen) != 1); + } + /* DER parsing tests. */ + /* Zero length r/s. */ + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder_zr, sizeof(sigcder_zr), pubkeyb, pubkeyblen) == -2); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder_zs, sizeof(sigcder_zs), pubkeyb, pubkeyblen) == -2); + /* Leading zeros. */ + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt1, sizeof(sigbderalt1), pubkeyb, pubkeyblen) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt2, sizeof(sigbderalt2), pubkeyb, pubkeyblen) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt3, sizeof(sigbderalt3), pubkeyb, pubkeyblen) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt4, sizeof(sigbderalt4), pubkeyb, pubkeyblen) == 1); + sigbderalt3[4] = 1; + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt3, sizeof(sigbderalt3), pubkeyb, pubkeyblen) == -2); + sigbderalt4[7] = 1; + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt4, sizeof(sigbderalt4), pubkeyb, pubkeyblen) == -2); + /* Damage signature. */ + sigbder[7]++; + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == 0); + sigbder[7]--; + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, 6, pubkeyb, pubkeyblen) == -2); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder)-1, pubkeyb, pubkeyblen) == -2); + for(i = 0; i < 8; i++) { + int c; + unsigned char orig = sigbder[i]; + /*Try every single-byte change.*/ + for (c = 0; c < 256; c++) { + if (c == orig ) { + continue; + } + sigbder[i] = c; + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == + (i==4 || i==7) ? 0 : -2 ); + } + sigbder[i] = orig; + } + } + + /* Test the case where ECDSA recomputes a point that is infinity. */ + { + secp256k1_gej_t keyj; + secp256k1_ge_t key; + secp256k1_scalar_t msg; + secp256k1_ecdsa_sig_t sig; + secp256k1_scalar_set_int(&sig.s, 1); + secp256k1_scalar_negate(&sig.s, &sig.s); + secp256k1_scalar_inverse(&sig.s, &sig.s); + secp256k1_scalar_set_int(&sig.r, 1); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &keyj, &sig.r); + secp256k1_ge_set_gej(&key, &keyj); + msg = sig.s; + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &key, &msg) == 0); + } + + /* Test r/s equal to zero */ + { + /* (1,1) encoded in DER. */ + unsigned char sigcder[8] = {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01}; + unsigned char sigc64[64] = { + 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, 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, 0x01, + }; + unsigned char pubkeyc[65]; + int pubkeyclen = 65; + CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, pubkeyc, &pubkeyclen, 0, 0) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 1); + sigcder[4] = 0; + sigc64[31] = 0; + CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, pubkeyb, &pubkeyblen, 1, 0) == 0); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 0); + sigcder[4] = 1; + sigcder[7] = 0; + sigc64[31] = 1; + sigc64[63] = 0; + CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, pubkeyb, &pubkeyblen, 1, 0) == 0); + CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 0); + } + + /*Signature where s would be zero.*/ + { + const unsigned char nonce[32] = { + 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, 0x01, + }; + static const unsigned char nonce2[32] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, + 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B, + 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x40 + }; + const unsigned char key[32] = { + 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, 0x01, + }; + unsigned char msg[32] = { + 0x86, 0x41, 0x99, 0x81, 0x06, 0x23, 0x44, 0x53, + 0xaa, 0x5f, 0x9d, 0x6a, 0x31, 0x78, 0xf4, 0xf7, + 0xb8, 0x12, 0xe0, 0x0b, 0x81, 0x7a, 0x77, 0x62, + 0x65, 0xdf, 0xdd, 0x31, 0xb9, 0x3e, 0x29, 0xa9, + }; + unsigned char sig[72]; + int siglen = 72; + CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce) == 0); + CHECK(siglen == 0); + CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce2) == 0); + CHECK(siglen == 0); + msg[31] = 0xaa; + siglen = 72; + CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce) == 1); + CHECK(siglen > 0); + CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce2) == 1); + CHECK(siglen > 0); + siglen = 10; + CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce) != 1); + CHECK(siglen == 0); + } + + /* Nonce function corner cases. */ + for (t = 0; t < 2; t++) { + static const unsigned char zero[32] = {0x00}; + int i; + unsigned char key[32]; + unsigned char msg[32]; + unsigned char sig[72]; + unsigned char sig2[72]; + secp256k1_ecdsa_sig_t s[512]; + int siglen = 72; + int siglen2 = 72; + int recid2; + const unsigned char *extra; + extra = t == 0 ? NULL : zero; + memset(msg, 0, 32); + msg[31] = 1; + /* High key results in signature failure. */ + memset(key, 0xFF, 32); + CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, NULL, extra) == 0); + CHECK(siglen == 0); + /* Zero key results in signature failure. */ + memset(key, 0, 32); + CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, NULL, extra) == 0); + CHECK(siglen == 0); + /* Nonce function failure results in signature failure. */ + key[31] = 1; + CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, nonce_function_test_fail, extra) == 0); + CHECK(siglen == 0); + CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig, key, nonce_function_test_fail, extra, &recid) == 0); + CHECK(is_empty_compact_signature(sig)); + /* The retry loop successfully makes its way to the first good value. */ + siglen = 72; + CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, nonce_function_test_retry, extra) == 1); + CHECK(siglen > 0); + CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, nonce_function_rfc6979, extra) == 1); + CHECK(siglen > 0); + CHECK((siglen == siglen2) && (memcmp(sig, sig2, siglen) == 0)); + CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig, key, nonce_function_test_retry, extra, &recid) == 1); + CHECK(!is_empty_compact_signature(sig)); + CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig2, key, nonce_function_rfc6979, extra, &recid2) == 1); + CHECK(!is_empty_compact_signature(sig2)); + CHECK((recid == recid2) && (memcmp(sig, sig2, 64) == 0)); + /* The default nonce function is determinstic. */ + siglen = 72; + siglen2 = 72; + CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, NULL, extra) == 1); + CHECK(siglen > 0); + CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, NULL, extra) == 1); + CHECK(siglen2 > 0); + CHECK((siglen == siglen2) && (memcmp(sig, sig2, siglen) == 0)); + CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig, key, NULL, extra, &recid) == 1); + CHECK(!is_empty_compact_signature(sig)); + CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig2, key, NULL, extra, &recid2) == 1); + CHECK(!is_empty_compact_signature(sig)); + CHECK((recid == recid2) && (memcmp(sig, sig2, 64) == 0)); + /* The default nonce function changes output with different messages. */ + for(i = 0; i < 256; i++) { + int j; + siglen2 = 72; + msg[0] = i; + CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, NULL, extra) == 1); + CHECK(!is_empty_compact_signature(sig)); + CHECK(secp256k1_ecdsa_sig_parse(&s[i], sig2, siglen2)); + for (j = 0; j < i; j++) { + CHECK(!secp256k1_scalar_eq(&s[i].r, &s[j].r)); + } + } + msg[0] = 0; + msg[31] = 2; + /* The default nonce function changes output with different keys. */ + for(i = 256; i < 512; i++) { + int j; + siglen2 = 72; + key[0] = i - 256; + CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, NULL, extra) == 1); + CHECK(secp256k1_ecdsa_sig_parse(&s[i], sig2, siglen2)); + for (j = 0; j < i; j++) { + CHECK(!secp256k1_scalar_eq(&s[i].r, &s[j].r)); + } + } + key[0] = 0; + } + + /* Privkey export where pubkey is the point at infinity. */ + { + unsigned char privkey[300]; + unsigned char seckey[32] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41, + }; + int outlen = 300; + CHECK(!secp256k1_ec_privkey_export(ctx, seckey, privkey, &outlen, 0)); + CHECK(!secp256k1_ec_privkey_export(ctx, seckey, privkey, &outlen, 1)); + } +} + +void run_ecdsa_edge_cases(void) { + test_ecdsa_edge_cases(); +} + +#ifdef ENABLE_OPENSSL_TESTS +EC_KEY *get_openssl_key(const secp256k1_scalar_t *key) { + unsigned char privkey[300]; + int privkeylen; + const unsigned char* pbegin = privkey; + int compr = secp256k1_rand32() & 1; + EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_secp256k1); + CHECK(secp256k1_eckey_privkey_serialize(&ctx->ecmult_gen_ctx, privkey, &privkeylen, key, compr)); + CHECK(d2i_ECPrivateKey(&ec_key, &pbegin, privkeylen)); + CHECK(EC_KEY_check_key(ec_key)); + return ec_key; +} + +void test_ecdsa_openssl(void) { + secp256k1_gej_t qj; + secp256k1_ge_t q; + secp256k1_ecdsa_sig_t sig; + secp256k1_scalar_t one; + secp256k1_scalar_t msg2; + secp256k1_scalar_t key, msg; + EC_KEY *ec_key; + unsigned int sigsize = 80; + int secp_sigsize = 80; + unsigned char message[32]; + unsigned char signature[80]; + secp256k1_rand256_test(message); + secp256k1_scalar_set_b32(&msg, message, NULL); + random_scalar_order_test(&key); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &qj, &key); + secp256k1_ge_set_gej(&q, &qj); + ec_key = get_openssl_key(&key); + CHECK(ec_key); + CHECK(ECDSA_sign(0, message, sizeof(message), signature, &sigsize, ec_key)); + CHECK(secp256k1_ecdsa_sig_parse(&sig, signature, sigsize)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &q, &msg)); + secp256k1_scalar_set_int(&one, 1); + secp256k1_scalar_add(&msg2, &msg, &one); + CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &q, &msg2)); + + random_sign(&sig, &key, &msg, NULL); + CHECK(secp256k1_ecdsa_sig_serialize(signature, &secp_sigsize, &sig)); + CHECK(ECDSA_verify(0, message, sizeof(message), signature, secp_sigsize, ec_key) == 1); + + EC_KEY_free(ec_key); +} + +void run_ecdsa_openssl(void) { + int i; + for (i = 0; i < 10*count; i++) { + test_ecdsa_openssl(); + } +} +#endif + +int main(int argc, char **argv) { + unsigned char seed16[16] = {0}; + unsigned char run32[32] = {0}; + /* find iteration count */ + if (argc > 1) { + count = strtol(argv[1], NULL, 0); + } + + /* find random seed */ + if (argc > 2) { + int pos = 0; + const char* ch = argv[2]; + while (pos < 16 && ch[0] != 0 && ch[1] != 0) { + unsigned short sh; + if (sscanf(ch, "%2hx", &sh)) { + seed16[pos] = sh; + } else { + break; + } + ch += 2; + pos++; + } + } else { + FILE *frand = fopen("/dev/urandom", "r"); + if (!frand || !fread(&seed16, sizeof(seed16), 1, frand)) { + uint64_t t = time(NULL) * (uint64_t)1337; + seed16[0] ^= t; + seed16[1] ^= t >> 8; + seed16[2] ^= t >> 16; + seed16[3] ^= t >> 24; + seed16[4] ^= t >> 32; + seed16[5] ^= t >> 40; + seed16[6] ^= t >> 48; + seed16[7] ^= t >> 56; + } + fclose(frand); + } + secp256k1_rand_seed(seed16); + + printf("test count = %i\n", count); + printf("random seed = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", seed16[0], seed16[1], seed16[2], seed16[3], seed16[4], seed16[5], seed16[6], seed16[7], seed16[8], seed16[9], seed16[10], seed16[11], seed16[12], seed16[13], seed16[14], seed16[15]); + + /* initialize */ + run_context_tests(); + ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + + if (secp256k1_rand32() & 1) { + secp256k1_rand256(run32); + CHECK(secp256k1_context_randomize(ctx, secp256k1_rand32() & 1 ? run32 : NULL)); + } + + run_sha256_tests(); + run_hmac_sha256_tests(); + run_rfc6979_hmac_sha256_tests(); + +#ifndef USE_NUM_NONE + /* num tests */ + run_num_smalltests(); +#endif + + /* scalar tests */ + run_scalar_tests(); + + /* field tests */ + run_field_inv(); + run_field_inv_var(); + run_field_inv_all_var(); + run_field_misc(); + run_field_convert(); + run_sqr(); + run_sqrt(); + + /* group tests */ + run_ge(); + + /* ecmult tests */ + run_wnaf(); + run_point_times_order(); + run_ecmult_chain(); + run_ecmult_constants(); + run_ecmult_gen_blind(); + + /* ecdsa tests */ + run_random_pubkeys(); + run_ecdsa_sign_verify(); + run_ecdsa_end_to_end(); + run_ecdsa_edge_cases(); +#ifdef ENABLE_OPENSSL_TESTS + run_ecdsa_openssl(); +#endif + + secp256k1_rand256(run32); + printf("random run = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", run32[0], run32[1], run32[2], run32[3], run32[4], run32[5], run32[6], run32[7], run32[8], run32[9], run32[10], run32[11], run32[12], run32[13], run32[14], run32[15]); + + /* shutdown */ + secp256k1_context_destroy(ctx); + return 0; +} diff --git a/src/cryptoconditions/src/include/secp256k1/src/util.h b/src/cryptoconditions/src/include/secp256k1/src/util.h new file mode 100644 index 000000000..ae98639f7 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/util.h @@ -0,0 +1,104 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef _SECP256K1_UTIL_H_ +#define _SECP256K1_UTIL_H_ + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#include +#include +#include + +#ifdef DETERMINISTIC +#define TEST_FAILURE(msg) do { \ + fprintf(stderr, "%s\n", msg); \ + abort(); \ +} while(0); +#else +#define TEST_FAILURE(msg) do { \ + fprintf(stderr, "%s:%d: %s\n", __FILE__, __LINE__, msg); \ + abort(); \ +} while(0) +#endif + +#ifdef HAVE_BUILTIN_EXPECT +#define EXPECT(x,c) __builtin_expect((x),(c)) +#else +#define EXPECT(x,c) (x) +#endif + +#ifdef DETERMINISTIC +#define CHECK(cond) do { \ + if (EXPECT(!(cond), 0)) { \ + TEST_FAILURE("test condition failed"); \ + } \ +} while(0) +#else +#define CHECK(cond) do { \ + if (EXPECT(!(cond), 0)) { \ + TEST_FAILURE("test condition failed: " #cond); \ + } \ +} while(0) +#endif + +/* Like assert(), but safe to use on expressions with side effects. */ +#ifndef NDEBUG +#define DEBUG_CHECK CHECK +#else +#define DEBUG_CHECK(cond) do { (void)(cond); } while(0) +#endif + +/* Like DEBUG_CHECK(), but when VERIFY is defined instead of NDEBUG not defined. */ +#ifdef VERIFY +#define VERIFY_CHECK CHECK +#else +#define VERIFY_CHECK(cond) do { (void)(cond); } while(0) +#endif + +static SECP256K1_INLINE void *checked_malloc(size_t size) { + void *ret = malloc(size); + CHECK(ret != NULL); + return ret; +} + +/* Macro for restrict, when available and not in a VERIFY build. */ +#if defined(SECP256K1_BUILD) && defined(VERIFY) +# define SECP256K1_RESTRICT +#else +# if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) +# if SECP256K1_GNUC_PREREQ(3,0) +# define SECP256K1_RESTRICT __restrict__ +# elif (defined(_MSC_VER) && _MSC_VER >= 1400) +# define SECP256K1_RESTRICT __restrict +# else +# define SECP256K1_RESTRICT +# endif +# else +# define SECP256K1_RESTRICT restrict +# endif +#endif + +#if defined(_WIN32) +# define I64FORMAT "I64d" +# define I64uFORMAT "I64u" +#else +# define I64FORMAT "lld" +# define I64uFORMAT "llu" +#endif + +#if defined(HAVE___INT128) +# if defined(__GNUC__) +# define SECP256K1_GNUC_EXT __extension__ +# else +# define SECP256K1_GNUC_EXT +# endif +SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t; +#endif + +#endif diff --git a/src/cryptoconditions/src/include/sha256.c b/src/cryptoconditions/src/include/sha256.c new file mode 100644 index 000000000..e273836ce --- /dev/null +++ b/src/cryptoconditions/src/include/sha256.c @@ -0,0 +1,264 @@ +/*- + * Copyright 2005 Colin Percival + * Copyright 2013 Christian Mehlis & René Kijewski + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libmd/sha256c.c,v 1.2 2006/01/17 15:35:56 phk Exp $ + */ + +/** + * @ingroup sys_crypto + * @{ + * + * @file sha256.c + * @brief SHA256 hash function implementation + * + * @author Colin Percival + * @author Christian Mehlis + * @author Rene Kijewski + * + * @} + */ + +#include "sha256.h" + +#define memcpy __builtin_memcpy +#define memset __builtin_memset + +#ifdef __BIG_ENDIAN__ +/* Copy a vector of big-endian uint32_t into a vector of bytes */ +#define be32enc_vect memcpy + +/* Copy a vector of bytes into a vector of big-endian uint32_t */ +#define be32dec_vect memcpy + +#else /* !__BIG_ENDIAN__ */ + +/* + * Encode a length len/4 vector of (uint32_t) into a length len vector of + * (unsigned char) in big-endian form. Assumes len is a multiple of 4. + */ +static void be32enc_vect(void *dst_, const void *src_, size_t len) +{ + uint32_t *dst = dst_; + const uint32_t *src = src_; + size_t i; + + for (i = 0; i < len / 4; i++) { + dst[i] = __builtin_bswap32(src[i]); + } +} + +/* + * Decode a big-endian length len vector of (unsigned char) into a length + * len/4 vector of (uint32_t). Assumes len is a multiple of 4. + */ +#define be32dec_vect be32enc_vect + +#endif /* __BYTE_ORDER__ != __ORDER_BIG_ENDIAN__ */ + +/* Elementary functions used by SHA256 */ +#define Ch(x, y, z) ((x & (y ^ z)) ^ z) +#define Maj(x, y, z) ((x & (y | z)) | (y & z)) +#define SHR(x, n) (x >> n) +#define ROTR(x, n) ((x >> n) | (x << (32 - n))) +#define S0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22)) +#define S1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25)) +#define s0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ SHR(x, 3)) +#define s1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHR(x, 10)) + +static const uint32_t 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, +}; + +/* + * SHA256 block compression function. The 256-bit state is transformed via + * the 512-bit input block to produce a new state. + */ +static void sha256_transform(uint32_t *state, const unsigned char block[64]) +{ + uint32_t W[64]; + uint32_t S[8]; + int i; + + /* 1. Prepare message schedule W. */ + be32dec_vect(W, block, 64); + for (i = 16; i < 64; i++) { + W[i] = s1(W[i - 2]) + W[i - 7] + s0(W[i - 15]) + W[i - 16]; + } + + /* 2. Initialize working variables. */ + memcpy(S, state, 32); + + /* 3. Mix. */ + for (i = 0; i < 64; ++i) { + uint32_t e = S[(68 - i) % 8], f = S[(69 - i) % 8]; + uint32_t g = S[(70 - i) % 8], h = S[(71 - i) % 8]; + uint32_t t0 = h + S1(e) + Ch(e, f, g) + W[i] + K[i]; + + uint32_t a = S[(64 - i) % 8], b = S[(65 - i) % 8]; + uint32_t c = S[(66 - i) % 8], d = S[(67 - i) % 8]; + uint32_t t1 = S0(a) + Maj(a, b, c); + + S[(67 - i) % 8] = d + t0; + S[(71 - i) % 8] = t0 + t1; + } + + /* 4. Mix local working variables into global state */ + for (i = 0; i < 8; i++) { + state[i] += S[i]; + } +} + +/* Add padding and terminating bit-count. */ +static void sha256_pad(sha256_context_t *ctx) +{ + + const unsigned char PAD[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + /* + * Convert length to a vector of bytes -- we do this now rather + * than later because the length will change after we pad. + */ + unsigned char len[8]; + be32enc_vect(len, ctx->count, 8); + + /* Add 1--64 bytes so that the resulting length is 56 mod 64 */ + uint32_t r = (ctx->count[1] >> 3) & 0x3f; + uint32_t plen = (r < 56) ? (56 - r) : (120 - r); + sha256_update(ctx, PAD, (size_t) plen); + + /* Add the terminating bit-count */ + sha256_update(ctx, len, 8); +} + +/* SHA-256 initialization. Begins a SHA-256 operation. */ +void sha256_init(sha256_context_t *ctx) +{ + /* Zero bits processed so far */ + ctx->count[0] = ctx->count[1] = 0; + + /* Magic initialization constants */ + ctx->state[0] = 0x6A09E667; + ctx->state[1] = 0xBB67AE85; + ctx->state[2] = 0x3C6EF372; + ctx->state[3] = 0xA54FF53A; + ctx->state[4] = 0x510E527F; + ctx->state[5] = 0x9B05688C; + ctx->state[6] = 0x1F83D9AB; + ctx->state[7] = 0x5BE0CD19; +} + +/* Add bytes into the hash */ +void sha256_update(sha256_context_t *ctx, const void *in, size_t len) +{ + /* Number of bytes left in the buffer from previous updates */ + uint32_t r = (ctx->count[1] >> 3) & 0x3f; + + /* Convert the length into a number of bits */ + uint32_t bitlen1 = ((uint32_t) len) << 3; + uint32_t bitlen0 = ((uint32_t) len) >> 29; + + /* Update number of bits */ + if ((ctx->count[1] += bitlen1) < bitlen1) { + ctx->count[0]++; + } + + ctx->count[0] += bitlen0; + + /* Handle the case where we don't need to perform any transforms */ + if (len < 64 - r) { + memcpy(&ctx->buf[r], in, len); + return; + } + + /* Finish the current block */ + const unsigned char *src = in; + + memcpy(&ctx->buf[r], src, 64 - r); + sha256_transform(ctx->state, ctx->buf); + src += 64 - r; + len -= 64 - r; + + /* Perform complete blocks */ + while (len >= 64) { + sha256_transform(ctx->state, src); + src += 64; + len -= 64; + } + + /* Copy left over data into buffer */ + memcpy(ctx->buf, src, len); +} + +/* + * SHA-256 finalization. Pads the input data, exports the hash value, + * and clears the context state. + */ +void sha256_final(unsigned char digest[32], sha256_context_t *ctx) +{ + /* Add padding */ + sha256_pad(ctx); + + /* Write the hash */ + be32enc_vect(digest, ctx->state, 32); + + /* Clear the context state */ + memset((void *) ctx, 0, sizeof(*ctx)); +} + +unsigned char *sha256(const unsigned char *d, size_t n, unsigned char *md) +{ + sha256_context_t c __attribute__((aligned(4))); + static unsigned char m[SHA256_DIGEST_LENGTH] __attribute__((aligned(4))); + + if (md == NULL) { + md = m; + } + + sha256_init(&c); + sha256_update(&c, d, n); + sha256_final(md, &c); + + return md; +} diff --git a/src/cryptoconditions/src/include/sha256.h b/src/cryptoconditions/src/include/sha256.h new file mode 100644 index 000000000..7bbf3f43a --- /dev/null +++ b/src/cryptoconditions/src/include/sha256.h @@ -0,0 +1,114 @@ +/*- + * Copyright 2005 Colin Percival + * Copyright 2013 Christian Mehlis & René Kijewski + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libmd/sha256.h,v 1.1.2.1 2005/06/24 13:32:25 cperciva Exp $ + */ + +/** + * @defgroup sys_sha256 SHA264 + * @ingroup sys + * @brief SHA264 hash generator + */ + +/** + * @ingroup sys_crypto + * @{ + * + * @file sha256.h + * @brief Header definitions for the SHA256 hash function + * + * @author Colin Percival + * @author Christian Mehlis + * @author Rene Kijewski + */ + +#ifndef _SHA256_H_ +#define _SHA256_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define SHA256_DIGEST_LENGTH 32 + +/** + * @brief Context for ciper operatins based on sha256 + */ +typedef struct { + /** global state */ + uint32_t state[8]; + /** processed bytes counter */ + uint32_t count[2]; + /** data buffer */ + unsigned char buf[64]; +} sha256_context_t; + +/** + * @brief SHA-256 initialization. Begins a SHA-256 operation. + * + * @param ctx sha256_context_t handle to init + */ +void sha256_init(sha256_context_t *ctx); + +/** + * @brief Add bytes into the hash + * + * @param ctx sha256_context_t handle to use + * @param in pointer to the input buffer + * @param len length of the buffer + */ +void sha256_update(sha256_context_t *ctx, const void *in, size_t len); + +/** + * @brief SHA-256 finalization. Pads the input data, exports the hash value, + * and clears the context state. + * + * @param digest resulting digest, this is the hash of all the bytes + * @param ctx sha256_context_t handle to use + */ +void sha256_final(unsigned char digest[32], sha256_context_t *ctx); + +/** + * @brief A wrapper function to simplify the generation of a hash, this is + * usefull for generating sha256 for one buffer + * + * @param d pointer to the buffer to generate hash from + * @param n length of the buffer + * @param md optional pointer to an array for the result, length must be + * SHA256_DIGEST_LENGTH + * if md == NULL, one static buffer is used + */ +unsigned char *sha256(const unsigned char *d, size_t n, unsigned char *md); + +#ifdef __cplusplus +} +#endif + +/** @} */ +#endif /* _SHA256_H_ */ diff --git a/src/cryptoconditions/src/include/tweetnacl.c b/src/cryptoconditions/src/include/tweetnacl.c new file mode 100644 index 000000000..8ac0a1806 --- /dev/null +++ b/src/cryptoconditions/src/include/tweetnacl.c @@ -0,0 +1,809 @@ +#include "tweetnacl.h" +#define FOR(i,n) for (i = 0;i < n;++i) +#define sv static void + +typedef unsigned char u8; +typedef unsigned long u32; +typedef unsigned long long u64; +typedef long long i64; +typedef i64 gf[16]; +extern void randombytes(u8 *,u64); + +static const u8 + _0[16], + _9[32] = {9}; +static const gf + gf0, + gf1 = {1}, + _121665 = {0xDB41,1}, + D = {0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203}, + D2 = {0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406}, + X = {0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169}, + Y = {0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666}, + I = {0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83}; + +static u32 L32(u32 x,int c) { return (x << c) | ((x&0xffffffff) >> (32 - c)); } + +static u32 ld32(const u8 *x) +{ + u32 u = x[3]; + u = (u<<8)|x[2]; + u = (u<<8)|x[1]; + return (u<<8)|x[0]; +} + +static u64 dl64(const u8 *x) +{ + u64 i,u=0; + FOR(i,8) u=(u<<8)|x[i]; + return u; +} + +sv st32(u8 *x,u32 u) +{ + int i; + FOR(i,4) { x[i] = u; u >>= 8; } +} + +sv ts64(u8 *x,u64 u) +{ + int i; + for (i = 7;i >= 0;--i) { x[i] = u; u >>= 8; } +} + +static int vn(const u8 *x,const u8 *y,int n) +{ + u32 i,d = 0; + FOR(i,n) d |= x[i]^y[i]; + return (1 & ((d - 1) >> 8)) - 1; +} + +int crypto_verify_16(const u8 *x,const u8 *y) +{ + return vn(x,y,16); +} + +int crypto_verify_32(const u8 *x,const u8 *y) +{ + return vn(x,y,32); +} + +sv core(u8 *out,const u8 *in,const u8 *k,const u8 *c,int h) +{ + u32 w[16],x[16],y[16],t[4]; + int i,j,m; + + FOR(i,4) { + x[5*i] = ld32(c+4*i); + x[1+i] = ld32(k+4*i); + x[6+i] = ld32(in+4*i); + x[11+i] = ld32(k+16+4*i); + } + + FOR(i,16) y[i] = x[i]; + + FOR(i,20) { + FOR(j,4) { + FOR(m,4) t[m] = x[(5*j+4*m)%16]; + t[1] ^= L32(t[0]+t[3], 7); + t[2] ^= L32(t[1]+t[0], 9); + t[3] ^= L32(t[2]+t[1],13); + t[0] ^= L32(t[3]+t[2],18); + FOR(m,4) w[4*j+(j+m)%4] = t[m]; + } + FOR(m,16) x[m] = w[m]; + } + + if (h) { + FOR(i,16) x[i] += y[i]; + FOR(i,4) { + x[5*i] -= ld32(c+4*i); + x[6+i] -= ld32(in+4*i); + } + FOR(i,4) { + st32(out+4*i,x[5*i]); + st32(out+16+4*i,x[6+i]); + } + } else + FOR(i,16) st32(out + 4 * i,x[i] + y[i]); +} + +int crypto_core_salsa20(u8 *out,const u8 *in,const u8 *k,const u8 *c) +{ + core(out,in,k,c,0); + return 0; +} + +int crypto_core_hsalsa20(u8 *out,const u8 *in,const u8 *k,const u8 *c) +{ + core(out,in,k,c,1); + return 0; +} + +static const u8 sigma[16] = "expand 32-byte k"; + +int crypto_stream_salsa20_xor(u8 *c,const u8 *m,u64 b,const u8 *n,const u8 *k) +{ + u8 z[16],x[64]; + u32 u,i; + if (!b) return 0; + FOR(i,16) z[i] = 0; + FOR(i,8) z[i] = n[i]; + while (b >= 64) { + crypto_core_salsa20(x,z,k,sigma); + FOR(i,64) c[i] = (m?m[i]:0) ^ x[i]; + u = 1; + for (i = 8;i < 16;++i) { + u += (u32) z[i]; + z[i] = u; + u >>= 8; + } + b -= 64; + c += 64; + if (m) m += 64; + } + if (b) { + crypto_core_salsa20(x,z,k,sigma); + FOR(i,b) c[i] = (m?m[i]:0) ^ x[i]; + } + return 0; +} + +int crypto_stream_salsa20(u8 *c,u64 d,const u8 *n,const u8 *k) +{ + return crypto_stream_salsa20_xor(c,0,d,n,k); +} + +int crypto_stream(u8 *c,u64 d,const u8 *n,const u8 *k) +{ + u8 s[32]; + crypto_core_hsalsa20(s,n,k,sigma); + return crypto_stream_salsa20(c,d,n+16,s); +} + +int crypto_stream_xor(u8 *c,const u8 *m,u64 d,const u8 *n,const u8 *k) +{ + u8 s[32]; + crypto_core_hsalsa20(s,n,k,sigma); + return crypto_stream_salsa20_xor(c,m,d,n+16,s); +} + +sv add1305(u32 *h,const u32 *c) +{ + u32 j,u = 0; + FOR(j,17) { + u += h[j] + c[j]; + h[j] = u & 255; + u >>= 8; + } +} + +static const u32 minusp[17] = { + 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252 +} ; + +int crypto_onetimeauth(u8 *out,const u8 *m,u64 n,const u8 *k) +{ + u32 s,i,j,u,x[17],r[17],h[17],c[17],g[17]; + + FOR(j,17) r[j]=h[j]=0; + FOR(j,16) r[j]=k[j]; + r[3]&=15; + r[4]&=252; + r[7]&=15; + r[8]&=252; + r[11]&=15; + r[12]&=252; + r[15]&=15; + + while (n > 0) { + FOR(j,17) c[j] = 0; + for (j = 0;(j < 16) && (j < n);++j) c[j] = m[j]; + c[j] = 1; + m += j; n -= j; + add1305(h,c); + FOR(i,17) { + x[i] = 0; + FOR(j,17) x[i] += h[j] * ((j <= i) ? r[i - j] : 320 * r[i + 17 - j]); + } + FOR(i,17) h[i] = x[i]; + u = 0; + FOR(j,16) { + u += h[j]; + h[j] = u & 255; + u >>= 8; + } + u += h[16]; h[16] = u & 3; + u = 5 * (u >> 2); + FOR(j,16) { + u += h[j]; + h[j] = u & 255; + u >>= 8; + } + u += h[16]; h[16] = u; + } + + FOR(j,17) g[j] = h[j]; + add1305(h,minusp); + s = -(h[16] >> 7); + FOR(j,17) h[j] ^= s & (g[j] ^ h[j]); + + FOR(j,16) c[j] = k[j + 16]; + c[16] = 0; + add1305(h,c); + FOR(j,16) out[j] = h[j]; + return 0; +} + +int crypto_onetimeauth_verify(const u8 *h,const u8 *m,u64 n,const u8 *k) +{ + u8 x[16]; + crypto_onetimeauth(x,m,n,k); + return crypto_verify_16(h,x); +} + +int crypto_secretbox(u8 *c,const u8 *m,u64 d,const u8 *n,const u8 *k) +{ + int i; + if (d < 32) return -1; + crypto_stream_xor(c,m,d,n,k); + crypto_onetimeauth(c + 16,c + 32,d - 32,c); + FOR(i,16) c[i] = 0; + return 0; +} + +int crypto_secretbox_open(u8 *m,const u8 *c,u64 d,const u8 *n,const u8 *k) +{ + int i; + u8 x[32]; + if (d < 32) return -1; + crypto_stream(x,32,n,k); + if (crypto_onetimeauth_verify(c + 16,c + 32,d - 32,x) != 0) return -1; + crypto_stream_xor(m,c,d,n,k); + FOR(i,32) m[i] = 0; + return 0; +} + +sv set25519(gf r, const gf a) +{ + int i; + FOR(i,16) r[i]=a[i]; +} + +sv car25519(gf o) +{ + int i; + i64 c; + FOR(i,16) { + o[i]+=(1LL<<16); + c=o[i]>>16; + o[(i+1)*(i<15)]+=c-1+37*(c-1)*(i==15); + o[i]-=c<<16; + } +} + +sv sel25519(gf p,gf q,int b) +{ + i64 t,i,c=~(b-1); + FOR(i,16) { + t= c&(p[i]^q[i]); + p[i]^=t; + q[i]^=t; + } +} + +sv pack25519(u8 *o,const gf n) +{ + int i,j,b; + gf m,t; + FOR(i,16) t[i]=n[i]; + car25519(t); + car25519(t); + car25519(t); + FOR(j,2) { + m[0]=t[0]-0xffed; + for(i=1;i<15;i++) { + m[i]=t[i]-0xffff-((m[i-1]>>16)&1); + m[i-1]&=0xffff; + } + m[15]=t[15]-0x7fff-((m[14]>>16)&1); + b=(m[15]>>16)&1; + m[14]&=0xffff; + sel25519(t,m,1-b); + } + FOR(i,16) { + o[2*i]=t[i]&0xff; + o[2*i+1]=t[i]>>8; + } +} + +static int neq25519(const gf a, const gf b) +{ + u8 c[32],d[32]; + pack25519(c,a); + pack25519(d,b); + return crypto_verify_32(c,d); +} + +static u8 par25519(const gf a) +{ + u8 d[32]; + pack25519(d,a); + return d[0]&1; +} + +sv unpack25519(gf o, const u8 *n) +{ + int i; + FOR(i,16) o[i]=n[2*i]+((i64)n[2*i+1]<<8); + o[15]&=0x7fff; +} + +sv A(gf o,const gf a,const gf b) +{ + int i; + FOR(i,16) o[i]=a[i]+b[i]; +} + +sv Z(gf o,const gf a,const gf b) +{ + int i; + FOR(i,16) o[i]=a[i]-b[i]; +} + +sv M(gf o,const gf a,const gf b) +{ + i64 i,j,t[31]; + FOR(i,31) t[i]=0; + FOR(i,16) FOR(j,16) t[i+j]+=a[i]*b[j]; + FOR(i,15) t[i]+=38*t[i+16]; + FOR(i,16) o[i]=t[i]; + car25519(o); + car25519(o); +} + +sv S(gf o,const gf a) +{ + M(o,a,a); +} + +sv inv25519(gf o,const gf i) +{ + gf c; + int a; + FOR(a,16) c[a]=i[a]; + for(a=253;a>=0;a--) { + S(c,c); + if(a!=2&&a!=4) M(c,c,i); + } + FOR(a,16) o[a]=c[a]; +} + +sv pow2523(gf o,const gf i) +{ + gf c; + int a; + FOR(a,16) c[a]=i[a]; + for(a=250;a>=0;a--) { + S(c,c); + if(a!=1) M(c,c,i); + } + FOR(a,16) o[a]=c[a]; +} + +int crypto_scalarmult(u8 *q,const u8 *n,const u8 *p) +{ + u8 z[32]; + i64 x[80],r,i; + gf a,b,c,d,e,f; + FOR(i,31) z[i]=n[i]; + z[31]=(n[31]&127)|64; + z[0]&=248; + unpack25519(x,p); + FOR(i,16) { + b[i]=x[i]; + d[i]=a[i]=c[i]=0; + } + a[0]=d[0]=1; + for(i=254;i>=0;--i) { + r=(z[i>>3]>>(i&7))&1; + sel25519(a,b,r); + sel25519(c,d,r); + A(e,a,c); + Z(a,a,c); + A(c,b,d); + Z(b,b,d); + S(d,e); + S(f,a); + M(a,c,a); + M(c,b,e); + A(e,a,c); + Z(a,a,c); + S(b,a); + Z(c,d,f); + M(a,c,_121665); + A(a,a,d); + M(c,c,a); + M(a,d,f); + M(d,b,x); + S(b,e); + sel25519(a,b,r); + sel25519(c,d,r); + } + FOR(i,16) { + x[i+16]=a[i]; + x[i+32]=c[i]; + x[i+48]=b[i]; + x[i+64]=d[i]; + } + inv25519(x+32,x+32); + M(x+16,x+16,x+32); + pack25519(q,x+16); + return 0; +} + +int crypto_scalarmult_base(u8 *q,const u8 *n) +{ + return crypto_scalarmult(q,n,_9); +} + +int crypto_box_keypair(u8 *y,u8 *x) +{ + randombytes(x,32); + return crypto_scalarmult_base(y,x); +} + +int crypto_box_beforenm(u8 *k,const u8 *y,const u8 *x) +{ + u8 s[32]; + crypto_scalarmult(s,x,y); + return crypto_core_hsalsa20(k,_0,s,sigma); +} + +int crypto_box_afternm(u8 *c,const u8 *m,u64 d,const u8 *n,const u8 *k) +{ + return crypto_secretbox(c,m,d,n,k); +} + +int crypto_box_open_afternm(u8 *m,const u8 *c,u64 d,const u8 *n,const u8 *k) +{ + return crypto_secretbox_open(m,c,d,n,k); +} + +int crypto_box(u8 *c,const u8 *m,u64 d,const u8 *n,const u8 *y,const u8 *x) +{ + u8 k[32]; + crypto_box_beforenm(k,y,x); + return crypto_box_afternm(c,m,d,n,k); +} + +int crypto_box_open(u8 *m,const u8 *c,u64 d,const u8 *n,const u8 *y,const u8 *x) +{ + u8 k[32]; + crypto_box_beforenm(k,y,x); + return crypto_box_open_afternm(m,c,d,n,k); +} + +static u64 R(u64 x,int c) { return (x >> c) | (x << (64 - c)); } +static u64 Ch(u64 x,u64 y,u64 z) { return (x & y) ^ (~x & z); } +static u64 Maj(u64 x,u64 y,u64 z) { return (x & y) ^ (x & z) ^ (y & z); } +static u64 Sigma0(u64 x) { return R(x,28) ^ R(x,34) ^ R(x,39); } +static u64 Sigma1(u64 x) { return R(x,14) ^ R(x,18) ^ R(x,41); } +static u64 sigma0(u64 x) { return R(x, 1) ^ R(x, 8) ^ (x >> 7); } +static u64 sigma1(u64 x) { return R(x,19) ^ R(x,61) ^ (x >> 6); } + +static const u64 K[80] = +{ + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, + 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, + 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, + 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, + 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, + 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, + 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, + 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, + 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, + 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, + 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, + 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, + 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, + 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL +}; + +int crypto_hashblocks(u8 *x,const u8 *m,u64 n) +{ + u64 z[8],b[8],a[8],w[16],t; + int i,j; + + FOR(i,8) z[i] = a[i] = dl64(x + 8 * i); + + while (n >= 128) { + FOR(i,16) w[i] = dl64(m + 8 * i); + + FOR(i,80) { + FOR(j,8) b[j] = a[j]; + t = a[7] + Sigma1(a[4]) + Ch(a[4],a[5],a[6]) + K[i] + w[i%16]; + b[7] = t + Sigma0(a[0]) + Maj(a[0],a[1],a[2]); + b[3] += t; + FOR(j,8) a[(j+1)%8] = b[j]; + if (i%16 == 15) + FOR(j,16) + w[j] += w[(j+9)%16] + sigma0(w[(j+1)%16]) + sigma1(w[(j+14)%16]); + } + + FOR(i,8) { a[i] += z[i]; z[i] = a[i]; } + + m += 128; + n -= 128; + } + + FOR(i,8) ts64(x+8*i,z[i]); + + return n; +} + +static const u8 iv[64] = { + 0x6a,0x09,0xe6,0x67,0xf3,0xbc,0xc9,0x08, + 0xbb,0x67,0xae,0x85,0x84,0xca,0xa7,0x3b, + 0x3c,0x6e,0xf3,0x72,0xfe,0x94,0xf8,0x2b, + 0xa5,0x4f,0xf5,0x3a,0x5f,0x1d,0x36,0xf1, + 0x51,0x0e,0x52,0x7f,0xad,0xe6,0x82,0xd1, + 0x9b,0x05,0x68,0x8c,0x2b,0x3e,0x6c,0x1f, + 0x1f,0x83,0xd9,0xab,0xfb,0x41,0xbd,0x6b, + 0x5b,0xe0,0xcd,0x19,0x13,0x7e,0x21,0x79 +} ; + +int crypto_hash(u8 *out,const u8 *m,u64 n) +{ + u8 h[64],x[256]; + u64 i,b = n; + + FOR(i,64) h[i] = iv[i]; + + crypto_hashblocks(h,m,n); + m += n; + n &= 127; + m -= n; + + FOR(i,256) x[i] = 0; + FOR(i,n) x[i] = m[i]; + x[n] = 128; + + n = 256-128*(n<112); + x[n-9] = b >> 61; + ts64(x+n-8,b<<3); + crypto_hashblocks(h,x,n); + + FOR(i,64) out[i] = h[i]; + + return 0; +} + +sv add(gf p[4],gf q[4]) +{ + gf a,b,c,d,t,e,f,g,h; + + Z(a, p[1], p[0]); + Z(t, q[1], q[0]); + M(a, a, t); + A(b, p[0], p[1]); + A(t, q[0], q[1]); + M(b, b, t); + M(c, p[3], q[3]); + M(c, c, D2); + M(d, p[2], q[2]); + A(d, d, d); + Z(e, b, a); + Z(f, d, c); + A(g, d, c); + A(h, b, a); + + M(p[0], e, f); + M(p[1], h, g); + M(p[2], g, f); + M(p[3], e, h); +} + +sv cswap(gf p[4],gf q[4],u8 b) +{ + int i; + FOR(i,4) + sel25519(p[i],q[i],b); +} + +sv pack(u8 *r,gf p[4]) +{ + gf tx, ty, zi; + inv25519(zi, p[2]); + M(tx, p[0], zi); + M(ty, p[1], zi); + pack25519(r, ty); + r[31] ^= par25519(tx) << 7; +} + +sv scalarmult(gf p[4],gf q[4],const u8 *s) +{ + int i; + set25519(p[0],gf0); + set25519(p[1],gf1); + set25519(p[2],gf1); + set25519(p[3],gf0); + for (i = 255;i >= 0;--i) { + u8 b = (s[i/8]>>(i&7))&1; + cswap(p,q,b); + add(q,p); + add(p,p); + cswap(p,q,b); + } +} + +sv scalarbase(gf p[4],const u8 *s) +{ + gf q[4]; + set25519(q[0],X); + set25519(q[1],Y); + set25519(q[2],gf1); + M(q[3],X,Y); + scalarmult(p,q,s); +} + +int crypto_sign_keypair(u8 *pk, u8 *sk) +{ + u8 d[64]; + gf p[4]; + int i; + + randombytes(sk, 32); + crypto_hash(d, sk, 32); + d[0] &= 248; + d[31] &= 127; + d[31] |= 64; + + scalarbase(p,d); + pack(pk,p); + + FOR(i,32) sk[32 + i] = pk[i]; + return 0; +} + +static const u64 L[32] = {0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10}; + +sv modL(u8 *r,i64 x[64]) +{ + i64 carry,i,j; + for (i = 63;i >= 32;--i) { + carry = 0; + for (j = i - 32;j < i - 12;++j) { + x[j] += carry - 16 * x[i] * L[j - (i - 32)]; + carry = (x[j] + 128) >> 8; + x[j] -= carry << 8; + } + x[j] += carry; + x[i] = 0; + } + carry = 0; + FOR(j,32) { + x[j] += carry - (x[31] >> 4) * L[j]; + carry = x[j] >> 8; + x[j] &= 255; + } + FOR(j,32) x[j] -= carry * L[j]; + FOR(i,32) { + x[i+1] += x[i] >> 8; + r[i] = x[i] & 255; + } +} + +sv reduce(u8 *r) +{ + i64 x[64],i; + FOR(i,64) x[i] = (u64) r[i]; + FOR(i,64) r[i] = 0; + modL(r,x); +} + +int crypto_sign(u8 *sm,u64 *smlen,const u8 *m,u64 n,const u8 *sk) +{ + u8 d[64],h[64],r[64]; + i64 i,j,x[64]; + gf p[4]; + + crypto_hash(d, sk, 32); + d[0] &= 248; + d[31] &= 127; + d[31] |= 64; + + *smlen = n+64; + FOR(i,n) sm[64 + i] = m[i]; + FOR(i,32) sm[32 + i] = d[32 + i]; + + crypto_hash(r, sm+32, n+32); + reduce(r); + scalarbase(p,r); + pack(sm,p); + + FOR(i,32) sm[i+32] = sk[i+32]; + crypto_hash(h,sm,n + 64); + reduce(h); + + FOR(i,64) x[i] = 0; + FOR(i,32) x[i] = (u64) r[i]; + FOR(i,32) FOR(j,32) x[i+j] += h[i] * (u64) d[j]; + modL(sm + 32,x); + + return 0; +} + +static int unpackneg(gf r[4],const u8 p[32]) +{ + gf t, chk, num, den, den2, den4, den6; + set25519(r[2],gf1); + unpack25519(r[1],p); + S(num,r[1]); + M(den,num,D); + Z(num,num,r[2]); + A(den,r[2],den); + + S(den2,den); + S(den4,den2); + M(den6,den4,den2); + M(t,den6,num); + M(t,t,den); + + pow2523(t,t); + M(t,t,num); + M(t,t,den); + M(t,t,den); + M(r[0],t,den); + + S(chk,r[0]); + M(chk,chk,den); + if (neq25519(chk, num)) M(r[0],r[0],I); + + S(chk,r[0]); + M(chk,chk,den); + if (neq25519(chk, num)) return -1; + + if (par25519(r[0]) == (p[31]>>7)) Z(r[0],gf0,r[0]); + + M(r[3],r[0],r[1]); + return 0; +} + +int crypto_sign_open(u8 *m,u64 *mlen,const u8 *sm,u64 n,const u8 *pk) +{ + int i; + u8 t[32],h[64]; + gf p[4],q[4]; + + *mlen = -1; + if (n < 64) return -1; + + if (unpackneg(q,pk)) return -1; + + FOR(i,n) m[i] = sm[i]; + FOR(i,32) m[i+32] = pk[i]; + crypto_hash(h,m,n); + reduce(h); + scalarmult(p,q,h); + + scalarbase(q,sm + 32); + add(p,q); + pack(t,p); + + n -= 64; + if (crypto_verify_32(sm, t)) { + FOR(i,n) m[i] = 0; + return -1; + } + + FOR(i,n) m[i] = sm[i + 64]; + *mlen = n; + return 0; +} diff --git a/src/cryptoconditions/src/include/tweetnacl.h b/src/cryptoconditions/src/include/tweetnacl.h new file mode 100644 index 000000000..9277fbf8f --- /dev/null +++ b/src/cryptoconditions/src/include/tweetnacl.h @@ -0,0 +1,272 @@ +#ifndef TWEETNACL_H +#define TWEETNACL_H +#define crypto_auth_PRIMITIVE "hmacsha512256" +#define crypto_auth crypto_auth_hmacsha512256 +#define crypto_auth_verify crypto_auth_hmacsha512256_verify +#define crypto_auth_BYTES crypto_auth_hmacsha512256_BYTES +#define crypto_auth_KEYBYTES crypto_auth_hmacsha512256_KEYBYTES +#define crypto_auth_IMPLEMENTATION crypto_auth_hmacsha512256_IMPLEMENTATION +#define crypto_auth_VERSION crypto_auth_hmacsha512256_VERSION +#define crypto_auth_hmacsha512256_tweet_BYTES 32 +#define crypto_auth_hmacsha512256_tweet_KEYBYTES 32 +extern int crypto_auth_hmacsha512256_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *); +extern int crypto_auth_hmacsha512256_tweet_verify(const unsigned char *,const unsigned char *,unsigned long long,const unsigned char *); +#define crypto_auth_hmacsha512256_tweet_VERSION "-" +#define crypto_auth_hmacsha512256 crypto_auth_hmacsha512256_tweet +#define crypto_auth_hmacsha512256_verify crypto_auth_hmacsha512256_tweet_verify +#define crypto_auth_hmacsha512256_BYTES crypto_auth_hmacsha512256_tweet_BYTES +#define crypto_auth_hmacsha512256_KEYBYTES crypto_auth_hmacsha512256_tweet_KEYBYTES +#define crypto_auth_hmacsha512256_VERSION crypto_auth_hmacsha512256_tweet_VERSION +#define crypto_auth_hmacsha512256_IMPLEMENTATION "crypto_auth/hmacsha512256/tweet" +#define crypto_box_PRIMITIVE "curve25519xsalsa20poly1305" +#define crypto_box crypto_box_curve25519xsalsa20poly1305 +#define crypto_box_open crypto_box_curve25519xsalsa20poly1305_open +#define crypto_box_keypair crypto_box_curve25519xsalsa20poly1305_keypair +#define crypto_box_beforenm crypto_box_curve25519xsalsa20poly1305_beforenm +#define crypto_box_afternm crypto_box_curve25519xsalsa20poly1305_afternm +#define crypto_box_open_afternm crypto_box_curve25519xsalsa20poly1305_open_afternm +#define crypto_box_PUBLICKEYBYTES crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES +#define crypto_box_SECRETKEYBYTES crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES +#define crypto_box_BEFORENMBYTES crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES +#define crypto_box_NONCEBYTES crypto_box_curve25519xsalsa20poly1305_NONCEBYTES +#define crypto_box_ZEROBYTES crypto_box_curve25519xsalsa20poly1305_ZEROBYTES +#define crypto_box_BOXZEROBYTES crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES +#define crypto_box_IMPLEMENTATION crypto_box_curve25519xsalsa20poly1305_IMPLEMENTATION +#define crypto_box_VERSION crypto_box_curve25519xsalsa20poly1305_VERSION +#define crypto_box_curve25519xsalsa20poly1305_tweet_PUBLICKEYBYTES 32 +#define crypto_box_curve25519xsalsa20poly1305_tweet_SECRETKEYBYTES 32 +#define crypto_box_curve25519xsalsa20poly1305_tweet_BEFORENMBYTES 32 +#define crypto_box_curve25519xsalsa20poly1305_tweet_NONCEBYTES 24 +#define crypto_box_curve25519xsalsa20poly1305_tweet_ZEROBYTES 32 +#define crypto_box_curve25519xsalsa20poly1305_tweet_BOXZEROBYTES 16 +extern int crypto_box_curve25519xsalsa20poly1305_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *,const unsigned char *); +extern int crypto_box_curve25519xsalsa20poly1305_tweet_open(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *,const unsigned char *); +extern int crypto_box_curve25519xsalsa20poly1305_tweet_keypair(unsigned char *,unsigned char *); +extern int crypto_box_curve25519xsalsa20poly1305_tweet_beforenm(unsigned char *,const unsigned char *,const unsigned char *); +extern int crypto_box_curve25519xsalsa20poly1305_tweet_afternm(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); +extern int crypto_box_curve25519xsalsa20poly1305_tweet_open_afternm(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); +#define crypto_box_curve25519xsalsa20poly1305_tweet_VERSION "-" +#define crypto_box_curve25519xsalsa20poly1305 crypto_box_curve25519xsalsa20poly1305_tweet +#define crypto_box_curve25519xsalsa20poly1305_open crypto_box_curve25519xsalsa20poly1305_tweet_open +#define crypto_box_curve25519xsalsa20poly1305_keypair crypto_box_curve25519xsalsa20poly1305_tweet_keypair +#define crypto_box_curve25519xsalsa20poly1305_beforenm crypto_box_curve25519xsalsa20poly1305_tweet_beforenm +#define crypto_box_curve25519xsalsa20poly1305_afternm crypto_box_curve25519xsalsa20poly1305_tweet_afternm +#define crypto_box_curve25519xsalsa20poly1305_open_afternm crypto_box_curve25519xsalsa20poly1305_tweet_open_afternm +#define crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES crypto_box_curve25519xsalsa20poly1305_tweet_PUBLICKEYBYTES +#define crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES crypto_box_curve25519xsalsa20poly1305_tweet_SECRETKEYBYTES +#define crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES crypto_box_curve25519xsalsa20poly1305_tweet_BEFORENMBYTES +#define crypto_box_curve25519xsalsa20poly1305_NONCEBYTES crypto_box_curve25519xsalsa20poly1305_tweet_NONCEBYTES +#define crypto_box_curve25519xsalsa20poly1305_ZEROBYTES crypto_box_curve25519xsalsa20poly1305_tweet_ZEROBYTES +#define crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES crypto_box_curve25519xsalsa20poly1305_tweet_BOXZEROBYTES +#define crypto_box_curve25519xsalsa20poly1305_VERSION crypto_box_curve25519xsalsa20poly1305_tweet_VERSION +#define crypto_box_curve25519xsalsa20poly1305_IMPLEMENTATION "crypto_box/curve25519xsalsa20poly1305/tweet" +#define crypto_core_PRIMITIVE "salsa20" +#define crypto_core crypto_core_salsa20 +#define crypto_core_OUTPUTBYTES crypto_core_salsa20_OUTPUTBYTES +#define crypto_core_INPUTBYTES crypto_core_salsa20_INPUTBYTES +#define crypto_core_KEYBYTES crypto_core_salsa20_KEYBYTES +#define crypto_core_CONSTBYTES crypto_core_salsa20_CONSTBYTES +#define crypto_core_IMPLEMENTATION crypto_core_salsa20_IMPLEMENTATION +#define crypto_core_VERSION crypto_core_salsa20_VERSION +#define crypto_core_salsa20_tweet_OUTPUTBYTES 64 +#define crypto_core_salsa20_tweet_INPUTBYTES 16 +#define crypto_core_salsa20_tweet_KEYBYTES 32 +#define crypto_core_salsa20_tweet_CONSTBYTES 16 +extern int crypto_core_salsa20_tweet(unsigned char *,const unsigned char *,const unsigned char *,const unsigned char *); +#define crypto_core_salsa20_tweet_VERSION "-" +#define crypto_core_salsa20 crypto_core_salsa20_tweet +#define crypto_core_salsa20_OUTPUTBYTES crypto_core_salsa20_tweet_OUTPUTBYTES +#define crypto_core_salsa20_INPUTBYTES crypto_core_salsa20_tweet_INPUTBYTES +#define crypto_core_salsa20_KEYBYTES crypto_core_salsa20_tweet_KEYBYTES +#define crypto_core_salsa20_CONSTBYTES crypto_core_salsa20_tweet_CONSTBYTES +#define crypto_core_salsa20_VERSION crypto_core_salsa20_tweet_VERSION +#define crypto_core_salsa20_IMPLEMENTATION "crypto_core/salsa20/tweet" +#define crypto_core_hsalsa20_tweet_OUTPUTBYTES 32 +#define crypto_core_hsalsa20_tweet_INPUTBYTES 16 +#define crypto_core_hsalsa20_tweet_KEYBYTES 32 +#define crypto_core_hsalsa20_tweet_CONSTBYTES 16 +extern int crypto_core_hsalsa20_tweet(unsigned char *,const unsigned char *,const unsigned char *,const unsigned char *); +#define crypto_core_hsalsa20_tweet_VERSION "-" +#define crypto_core_hsalsa20 crypto_core_hsalsa20_tweet +#define crypto_core_hsalsa20_OUTPUTBYTES crypto_core_hsalsa20_tweet_OUTPUTBYTES +#define crypto_core_hsalsa20_INPUTBYTES crypto_core_hsalsa20_tweet_INPUTBYTES +#define crypto_core_hsalsa20_KEYBYTES crypto_core_hsalsa20_tweet_KEYBYTES +#define crypto_core_hsalsa20_CONSTBYTES crypto_core_hsalsa20_tweet_CONSTBYTES +#define crypto_core_hsalsa20_VERSION crypto_core_hsalsa20_tweet_VERSION +#define crypto_core_hsalsa20_IMPLEMENTATION "crypto_core/hsalsa20/tweet" +#define crypto_hashblocks_PRIMITIVE "sha512" +#define crypto_hashblocks crypto_hashblocks_sha512 +#define crypto_hashblocks_STATEBYTES crypto_hashblocks_sha512_STATEBYTES +#define crypto_hashblocks_BLOCKBYTES crypto_hashblocks_sha512_BLOCKBYTES +#define crypto_hashblocks_IMPLEMENTATION crypto_hashblocks_sha512_IMPLEMENTATION +#define crypto_hashblocks_VERSION crypto_hashblocks_sha512_VERSION +#define crypto_hashblocks_sha512_tweet_STATEBYTES 64 +#define crypto_hashblocks_sha512_tweet_BLOCKBYTES 128 +extern int crypto_hashblocks_sha512_tweet(unsigned char *,const unsigned char *,unsigned long long); +#define crypto_hashblocks_sha512_tweet_VERSION "-" +#define crypto_hashblocks_sha512 crypto_hashblocks_sha512_tweet +#define crypto_hashblocks_sha512_STATEBYTES crypto_hashblocks_sha512_tweet_STATEBYTES +#define crypto_hashblocks_sha512_BLOCKBYTES crypto_hashblocks_sha512_tweet_BLOCKBYTES +#define crypto_hashblocks_sha512_VERSION crypto_hashblocks_sha512_tweet_VERSION +#define crypto_hashblocks_sha512_IMPLEMENTATION "crypto_hashblocks/sha512/tweet" +#define crypto_hashblocks_sha256_tweet_STATEBYTES 32 +#define crypto_hashblocks_sha256_tweet_BLOCKBYTES 64 +extern int crypto_hashblocks_sha256_tweet(unsigned char *,const unsigned char *,unsigned long long); +#define crypto_hashblocks_sha256_tweet_VERSION "-" +#define crypto_hashblocks_sha256 crypto_hashblocks_sha256_tweet +#define crypto_hashblocks_sha256_STATEBYTES crypto_hashblocks_sha256_tweet_STATEBYTES +#define crypto_hashblocks_sha256_BLOCKBYTES crypto_hashblocks_sha256_tweet_BLOCKBYTES +#define crypto_hashblocks_sha256_VERSION crypto_hashblocks_sha256_tweet_VERSION +#define crypto_hashblocks_sha256_IMPLEMENTATION "crypto_hashblocks/sha256/tweet" +#define crypto_hash_PRIMITIVE "sha512" +#define crypto_hash crypto_hash_sha512 +#define crypto_hash_BYTES crypto_hash_sha512_BYTES +#define crypto_hash_IMPLEMENTATION crypto_hash_sha512_IMPLEMENTATION +#define crypto_hash_VERSION crypto_hash_sha512_VERSION +#define crypto_hash_sha512_tweet_BYTES 64 +extern int crypto_hash_sha512_tweet(unsigned char *,const unsigned char *,unsigned long long); +#define crypto_hash_sha512_tweet_VERSION "-" +#define crypto_hash_sha512 crypto_hash_sha512_tweet +#define crypto_hash_sha512_BYTES crypto_hash_sha512_tweet_BYTES +#define crypto_hash_sha512_VERSION crypto_hash_sha512_tweet_VERSION +#define crypto_hash_sha512_IMPLEMENTATION "crypto_hash/sha512/tweet" +#define crypto_hash_sha256_tweet_BYTES 32 +extern int crypto_hash_sha256_tweet(unsigned char *,const unsigned char *,unsigned long long); +#define crypto_hash_sha256_tweet_VERSION "-" +#define crypto_hash_sha256 crypto_hash_sha256_tweet +#define crypto_hash_sha256_BYTES crypto_hash_sha256_tweet_BYTES +#define crypto_hash_sha256_VERSION crypto_hash_sha256_tweet_VERSION +#define crypto_hash_sha256_IMPLEMENTATION "crypto_hash/sha256/tweet" +#define crypto_onetimeauth_PRIMITIVE "poly1305" +#define crypto_onetimeauth crypto_onetimeauth_poly1305 +#define crypto_onetimeauth_verify crypto_onetimeauth_poly1305_verify +#define crypto_onetimeauth_BYTES crypto_onetimeauth_poly1305_BYTES +#define crypto_onetimeauth_KEYBYTES crypto_onetimeauth_poly1305_KEYBYTES +#define crypto_onetimeauth_IMPLEMENTATION crypto_onetimeauth_poly1305_IMPLEMENTATION +#define crypto_onetimeauth_VERSION crypto_onetimeauth_poly1305_VERSION +#define crypto_onetimeauth_poly1305_tweet_BYTES 16 +#define crypto_onetimeauth_poly1305_tweet_KEYBYTES 32 +extern int crypto_onetimeauth_poly1305_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *); +extern int crypto_onetimeauth_poly1305_tweet_verify(const unsigned char *,const unsigned char *,unsigned long long,const unsigned char *); +#define crypto_onetimeauth_poly1305_tweet_VERSION "-" +#define crypto_onetimeauth_poly1305 crypto_onetimeauth_poly1305_tweet +#define crypto_onetimeauth_poly1305_verify crypto_onetimeauth_poly1305_tweet_verify +#define crypto_onetimeauth_poly1305_BYTES crypto_onetimeauth_poly1305_tweet_BYTES +#define crypto_onetimeauth_poly1305_KEYBYTES crypto_onetimeauth_poly1305_tweet_KEYBYTES +#define crypto_onetimeauth_poly1305_VERSION crypto_onetimeauth_poly1305_tweet_VERSION +#define crypto_onetimeauth_poly1305_IMPLEMENTATION "crypto_onetimeauth/poly1305/tweet" +#define crypto_scalarmult_PRIMITIVE "curve25519" +#define crypto_scalarmult crypto_scalarmult_curve25519 +#define crypto_scalarmult_base crypto_scalarmult_curve25519_base +#define crypto_scalarmult_BYTES crypto_scalarmult_curve25519_BYTES +#define crypto_scalarmult_SCALARBYTES crypto_scalarmult_curve25519_SCALARBYTES +#define crypto_scalarmult_IMPLEMENTATION crypto_scalarmult_curve25519_IMPLEMENTATION +#define crypto_scalarmult_VERSION crypto_scalarmult_curve25519_VERSION +#define crypto_scalarmult_curve25519_tweet_BYTES 32 +#define crypto_scalarmult_curve25519_tweet_SCALARBYTES 32 +extern int crypto_scalarmult_curve25519_tweet(unsigned char *,const unsigned char *,const unsigned char *); +extern int crypto_scalarmult_curve25519_tweet_base(unsigned char *,const unsigned char *); +#define crypto_scalarmult_curve25519_tweet_VERSION "-" +#define crypto_scalarmult_curve25519 crypto_scalarmult_curve25519_tweet +#define crypto_scalarmult_curve25519_base crypto_scalarmult_curve25519_tweet_base +#define crypto_scalarmult_curve25519_BYTES crypto_scalarmult_curve25519_tweet_BYTES +#define crypto_scalarmult_curve25519_SCALARBYTES crypto_scalarmult_curve25519_tweet_SCALARBYTES +#define crypto_scalarmult_curve25519_VERSION crypto_scalarmult_curve25519_tweet_VERSION +#define crypto_scalarmult_curve25519_IMPLEMENTATION "crypto_scalarmult/curve25519/tweet" +#define crypto_secretbox_PRIMITIVE "xsalsa20poly1305" +#define crypto_secretbox crypto_secretbox_xsalsa20poly1305 +#define crypto_secretbox_open crypto_secretbox_xsalsa20poly1305_open +#define crypto_secretbox_KEYBYTES crypto_secretbox_xsalsa20poly1305_KEYBYTES +#define crypto_secretbox_NONCEBYTES crypto_secretbox_xsalsa20poly1305_NONCEBYTES +#define crypto_secretbox_ZEROBYTES crypto_secretbox_xsalsa20poly1305_ZEROBYTES +#define crypto_secretbox_BOXZEROBYTES crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES +#define crypto_secretbox_IMPLEMENTATION crypto_secretbox_xsalsa20poly1305_IMPLEMENTATION +#define crypto_secretbox_VERSION crypto_secretbox_xsalsa20poly1305_VERSION +#define crypto_secretbox_xsalsa20poly1305_tweet_KEYBYTES 32 +#define crypto_secretbox_xsalsa20poly1305_tweet_NONCEBYTES 24 +#define crypto_secretbox_xsalsa20poly1305_tweet_ZEROBYTES 32 +#define crypto_secretbox_xsalsa20poly1305_tweet_BOXZEROBYTES 16 +extern int crypto_secretbox_xsalsa20poly1305_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); +extern int crypto_secretbox_xsalsa20poly1305_tweet_open(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); +#define crypto_secretbox_xsalsa20poly1305_tweet_VERSION "-" +#define crypto_secretbox_xsalsa20poly1305 crypto_secretbox_xsalsa20poly1305_tweet +#define crypto_secretbox_xsalsa20poly1305_open crypto_secretbox_xsalsa20poly1305_tweet_open +#define crypto_secretbox_xsalsa20poly1305_KEYBYTES crypto_secretbox_xsalsa20poly1305_tweet_KEYBYTES +#define crypto_secretbox_xsalsa20poly1305_NONCEBYTES crypto_secretbox_xsalsa20poly1305_tweet_NONCEBYTES +#define crypto_secretbox_xsalsa20poly1305_ZEROBYTES crypto_secretbox_xsalsa20poly1305_tweet_ZEROBYTES +#define crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES crypto_secretbox_xsalsa20poly1305_tweet_BOXZEROBYTES +#define crypto_secretbox_xsalsa20poly1305_VERSION crypto_secretbox_xsalsa20poly1305_tweet_VERSION +#define crypto_secretbox_xsalsa20poly1305_IMPLEMENTATION "crypto_secretbox/xsalsa20poly1305/tweet" +#define crypto_sign_PRIMITIVE "ed25519" +#define crypto_sign crypto_sign_ed25519 +#define crypto_sign_open crypto_sign_ed25519_open +#define crypto_sign_keypair crypto_sign_ed25519_keypair +#define crypto_sign_BYTES crypto_sign_ed25519_BYTES +#define crypto_sign_PUBLICKEYBYTES crypto_sign_ed25519_PUBLICKEYBYTES +#define crypto_sign_SECRETKEYBYTES crypto_sign_ed25519_SECRETKEYBYTES +#define crypto_sign_IMPLEMENTATION crypto_sign_ed25519_IMPLEMENTATION +#define crypto_sign_VERSION crypto_sign_ed25519_VERSION +#define crypto_sign_ed25519_tweet_BYTES 64 +#define crypto_sign_ed25519_tweet_PUBLICKEYBYTES 32 +#define crypto_sign_ed25519_tweet_SECRETKEYBYTES 64 +extern int crypto_sign_ed25519_tweet(unsigned char *,unsigned long long *,const unsigned char *,unsigned long long,const unsigned char *); +extern int crypto_sign_ed25519_tweet_open(unsigned char *,unsigned long long *,const unsigned char *,unsigned long long,const unsigned char *); +extern int crypto_sign_ed25519_tweet_keypair(unsigned char *,unsigned char *); +#define crypto_sign_ed25519_tweet_VERSION "-" +#define crypto_sign_ed25519 crypto_sign_ed25519_tweet +#define crypto_sign_ed25519_open crypto_sign_ed25519_tweet_open +#define crypto_sign_ed25519_keypair crypto_sign_ed25519_tweet_keypair +#define crypto_sign_ed25519_BYTES crypto_sign_ed25519_tweet_BYTES +#define crypto_sign_ed25519_PUBLICKEYBYTES crypto_sign_ed25519_tweet_PUBLICKEYBYTES +#define crypto_sign_ed25519_SECRETKEYBYTES crypto_sign_ed25519_tweet_SECRETKEYBYTES +#define crypto_sign_ed25519_VERSION crypto_sign_ed25519_tweet_VERSION +#define crypto_sign_ed25519_IMPLEMENTATION "crypto_sign/ed25519/tweet" +#define crypto_stream_PRIMITIVE "xsalsa20" +#define crypto_stream crypto_stream_xsalsa20 +#define crypto_stream_xor crypto_stream_xsalsa20_xor +#define crypto_stream_KEYBYTES crypto_stream_xsalsa20_KEYBYTES +#define crypto_stream_NONCEBYTES crypto_stream_xsalsa20_NONCEBYTES +#define crypto_stream_IMPLEMENTATION crypto_stream_xsalsa20_IMPLEMENTATION +#define crypto_stream_VERSION crypto_stream_xsalsa20_VERSION +#define crypto_stream_xsalsa20_tweet_KEYBYTES 32 +#define crypto_stream_xsalsa20_tweet_NONCEBYTES 24 +extern int crypto_stream_xsalsa20_tweet(unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); +extern int crypto_stream_xsalsa20_tweet_xor(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); +#define crypto_stream_xsalsa20_tweet_VERSION "-" +#define crypto_stream_xsalsa20 crypto_stream_xsalsa20_tweet +#define crypto_stream_xsalsa20_xor crypto_stream_xsalsa20_tweet_xor +#define crypto_stream_xsalsa20_KEYBYTES crypto_stream_xsalsa20_tweet_KEYBYTES +#define crypto_stream_xsalsa20_NONCEBYTES crypto_stream_xsalsa20_tweet_NONCEBYTES +#define crypto_stream_xsalsa20_VERSION crypto_stream_xsalsa20_tweet_VERSION +#define crypto_stream_xsalsa20_IMPLEMENTATION "crypto_stream/xsalsa20/tweet" +#define crypto_stream_salsa20_tweet_KEYBYTES 32 +#define crypto_stream_salsa20_tweet_NONCEBYTES 8 +extern int crypto_stream_salsa20_tweet(unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); +extern int crypto_stream_salsa20_tweet_xor(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *); +#define crypto_stream_salsa20_tweet_VERSION "-" +#define crypto_stream_salsa20 crypto_stream_salsa20_tweet +#define crypto_stream_salsa20_xor crypto_stream_salsa20_tweet_xor +#define crypto_stream_salsa20_KEYBYTES crypto_stream_salsa20_tweet_KEYBYTES +#define crypto_stream_salsa20_NONCEBYTES crypto_stream_salsa20_tweet_NONCEBYTES +#define crypto_stream_salsa20_VERSION crypto_stream_salsa20_tweet_VERSION +#define crypto_stream_salsa20_IMPLEMENTATION "crypto_stream/salsa20/tweet" +#define crypto_verify_PRIMITIVE "16" +#define crypto_verify crypto_verify_16 +#define crypto_verify_BYTES crypto_verify_16_BYTES +#define crypto_verify_IMPLEMENTATION crypto_verify_16_IMPLEMENTATION +#define crypto_verify_VERSION crypto_verify_16_VERSION +#define crypto_verify_16_tweet_BYTES 16 +extern int crypto_verify_16_tweet(const unsigned char *,const unsigned char *); +#define crypto_verify_16_tweet_VERSION "-" +#define crypto_verify_16 crypto_verify_16_tweet +#define crypto_verify_16_BYTES crypto_verify_16_tweet_BYTES +#define crypto_verify_16_VERSION crypto_verify_16_tweet_VERSION +#define crypto_verify_16_IMPLEMENTATION "crypto_verify/16/tweet" +#define crypto_verify_32_tweet_BYTES 32 +extern int crypto_verify_32_tweet(const unsigned char *,const unsigned char *); +#define crypto_verify_32_tweet_VERSION "-" +#define crypto_verify_32 crypto_verify_32_tweet +#define crypto_verify_32_BYTES crypto_verify_32_tweet_BYTES +#define crypto_verify_32_VERSION crypto_verify_32_tweet_VERSION +#define crypto_verify_32_IMPLEMENTATION "crypto_verify/32/tweet" +#endif diff --git a/src/cryptoconditions/src/internal.h b/src/cryptoconditions/src/internal.h new file mode 100644 index 000000000..bd0e6376a --- /dev/null +++ b/src/cryptoconditions/src/internal.h @@ -0,0 +1,76 @@ +#include "include/cJSON.h" +#include "asn/asn_application.h" +#include "cryptoconditions.h" + +#ifndef INTERNAL_H +#define INTERNAL_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define BUF_SIZE 1024 * 1024 + + +/* + * Condition Type */ +typedef struct CCType { + uint8_t typeId; + unsigned char name[100]; + Condition_PR asnType; + int hasSubtypes; + int (*visitChildren)(CC *cond, CCVisitor visitor); + unsigned char *(*fingerprint)(const CC *cond); + unsigned long (*getCost)(const CC *cond); + uint32_t (*getSubtypes)(const CC *cond); + CC *(*fromJSON)(const cJSON *params, unsigned char *err); + void (*toJSON)(const CC *cond, cJSON *params); + CC *(*fromFulfillment)(const Fulfillment_t *ffill); + Fulfillment_t *(*toFulfillment)(const CC *cond); + int (*isFulfilled)(const CC *cond); + void (*free)(struct CC *cond); +} CCType; + + +/* + * Globals + */ +static struct CCType *typeRegistry[]; +static int typeRegistryLength; + + +/* + * Internal API + */ +static uint32_t fromAsnSubtypes(ConditionTypes_t types); +static CC *mkAnon(const Condition_t *asnCond); +static void asnCondition(const CC *cond, Condition_t *asn); +static Condition_t *asnConditionNew(const CC *cond); +static Fulfillment_t *asnFulfillmentNew(const CC *cond); +static uint32_t getSubtypes(CC *cond); +static cJSON *jsonEncodeCondition(cJSON *params, unsigned char *err); +static struct CC *fulfillmentToCC(Fulfillment_t *ffill); +static struct CCType *getTypeByAsnEnum(Condition_PR present); + + +/* + * Utility functions + */ +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 dumpStr(unsigned char *str, size_t len); +int checkString(const cJSON *value, unsigned char *key, unsigned char *err); +int checkDecodeBase64(const cJSON *value, unsigned char *key, unsigned char *err, unsigned char **data, size_t *size); +int jsonGetBase64(const cJSON *params, unsigned char *key, unsigned char *err, unsigned char **data, size_t *size); +int jsonGetBase64Optional(const cJSON *params, unsigned char *key, unsigned char *err, unsigned char **data, size_t *size); +void jsonAddBase64(cJSON *params, unsigned char *key, unsigned char *bin, size_t size); + + +#ifdef __cplusplus +} +#endif + +#endif /* INTERNAL_H */ diff --git a/src/cryptoconditions/src/json_rpc.c b/src/cryptoconditions/src/json_rpc.c new file mode 100644 index 000000000..8fcf47fdb --- /dev/null +++ b/src/cryptoconditions/src/json_rpc.c @@ -0,0 +1,332 @@ +#include "cryptoconditions.h" +#include "internal.h" +#include +#include + + +static cJSON *jsonCondition(CC *cond) { + unsigned char buf[1000]; + size_t conditionBinLength = cc_conditionBinary(cond, buf); + + cJSON *root = cJSON_CreateObject(); + unsigned char *uri = cc_conditionUri(cond); + cJSON_AddItemToObject(root, "uri", cJSON_CreateString(uri)); + free(uri); + + unsigned char *b64 = base64_encode(buf, conditionBinLength); + cJSON_AddItemToObject(root, "bin", cJSON_CreateString(b64)); + free(b64); + + return root; +} + + +static cJSON *jsonFulfillment(CC *cond) { + unsigned char buf[1000000]; + size_t fulfillmentBinLength = cc_fulfillmentBinary(cond, buf, 1000000); + + cJSON *root = cJSON_CreateObject(); + unsigned char *b64 = base64_encode(buf, fulfillmentBinLength); + cJSON_AddItemToObject(root, "fulfillment", cJSON_CreateString(b64)); + free(b64); + + return root; +} + + +CC *cc_conditionFromJSON(cJSON *params, unsigned char *err) { + if (!params || !cJSON_IsObject(params)) { + strcpy(err, "Condition params must be an object"); + return NULL; + } + cJSON *typeName = cJSON_GetObjectItem(params, "type"); + if (!typeName || !cJSON_IsString(typeName)) { + strcpy(err, "\"type\" must be a string"); + return NULL; + } + for (int i=0; ivaluestring, typeRegistry[i]->name)) { + return typeRegistry[i]->fromJSON(params, err); + } + } + } + strcpy(err, "cannot detect type of condition"); + return NULL; +} + + +CC *cc_conditionFromJSONString(const unsigned char *data, unsigned char *err) { + cJSON *params = cJSON_Parse(data); + CC *out = cc_conditionFromJSON(params, err); + cJSON_Delete(params); + return out; +} + + +static cJSON *jsonEncodeCondition(cJSON *params, unsigned char *err) { + CC *cond = cc_conditionFromJSON(params, err); + cJSON *out = NULL; + if (cond != NULL) { + out = jsonCondition(cond); + cc_free(cond); + } + return out; +} + + +static cJSON *jsonEncodeFulfillment(cJSON *params, unsigned char *err) { + CC *cond = cc_conditionFromJSON(params, err); + cJSON *out = NULL; + if (cond != NULL) { + out = jsonFulfillment(cond); + cc_free(cond); + } + return out; +} + + +static cJSON *jsonErr(unsigned char *err) { + cJSON *out = cJSON_CreateObject(); + cJSON_AddItemToObject(out, "error", cJSON_CreateString(err)); + return out; +} + + +static cJSON *jsonVerifyFulfillment(cJSON *params, unsigned char *err) { + unsigned char *ffill_bin = 0, *msg = 0, *cond_bin = 0; + size_t ffill_bin_len, msg_len, cond_bin_len; + cJSON *out = 0; + + if (!(jsonGetBase64(params, "fulfillment", err, &ffill_bin, &ffill_bin_len) && + jsonGetBase64(params, "message", err, &msg, &msg_len) && + jsonGetBase64(params, "condition", err, &cond_bin, &cond_bin_len))) + goto END; + + CC *cond = cc_readFulfillmentBinary(ffill_bin, ffill_bin_len); + + if (!cond) { + strcpy(err, "Invalid fulfillment payload"); + goto END; + } + + int valid = cc_verify(cond, msg, msg_len, 1, cond_bin, cond_bin_len, &jsonVerifyEval, NULL); + cc_free(cond); + out = cJSON_CreateObject(); + cJSON_AddItemToObject(out, "valid", cJSON_CreateBool(valid)); + +END: + free(ffill_bin); free(msg); free(cond_bin); + return out; +} + + +static cJSON *jsonDecodeFulfillment(cJSON *params, unsigned char *err) { + size_t ffill_bin_len; + unsigned char *ffill_bin; + if (!jsonGetBase64(params, "fulfillment", err, &ffill_bin, &ffill_bin_len)) + return NULL; + + CC *cond = cc_readFulfillmentBinary(ffill_bin, ffill_bin_len); + free(ffill_bin); + if (!cond) { + strcpy(err, "Invalid fulfillment payload"); + return NULL; + } + cJSON *out = jsonCondition(cond); + cc_free(cond); + return out; +} + + +static cJSON *jsonDecodeCondition(cJSON *params, unsigned char *err) { + size_t cond_bin_len; + unsigned char *cond_bin; + if (!jsonGetBase64(params, "bin", err, &cond_bin, &cond_bin_len)) + return NULL; + + CC *cond = cc_readConditionBinary(cond_bin, cond_bin_len); + free(cond_bin); + + if (!cond) { + strcpy(err, "Invalid condition payload"); + return NULL; + } + + cJSON *out = jsonCondition(cond); + cJSON_AddItemToObject(out, "condition", cc_conditionToJSON(cond)); + cc_free(cond); + return out; +} + + +static cJSON *jsonSignTreeEd25519(cJSON *params, unsigned char *err) { + cJSON *out = 0; + unsigned char *msg = 0, *sk = 0; + + cJSON *condition_item = cJSON_GetObjectItem(params, "condition"); + CC *cond = cc_conditionFromJSON(condition_item, err); + if (cond == NULL) { + goto END; + } + + size_t skLength; + if (!jsonGetBase64(params, "privateKey", err, &sk, &skLength)) { + goto END; + } + + if (skLength != 32) { + strcpy(err, "privateKey wrong length"); + } + + size_t msgLength; + if (!jsonGetBase64(params, "message", err, &msg, &msgLength)) { + goto END; + } + + int nSigned = cc_signTreeEd25519(cond, sk, msg, msgLength); + out = cJSON_CreateObject(); + cJSON_AddItemToObject(out, "num_signed", cJSON_CreateNumber(nSigned)); + cJSON_AddItemToObject(out, "condition", cc_conditionToJSON(cond)); + +END: + cc_free(cond); + free(msg); + free(sk); + return out; +} + + +static cJSON *jsonSignTreeSecp256k1(cJSON *params, unsigned char *err) { + cJSON *out = 0; + unsigned char *msg = 0, *sk = 0; + + cJSON *condition_item = cJSON_GetObjectItem(params, "condition"); + CC *cond = cc_conditionFromJSON(condition_item, err); + if (cond == NULL) { + goto END; + } + + size_t skLength; + if (!jsonGetBase64(params, "privateKey", err, &sk, &skLength)) { + goto END; + } + + if (skLength != SECP256K1_SK_SIZE) { + strcpy(err, "privateKey wrong length"); + } + + size_t msgLength; + if (!jsonGetBase64(params, "message", err, &msg, &msgLength)) { + goto END; + } + + char msgHash[32]; + sha256(msg, msgLength, msgHash); + int nSigned = cc_signTreeSecp256k1Msg32(cond, sk, msgHash); + out = cJSON_CreateObject(); + cJSON_AddItemToObject(out, "num_signed", cJSON_CreateNumber(nSigned)); + cJSON_AddItemToObject(out, "condition", cc_conditionToJSON(cond)); + +END: + cc_free(cond); + free(msg); + free(sk); + return out; +} + + +cJSON *cc_conditionToJSON(const CC *cond) { + cJSON *params = cJSON_CreateObject(); + cJSON_AddItemToObject(params, "type", cJSON_CreateString(cond->type->name)); + cond->type->toJSON(cond, params); + return params; +} + + +unsigned char *cc_conditionToJSONString(const CC *cond) { + assert(cond != NULL); + cJSON *params = cc_conditionToJSON(cond); + unsigned char *out = cJSON_Print(params); + cJSON_Delete(params); + return out; +} + + +static cJSON *jsonListMethods(cJSON *params, unsigned char *err); + + +typedef struct JsonMethod { + unsigned char *name; + cJSON* (*method)(cJSON *params, unsigned char *err); + unsigned char *description; +} JsonMethod; + + +static JsonMethod cc_jsonMethods[] = { + {"encodeCondition", &jsonEncodeCondition, "Encode a JSON condition to binary"}, + {"decodeCondition", &jsonDecodeCondition, "Decode a binary condition"}, + {"encodeFulfillment", &jsonEncodeFulfillment, "Encode a JSON condition to a fulfillment"}, + {"decodeFulfillment", &jsonDecodeFulfillment, "Decode a binary fulfillment"}, + {"verifyFulfillment", &jsonVerifyFulfillment, "Verify a fulfillment"}, + {"signTreeEd25519", &jsonSignTreeEd25519, "Sign ed25519 condition nodes"}, + {"signTreeSecp256k1", &jsonSignTreeSecp256k1, "Sign secp256k1 condition nodes"}, + {"listMethods", &jsonListMethods, "List available methods"} +}; + + +static int nJsonMethods = sizeof(cc_jsonMethods) / sizeof(*cc_jsonMethods); + + +static cJSON *jsonListMethods(cJSON *params, unsigned char *err) { + cJSON *list = cJSON_CreateArray(); + for (int i=0; ivaluestring)) { + return method.method(params, err); + } + } + + return jsonErr("invalid method"); +} + + +unsigned char *cc_jsonRPC(unsigned char* input) { + unsigned char err[1000] = "\0"; + cJSON *out; + cJSON *root = cJSON_Parse(input); + if (!root) out = jsonErr("Error parsing JSON request"); + else { + out = execJsonRPC(root, err); + if (NULL == out) out = jsonErr(err); + } + unsigned char *res = cJSON_Print(out); + cJSON_Delete(out); + cJSON_Delete(root); + return res; +} diff --git a/src/cryptoconditions/src/prefix.c b/src/cryptoconditions/src/prefix.c new file mode 100644 index 000000000..8fdd0a483 --- /dev/null +++ b/src/cryptoconditions/src/prefix.c @@ -0,0 +1,126 @@ + +#include "asn/Condition.h" +#include "asn/Fulfillment.h" +#include "asn/PrefixFingerprintContents.h" +#include "asn/OCTET_STRING.h" +#include "include/cJSON.h" +#include "cryptoconditions.h" + + +struct CCType cc_prefixType; + + +static int prefixVisitChildren(CC *cond, CCVisitor visitor) { + size_t prefixedLength = cond->prefixLength + visitor.msgLength; + unsigned char *prefixed = malloc(prefixedLength); + memcpy(prefixed, cond->prefix, cond->prefixLength); + memcpy(prefixed + cond->prefixLength, visitor.msg, visitor.msgLength); + visitor.msg = prefixed; + visitor.msgLength = prefixedLength; + int res = cc_visit(cond->subcondition, visitor); + free(prefixed); + return res; +} + + +static unsigned char *prefixFingerprint(const CC *cond) { + PrefixFingerprintContents_t *fp = calloc(1, sizeof(PrefixFingerprintContents_t)); + asnCondition(cond->subcondition, &fp->subcondition); // TODO: check asnCondition for safety + fp->maxMessageLength = cond->maxMessageLength; + OCTET_STRING_fromBuf(&fp->prefix, cond->prefix, cond->prefixLength); + return hashFingerprintContents(&asn_DEF_PrefixFingerprintContents, fp); +} + + +static unsigned long prefixCost(const CC *cond) { + return 1024 + cond->prefixLength + cond->maxMessageLength + + cond->subcondition->type->getCost(cond->subcondition); +} + + +static CC *prefixFromFulfillment(const Fulfillment_t *ffill) { + PrefixFulfillment_t *p = ffill->choice.prefixSha256; + CC *sub = fulfillmentToCC(p->subfulfillment); + if (!sub) return 0; + CC *cond = calloc(1, sizeof(CC)); + cond->type = &cc_prefixType; + cond->maxMessageLength = p->maxMessageLength; + cond->prefix = calloc(1, p->prefix.size); + memcpy(cond->prefix, p->prefix.buf, p->prefix.size); + cond->prefixLength = p->prefix.size; + cond->subcondition = sub; + return cond; +} + + +static Fulfillment_t *prefixToFulfillment(const CC *cond) { + Fulfillment_t *ffill = asnFulfillmentNew(cond->subcondition); + if (!ffill) { + return NULL; + } + PrefixFulfillment_t *pf = calloc(1, sizeof(PrefixFulfillment_t)); + OCTET_STRING_fromBuf(&pf->prefix, cond->prefix, cond->prefixLength); + pf->maxMessageLength = cond->maxMessageLength; + pf->subfulfillment = ffill; + + ffill = calloc(1, sizeof(Fulfillment_t)); + ffill->present = Fulfillment_PR_prefixSha256; + ffill->choice.prefixSha256 = pf; + return ffill; +} + + +static uint32_t prefixSubtypes(const CC *cond) { + return getSubtypes(cond->subcondition) & ~(1 << cc_prefixType.typeId); +} + + +static CC *prefixFromJSON(const cJSON *params, unsigned char *err) { + cJSON *mml_item = cJSON_GetObjectItem(params, "maxMessageLength"); + if (!cJSON_IsNumber(mml_item)) { + strcpy(err, "maxMessageLength must be a number"); + return NULL; + } + + cJSON *subcond_item = cJSON_GetObjectItem(params, "subfulfillment"); + CC *sub = cc_conditionFromJSON(subcond_item, err); + if (!sub) { + return NULL; + } + + CC *cond = calloc(1, sizeof(CC)); + cond->type = &cc_prefixType; + cond->maxMessageLength = (unsigned long) mml_item->valuedouble; + cond->subcondition = sub; + + if (!jsonGetBase64(params, "prefix", err, &cond->prefix, &cond->prefixLength)) { + cc_free(cond); + return NULL; + } + + return cond; +} + + +static void prefixToJSON(const CC *cond, cJSON *params) { + cJSON_AddNumberToObject(params, "maxMessageLength", (double)cond->maxMessageLength); + unsigned char *b64 = base64_encode(cond->prefix, cond->prefixLength); + cJSON_AddStringToObject(params, "prefix", b64); + free(b64); + cJSON_AddItemToObject(params, "subfulfillment", cc_conditionToJSON(cond->subcondition)); +} + + +int prefixIsFulfilled(const CC *cond) { + return cc_isFulfilled(cond->subcondition); +} + + +static void prefixFree(CC *cond) { + free(cond->prefix); + cc_free(cond->subcondition); + free(cond); +} + + +struct CCType cc_prefixType = { 1, "prefix-sha-256", Condition_PR_prefixSha256, 1, &prefixVisitChildren, &prefixFingerprint, &prefixCost, &prefixSubtypes, &prefixFromJSON, &prefixToJSON, &prefixFromFulfillment, &prefixToFulfillment, &prefixIsFulfilled, &prefixFree }; diff --git a/src/cryptoconditions/src/preimage.c b/src/cryptoconditions/src/preimage.c new file mode 100644 index 000000000..71d3b2e89 --- /dev/null +++ b/src/cryptoconditions/src/preimage.c @@ -0,0 +1,83 @@ + +#include "asn/Condition.h" +#include "asn/Fulfillment.h" +#include "asn/OCTET_STRING.h" +#include "include/cJSON.h" +#include "include/sha256.h" +#include "cryptoconditions.h" + + +struct CCType cc_preimageType; + + +static CC *preimageFromJSON(const cJSON *params, unsigned char *err) { + cJSON *preimage_item = cJSON_GetObjectItem(params, "preimage"); + if (!cJSON_IsString(preimage_item)) { + strcpy(err, "preimage must be a string"); + return NULL; + } + unsigned char *preimage_b64 = preimage_item->valuestring; + + CC *cond = calloc(1, sizeof(CC)); + cond->type = &cc_preimageType; + cond->preimage = base64_decode(preimage_b64, &cond->preimageLength); + return cond; +} + + +static void preimageToJSON(const CC *cond, cJSON *params) { + unsigned char *encoded = base64_encode(cond->preimage, cond->preimageLength); + cJSON_AddStringToObject(params, "preimage", encoded); + free(encoded); +} + + +static unsigned long preimageCost(const CC *cond) { + return (unsigned long) cond->preimageLength; +} + + +static unsigned char *preimageFingerprint(const CC *cond) { + unsigned char *hash = calloc(1, 32); + sha256(cond->preimage, cond->preimageLength, hash); + return hash; +} + + +static CC *preimageFromFulfillment(const Fulfillment_t *ffill) { + CC *cond = calloc(1, sizeof(CC)); + cond->type = &cc_preimageType; + PreimageFulfillment_t p = ffill->choice.preimageSha256; + cond->preimage = calloc(1, p.preimage.size); + memcpy(cond->preimage, p.preimage.buf, p.preimage.size); + cond->preimageLength = p.preimage.size; + return cond; +} + + +static Fulfillment_t *preimageToFulfillment(const CC *cond) { + Fulfillment_t *ffill = calloc(1, sizeof(Fulfillment_t)); + ffill->present = Fulfillment_PR_preimageSha256; + PreimageFulfillment_t *pf = &ffill->choice.preimageSha256; + OCTET_STRING_fromBuf(&pf->preimage, cond->preimage, cond->preimageLength); + return ffill; +} + + +int preimageIsFulfilled(const CC *cond) { + return 1; +} + + +static void preimageFree(CC *cond) { + free(cond->preimage); + free(cond); +} + + +static uint32_t preimageSubtypes(const CC *cond) { + return 0; +} + + +struct CCType cc_preimageType = { 0, "preimage-sha-256", Condition_PR_preimageSha256, 0, 0, &preimageFingerprint, &preimageCost, &preimageSubtypes, &preimageFromJSON, &preimageToJSON, &preimageFromFulfillment, &preimageToFulfillment, &preimageIsFulfilled, &preimageFree }; diff --git a/src/cryptoconditions/src/secp256k1.c b/src/cryptoconditions/src/secp256k1.c new file mode 100644 index 000000000..507c9c84f --- /dev/null +++ b/src/cryptoconditions/src/secp256k1.c @@ -0,0 +1,253 @@ +#define _GNU_SOURCE 1 + +#include +#include +#include + +#include "asn/Condition.h" +#include "asn/Fulfillment.h" +#include "asn/Secp256k1Fulfillment.h" +#include "asn/Secp256k1FingerprintContents.h" +#include "asn/OCTET_STRING.h" +#include "include/cJSON.h" +#include "include/secp256k1/include/secp256k1.h" +#include "cryptoconditions.h" +#include "internal.h" + + +struct CCType cc_secp256k1Type; + + +static const size_t SECP256K1_PK_SIZE = 33; +static const size_t SECP256K1_SK_SIZE = 32; +static const size_t SECP256K1_SIG_SIZE = 64; + + +secp256k1_context_t *ec_ctx_sign = 0, *ec_ctx_verify = 0; +pthread_mutex_t cc_secp256k1ContextLock = PTHREAD_MUTEX_INITIALIZER; + + +void lockSign() { + pthread_mutex_lock(&cc_secp256k1ContextLock); + if (!ec_ctx_sign) { + ec_ctx_sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + } + unsigned char ent[32]; +#ifdef SYS_getrandom + int read = syscall(SYS_getrandom, ent, 32, 0); +#else + FILE *fp = fopen("/dev/urandom", "r"); + int read = (int) fread(&ent, 1, 32, fp); + fclose(fp); +#endif + if (read != 32) { + fprintf(stderr, "Could not read 32 bytes entropy from system\n"); + exit(1); + } + if (!secp256k1_context_randomize(ec_ctx_sign, ent)) { + fprintf(stderr, "Could not randomize secp256k1 context\n"); + exit(1); + } +} + + +void unlockSign() { + pthread_mutex_unlock(&cc_secp256k1ContextLock); +} + + +void initVerify() { + if (!ec_ctx_verify) { + pthread_mutex_lock(&cc_secp256k1ContextLock); + if (!ec_ctx_verify) + ec_ctx_verify = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + pthread_mutex_unlock(&cc_secp256k1ContextLock); + } +} + + +static unsigned char *secp256k1Fingerprint(const CC *cond) { + Secp256k1FingerprintContents_t *fp = calloc(1, sizeof(Secp256k1FingerprintContents_t)); + OCTET_STRING_fromBuf(&fp->publicKey, cond->publicKey, SECP256K1_PK_SIZE); + return hashFingerprintContents(&asn_DEF_Secp256k1FingerprintContents, fp); +} + + +int secp256k1Verify(CC *cond, CCVisitor visitor) { + if (cond->type->typeId != cc_secp256k1Type.typeId) return 1; + // TODO: test failure mode: empty sig / null pointer + initVerify(); + int rc = secp256k1_ecdsa_verify(ec_ctx_verify, visitor.msg, cond->signature, SECP256K1_SIG_SIZE, + cond->publicKey, SECP256K1_PK_SIZE); + return rc == 1; +} + + +static int cc_secp256k1VerifyTreeMsg32(const CC *cond, const unsigned char *msg32) { + int subtypes = getSubtypes(cond); + if (subtypes & (1 << cc_prefixType.typeId) && + subtypes & (1 << cc_secp256k1Type.typeId)) { + // No support for prefix currently, due to pending protocol decision on + // how to combine message and prefix into 32 byte hash + return 0; + } + CCVisitor visitor = {&secp256k1Verify, msg32, 0, NULL}; + int out = cc_visit(cond, visitor); + return out; +} + + +/* + * Signing data + */ +typedef struct CCSecp256k1SigningData { + const unsigned char *pk; + const unsigned char *sk; + int nSigned; +} CCSecp256k1SigningData; + + +/* + * Visitor that signs an secp256k1 condition if it has a matching public key + */ +static int secp256k1Sign(CC *cond, CCVisitor visitor) { + if (cond->type->typeId != cc_secp256k1Type.typeId) return 1; + CCSecp256k1SigningData *signing = (CCSecp256k1SigningData*) visitor.context; + if (0 != memcmp(cond->publicKey, signing->pk, SECP256K1_PK_SIZE)) return 1; + if (!cond->signature) cond->signature = calloc(1, SECP256K1_SIG_SIZE); + lockSign(); + int rc = secp256k1_ecdsa_sign_compact(ec_ctx_sign, visitor.msg, cond->signature, signing->sk, NULL, NULL, NULL); + unlockSign(); + if (rc) { + signing->nSigned++; + return 1; + } + return 0; +} + + +/* + * Sign secp256k1 conditions in a tree + */ +int cc_signTreeSecp256k1Msg32(CC *cond, const unsigned char *privateKey, const unsigned char *msg32) { + if (getSubtypes(cond) & (1 << cc_preimageType.typeId)) { + // No support for prefix currently, due to pending protocol decision on + // how to combine message and prefix into 32 byte hash + return 0; + } + unsigned char *publicKey = calloc(1, SECP256K1_PK_SIZE); + CCSecp256k1SigningData signing = {publicKey, privateKey, 0}; + CCVisitor visitor = {&secp256k1Sign, msg32, 32, &signing}; + int ol = 0; + lockSign(); + int rc = secp256k1_ec_pubkey_create(ec_ctx_sign, publicKey, &ol, privateKey, 1); + unlockSign(); + if (rc) cc_visit(cond, visitor); + free(publicKey); + return signing.nSigned; +} + + +static unsigned long secp256k1Cost(const CC *cond) { + return 131072; +} + + +static CC *cc_secp256k1Condition(const unsigned char *publicKey, const unsigned char *signature) { + unsigned char *pk = 0, *sig = 0; + + + initVerify(); + int rc = secp256k1_ec_pubkey_verify(ec_ctx_verify, publicKey, SECP256K1_PK_SIZE); + if (!rc) { + return NULL; + } + + pk = calloc(1, SECP256K1_PK_SIZE); + memcpy(pk, publicKey, SECP256K1_PK_SIZE); + if (signature) { + sig = calloc(1, SECP256K1_SIG_SIZE); + memcpy(sig, signature, SECP256K1_SIG_SIZE); + } + + CC *cond = calloc(1, sizeof(CC)); + cond->type = &cc_secp256k1Type; + cond->publicKey = pk; + cond->signature = sig; + return cond; +} + + +static CC *secp256k1FromJSON(const cJSON *params, unsigned char *err) { + CC *cond = 0; + unsigned char *pk = 0, *sig = 0; + size_t pkSize, sigSize; + + if (!jsonGetBase64(params, "publicKey", err, &pk, &pkSize)) goto END; + + if (!jsonGetBase64Optional(params, "signature", err, &sig, &sigSize)) goto END; + if (sig && SECP256K1_SIG_SIZE != sigSize) { + strcpy(err, "signature has incorrect length"); + goto END; + } + + cond = cc_secp256k1Condition(pk, sig); + if (!cond) { + strcpy(err, "invalid public key"); + } +END: + free(pk); + free(sig); + return cond; +} + + +static void secp256k1ToJSON(const CC *cond, cJSON *params) { + jsonAddBase64(params, "publicKey", cond->publicKey, SECP256K1_PK_SIZE); + if (cond->signature) { + jsonAddBase64(params, "signature", cond->signature, SECP256K1_SIG_SIZE); + } +} + + +static CC *secp256k1FromFulfillment(const Fulfillment_t *ffill) { + return cc_secp256k1Condition(ffill->choice.secp256k1Sha256.publicKey.buf, + ffill->choice.secp256k1Sha256.signature.buf); +} + + +static Fulfillment_t *secp256k1ToFulfillment(const CC *cond) { + if (!cond->signature) { + return NULL; + } + + Fulfillment_t *ffill = calloc(1, sizeof(Fulfillment_t)); + ffill->present = Fulfillment_PR_secp256k1Sha256; + Secp256k1Fulfillment_t *sec = &ffill->choice.secp256k1Sha256; + + OCTET_STRING_fromBuf(&sec->publicKey, cond->publicKey, SECP256K1_PK_SIZE); + OCTET_STRING_fromBuf(&sec->signature, cond->signature, SECP256K1_SIG_SIZE); + return ffill; +} + + +int secp256k1IsFulfilled(const CC *cond) { + return cond->signature > 0; +} + + +static void secp256k1Free(CC *cond) { + free(cond->publicKey); + if (cond->signature) { + free(cond->signature); + } + free(cond); +} + + +static uint32_t secp256k1Subtypes(const CC *cond) { + return 0; +} + + +struct CCType cc_secp256k1Type = { 5, "secp256k1-sha-256", Condition_PR_secp256k1Sha256, 0, 0, &secp256k1Fingerprint, &secp256k1Cost, &secp256k1Subtypes, &secp256k1FromJSON, &secp256k1ToJSON, &secp256k1FromFulfillment, &secp256k1ToFulfillment, &secp256k1IsFulfilled, &secp256k1Free }; diff --git a/src/cryptoconditions/src/stamp-h1 b/src/cryptoconditions/src/stamp-h1 new file mode 100644 index 000000000..8f14c586a --- /dev/null +++ b/src/cryptoconditions/src/stamp-h1 @@ -0,0 +1 @@ +timestamp for src/cryptoconditions-config.h diff --git a/src/cryptoconditions/src/threshold.c b/src/cryptoconditions/src/threshold.c new file mode 100644 index 000000000..68f4c557d --- /dev/null +++ b/src/cryptoconditions/src/threshold.c @@ -0,0 +1,206 @@ + +#include "asn/Condition.h" +#include "asn/Fulfillment.h" +#include "asn/ThresholdFingerprintContents.h" +#include "asn/OCTET_STRING.h" +#include "include/cJSON.h" +#include "cryptoconditions.h" +#include "internal.h" + + +struct CCType cc_thresholdType; + + +static uint32_t thresholdSubtypes(const CC *cond) { + uint32_t mask = 0; + for (int i=0; isize; i++) { + mask |= getSubtypes(cond->subconditions[i]); + } + mask &= ~(1 << cc_thresholdType.typeId); + return mask; +} + + +static int cmpCostDesc(const void *a, const void *b) { + return (int) ( *(unsigned long*)b - *(unsigned long*)a ); +} + + +static unsigned long thresholdCost(const CC *cond) { + CC *sub; + unsigned long *costs = calloc(1, cond->size * sizeof(unsigned long)); + for (int i=0; isize; i++) { + sub = cond->subconditions[i]; + costs[i] = cc_getCost(sub); + } + qsort(costs, cond->size, sizeof(unsigned long), cmpCostDesc); + unsigned long cost = 0; + for (int i=0; ithreshold; i++) { + cost += costs[i]; + } + free(costs); + return cost + 1024 * cond->size; +} + + +static int thresholdVisitChildren(CC *cond, CCVisitor visitor) { + for (int i=0; ithreshold; i++) { + if (!cc_visit(cond->subconditions[i], visitor)) { + return 0; + } + } + return 1; +} + + +static int cmpConditions(const void *a, const void *b) { + /* Compare conditions by their ASN binary representation */ + unsigned char bufa[BUF_SIZE], bufb[BUF_SIZE]; + asn_enc_rval_t r0 = der_encode_to_buffer(&asn_DEF_Condition, *(Condition_t**)a, bufa, BUF_SIZE); + asn_enc_rval_t r1 = der_encode_to_buffer(&asn_DEF_Condition, *(Condition_t**)b, bufb, BUF_SIZE); + int diff = r0.encoded - r1.encoded; + return diff != 0 ? diff : strcmp(bufa, bufb); +} + + +static unsigned char *thresholdFingerprint(const CC *cond) { + /* Create fingerprint */ + ThresholdFingerprintContents_t *fp = calloc(1, sizeof(ThresholdFingerprintContents_t)); + fp->threshold = cond->threshold; + for (int i=0; isize; i++) { + asn_set_add(&fp->subconditions2, asnConditionNew(cond->subconditions[i])); + } + qsort(fp->subconditions2.list.array, cond->size, sizeof(Condition_t*), cmpConditions); + return hashFingerprintContents(&asn_DEF_ThresholdFingerprintContents, fp); +} + + +static CC *thresholdFromFulfillment(const Fulfillment_t *ffill) { + ThresholdFulfillment_t *t = ffill->choice.thresholdSha256; + int threshold = t->subfulfillments.list.count; + int size = threshold + t->subconditions.list.count; + + CC **subconditions = calloc(size, sizeof(CC*)); + + for (int i=0; isubfulfillments.list.array[i]) : + mkAnon(t->subconditions.list.array[i-threshold]); + + if (!subconditions[i]) { + for (int j=0; jtype = &cc_thresholdType; + cond->threshold = threshold; + cond->size = size; + cond->subconditions = subconditions; + return cond; +} + + +static int cmpByCostDesc(const void *c1, const void *c2) { + return cc_getCost(*((CC**)c1)) - cc_getCost(*((CC**)c2)); +} + + +static Fulfillment_t *thresholdToFulfillment(const CC *cond) { + CC *sub; + Fulfillment_t *fulfillment; + + qsort(cond->subconditions, cond->size, sizeof(CC*), cmpByCostDesc); + + ThresholdFulfillment_t *tf = calloc(1, sizeof(ThresholdFulfillment_t)); + + int needed = cond->threshold; + + for (int i=0; isize; i++) { + sub = cond->subconditions[i]; + if (needed && (fulfillment = asnFulfillmentNew(sub))) { + asn_set_add(&tf->subfulfillments, fulfillment); + needed--; + } else { + asn_set_add(&tf->subconditions, asnConditionNew(cond->subconditions[i])); + } + } + + if (needed) { + ASN_STRUCT_FREE(asn_DEF_ThresholdFulfillment, tf); + return NULL; + } + + fulfillment = calloc(1, sizeof(Fulfillment_t)); + fulfillment->present = Fulfillment_PR_thresholdSha256; + fulfillment->choice.thresholdSha256 = tf; + return fulfillment; +} + + +static CC *thresholdFromJSON(const cJSON *params, unsigned char *err) { + cJSON *threshold_item = cJSON_GetObjectItem(params, "threshold"); + if (!cJSON_IsNumber(threshold_item)) { + strcpy(err, "threshold must be a number"); + return NULL; + } + + cJSON *subfulfillments_item = cJSON_GetObjectItem(params, "subfulfillments"); + if (!cJSON_IsArray(subfulfillments_item)) { + strcpy(err, "subfulfullments must be an array"); + return NULL; + } + + CC *cond = calloc(1, sizeof(CC)); + cond->type = &cc_thresholdType; + cond->threshold = (long) threshold_item->valuedouble; + cond->size = cJSON_GetArraySize(subfulfillments_item); + cond->subconditions = calloc(cond->size, sizeof(CC*)); + + cJSON *sub; + for (int i=0; isize; i++) { + sub = cJSON_GetArrayItem(subfulfillments_item, i); + cond->subconditions[i] = cc_conditionFromJSON(sub, err); + if (err[0]) return NULL; + } + + return cond; +} + + +static void thresholdToJSON(const CC *cond, cJSON *params) { + cJSON *subs = cJSON_CreateArray(); + cJSON_AddNumberToObject(params, "threshold", cond->threshold); + for (int i=0; isize; i++) { + cJSON_AddItemToArray(subs, cc_conditionToJSON(cond->subconditions[i])); + } + cJSON_AddItemToObject(params, "subfulfillments", subs); +} + + +static int thresholdIsFulfilled(const CC *cond) { + int nFulfilled = 0; + for (int i=0; ithreshold; i++) { + if (!cc_isFulfilled(cond->subconditions[i])) { + nFulfilled++; + } + if (nFulfilled == cond->threshold) { + return 1; + } + } + return 0; +} + + +static void thresholdFree(CC *cond) { + for (int i=0; isize; i++) { + cc_free(cond->subconditions[i]); + } + free(cond->subconditions); + free(cond); +} + + +struct CCType cc_thresholdType = { 2, "threshold-sha-256", Condition_PR_thresholdSha256, 1, &thresholdVisitChildren, &thresholdFingerprint, &thresholdCost, &thresholdSubtypes, &thresholdFromJSON, &thresholdToJSON, &thresholdFromFulfillment, &thresholdToFulfillment, &thresholdIsFulfilled, &thresholdFree }; diff --git a/src/cryptoconditions/src/utils.c b/src/cryptoconditions/src/utils.c new file mode 100644 index 000000000..d1e63629f --- /dev/null +++ b/src/cryptoconditions/src/utils.c @@ -0,0 +1,208 @@ +#include +#include +#include +#include +#include + +#include "include/cJSON.h" +#include "include/sha256.h" +#include "asn/asn_application.h" +#include "cryptoconditions.h" +#include "internal.h" + + +static unsigned char encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/'}; +static unsigned char *decoding_table = NULL; +static int mod_table[] = {0, 2, 1}; + + +void build_decoding_table() { + decoding_table = malloc(256); + for (int i = 0; i < 64; i++) + decoding_table[(unsigned char) encoding_table[i]] = i; +} + + +unsigned char *base64_encode(const unsigned char *data, size_t input_length) { + + size_t output_length = 4 * ((input_length + 2) / 3); + + unsigned char *encoded_data = malloc(output_length + 1); + if (encoded_data == NULL) return NULL; + + for (int i = 0, j = 0; i < input_length;) { + + uint32_t octet_a = i < input_length ? (unsigned char)data[i++] : 0; + uint32_t octet_b = i < input_length ? (unsigned char)data[i++] : 0; + uint32_t octet_c = i < input_length ? (unsigned char)data[i++] : 0; + + uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c; + + encoded_data[j++] = encoding_table[(triple >> 3 * 6) & 0x3F]; + encoded_data[j++] = encoding_table[(triple >> 2 * 6) & 0x3F]; + encoded_data[j++] = encoding_table[(triple >> 1 * 6) & 0x3F]; + encoded_data[j++] = encoding_table[(triple >> 0 * 6) & 0x3F]; + } + + int strip = mod_table[input_length % 3]; + for (int i = 0; i < strip; i++) + encoded_data[output_length - 1 - i] = '\0'; + // make sure there's a null termination for string protocol + encoded_data[output_length] = '\0'; + + + // url safe + for (int i=0; i> 2 * 8) & 0xFF; + if (j < *output_length) decoded_data[j++] = (triple >> 1 * 8) & 0xFF; + if (j < *output_length) decoded_data[j++] = (triple >> 0 * 8) & 0xFF; + } + + return decoded_data; +} + + +void base64_cleanup() { + free(decoding_table); +} + + +void dumpStr(unsigned char *str, size_t len) { + if (-1 == len) len = strlen(str); + fprintf(stderr, "len:%i ", (int)len); + for (int i=0; ivaluestring, size); + if (!*data) { + sprintf(err, "%s must be valid base64 string", key); + return 0; + } + return 1; +} + + +int jsonGetBase64(const cJSON *params, unsigned char *key, unsigned char *err, unsigned char **data, size_t *size) +{ + cJSON *item = cJSON_GetObjectItem(params, key); + if (!item) { + sprintf(err, "%s is required", key); + return 0; + } + return checkDecodeBase64(item, key, err, data, size); +} + + +int jsonGetBase64Optional(const cJSON *params, unsigned char *key, unsigned char *err, unsigned char **data, size_t *size) { + cJSON *item = cJSON_GetObjectItem(params, key); + if (!item) { + return 1; + } + return checkDecodeBase64(item, key, err, data, size); +} + +void jsonAddBase64(cJSON *params, unsigned char *key, unsigned char *bin, size_t size) { + unsigned char *b64 = base64_encode(bin, size); + cJSON_AddItemToObject(params, key, cJSON_CreateString(b64)); + free(b64); +} + + +unsigned char *hashFingerprintContents(asn_TYPE_descriptor_t *asnType, void *fp) { + 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) { + printf("Encoding fingerprint failed\n"); + return 0; + } + unsigned char *hash = malloc(32); + sha256(buf, rc.encoded, hash); + return hash; +} diff --git a/src/cryptoconditions/test-requirements.txt b/src/cryptoconditions/test-requirements.txt new file mode 100644 index 000000000..2858c9ae3 --- /dev/null +++ b/src/cryptoconditions/test-requirements.txt @@ -0,0 +1,3 @@ +nose +base58==0.2.5 +secp256k1 diff --git a/src/cryptoconditions/tests/__init__.py b/src/cryptoconditions/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/cryptoconditions/tests/custom-vectors/1000_test-minimal-eval.json b/src/cryptoconditions/tests/custom-vectors/1000_test-minimal-eval.json new file mode 100644 index 000000000..14ab8ca49 --- /dev/null +++ b/src/cryptoconditions/tests/custom-vectors/1000_test-minimal-eval.json @@ -0,0 +1,14 @@ +{ + "json": { + "type": "eval-sha-256", + "method": "testEval", + "params": "dGVzdEV2YWw" + }, + "cost": 131072, + "subtypes": [], + "fingerprintContents": "", + "fulfillment": "AF148008746573744576616C8108746573744576616C", + "conditionBinary": "AF27802062CC11575F91E1611379B5A0B53678805FC03858544FC28E72BB66A14629C08F8103100000", + "conditionUri": "ni:///sha-256;YswRV1-R4WETebWgtTZ4gF_AOFhUT8KOcrtmoUYpwI8?fpt=eval-sha-256&cost=1048576", + "message": "" +} diff --git a/src/cryptoconditions/tests/custom-vectors/1001_test-minimal-secp256k1.json b/src/cryptoconditions/tests/custom-vectors/1001_test-minimal-secp256k1.json new file mode 100644 index 000000000..d34de80fa --- /dev/null +++ b/src/cryptoconditions/tests/custom-vectors/1001_test-minimal-secp256k1.json @@ -0,0 +1,14 @@ +{ + "json": { + "type": "secp256k1-sha-256", + "publicKey": "AtXZaTBVNawpp3B5wR1PDdQGYc-W4E6XSl6NfjdO4iWq", + "signature": "nC1v8580C7r2XohL3_rnQ2p7dWiDnFuhF_poGCRfudo83sfP1NPfcZG9siY4_Ybz2aO4yyV_z5tU0JMcTQGV0w" + }, + "cost": 131072, + "subtypes": [], + "fingerprintContents": "", + "fulfillment": "A565802102D5D969305535AC29A77079C11D4F0DD40661CF96E04E974A5E8D7E374EE225AA81409C2D6FF39F340BBAF65E884BDFFAE7436A7B7568839C5BA117FA6818245FB9DA3CDEC7CFD4D3DF7191BDB22638FD86F3D9A3B8CB257FCF9B54D0931C4D0195D3", + "conditionBinary": "A52780209C2850F5147E9903DD317C650AC1D6E80E695280789887F2E3179E5C65C9DF3A8103020000", + "conditionUri": "ni:///sha-256;nChQ9RR-mQPdMXxlCsHW6A5pUoB4mIfy4xeeXGXJ3zo?fpt=secp256k1-sha-256&cost=131072", + "message": "" +} diff --git a/src/cryptoconditions/tests/test_ed25519.py b/src/cryptoconditions/tests/test_ed25519.py new file mode 100644 index 000000000..081a7efd5 --- /dev/null +++ b/src/cryptoconditions/tests/test_ed25519.py @@ -0,0 +1,73 @@ +import json +import base64 +from test_vectors import jsonRPC + + +def test_sign_ed25519_pass_simple(): + res = jsonRPC('signTreeEd25519', { + 'condition': { + 'type': 'ed25519-sha-256', + 'publicKey': "E0x0Ws4GhWhO_zBoUyaLbuqCz6hDdq11Ft1Dgbe9y9k", + }, + 'privateKey': '11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo', + 'message': '', + }) + + assert res == { + "num_signed": 1, + "condition": { + "type": "ed25519-sha-256", + "publicKey": "E0x0Ws4GhWhO_zBoUyaLbuqCz6hDdq11Ft1Dgbe9y9k", + "signature": "jcuovSRpHwqiC781KzSM1Jd0Qtyfge0cMGttUdLOVdjJlSBFLTtgpinASOaJpd-VGjhSGWkp1hPWuMAAZq6pAg" + } + } + + +def test_sign_ed25519_pass_prefix(): + res = jsonRPC('signTreeEd25519', { + 'condition': { + 'type': 'prefix-sha-256', + 'prefix': 'YmJi', + 'maxMessageLength': 3, + 'subfulfillment': { + 'type': 'ed25519-sha-256', + 'publicKey': "E0x0Ws4GhWhO_zBoUyaLbuqCz6hDdq11Ft1Dgbe9y9k", + } + }, + 'privateKey': '11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo', + 'message': '', + }) + + assert res == { + "num_signed": 1, + 'condition': { + 'type': 'prefix-sha-256', + 'prefix': 'YmJi', + 'maxMessageLength': 3, + 'subfulfillment': { + 'type': 'ed25519-sha-256', + 'publicKey': "E0x0Ws4GhWhO_zBoUyaLbuqCz6hDdq11Ft1Dgbe9y9k", + 'signature': '4Y6keUFEl4KgIum9e3MBdlhlp32FRas-1N1vhtdy5q3JEPdqMvmXo2Rb99fC6j_3vflh8_QtOEW5rj4utjMOBg', + } + }, + } + + +def test_sign_ed25519_fail(): + # privateKey doesnt match publicKey + res = jsonRPC('signTreeEd25519', { + 'condition': { + 'type': 'ed25519-sha-256', + 'publicKey': "E0x0Ws4GhWhO_zBoUyaLbuqCz6hDdq11Ft1Dgbe9y9k", + }, + 'privateKey': '22qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo', + 'message': '', + }) + + assert res == { + "num_signed": 0, + "condition": { + "type": "ed25519-sha-256", + "publicKey": "E0x0Ws4GhWhO_zBoUyaLbuqCz6hDdq11Ft1Dgbe9y9k", + } + } diff --git a/src/cryptoconditions/tests/test_failure_modes.py b/src/cryptoconditions/tests/test_failure_modes.py new file mode 100644 index 000000000..b95c8527e --- /dev/null +++ b/src/cryptoconditions/tests/test_failure_modes.py @@ -0,0 +1,63 @@ +import json +import ctypes +import base64 +from test_vectors import jsonRPC, so, decode_base64 as d64 + + +''' +These tests are aimed at edge cases of serverside deployment. + +As such, the main functions to test are decoding and verifying fulfillment payloads. +''' + + +cc_rfb = lambda f: so.cc_readFulfillmentBinary(f, len(f)) +cc_rcb = lambda f: so.cc_readConditionBinary(f, len(f)) + +unhex = lambda s: base64.b16decode(s.upper()) + + +def test_decode_valid_fulfillment(): + f = unhex('a42480206ee12ed43d7dce6fc0b2be20e6808380baafc03d400404bbf95165d7527b373a8100') + assert cc_rfb(f) + + +def test_decode_invalid_fulfillment(): + # This fulfillment payload has an invalid type ID but is otherwise valid + invalid_type_id = unhex('bf632480206ee12ed43d7dce6fc0b2be20e6808380baafc03d400404bbf95165d7527b373a8100') + assert cc_rfb(invalid_type_id) == 0 + assert cc_rfb('\0') == 0 + assert cc_rfb('') == 0 + + +def test_large_fulfillment(): + # This payload is valid and very large + f = unhex("a1839896b28083989680") + 10000000 * b'e' + \ + unhex("81030186a0a226a42480206ee12ed43d7dce6fc0b2be20e68083" + "80baafc03d400404bbf95165d7527b373a8100") + cond = cc_rfb(f) + buflen = len(f) + 1000 # Wiggle room + buf = ctypes.create_string_buffer(buflen) + assert so.cc_fulfillmentBinary(cond, buf, buflen) + so.cc_free(cond) + + +def test_decode_valid_condition(): + # Valid preimage + assert cc_rcb(d64('oCWAIMqXgRLKG73K-sIxs5oj3E2nhu_4FHxOcrmAd4Wv7ki7gQEB')) + + # Somewhat bogus condition (prefix with no subtypes) but nonetheless valid structure + assert cc_rcb(unhex("a10a8001618101ff82020700")) + + +def test_decode_invalid_condition(): + assert 0 == cc_rcb("") + assert 0 == cc_rcb("\0") + + # Bogus type ID + assert 0 == cc_rcb(unhex('bf630c80016181030186a082020700')) + + +def test_validate_empty_sigs(): + #// TODO: test failure mode: empty sig / null pointer + pass diff --git a/src/cryptoconditions/tests/test_secp256k1.py b/src/cryptoconditions/tests/test_secp256k1.py new file mode 100644 index 000000000..db36da218 --- /dev/null +++ b/src/cryptoconditions/tests/test_secp256k1.py @@ -0,0 +1,62 @@ +import json +import base64 +import hashlib +import secp256k1 +from test_vectors import jsonRPC, encode_base64, decode_base64 + + +key = secp256k1.PrivateKey() + + +def test_sign_secp256k1_pass_simple(): + pubkey = encode_base64(key.pubkey.serialize()) + msg = '' + res = jsonRPC('signTreeSecp256k1', { + 'condition': { + 'type': 'secp256k1-sha-256', + 'publicKey': pubkey, + }, + 'privateKey': encode_base64(key.private_key), + 'message': msg, + }) + + sig = encode_base64(key.ecdsa_serialize_compact(key.ecdsa_sign(msg))) + + assert res == { + "num_signed": 1, + "condition": { + "type": "secp256k1-sha-256", + "publicKey": pubkey, + "signature": sig + } + } + cond_bin = jsonRPC('encodeCondition', res['condition'])['bin'] + ffill_bin = jsonRPC('encodeFulfillment', res['condition'])['fulfillment'] + assert jsonRPC('verifyFulfillment', { + 'fulfillment': ffill_bin, + 'message': msg, + 'condition': cond_bin + }) == {'valid': True} + + + +def test_sign_secp256k1_fail(): + # privateKey doesnt match publicKey + pubkey = encode_base64(key.pubkey.serialize()) + msg = '' + res = jsonRPC('signTreeSecp256k1', { + 'condition': { + 'type': 'secp256k1-sha-256', + 'publicKey': pubkey, + }, + 'privateKey': encode_base64('0' * 32), + 'message': msg, + }) + + assert res == { + "num_signed": 0, + "condition": { + "type": "secp256k1-sha-256", + "publicKey": pubkey, + } + } diff --git a/src/cryptoconditions/tests/test_vectors.py b/src/cryptoconditions/tests/test_vectors.py new file mode 100644 index 000000000..b94ed9461 --- /dev/null +++ b/src/cryptoconditions/tests/test_vectors.py @@ -0,0 +1,149 @@ +import json +import ctypes +import base64 +import pytest +import os.path +from ctypes import * + + +v0000 = '0000_test-minimal-preimage' +v0001 = '0001_test-minimal-prefix' +v0002 = '0002_test-minimal-threshold' +v0003 = '0003_test-minimal-rsa' +v0004 = '0004_test-minimal-ed25519' +v0005 = '0005_test-basic-preimage' +v0006 = '0006_test-basic-prefix' +v0007 = '0007_test-basic-prefix-two-levels-deep' +v0010 = '0010_test-basic-threshold-same-fulfillment-twice' +v0015 = '0015_test-basic-ed25519' +v0016 = '0016_test-advanced-notarized-receipt' +v0017 = '0017_test-advanced-notarized-receipt-multiple-notaries' + +# These contain RSA conditions which are not implemented yet +#v0008 = '0008_test-basic-threshold' +#v0009 = '0009_test-basic-threshold-same-condition-twice' +#v0011 = '0011_test-basic-threshold-two-levels-deep' +#v0012 = '0012_test-basic-threshold-schroedinger' +#v0013 = '0013_test-basic-rsa' +#v0014 = '0014_test-basic-rsa4096' + +# Custom test vectors +v1000 = '1000_test-minimal-eval' +v1001 = '1001_test-minimal-secp256k1' + + +all_vectors = {v0000, v0001, v0002, v0004, v0005, v0006, v0007, v0010, + v0015, v0016, v0017, v1000, v1001} + + +@pytest.mark.parametrize('vectors_file', all_vectors) +def test_encodeCondition(vectors_file): + vectors = _read_vectors(vectors_file) + response = jsonRPC('encodeCondition', vectors['json']) + assert response == { + 'uri': vectors['conditionUri'], + 'bin': vectors['conditionBinary'], + } + + +@pytest.mark.parametrize('vectors_file', all_vectors) +def test_encodeFulfillment(vectors_file): + vectors = _read_vectors(vectors_file) + response = jsonRPC('encodeFulfillment', vectors['json']) + assert response == { + 'fulfillment': vectors['fulfillment'], + } + + +@pytest.mark.parametrize('vectors_file', all_vectors) +def test_verifyFulfillment(vectors_file): + vectors = _read_vectors(vectors_file) + req = { + 'fulfillment': vectors['fulfillment'], + 'message': vectors['message'], + 'condition': vectors['conditionBinary'], + } + assert jsonRPC('verifyFulfillment', req) == {'valid': True} + + +@pytest.mark.parametrize('vectors_file', all_vectors) +def test_decodeFulfillment(vectors_file): + vectors = _read_vectors(vectors_file) + response = jsonRPC('decodeFulfillment', { + 'fulfillment': vectors['fulfillment'], + }) + assert response == { + 'uri': vectors['conditionUri'], + 'bin': vectors['conditionBinary'], + } + + +@pytest.mark.parametrize('vectors_file', all_vectors) +def test_decodeCondition(vectors_file): + vectors = _read_vectors(vectors_file) + response = jsonRPC('decodeCondition', { + 'bin': vectors['conditionBinary'], + }) + assert response['uri'] == vectors['conditionUri'] + + +@pytest.mark.parametrize('vectors_file', all_vectors) +def test_json_condition_json_parse(vectors_file): + vectors = _read_vectors(vectors_file) + err = ctypes.create_string_buffer(100) + cc = so.cc_conditionFromJSONString(json.dumps(vectors['json']).encode(), err) + out_ptr = so.cc_conditionToJSONString(cc) + out = ctypes.cast(out_ptr, c_char_p).value.decode() + assert json.loads(out) == vectors['json'] + + +def b16_to_b64(b16): + return base64.urlsafe_b64encode(base64.b16decode(b16)).rstrip('=') + + +def decode_base64(data): + """Decode base64, padding being optional. + + :param data: Base64 data as an ASCII byte string + :returns: The decoded byte string. + """ + missing_padding = len(data) % 4 + if missing_padding: + data += '=' * (4 - missing_padding) + return base64.urlsafe_b64decode(data) + + +def encode_base64(data): + return base64.urlsafe_b64encode(data).rstrip(b'=') + + +def b16_to_b64(b16): + return encode_base64(base64.b16decode(b16)).decode() + + +def _read_vectors(name): + paths = ['ext/crypto-conditions/test-vectors/valid/%s.json', + 'tests/custom-vectors/%s.json'] + for fmt in paths: + path = fmt % name + if os.path.isfile(path): + vectors = json.load(open(path)) + break + else: + raise IOError("Vectors file not found: %s.json" % name) + for key in ['conditionBinary', 'fulfillment', 'message']: + vectors[key] = b16_to_b64(vectors[key]) + return vectors + + +so = cdll.LoadLibrary('.libs/libcryptoconditions.so') +so.cc_jsonRPC.restype = c_char_p + + +def jsonRPC(method, params): + req = json.dumps({ + 'method': method, + 'params': params, + }) + out = so.cc_jsonRPC(req.encode()) + return json.loads(out.decode()) From 91fe980a98e198564a3af89686c4ed50d0538230 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Mon, 12 Mar 2018 18:22:38 -0300 Subject: [PATCH 047/339] fix cryptoconditions qa --- qa/cryptoconditions/test_integration.py | 94 ------------------------- qa/cryptoconditions/testsupport.py | 4 +- 2 files changed, 2 insertions(+), 96 deletions(-) diff --git a/qa/cryptoconditions/test_integration.py b/qa/cryptoconditions/test_integration.py index 1f6746b69..16b5f93a6 100644 --- a/qa/cryptoconditions/test_integration.py +++ b/qa/cryptoconditions/test_integration.py @@ -91,45 +91,6 @@ def test_oversize_fulfillment(inp): assert 'scriptsig-size' in str(e), str(e) -@fanout_input(6) -def test_eval_basic(inp): - eval_cond = { - 'type': 'eval-sha-256', - 'method': 'testEval', - 'params': encode_base64('testEval') - } - - # Setup some eval outputs - spend0 = { - 'inputs': [inp], - 'outputs': [ - {'amount': 500, 'script': {'condition': eval_cond}}, - {'amount': 500, 'script': {'condition': eval_cond}} - ] - } - spend0_txid = submit(sign(spend0)) - assert rpc.getrawtransaction(spend0_txid) - - # Test a good fulfillment - spend1 = { - 'inputs': [{'txid': spend0_txid, 'idx': 0, 'script': {'fulfillment': eval_cond}}], - 'outputs': [{'amount': 500, 'script': {'condition': eval_cond}}] - } - spend1_txid = submit(sign(spend1)) - assert rpc.getrawtransaction(spend1_txid) - - # Test a bad fulfillment - eval_cond['params'] = '' - spend2 = { - 'inputs': [{'txid': spend0_txid, 'idx': 1, 'script': {'fulfillment': eval_cond}}], - 'outputs': [{'amount': 500, 'script': {'condition': eval_cond}}] - } - try: - assert not submit(sign(spend2)), 'should raise an error' - except RPCError as e: - assert SCRIPT_FALSE in str(e), str(e) - - @fanout_input(7) def test_secp256k1_condition(inp): ec_cond = { @@ -169,61 +130,6 @@ def test_secp256k1_condition(inp): except RPCError as e: assert SCRIPT_FALSE in str(e), str(e) - -@fanout_input(20) -def test_eval_replacement(inp): - eval_cond = { - 'type': 'eval-sha-256', - 'method': 'testReplace', - 'params': '', - } - - # Setup replaceable output - spend0 = { - 'inputs': [inp], - 'outputs': [ - {'amount': 1000, 'script': {'condition': eval_cond}}, - ] - } - spend0_txid = submit(sign(spend0)) - assert rpc.getrawtransaction(spend0_txid) - - b64_1 = 'AQ==' - spend1 = { - 'inputs': [{'txid': spend0_txid, 'idx': 0, 'script': {'fulfillment': eval_cond}}], - 'outputs': [{'amount': 1000, 'script': {'op_return': b64_1}}] - } - - b64_2 = 'Ag==' - spend2 = { - 'inputs': [{'txid': spend0_txid, 'idx': 0, 'script': {'fulfillment': eval_cond}}], - 'outputs': [{'amount': 1000, 'script': {'op_return': b64_2}}] - } - - # If spend2 is already registered, return true, as this test has already been performed - spend2_txid = hoek.encodeTx(sign(spend2))['txid'] - try: - rpc.getrawtransaction(spend2_txid) - return - except RPCError: - pass - - # Send replaceable - spend1_txid = submit(sign(spend1)) - assert rpc.getrawtransaction(spend1_txid) - - - # Send replacement (higher OP_RETURN data) - spend2_txid = submit(sign(spend2)) - assert rpc.getrawtransaction(spend2_txid) - - # Now the first transaction has gone - try: - assert not rpc.getrawtransaction(spend1_txid), "should raise an error" - except RPCError as e: - assert 'No information available about transaction' in str(e), str(e) - - if __name__ == '__main__': logging.basicConfig(level=logging.INFO) for name, f in globals().items(): diff --git a/qa/cryptoconditions/testsupport.py b/qa/cryptoconditions/testsupport.py index a127379f6..055f4cc30 100644 --- a/qa/cryptoconditions/testsupport.py +++ b/qa/cryptoconditions/testsupport.py @@ -32,7 +32,7 @@ class JsonClient(object): def run_cmd(cmd): proc = subprocess.Popen(cmd, stdout=subprocess.PIPE) - assert proc.wait() == 0 + assert proc.wait() == 0, cmd return proc.stdout.read() @@ -68,7 +68,7 @@ def wait_for_block(height): try: return rpc.getblock(str(height)) except RPCError as e: - time.sleep(3) + time.sleep(1) raise Exception('Time out waiting for block at height %s' % height) From aaff5dd10cdb03f31afe291d48f063bab969de31 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Sat, 17 Mar 2018 15:13:10 -0300 Subject: [PATCH 048/339] explicitly disable replacementpool if cryptoconditions is not enabled --- src/main.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 62fa0c726..fa366964f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1116,6 +1116,11 @@ CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowF */ bool AcceptToReplacementPool(const CTransaction &tx, CValidationState &state) { + // This is not actually required; if crypto-conditions is disabled, then transactions + // with replaceable outputs will not be accepted as standard. However, just to be a + // bit more explicit. + if (!IsCryptoConditionsEnabled()) return false; + CTxReplacementPoolItem item(tx, GetHeight()); if (!SetReplacementParams(item)) return false; From 49cd4daab29186139ef18b35340cd3552f36144f Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Sat, 17 Mar 2018 23:09:14 -0300 Subject: [PATCH 049/339] cryptoconditions secp256k1 tests canonical signature --- .../src/include/secp256k1/include/secp256k1.h | 12 ++++++++++++ .../src/include/secp256k1/src/secp256k1.c | 8 ++++++++ src/cryptoconditions/src/secp256k1.c | 7 ++++++- src/cryptoconditions/tests/test_failure_modes.py | 15 +++++++++++++++ 4 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/cryptoconditions/src/include/secp256k1/include/secp256k1.h b/src/cryptoconditions/src/include/secp256k1/include/secp256k1.h index 06afd4c65..9db5cf3a8 100644 --- a/src/cryptoconditions/src/include/secp256k1/include/secp256k1.h +++ b/src/cryptoconditions/src/include/secp256k1/include/secp256k1.h @@ -95,6 +95,18 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify( int pubkeylen ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5); +/** Check that signature is in canonical form + * Returns: 1: In canonical form + * 0: Non canonical + * -1: invalid signature + * In: sig: the signature being verified (cannot be NULL) + * siglen: the length of the signature + */ +SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_check_canonical_sig( + const unsigned char *sig, + int siglen +) SECP256K1_ARG_NONNULL(1); + /** A pointer to a function to deterministically generate a nonce. * Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail. * In: msg32: the 32-byte message hash being verified (will not be NULL) diff --git a/src/cryptoconditions/src/include/secp256k1/src/secp256k1.c b/src/cryptoconditions/src/include/secp256k1/src/secp256k1.c index d6192dc4e..48569ad9e 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/secp256k1.c +++ b/src/cryptoconditions/src/include/secp256k1/src/secp256k1.c @@ -85,6 +85,14 @@ int secp256k1_ecdsa_verify(const secp256k1_context_t* ctx, const unsigned char * return ret; } + +int secp256k1_ecdsa_check_canonical_sig(const unsigned char *sig, int siglen) { + secp256k1_ecdsa_sig_t s; + if (!secp256k1_ecdsa_sig_parse(&s, sig, siglen)) return -1; + return !secp256k1_scalar_is_high(&s.s); +} + + static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) { secp256k1_rfc6979_hmac_sha256_t rng; unsigned int i; diff --git a/src/cryptoconditions/src/secp256k1.c b/src/cryptoconditions/src/secp256k1.c index 507c9c84f..9e09cabe5 100644 --- a/src/cryptoconditions/src/secp256k1.c +++ b/src/cryptoconditions/src/secp256k1.c @@ -77,7 +77,12 @@ int secp256k1Verify(CC *cond, CCVisitor visitor) { if (cond->type->typeId != cc_secp256k1Type.typeId) return 1; // TODO: test failure mode: empty sig / null pointer initVerify(); - int rc = secp256k1_ecdsa_verify(ec_ctx_verify, visitor.msg, cond->signature, SECP256K1_SIG_SIZE, + + // Test for non canonical S + int rc = secp256k1_ecdsa_check_canonical_sig(cond->signature, SECP256K1_SIG_SIZE); + if (rc == 1) + // Test for correct sig + rc = secp256k1_ecdsa_verify(ec_ctx_verify, visitor.msg, cond->signature, SECP256K1_SIG_SIZE, cond->publicKey, SECP256K1_PK_SIZE); return rc == 1; } diff --git a/src/cryptoconditions/tests/test_failure_modes.py b/src/cryptoconditions/tests/test_failure_modes.py index b95c8527e..4e252424f 100644 --- a/src/cryptoconditions/tests/test_failure_modes.py +++ b/src/cryptoconditions/tests/test_failure_modes.py @@ -61,3 +61,18 @@ def test_decode_invalid_condition(): def test_validate_empty_sigs(): #// TODO: test failure mode: empty sig / null pointer pass + + +def test_non_canonical_secp256k1(): + cond = { + "type": "secp256k1-sha-256", + "publicKey": "AtXZaTBVNawpp3B5wR1PDdQGYc-W4E6XSl6NfjdO4iWq", + # Signature is correct, but non canonical; validation should fail + "signature": "nC1v8580C7r2XohL3_rnQ2p7dWiDnFuhF_poGCRfudrDITgwKywgjm5CTdnHAnkK4QskG4nI0KBrActwgzSrbg" + } + res = jsonRPC('verifyFulfillment', { + 'fulfillment': jsonRPC('encodeFulfillment', cond)['fulfillment'], + 'condition': jsonRPC('encodeCondition', cond)['bin'], + 'message': '' + }) + assert res['valid'] == False From 51aad1873397455645fcd188b2ae406fa44c9646 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Mon, 26 Mar 2018 16:21:33 -0300 Subject: [PATCH 050/339] remove replacementpool --- qa/cryptoconditions/test_integration.py | 86 +++- qa/cryptoconditions/testsupport.py | 10 +- src/Makefile.am | 9 +- src/Makefile.ktest.include | 16 - src/cryptoconditions/Makefile.am | 16 +- .../include/cryptoconditions.h | 1 + src/komodo_cryptoconditions.cpp | 79 +--- src/komodo_cryptoconditions.h | 7 +- src/main.cpp | 206 +++----- src/main.h | 2 +- src/replacementpool.cpp | 88 ---- src/replacementpool.h | 76 --- src/secp256k1/include/secp256k1.h | 12 + src/secp256k1/src/secp256k1.c | 8 + src/test-komodo/main.cpp | 9 - src/test-komodo/test_replacementpool.cpp | 440 ------------------ 16 files changed, 190 insertions(+), 875 deletions(-) delete mode 100644 src/Makefile.ktest.include delete mode 100644 src/replacementpool.cpp delete mode 100644 src/replacementpool.h delete mode 100644 src/test-komodo/main.cpp delete mode 100644 src/test-komodo/test_replacementpool.cpp diff --git a/qa/cryptoconditions/test_integration.py b/qa/cryptoconditions/test_integration.py index 16b5f93a6..bd72b961d 100644 --- a/qa/cryptoconditions/test_integration.py +++ b/qa/cryptoconditions/test_integration.py @@ -4,7 +4,6 @@ import json import logging import binascii import struct -import base64 from testsupport import * @@ -91,7 +90,91 @@ def test_oversize_fulfillment(inp): assert 'scriptsig-size' in str(e), str(e) +@fanout_input(6) +def test_aux_basic(inp): + aux_cond = { + 'type': 'aux-sha-256', + 'method': 'equals', + 'conditionAux': 'LTE', + 'fulfillmentAux': 'LTE' + } + + # Setup some aux outputs + spend0 = { + 'inputs': [inp], + 'outputs': [ + {'amount': 500, 'script': {'condition': aux_cond}}, + {'amount': 500, 'script': {'condition': aux_cond}} + ] + } + spend0_txid = submit(sign(spend0)) + assert rpc.getrawtransaction(spend0_txid) + + # Test a good fulfillment + spend1 = { + 'inputs': [{'txid': spend0_txid, 'idx': 0, 'script': {'fulfillment': aux_cond}}], + 'outputs': [{'amount': 500, 'script': {'condition': aux_cond}}] + } + spend1_txid = submit(sign(spend1)) + assert rpc.getrawtransaction(spend1_txid) + + # Test a bad fulfillment + aux_cond['fulfillmentAux'] = 'WYW' + spend2 = { + 'inputs': [{'txid': spend0_txid, 'idx': 1, 'script': {'fulfillment': aux_cond}}], + 'outputs': [{'amount': 500, 'script': {'condition': aux_cond}}] + } + try: + assert not submit(sign(spend2)), 'should raise an error' + except RPCError as e: + assert SCRIPT_FALSE in str(e), str(e) + + @fanout_input(7) +def test_aux_complex(inp): + aux_cond = { + 'type': 'aux-sha-256', + 'method': 'inputIsReturn', + 'conditionAux': '', + 'fulfillmentAux': 'AQ' # \1 (tx.vout[1]) + } + + # Setup some aux outputs + spend0 = { + 'inputs': [inp], + 'outputs': [ + {'amount': 500, 'script': {'condition': aux_cond}}, + {'amount': 500, 'script': {'condition': aux_cond}} + ] + } + spend0_txid = submit(sign(spend0)) + assert rpc.getrawtransaction(spend0_txid) + + # Test a good fulfillment + spend1 = { + 'inputs': [{'txid': spend0_txid, 'idx': 0, 'script': {'fulfillment': aux_cond}}], + 'outputs': [ + {'amount': 250, 'script': {'condition': aux_cond}}, + {'amount': 250, 'script': "6A0B68656C6C6F207468657265"} # OP_RETURN somedata + ] + } + spend1_txid = submit(sign(spend1)) + assert rpc.getrawtransaction(spend1_txid) + + # Test a bad fulfillment + spend2 = { + 'inputs': [{'txid': spend0_txid, 'idx': 1, 'script': {'fulfillment': aux_cond}}], + 'outputs': [ + {'amount': 500, 'script': "6A0B68656C6C6F207468657265"} # OP_RETURN somedata + ] + } + try: + assert not submit(sign(spend2)), 'should raise an error' + except RPCError as e: + assert SCRIPT_FALSE in str(e), str(e) + + +@fanout_input(8) def test_secp256k1_condition(inp): ec_cond = { 'type': 'secp256k1-sha-256', @@ -130,6 +213,7 @@ def test_secp256k1_condition(inp): except RPCError as e: assert SCRIPT_FALSE in str(e), str(e) + if __name__ == '__main__': logging.basicConfig(level=logging.INFO) for name, f in globals().items(): diff --git a/qa/cryptoconditions/testsupport.py b/qa/cryptoconditions/testsupport.py index 055f4cc30..e22520f3f 100644 --- a/qa/cryptoconditions/testsupport.py +++ b/qa/cryptoconditions/testsupport.py @@ -32,7 +32,7 @@ class JsonClient(object): def run_cmd(cmd): proc = subprocess.Popen(cmd, stdout=subprocess.PIPE) - assert proc.wait() == 0, cmd + assert proc.wait() == 0 return proc.stdout.read() @@ -68,7 +68,7 @@ def wait_for_block(height): try: return rpc.getblock(str(height)) except RPCError as e: - time.sleep(1) + time.sleep(3) raise Exception('Time out waiting for block at height %s' % height) @@ -97,7 +97,7 @@ def get_fanout_txid(): reward_tx = hoek.decodeTx({'hex': reward_tx_raw}) balance = reward_tx['outputs'][0]['amount'] - n_outs = 40 + n_outs = 16 remainder = balance - n_outs * 1000 fanout = { @@ -109,9 +109,7 @@ def get_fanout_txid(): ] + [{"amount": remainder, 'script': {'address': notary_addr}}]) } - txid = submit(sign(fanout)) - rpc.getrawtransaction(txid) - return txid + return submit(sign(fanout)) def fanout_input(n): diff --git a/src/Makefile.am b/src/Makefile.am index 7c0200623..00242776f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -39,7 +39,7 @@ LIBBITCOIN_CLI=libbitcoin_cli.a LIBBITCOIN_UTIL=libbitcoin_util.a LIBBITCOIN_CRYPTO=crypto/libbitcoin_crypto.a LIBSECP256K1=secp256k1/libsecp256k1.la -LIBCRYPTOCONDITIONS=cryptoconditions/libcryptoconditions.la +LIBCRYPTOCONDITIONS=cryptoconditions/cryptoconditions_core.a LIBUNIVALUE=univalue/libunivalue.la LIBZCASH=libzcash.a -lcurl @@ -156,7 +156,6 @@ BITCOIN_CORE_H = \ protocol.h \ pubkey.h \ random.h \ - replacementpool.h \ reverselock.h \ rpcclient.h \ rpcprotocol.h \ @@ -235,7 +234,6 @@ libbitcoin_server_a_SOURCES = \ noui.cpp \ policy/fees.cpp \ pow.cpp \ - replacementpool.cpp \ rest.cpp \ rpcblockchain.cpp \ rpcmining.cpp \ @@ -562,10 +560,9 @@ endif @test -f $(PROTOC) $(AM_V_GEN) $(PROTOC) --cpp_out=$(@D) --proto_path=$(abspath $( +#include #ifndef CRYPTOCONDITIONS_H diff --git a/src/komodo_cryptoconditions.cpp b/src/komodo_cryptoconditions.cpp index e2695af40..4ebbebbeb 100644 --- a/src/komodo_cryptoconditions.cpp +++ b/src/komodo_cryptoconditions.cpp @@ -1,94 +1,21 @@ - -#include "replacementpool.h" #include "komodo_cryptoconditions.h" #include "cryptoconditions/include/cryptoconditions.h" -bool ASSETCHAINS_CC_TEST = false; - - /* * Evaluate the validity of an Eval node */ bool EvalConditionValidity(const CC *cond, const CTransaction *txTo) { - if (ASSETCHAINS_CC_TEST) { - if (strcmp(cond->method, "testEval") == 0) { - return cond->paramsBinLength == 8 && - memcmp(cond->paramsBin, "testEval", 8) == 0; - } - if (strcmp(cond->method, "testReplace") == 0) { - std::vector data; - auto out = txTo->vout[txTo->vout.size()-1]; // Last output is data - return GetOpReturnData(out.scriptPubKey, data) && data.size() == 2; - } + if (strcmp(cond->method, "testEval") == 0) { + return cond->paramsBinLength == 8 && + memcmp(cond->paramsBin, "testEval", 8) == 0; } fprintf(stderr, "no defined behaviour for method: %s\n", cond->method); return 0; } -/* - * Evaluate the priority of an eval node. - * - * This method should set the ->priority and ->replacementWindow (in blocks) - * of the provided replacement pool item. Priority is a 64 bit unsigned int and - * 0 is invalid. - * - * This method does not need to validate, that is done separately. Actually, - * this method will nearly always be called with the same condition and transaction - * in sequence after EvalConditionValidity. If performance became an issue, a very - * small LRU cache could be used to cache a result. - */ -bool EvalConditionPriority(const CC *cond, CTxReplacementPoolItem *rep) -{ - if (ASSETCHAINS_CC_TEST) { - if (strcmp((const char*)cond->method, "testReplace") == 0) { - std::vector data; - auto out = rep->tx.vout[rep->tx.vout.size()-1]; // Last output is data - if (GetOpReturnData(out.scriptPubKey, data)) { - rep->replacementWindow = (int) data[0]; - rep->priority = (uint64_t) data[1]; - return true; - } - } - } - return false; -} - - -int visitConditionPriority(CC *cond, struct CCVisitor visitor) -{ - auto rep = (CTxReplacementPoolItem*)visitor.context; - // visitor protocol is 1 for continue, 0 for stop - return !(cc_typeId(cond) == CC_Eval && EvalConditionPriority(cond, rep)); -} - - -/* - * Try to get replacement parameters from a transaction in &rep. - */ -bool SetReplacementParams(CTxReplacementPoolItem &rep) -{ - // first, see if we have a cryptocondition - const CScript &sig = rep.tx.vin[0].scriptSig; - if (!sig.IsPushOnly()) return false; - CScript::const_iterator pc = sig.begin(); - std::vector data; - opcodetype opcode; - if (!sig.GetOp(pc, opcode, data)) return false; - CC *cond = cc_readFulfillmentBinary((unsigned char*)data.data(), data.size()); - if (!cond) return false; - - // now, see if it has a replacement node - CC *replacementNode = 0; - CCVisitor visitor = {&visitConditionPriority, (const unsigned char*)"", 0, &rep}; - bool out = cc_visit(cond, visitor); - cc_free(cond); - return !out; -} - - bool GetOpReturnData(const CScript &sig, std::vector &data) { auto pc = sig.begin(); diff --git a/src/komodo_cryptoconditions.h b/src/komodo_cryptoconditions.h index de12140ef..4edc2bedc 100644 --- a/src/komodo_cryptoconditions.h +++ b/src/komodo_cryptoconditions.h @@ -1,24 +1,19 @@ #ifndef KOMODO_CRYPTOCONDITIONS_H #define KOMODO_CRYPTOCONDITIONS_H -#include "replacementpool.h" #include "cryptoconditions/include/cryptoconditions.h" +#include "primitives/transaction.h" #include "script/script.h" extern int32_t ASSETCHAINS_CC; -extern bool ASSETCHAINS_CC_TEST; static bool IsCryptoConditionsEnabled() { return 0 != ASSETCHAINS_CC; } -extern CTxReplacementPool replacementPool; - bool EvalConditionValidity(const CC *cond, const CTransaction *tx); -bool SetReplacementParams(CTxReplacementPoolItem &rep); - bool GetOpReturnData(const CScript &sig, std::vector &data); #endif /* KOMODO_CRYPTOCONDITIONS_H */ diff --git a/src/main.cpp b/src/main.cpp index fa366964f..86b52495a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -21,8 +21,6 @@ #include "pow.h" #include "txdb.h" #include "txmempool.h" -#include "replacementpool.h" -#include "komodo_cryptoconditions.h" #include "ui_interface.h" #include "undo.h" #include "util.h" @@ -55,7 +53,6 @@ extern uint8_t NOTARY_PUBKEY33[33]; BlockMap mapBlockIndex; CChain chainActive; - CBlockIndex *pindexBestHeader = NULL; int64_t nTimeBestReceived = 0; CWaitableCriticalSection csBestBlock; @@ -1110,45 +1107,7 @@ CAmount GetMinRelayFee(const CTransaction& tx, unsigned int nBytes, bool fAllowF } -/* - * This should be called from AcceptToMemoryPool in order - * to perform all validations. - */ -bool AcceptToReplacementPool(const CTransaction &tx, CValidationState &state) -{ - // This is not actually required; if crypto-conditions is disabled, then transactions - // with replaceable outputs will not be accepted as standard. However, just to be a - // bit more explicit. - if (!IsCryptoConditionsEnabled()) return false; - - CTxReplacementPoolItem item(tx, GetHeight()); - if (!SetReplacementParams(item)) return false; - - switch (replacementPool.replace(item)) { - - case RP_Accept: - return true; - - case RP_HaveBetter: - // already have a better one - fprintf(stderr,"accept failure.20\n"); - return state.Invalid(error("AcceptToMemoryPool: Replacement is worse"), - REJECT_HAVEBETTER, "replacement-is-worse"); - - case RP_Invalid: - // Not valid according to replaceability rules - fprintf(stderr,"accept failure.22\n"); - return state.Invalid(error("AcceptToMemoryPool: Replacement has multiple inputs"), - REJECT_INVALID, "replacement-invalid"); - - default: - return false; - } -} - - - -bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,bool* pfMissingInputs, bool fRejectAbsurdFee, bool fAcceptReplacement) +bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,bool* pfMissingInputs, bool fRejectAbsurdFee) { AssertLockHeld(cs_main); if (pfMissingInputs) @@ -1372,20 +1331,14 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa return error("AcceptToMemoryPool: BUG! PLEASE REPORT THIS! ConnectInputs failed against MANDATORY but not STANDARD flags %s", hash.ToString()); } + // Store transaction in memory if ( komodo_is_notarytx(tx) == 0 ) KOMODO_ON_DEMAND++; - - if (fAcceptReplacement) - { - if (AcceptToReplacementPool(tx, state)) return true; - if (state.IsInvalid()) return false; - } - - // Store transaction in memory pool.addUnchecked(hash, entry, !IsInitialBlockDownload()); } SyncWithWallets(tx, NULL); + return true; } @@ -1401,12 +1354,6 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock return true; } - // replacementPool lookup is O(n) since there's no index by txid - if (fAllowSlow && replacementPool.lookup(hash, txOut)) - { - return true; - } - if (fTxIndex) { CDiskTxPos postx; if (pblocktree->ReadTxIndex(hash, postx)) { @@ -1456,21 +1403,6 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock return false; } - -void ProcessOrphanTransactions(uint256 initialHash); - -void ProcessReplacementPool(int newHeight) -{ - std::vector pending; - replacementPool.removePending(newHeight, pending); - CValidationState stateDummy; - BOOST_FOREACH(CTransaction tx, pending) { - if (AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL, false, false)) - ProcessOrphanTransactions(tx.GetHash()); - // otherwise silently drop. TODO: log - } -} - /*char *komodo_getspendscript(uint256 hash,int32_t n) { CTransaction tx; uint256 hashBlock; @@ -2000,7 +1932,7 @@ bool ContextualCheckInputs(const CTransaction& tx, CValidationState &state, cons // as to the correct behavior - we may want to continue // peering with non-upgraded nodes even after a soft-fork // super-majority vote has passed. - return state.DoS(100, false, REJECT_INVALID, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError()))); + return state.DoS(100,false, REJECT_INVALID, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(check.GetScriptError()))); } } } @@ -2770,13 +2702,6 @@ bool static DisconnectTip(CValidationState &state) { // Update cached incremental witnesses //fprintf(stderr,"chaintip false\n"); GetMainSignals().ChainTip(pindexDelete, &block, newTree, false); - - /* if chain tip disconnects, some transactions may return to the replacementPool - * via AcceptToMemoryPool. - * - * No double send conflicts may result as the winning transaction will be picked. - */ - return true; } @@ -2836,8 +2761,6 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * mempool.check(pcoinsTip); // Update chainActive & related variables. UpdateTip(pindexNew); - // Process pending replacements - ProcessReplacementPool(pindexNew->nHeight); // Tell wallet about transactions that went from mempool // to conflicted: BOOST_FOREACH(const CTransaction &tx, txConflicted) { @@ -2847,7 +2770,6 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * BOOST_FOREACH(const CTransaction &tx, pblock->vtx) { SyncWithWallets(tx, pblock); } - // Update cached incremental witnesses //fprintf(stderr,"chaintip true\n"); GetMainSignals().ChainTip(pindexNew, pblock, oldTree, true); @@ -4748,70 +4670,6 @@ void static ProcessGetData(CNode* pfrom) } } - -void ProcessOrphanTransactions(uint256 parentHash) -{ - AssertLockHeld(cs_main); - - vector vWorkQueue, vEraseQueue; - // Recursively process any orphan transactions that depended on this one - vWorkQueue.push_back(parentHash); - set setMisbehaving; - - for (unsigned int i = 0; i < vWorkQueue.size(); i++) - { - map >::iterator itByPrev = mapOrphanTransactionsByPrev.find(vWorkQueue[i]); - if (itByPrev == mapOrphanTransactionsByPrev.end()) - continue; - for (set::iterator mi = itByPrev->second.begin(); - mi != itByPrev->second.end(); - ++mi) - { - const uint256& orphanHash = *mi; - const CTransaction& orphanTx = mapOrphanTransactions[orphanHash].tx; - NodeId fromPeer = mapOrphanTransactions[orphanHash].fromPeer; - bool fMissingInputs2 = false; - // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan - // resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get - // anyone relaying LegitTxX banned) - CValidationState stateDummy; - - - if (setMisbehaving.count(fromPeer)) - continue; - if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) - { - LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString()); - RelayTransaction(orphanTx); - vWorkQueue.push_back(orphanHash); - vEraseQueue.push_back(orphanHash); - } - else if (!fMissingInputs2) - { - int nDos = 0; - if (stateDummy.IsInvalid(nDos) && nDos > 0) - { - // Punish peer that gave us an invalid orphan tx - Misbehaving(fromPeer, nDos); - setMisbehaving.insert(fromPeer); - LogPrint("mempool", " invalid orphan tx %s\n", orphanHash.ToString()); - } - // Has inputs but not accepted to mempool - // Probably non-standard or insufficient fee/priority - LogPrint("mempool", " removed orphan tx %s\n", orphanHash.ToString()); - vEraseQueue.push_back(orphanHash); - assert(recentRejects); - recentRejects->insert(orphanHash); - } - mempool.check(pcoinsTip); - } - } - - BOOST_FOREACH(uint256 hash, vEraseQueue) - EraseOrphanTx(hash); -} - - bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, int64_t nTimeReceived) { const CChainParams& chainparams = Params(); @@ -5212,6 +5070,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, else if (strCommand == "tx") { + vector vWorkQueue; + vector vEraseQueue; CTransaction tx; vRecv >> tx; @@ -5230,14 +5090,66 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, { mempool.check(pcoinsTip); RelayTransaction(tx); + vWorkQueue.push_back(inv.hash); LogPrint("mempool", "AcceptToMemoryPool: peer=%d %s: accepted %s (poolsz %u)\n", pfrom->id, pfrom->cleanSubVer, tx.GetHash().ToString(), mempool.mapTx.size()); - ProcessOrphanTransactions(inv.hash); + // Recursively process any orphan transactions that depended on this one + set setMisbehaving; + for (unsigned int i = 0; i < vWorkQueue.size(); i++) + { + map >::iterator itByPrev = mapOrphanTransactionsByPrev.find(vWorkQueue[i]); + if (itByPrev == mapOrphanTransactionsByPrev.end()) + continue; + for (set::iterator mi = itByPrev->second.begin(); + mi != itByPrev->second.end(); + ++mi) + { + const uint256& orphanHash = *mi; + const CTransaction& orphanTx = mapOrphanTransactions[orphanHash].tx; + NodeId fromPeer = mapOrphanTransactions[orphanHash].fromPeer; + bool fMissingInputs2 = false; + // Use a dummy CValidationState so someone can't setup nodes to counter-DoS based on orphan + // resolution (that is, feeding people an invalid transaction based on LegitTxX in order to get + // anyone relaying LegitTxX banned) + CValidationState stateDummy; + + if (setMisbehaving.count(fromPeer)) + continue; + if (AcceptToMemoryPool(mempool, stateDummy, orphanTx, true, &fMissingInputs2)) + { + LogPrint("mempool", " accepted orphan tx %s\n", orphanHash.ToString()); + RelayTransaction(orphanTx); + vWorkQueue.push_back(orphanHash); + vEraseQueue.push_back(orphanHash); + } + else if (!fMissingInputs2) + { + int nDos = 0; + if (stateDummy.IsInvalid(nDos) && nDos > 0) + { + // Punish peer that gave us an invalid orphan tx + Misbehaving(fromPeer, nDos); + setMisbehaving.insert(fromPeer); + LogPrint("mempool", " invalid orphan tx %s\n", orphanHash.ToString()); + } + // Has inputs but not accepted to mempool + // Probably non-standard or insufficient fee/priority + LogPrint("mempool", " removed orphan tx %s\n", orphanHash.ToString()); + vEraseQueue.push_back(orphanHash); + assert(recentRejects); + recentRejects->insert(orphanHash); + } + mempool.check(pcoinsTip); + } + } + + BOOST_FOREACH(uint256 hash, vEraseQueue) + EraseOrphanTx(hash); } // TODO: currently, prohibit joinsplits from entering mapOrphans else if (fMissingInputs && tx.vjoinsplit.size() == 0) diff --git a/src/main.h b/src/main.h index 061dcfcc5..bcdd04a5e 100644 --- a/src/main.h +++ b/src/main.h @@ -250,7 +250,7 @@ void PruneAndFlush(); /** (try to) add transaction to memory pool **/ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree, - bool* pfMissingInputs, bool fRejectAbsurdFee=false, bool fAcceptReplacement=true); + bool* pfMissingInputs, bool fRejectAbsurdFee=false); struct CNodeStateStats { diff --git a/src/replacementpool.cpp b/src/replacementpool.cpp deleted file mode 100644 index 168c30b6e..000000000 --- a/src/replacementpool.cpp +++ /dev/null @@ -1,88 +0,0 @@ - -#include "main.h" -#include "replacementpool.h" -#include "sync.h" - - -CTxReplacementPool replacementPool; -CCriticalSection cs_replacementPool; - - -/* - * Validate the item - * - * Compare the item with any current replacement candidate - * - * Ensure that the item is not passed the replacement window - * - * Insert the item into the map - */ -CTxReplacementPoolResult CTxReplacementPool::replace(CTxReplacementPoolItem &item) -{ - LOCK(cs_replacementPool); - - // Replaceable transactions with multiple inputs are disabled - // until someone figures out how they would work. - if (item.tx.vin.size() > 1) return RP_Invalid; - - // replacementWindow of 0 goes direct to mempool - if (item.replacementWindow == 0) - { - // But we also need to remove replacement candidates - replaceMap.erase(item.tx.vin[0].prevout); - return RP_NoReplace; - } - - int startBlock = item.startBlock; - - auto it = replaceMap.find(item.tx.vin[0].prevout); - if (it != replaceMap.end()) - { - if (it->second.replacementWindow <= item.replacementWindow && - it->second.priority >= item.priority) { - return RP_HaveBetter; - } - startBlock = it->second.startBlock; - } - - // This transaction has higher priority - replaceMap[item.tx.vin[0].prevout] = item; - replaceMap[item.tx.vin[0].prevout].startBlock = startBlock; - return RP_Accept; -} - - -/* - * Remove and return any spends that have matured - */ -void CTxReplacementPool::removePending(int height, std::vector &txs) -{ - LOCK(cs_replacementPool); - - for (auto it = replaceMap.begin(); it != replaceMap.end(); /**/) { - CTxReplacementPoolItem &rep = it->second; - - if (rep.GetTargetBlock() <= height) { - txs.push_back(rep.tx); - replaceMap.erase(it++); - } else { - ++it; - } - } -} - - -/* - * O(n) lookup of tx by hash - */ -bool CTxReplacementPool::lookup(uint256 txHash, CTransaction &tx) -{ - LOCK(cs_replacementPool); - for (auto it = replaceMap.begin(); it != replaceMap.end(); it++) { - if (it->second.tx.GetHash() == txHash) { - tx = it->second.tx; - return true; - } - } - return false; -} diff --git a/src/replacementpool.h b/src/replacementpool.h deleted file mode 100644 index d6ab2ed28..000000000 --- a/src/replacementpool.h +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) 2018 The Komodo Developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#ifndef KOMODO_REPLACEMENTCACHE_H -#define KOMODO_REPLACEMENTCACHE_H - -#include "primitives/transaction.h" - - -// My kingdom for a proper sum type... -enum CTxReplacementPoolResult { - RP_Accept, - RP_HaveBetter, - RP_Invalid, - RP_NoReplace -}; - - -class CTxReplacementPoolItem -{ -public: - CTransaction tx; - int startBlock; - uint64_t priority; - uint32_t replacementWindow; - - CTxReplacementPoolItem() {} - - CTxReplacementPoolItem(const CTransaction &_tx, int _startBlock) { - tx = _tx; - startBlock = _startBlock; - priority = 0; - replacementWindow = 0; - } - - int GetTargetBlock() { return startBlock + replacementWindow; } -}; - -/** - * CTxReplacementPool stores transactions that are valid but held for - * period of time during which they may be replaced. - * - * Transactions are added when they are found to be valid but not added - * to the mempool until a timeout. - * - * Replacement pool is like another mempool before the main mempool. - * - * Transactions in the replacement pool are indexed by the output - * that they are spending. Once a replaceable transaction tries to - * spend an output, a countdown of blocks begins at the current block - * plus a window that is set by "userland" code. If another, better - * transaction replaces the spend that's already pending, the countdown - * start block remains the same. - */ -class CTxReplacementPool -{ -private: - /* Index of spends that may be replaced */ - std::map replaceMap; -public: - /* Try to replace a transaction in the index */ - CTxReplacementPoolResult replace(CTxReplacementPoolItem &item); - - /* Remove and return all transactions up to a given block height */ - void removePending(int height, std::vector &txs); - - /* Find a transaction in the index by it's hash. */ - bool lookup(uint256 txHash, CTransaction &tx); -}; - - -/* Global instance */ -extern CTxReplacementPool replacementPool; - -#endif // KOMODO_REPLACEMENTCACHE_H diff --git a/src/secp256k1/include/secp256k1.h b/src/secp256k1/include/secp256k1.h index 06afd4c65..9db5cf3a8 100644 --- a/src/secp256k1/include/secp256k1.h +++ b/src/secp256k1/include/secp256k1.h @@ -95,6 +95,18 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify( int pubkeylen ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5); +/** Check that signature is in canonical form + * Returns: 1: In canonical form + * 0: Non canonical + * -1: invalid signature + * In: sig: the signature being verified (cannot be NULL) + * siglen: the length of the signature + */ +SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_check_canonical_sig( + const unsigned char *sig, + int siglen +) SECP256K1_ARG_NONNULL(1); + /** A pointer to a function to deterministically generate a nonce. * Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail. * In: msg32: the 32-byte message hash being verified (will not be NULL) diff --git a/src/secp256k1/src/secp256k1.c b/src/secp256k1/src/secp256k1.c index d6192dc4e..48569ad9e 100644 --- a/src/secp256k1/src/secp256k1.c +++ b/src/secp256k1/src/secp256k1.c @@ -85,6 +85,14 @@ int secp256k1_ecdsa_verify(const secp256k1_context_t* ctx, const unsigned char * return ret; } + +int secp256k1_ecdsa_check_canonical_sig(const unsigned char *sig, int siglen) { + secp256k1_ecdsa_sig_t s; + if (!secp256k1_ecdsa_sig_parse(&s, sig, siglen)) return -1; + return !secp256k1_scalar_is_high(&s.s); +} + + static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) { secp256k1_rfc6979_hmac_sha256_t rng; unsigned int i; diff --git a/src/test-komodo/main.cpp b/src/test-komodo/main.cpp deleted file mode 100644 index 7811d5f9a..000000000 --- a/src/test-komodo/main.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "gtest/gtest.h" -#include "crypto/common.h" - -int main(int argc, char **argv) { - assert(init_and_check_sodium() != -1); - - testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/src/test-komodo/test_replacementpool.cpp b/src/test-komodo/test_replacementpool.cpp deleted file mode 100644 index b0ccc4278..000000000 --- a/src/test-komodo/test_replacementpool.cpp +++ /dev/null @@ -1,440 +0,0 @@ -#include -#include - -#include "base58.h" -#include "core_io.h" -#include "key.h" -#include "komodo_cryptoconditions.h" -#include "main.h" -#include "miner.h" -#include "random.h" -#include "rpcserver.h" -#include "rpcprotocol.h" -#include "replacementpool.h" -#include "txdb.h" -#include "util.h" -#include "utilstrencodings.h" -#include "utiltime.h" -#include "consensus/validation.h" -#include "primitives/transaction.h" -#include "script/interpreter.h" -#include "cryptoconditions/include/cryptoconditions.h" - - -extern int32_t USE_EXTERNAL_PUBKEY; -extern std::string NOTARY_PUBKEY; -std::string _NOTARY_PUBKEY = "0205a8ad0c1dbc515f149af377981aab58b836af008d4d7ab21bd76faf80550b47"; -std::string NOTARY_SECRET = "UxFWWxsf1d7w7K5TvAWSkeX4H95XQKwdwGv49DXwWUTzPTTjHBbU"; -CKey notaryKey; - -#define VCH(a,b) std::vector(a, a + b) - - -/* - * We need to have control of clock, - * otherwise block production can fail. - */ -int64_t nMockTime; - - -void testSetup() -{ - SelectParams(CBaseChainParams::REGTEST); - - // enable CC - ASSETCHAINS_CC = 1; - ASSETCHAINS_CC_TEST = true; - - // Settings to get block reward - NOTARY_PUBKEY = _NOTARY_PUBKEY; - USE_EXTERNAL_PUBKEY = 1; - mapArgs["-mineraddress"] = "bogus"; - COINBASE_MATURITY = 1; - // Global mock time - nMockTime = GetTime(); - - // Init blockchain - ClearDatadirCache(); - auto pathTemp = GetTempPath() / strprintf("test_komodo_%li_%i", GetTime(), GetRand(100000)); - boost::filesystem::create_directories(pathTemp); - mapArgs["-datadir"] = pathTemp.string(); - pblocktree = new CBlockTreeDB(1 << 20, true); - CCoinsViewDB *pcoinsdbview = new CCoinsViewDB(1 << 23, true); - pcoinsTip = new CCoinsViewCache(pcoinsdbview); - InitBlockIndex(); - - // Set address - ECC_Start(); - - // Notary key - CBitcoinSecret vchSecret; - // this returns false due to network prefix mismatch but works anyway - vchSecret.SetString(NOTARY_SECRET); - notaryKey = vchSecret.GetKey(); -} - - -void generateBlock(CBlock *block=NULL) -{ - UniValue params; - params.setArray(); - params.push_back(1); - uint256 blockId; - - SetMockTime(nMockTime++); // CreateNewBlock can fail if not enough time passes - - try { - UniValue out = generate(params, false); - blockId.SetHex(out[0].getValStr()); - } catch (const UniValue& e) { - FAIL() << "failed to create block: " << e.write().data(); - } - if (block) ASSERT_TRUE(ReadBlockFromDisk(*block, mapBlockIndex[blockId])); -} - - -void acceptTx(const CTransaction tx) -{ - CValidationState state; - LOCK(cs_main); - if (!AcceptToMemoryPool(mempool, state, tx, false, NULL)) - FAIL() << state.GetRejectReason(); -} - - -static CMutableTransaction spendTx(const CTransaction &txIn, int nOut=0) -{ - CMutableTransaction mtx; - mtx.vin.resize(1); - mtx.vin[0].prevout.hash = txIn.GetHash(); - mtx.vin[0].prevout.n = nOut; - mtx.vout.resize(1); - mtx.vout[0].nValue = txIn.vout[nOut].nValue - 1000; - return mtx; -} - - -/* - * In order to do tests there needs to be inputs to spend. - * This method creates a block and returns a transaction that spends the coinbase. - */ -void getInputTx(CScript scriptPubKey, CTransaction &txIn) -{ - // Get coinbase - CBlock block; - generateBlock(&block); - CTransaction coinbase = block.vtx[0]; - - // Create tx - auto mtx = spendTx(coinbase); - mtx.vout[0].scriptPubKey = scriptPubKey; - uint256 hash = SignatureHash(coinbase.vout[0].scriptPubKey, mtx, 0, SIGHASH_ALL); - std::vector vchSig; - notaryKey.Sign(hash, vchSig); - vchSig.push_back((unsigned char)SIGHASH_ALL); - mtx.vin[0].scriptSig << vchSig; - - // Accept - acceptTx(mtx); - txIn = CTransaction(mtx); -} - - -std::string HexToB64(std::string hexStr) -{ - auto d = ParseHex(hexStr); - return EncodeBase64(d.data(), d.size()); -} - - -CC *getReplaceCond() -{ - const char *condJsonTpl = R"V0G0N( - { "type": "threshold-sha-256", - "threshold": 2, - "subfulfillments": [ - { "type": "secp256k1-sha-256", "publicKey": "%s"}, - { "type": "eval-sha-256", "method": "testReplace", "params": "" } - ] })V0G0N"; - char condJson[1000]; - sprintf(condJson, condJsonTpl, (char*)HexToB64(NOTARY_PUBKEY).data()); - - unsigned char err[1000] = "\0"; - return cc_conditionFromJSONString((const unsigned char*)condJson, err); - // above could fail -} - -CScript condPK(CC *cond) -{ - unsigned char buf[1000]; - size_t bufLen = cc_conditionBinary(cond, buf); - return CScript() << VCH(buf, bufLen) << OP_CHECKCRYPTOCONDITION; -} - -void setFulfillment(CMutableTransaction &mtx, CC *cond, const CScript &spk, int nIn=0) -{ - uint256 hash = SignatureHash(spk, mtx, nIn, SIGHASH_ALL); - int nSigned = cc_signTreeSecp256k1Msg32(cond, notaryKey.begin(), hash.begin()); - unsigned char buf[1000]; - size_t bufLen = cc_fulfillmentBinary(cond, buf, 1000); - mtx.vin[nIn].scriptSig = CScript() << VCH(buf, bufLen); -} - - -CScript getReplaceOut(unsigned char replacementWindow, unsigned char priority) -{ - std::vector v = {replacementWindow, priority}; - return CScript() << OP_RETURN << v; -} - - -CTransaction _txout; -#define ONLY_REPLACEMENT_POOL(hash) ASSERT_TRUE(replacementPool.lookup(hash, _txout)); \ - ASSERT_FALSE(mempool.lookup(hash, _txout)); -#define ONLY_MEM_POOL(hash) ASSERT_FALSE(replacementPool.lookup(hash, _txout)); \ - ASSERT_TRUE(mempool.lookup(hash, _txout)); - - - -// Setup environment and perform basic spend as test -TEST(replacementpool, 0_setup) -{ - testSetup(); // Only call this method here - - CTransaction txIn; - getInputTx(CScript() << OP_RETURN << VCH("1", 1), txIn); -} - - -// Perform replaceable spend -TEST(replacementpool, basic) -{ - CTransaction txIn; - CC *cond = getReplaceCond(); - getInputTx(condPK(cond), txIn); - - // Spend output to replaceable - auto mtx = spendTx(txIn); - mtx.vout[0].scriptPubKey = getReplaceOut(2, 100); - setFulfillment(mtx, cond, txIn.vout[0].scriptPubKey); - - acceptTx(mtx); - - ONLY_REPLACEMENT_POOL(mtx.GetHash()); - generateBlock(); - ONLY_REPLACEMENT_POOL(mtx.GetHash()); - generateBlock(); - ONLY_MEM_POOL(mtx.GetHash()); -} - - -/* - * replacementWindow is 0, transaction should go direct to mempool - */ -TEST(replacementpool, noWindow) -{ - CTransaction txIn; - CC *cond = getReplaceCond(); - getInputTx(condPK(cond), txIn); - - // First set a tx with a 1 block wait. It should stay in the replacement pool. - auto mtx = spendTx(txIn); - mtx.vout[0].scriptPubKey = getReplaceOut(1, 100); - setFulfillment(mtx, cond, txIn.vout[0].scriptPubKey); - acceptTx(mtx); - ONLY_REPLACEMENT_POOL(mtx.GetHash()); - - // Now set a transaction with a 0 block wait and higher priority. - // It should go direct to the mem pool. - auto mtx2 = spendTx(txIn); - mtx2.vout[0].scriptPubKey = getReplaceOut(0, 101); - setFulfillment(mtx2, cond, txIn.vout[0].scriptPubKey); - acceptTx(mtx2); - ONLY_MEM_POOL(mtx2.GetHash()); - - // Additionally, there should be no replacement remaining for txIn in the mempool - ASSERT_FALSE(replacementPool.lookup(mtx.GetHash(), _txout)); -} - - -/* - * Multiple replaceable transactions dont interfere - */ -TEST(replacementpool, noInterfere) -{ - CTransaction txIn1, txIn2; - CC *cond = getReplaceCond(); - getInputTx(condPK(cond), txIn1); - getInputTx(condPK(cond), txIn2); - - // First set a transaction with a low window - auto mtx = spendTx(txIn1); - mtx.vout[0].scriptPubKey = getReplaceOut(1, 100); - setFulfillment(mtx, cond, txIn1.vout[0].scriptPubKey); - acceptTx(mtx); - ONLY_REPLACEMENT_POOL(mtx.GetHash()); - - // Now, a different spend with a higher window - auto mtx2 = spendTx(txIn2); - mtx2.vout[0].scriptPubKey = getReplaceOut(10, 100); - setFulfillment(mtx2, cond, txIn2.vout[0].scriptPubKey); - acceptTx(mtx2); - ONLY_REPLACEMENT_POOL(mtx2.GetHash()); - - generateBlock(); - - // mtx has gone to mempool - ONLY_MEM_POOL(mtx.GetHash()); - - // mtx2 still in replacementpool - ONLY_REPLACEMENT_POOL(mtx2.GetHash()); - - // But 9 blocks later... - for (int i=0; i<9; i++) - { - generateBlock(); - ASSERT_EQ(i == 8, mempool.lookup(mtx2.GetHash(), _txout)); - } -} - - -/* - * Multiple inputs is invalid - */ -TEST(replacementpool, invalidMultipleInputs) -{ - LOCK(cs_main); - - CTransaction txIn, txIn2; - CC *cond = getReplaceCond(); - getInputTx(condPK(cond), txIn); - getInputTx(condPK(cond), txIn2); - - CMutableTransaction mtx; - mtx.vout.resize(1); - mtx.vout[0].nValue = txIn.vout[0].nValue * 2 - 1000; - mtx.vout[0].scriptPubKey = getReplaceOut(1, 100); - mtx.vin.resize(2); - mtx.vin[0].prevout.hash = txIn.GetHash(); - mtx.vin[0].prevout.n = 0; - mtx.vin[1].prevout.hash = txIn2.GetHash(); - mtx.vin[1].prevout.n = 0; - setFulfillment(mtx, cond, txIn.vout[0].scriptPubKey); - setFulfillment(mtx, cond, txIn2.vout[0].scriptPubKey, 1); - - CValidationState state; - ASSERT_FALSE(AcceptToMemoryPool(mempool, state, mtx, false, NULL)); - ASSERT_EQ("replacement-invalid", state.GetRejectReason()); -} - - -extern bool AddOrphanTx(const CTransaction& tx, NodeId peer); -extern void ProcessOrphanTransactions(uint256 parentHash); -struct COrphanTx { CTransaction tx; NodeId fromPeer; }; -extern std::map mapOrphanTransactions; - -/* - * Orphans are processed - */ -TEST(replacementpool, orphansAreProcessed) -{ - LOCK(cs_main); - - CTransaction txIn; - CC *cond = getReplaceCond(); - getInputTx(condPK(cond), txIn); - - // Make basic replaceable spend and dont submit - auto mtx = spendTx(txIn); - mtx.vout.resize(2); - mtx.vout[0].nValue = txIn.vout[0].nValue - 1000; - mtx.vout[0].scriptPubKey = condPK(cond); - mtx.vout[1].nValue = 1; - mtx.vout[1].scriptPubKey = getReplaceOut(1, 100); - setFulfillment(mtx, cond, txIn.vout[0].scriptPubKey); - - // Make an orphan and add it - auto orphan = spendTx(mtx); - orphan.vout[0].scriptPubKey = getReplaceOut(0, 100); - setFulfillment(orphan, cond, mtx.vout[0].scriptPubKey); - ASSERT_TRUE(AddOrphanTx(orphan, 1001)); - ASSERT_EQ(1, mapOrphanTransactions.count(orphan.GetHash())); - - // parent goes into replacement pool - acceptTx(mtx); - ONLY_REPLACEMENT_POOL(mtx.GetHash()); - - // this should not result in the movement of any orphans - ProcessOrphanTransactions(mtx.GetHash()); - ASSERT_EQ(1, mapOrphanTransactions.count(orphan.GetHash())); - - // Processing of parent transaction also un-orphanises orphan - generateBlock(); - ONLY_MEM_POOL(mtx.GetHash()); - ONLY_MEM_POOL(orphan.GetHash()); - ASSERT_EQ(0, mapOrphanTransactions.count(orphan.GetHash())); -} - - -/* - * Add transaction with lower priority, already have better - */ -TEST(replacementpool, haveBetter) -{ - LOCK(cs_main); - - CTransaction txIn; - CC *cond = getReplaceCond(); - getInputTx(condPK(cond), txIn); - - // A replaceable tx. - auto mtx = spendTx(txIn); - mtx.vout[0].scriptPubKey = getReplaceOut(2, 100); - setFulfillment(mtx, cond, txIn.vout[0].scriptPubKey); - acceptTx(mtx); - ONLY_REPLACEMENT_POOL(mtx.GetHash()); - - // Another one, but not as good. - auto mtx2 = spendTx(txIn); - mtx2.vout[0].scriptPubKey = getReplaceOut(2, 99); - setFulfillment(mtx2, cond, txIn.vout[0].scriptPubKey); - CValidationState state; - ASSERT_FALSE(AcceptToMemoryPool(mempool, state, mtx, false, NULL)); - ASSERT_EQ("replacement-is-worse", state.GetRejectReason()); - ONLY_REPLACEMENT_POOL(mtx.GetHash()); -} - - -/* - * Add transaction with lower priority, but shorter replacementWindow - */ -TEST(replacementpool, shorterReplacementWindow) -{ - LOCK(cs_main); - - CTransaction txIn; - CC *cond = getReplaceCond(); - getInputTx(condPK(cond), txIn); - - // A replaceable tx. - auto mtx = spendTx(txIn); - mtx.vout[0].scriptPubKey = getReplaceOut(2, 100); - setFulfillment(mtx, cond, txIn.vout[0].scriptPubKey); - acceptTx(mtx); - ONLY_REPLACEMENT_POOL(mtx.GetHash()); - - // Another one, lower priority but shorter replacementWindow so wins. - auto mtx2 = spendTx(txIn); - mtx2.vout[0].scriptPubKey = getReplaceOut(1, 99); - setFulfillment(mtx2, cond, txIn.vout[0].scriptPubKey); - acceptTx(mtx2); - ONLY_REPLACEMENT_POOL(mtx2.GetHash()); - ASSERT_FALSE(replacementPool.lookup(mtx.GetHash(), _txout)); - - // Shorter still, in fact direct to mem pool - auto mtx3 = spendTx(txIn); - mtx3.vout[0].scriptPubKey = getReplaceOut(0, 98); - setFulfillment(mtx3, cond, txIn.vout[0].scriptPubKey); - acceptTx(mtx3); - ONLY_MEM_POOL(mtx3.GetHash()); -} From 991c422a9d8b156d45710c56f4b7759b55404b71 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Wed, 28 Mar 2018 15:02:20 -0300 Subject: [PATCH 051/339] fix CC --- src/cryptoconditions/Makefile.am | 13 +- .../src/include/secp256k1/.gitignore | 24 +- .../src/include/secp256k1/.travis.yml | 24 +- .../src/include/secp256k1/Makefile.am | 138 +- .../src/include/secp256k1/README.md | 2 +- .../build-aux/m4/ax_jni_include_dir.m4 | 140 + .../build-aux/m4/ax_prog_cc_for_build.m4 | 125 + .../secp256k1/build-aux/m4/bitcoin_secp.m4 | 69 + .../src/include/secp256k1/configure.ac | 203 +- .../secp256k1/contrib/lax_der_parsing.c | 150 + .../secp256k1/contrib/lax_der_parsing.h | 91 + .../contrib/lax_der_privatekey_parsing.c | 113 + .../contrib/lax_der_privatekey_parsing.h | 90 + .../src/include/secp256k1/include/secp256k1.h | 760 ++-- .../secp256k1/include/secp256k1_ecdh.h | 31 + .../secp256k1/include/secp256k1_recovery.h | 110 + .../src/include/secp256k1/libsecp256k1.pc.in | 2 +- .../include/secp256k1/sage/group_prover.sage | 322 ++ .../src/include/secp256k1/sage/secp256k1.sage | 306 ++ .../secp256k1/sage/weierstrass_prover.sage | 264 ++ .../secp256k1/src/asm/field_10x26_arm.s | 919 +++++ .../src/include/secp256k1/src/basic-config.h | 33 + .../src/include/secp256k1/src/bench.h | 28 +- .../src/include/secp256k1/src/bench_ecdh.c | 54 + .../include/secp256k1/src/bench_internal.c | 152 +- .../src/include/secp256k1/src/bench_recover.c | 33 +- .../src/include/secp256k1/src/bench_sign.c | 34 +- .../src/include/secp256k1/src/bench_verify.c | 72 +- .../src/include/secp256k1/src/ecdsa.h | 21 +- .../src/include/secp256k1/src/ecdsa_impl.h | 286 +- .../src/include/secp256k1/src/eckey.h | 23 +- .../src/include/secp256k1/src/eckey_impl.h | 144 +- .../src/include/secp256k1/src/ecmult.h | 26 +- .../src/include/secp256k1/src/ecmult_const.h | 15 + .../include/secp256k1/src/ecmult_const_impl.h | 240 ++ .../src/include/secp256k1/src/ecmult_gen.h | 30 +- .../include/secp256k1/src/ecmult_gen_impl.h | 110 +- .../src/include/secp256k1/src/ecmult_impl.h | 309 +- .../src/include/secp256k1/src/field.h | 79 +- .../src/include/secp256k1/src/field_10x26.h | 29 +- .../include/secp256k1/src/field_10x26_impl.h | 139 +- .../src/include/secp256k1/src/field_5x52.h | 28 +- .../secp256k1/src/field_5x52_asm_impl.h | 6 +- .../include/secp256k1/src/field_5x52_impl.h | 150 +- .../secp256k1/src/field_5x52_int128_impl.h | 10 +- .../src/include/secp256k1/src/field_impl.h | 84 +- .../src/include/secp256k1/src/gen_context.c | 74 + .../src/include/secp256k1/src/group.h | 115 +- .../src/include/secp256k1/src/group_impl.h | 475 ++- .../src/include/secp256k1/src/hash.h | 34 +- .../src/include/secp256k1/src/hash_impl.h | 52 +- .../src/java/org/bitcoin/NativeSecp256k1.java | 440 +- .../java/org/bitcoin/NativeSecp256k1Test.java | 226 ++ .../java/org/bitcoin/NativeSecp256k1Util.java | 45 + .../java/org/bitcoin/Secp256k1Context.java | 51 + .../src/java/org_bitcoin_NativeSecp256k1.c | 378 +- .../src/java/org_bitcoin_NativeSecp256k1.h | 106 +- .../src/java/org_bitcoin_Secp256k1Context.c | 15 + .../src/java/org_bitcoin_Secp256k1Context.h | 22 + .../src/modules/ecdh/Makefile.am.include | 8 + .../secp256k1/src/modules/ecdh/main_impl.h | 54 + .../secp256k1/src/modules/ecdh/tests_impl.h | 105 + .../src/modules/recovery/Makefile.am.include | 8 + .../src/modules/recovery/main_impl.h | 193 + .../src/modules/recovery/tests_impl.h | 393 ++ .../src/include/secp256k1/src/num.h | 40 +- .../src/include/secp256k1/src/num_gmp.h | 8 +- .../src/include/secp256k1/src/num_gmp_impl.h | 72 +- .../src/include/secp256k1/src/num_impl.h | 6 +- .../src/include/secp256k1/src/scalar.h | 67 +- .../src/include/secp256k1/src/scalar_4x64.h | 8 +- .../include/secp256k1/src/scalar_4x64_impl.h | 113 +- .../src/include/secp256k1/src/scalar_8x32.h | 8 +- .../include/secp256k1/src/scalar_8x32_impl.h | 96 +- .../src/include/secp256k1/src/scalar_impl.h | 260 +- .../src/include/secp256k1/src/scalar_low.h | 15 + .../include/secp256k1/src/scalar_low_impl.h | 114 + .../src/include/secp256k1/src/secp256k1.c | 705 ++-- .../src/include/secp256k1/src/testrand.h | 18 +- .../src/include/secp256k1/src/testrand_impl.h | 94 +- .../src/include/secp256k1/src/tests.c | 3573 ++++++++++++++--- .../include/secp256k1/src/tests_exhaustive.c | 470 +++ .../src/include/secp256k1/src/util.h | 37 +- src/cryptoconditions/src/secp256k1.c | 74 +- src/cryptoconditions/test-requirements.txt | 2 +- src/cryptoconditions/tests/test_ed25519.py | 2 +- .../tests/test_failure_modes.py | 2 +- src/cryptoconditions/tests/test_secp256k1.py | 4 +- src/cryptoconditions/tests/test_vectors.py | 8 +- src/script/interpreter.cpp | 13 +- src/script/interpreter.h | 4 +- 91 files changed, 12158 insertions(+), 2480 deletions(-) create mode 100644 src/cryptoconditions/src/include/secp256k1/build-aux/m4/ax_jni_include_dir.m4 create mode 100644 src/cryptoconditions/src/include/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4 create mode 100644 src/cryptoconditions/src/include/secp256k1/build-aux/m4/bitcoin_secp.m4 create mode 100644 src/cryptoconditions/src/include/secp256k1/contrib/lax_der_parsing.c create mode 100644 src/cryptoconditions/src/include/secp256k1/contrib/lax_der_parsing.h create mode 100644 src/cryptoconditions/src/include/secp256k1/contrib/lax_der_privatekey_parsing.c create mode 100644 src/cryptoconditions/src/include/secp256k1/contrib/lax_der_privatekey_parsing.h create mode 100644 src/cryptoconditions/src/include/secp256k1/include/secp256k1_ecdh.h create mode 100644 src/cryptoconditions/src/include/secp256k1/include/secp256k1_recovery.h create mode 100644 src/cryptoconditions/src/include/secp256k1/sage/group_prover.sage create mode 100644 src/cryptoconditions/src/include/secp256k1/sage/secp256k1.sage create mode 100644 src/cryptoconditions/src/include/secp256k1/sage/weierstrass_prover.sage create mode 100644 src/cryptoconditions/src/include/secp256k1/src/asm/field_10x26_arm.s create mode 100644 src/cryptoconditions/src/include/secp256k1/src/basic-config.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/bench_ecdh.c create mode 100644 src/cryptoconditions/src/include/secp256k1/src/ecmult_const.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/ecmult_const_impl.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/gen_context.c create mode 100644 src/cryptoconditions/src/include/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java create mode 100644 src/cryptoconditions/src/include/secp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java create mode 100644 src/cryptoconditions/src/include/secp256k1/src/java/org/bitcoin/Secp256k1Context.java create mode 100644 src/cryptoconditions/src/include/secp256k1/src/java/org_bitcoin_Secp256k1Context.c create mode 100644 src/cryptoconditions/src/include/secp256k1/src/java/org_bitcoin_Secp256k1Context.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/modules/ecdh/Makefile.am.include create mode 100644 src/cryptoconditions/src/include/secp256k1/src/modules/ecdh/main_impl.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/modules/ecdh/tests_impl.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/modules/recovery/Makefile.am.include create mode 100755 src/cryptoconditions/src/include/secp256k1/src/modules/recovery/main_impl.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/modules/recovery/tests_impl.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/scalar_low.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/scalar_low_impl.h create mode 100644 src/cryptoconditions/src/include/secp256k1/src/tests_exhaustive.c diff --git a/src/cryptoconditions/Makefile.am b/src/cryptoconditions/Makefile.am index 9c7af8c03..9469acdbf 100644 --- a/src/cryptoconditions/Makefile.am +++ b/src/cryptoconditions/Makefile.am @@ -1,10 +1,10 @@ lib_LTLIBRARIES=libcryptoconditions.la -noinst_LTLIBRARIES=cryptoconditions_core.a +noinst_LTLIBRARIES=$(CRYPTOCONDITIONS_CORE) SUBDIRS = src/include/secp256k1 # Have a separate build target for cryptoconditions that does not contain secp256k1 -libcryptoconditions_la_SOURCES = +libcryptoconditions_la_SOURCES = include/cryptoconditions.h libcryptoconditions_la_LIBADD = $(CRYPTOCONDITIONS_CORE) $(LIBSECP256K1) AM_CFLAGS = -I$(top_srcdir)/src/asn -I$(top_srcdir)/include -I$(top_srcdir)/src/include \ @@ -15,12 +15,9 @@ LIBSECP256K1=src/include/secp256k1/libsecp256k1.la $(LIBSECP256K1): $(wildcard src/secp256k1/*) $(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C $(@D) $(@F) -CRYPTOCONDITIONS_CORE=cryptoconditions_core.a +CRYPTOCONDITIONS_CORE=libcryptoconditions_core.la -# libcryptoconditions_la_SOURCES = \ -cryptoconditions_core_a_CFLAGS = -I$(top_srcdir)/src/asn -I$(top_srcdir)/include -I$(top_srcdir)/src/include \ - -Wall -Wno-pointer-sign -Wno-discarded-qualifiers -cryptoconditions_core_a_SOURCES = \ +libcryptoconditions_core_la_SOURCES = \ src/cryptoconditions.c \ src/include/cJSON.c \ src/include/sha256.c \ @@ -77,7 +74,7 @@ cryptoconditions_core_a_SOURCES = \ src/asn/per_opentype.c test: - bash -c '[ -d .env ] || virtualenv .env' + bash -c '[ -d .env ] || virtualenv .env -p python3' .env/bin/pip install pytest gdb -batch -ex run -ex bt --args .env/bin/python -m pytest -s -x -v 2>&1 | grep -v ^"No stack."$ diff --git a/src/cryptoconditions/src/include/secp256k1/.gitignore b/src/cryptoconditions/src/include/secp256k1/.gitignore index 076ff1295..87fea161b 100644 --- a/src/cryptoconditions/src/include/secp256k1/.gitignore +++ b/src/cryptoconditions/src/include/secp256k1/.gitignore @@ -1,9 +1,13 @@ bench_inv +bench_ecdh bench_sign bench_verify +bench_schnorr_verify bench_recover bench_internal tests +exhaustive_tests +gen_context *.exe *.so *.a @@ -22,16 +26,24 @@ config.status libtool .deps/ .dirstamp -build-aux/ *.lo *.o *~ src/libsecp256k1-config.h src/libsecp256k1-config.h.in -m4/libtool.m4 -m4/ltoptions.m4 -m4/ltsugar.m4 -m4/ltversion.m4 -m4/lt~obsolete.m4 +src/ecmult_static_context.h +build-aux/config.guess +build-aux/config.sub +build-aux/depcomp +build-aux/install-sh +build-aux/ltmain.sh +build-aux/m4/libtool.m4 +build-aux/m4/lt~obsolete.m4 +build-aux/m4/ltoptions.m4 +build-aux/m4/ltsugar.m4 +build-aux/m4/ltversion.m4 +build-aux/missing +build-aux/compile +build-aux/test-driver src/stamp-h1 libsecp256k1.pc diff --git a/src/cryptoconditions/src/include/secp256k1/.travis.yml b/src/cryptoconditions/src/include/secp256k1/.travis.yml index 0d8089cfe..243952924 100644 --- a/src/cryptoconditions/src/include/secp256k1/.travis.yml +++ b/src/cryptoconditions/src/include/secp256k1/.travis.yml @@ -6,22 +6,30 @@ addons: compiler: - clang - gcc +cache: + directories: + - src/java/guava/ env: global: - - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no ASM=no BUILD=check EXTRAFLAGS= HOST= + - FIELD=auto BIGNUM=auto SCALAR=auto ENDOMORPHISM=no STATICPRECOMPUTATION=yes ASM=no BUILD=check EXTRAFLAGS= HOST= ECDH=no RECOVERY=no EXPERIMENTAL=no + - GUAVA_URL=https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar GUAVA_JAR=src/java/guava/guava-18.0.jar matrix: - - SCALAR=32bit + - SCALAR=32bit RECOVERY=yes + - SCALAR=32bit FIELD=32bit ECDH=yes EXPERIMENTAL=yes - SCALAR=64bit - - FIELD=64bit + - FIELD=64bit RECOVERY=yes - FIELD=64bit ENDOMORPHISM=yes + - FIELD=64bit ENDOMORPHISM=yes ECDH=yes EXPERIMENTAL=yes - FIELD=64bit ASM=x86_64 - FIELD=64bit ENDOMORPHISM=yes ASM=x86_64 - - FIELD=32bit - FIELD=32bit ENDOMORPHISM=yes - BIGNUM=no - - BIGNUM=no ENDOMORPHISM=yes + - BIGNUM=no ENDOMORPHISM=yes RECOVERY=yes EXPERIMENTAL=yes + - BIGNUM=no STATICPRECOMPUTATION=no - BUILD=distcheck - - EXTRAFLAGS=CFLAGS=-DDETERMINISTIC + - EXTRAFLAGS=CPPFLAGS=-DDETERMINISTIC + - EXTRAFLAGS=CFLAGS=-O0 + - BUILD=check-java ECDH=yes EXPERIMENTAL=yes matrix: fast_finish: true include: @@ -51,9 +59,11 @@ matrix: packages: - gcc-multilib - libgmp-dev:i386 +before_install: mkdir -p `dirname $GUAVA_JAR` +install: if [ ! -f $GUAVA_JAR ]; then wget $GUAVA_URL -O $GUAVA_JAR; fi before_script: ./autogen.sh script: - if [ -n "$HOST" ]; then export USE_HOST="--host=$HOST"; fi - if [ "x$HOST" = "xi686-linux-gnu" ]; then export CC="$CC -m32"; fi - - ./configure --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR $EXTRAFLAGS $USE_HOST && make -j2 $BUILD + - ./configure --enable-experimental=$EXPERIMENTAL --enable-endomorphism=$ENDOMORPHISM --with-field=$FIELD --with-bignum=$BIGNUM --with-scalar=$SCALAR --enable-ecmult-static-precomputation=$STATICPRECOMPUTATION --enable-module-ecdh=$ECDH --enable-module-recovery=$RECOVERY $EXTRAFLAGS $USE_HOST && make -j2 $BUILD os: linux diff --git a/src/cryptoconditions/src/include/secp256k1/Makefile.am b/src/cryptoconditions/src/include/secp256k1/Makefile.am index 5f388f3fd..c071fbe27 100644 --- a/src/cryptoconditions/src/include/secp256k1/Makefile.am +++ b/src/cryptoconditions/src/include/secp256k1/Makefile.am @@ -1,14 +1,22 @@ ACLOCAL_AMFLAGS = -I build-aux/m4 lib_LTLIBRARIES = libsecp256k1.la +if USE_JNI +JNI_LIB = libsecp256k1_jni.la +noinst_LTLIBRARIES = $(JNI_LIB) +else +JNI_LIB = +endif include_HEADERS = include/secp256k1.h noinst_HEADERS = noinst_HEADERS += src/scalar.h noinst_HEADERS += src/scalar_4x64.h noinst_HEADERS += src/scalar_8x32.h +noinst_HEADERS += src/scalar_low.h noinst_HEADERS += src/scalar_impl.h noinst_HEADERS += src/scalar_4x64_impl.h noinst_HEADERS += src/scalar_8x32_impl.h +noinst_HEADERS += src/scalar_low_impl.h noinst_HEADERS += src/group.h noinst_HEADERS += src/group_impl.h noinst_HEADERS += src/num_gmp.h @@ -19,6 +27,8 @@ noinst_HEADERS += src/eckey.h noinst_HEADERS += src/eckey_impl.h noinst_HEADERS += src/ecmult.h noinst_HEADERS += src/ecmult_impl.h +noinst_HEADERS += src/ecmult_const.h +noinst_HEADERS += src/ecmult_const_impl.h noinst_HEADERS += src/ecmult_gen.h noinst_HEADERS += src/ecmult_gen_impl.h noinst_HEADERS += src/num.h @@ -30,6 +40,7 @@ noinst_HEADERS += src/field_5x52_impl.h noinst_HEADERS += src/field_5x52_int128_impl.h noinst_HEADERS += src/field_5x52_asm_impl.h noinst_HEADERS += src/java/org_bitcoin_NativeSecp256k1.h +noinst_HEADERS += src/java/org_bitcoin_Secp256k1Context.h noinst_HEADERS += src/util.h noinst_HEADERS += src/testrand.h noinst_HEADERS += src/testrand_impl.h @@ -38,40 +49,129 @@ noinst_HEADERS += src/hash_impl.h noinst_HEADERS += src/field.h noinst_HEADERS += src/field_impl.h noinst_HEADERS += src/bench.h +noinst_HEADERS += contrib/lax_der_parsing.h +noinst_HEADERS += contrib/lax_der_parsing.c +noinst_HEADERS += contrib/lax_der_privatekey_parsing.h +noinst_HEADERS += contrib/lax_der_privatekey_parsing.c + +if USE_EXTERNAL_ASM +COMMON_LIB = libsecp256k1_common.la +noinst_LTLIBRARIES = $(COMMON_LIB) +else +COMMON_LIB = +endif pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libsecp256k1.pc -libsecp256k1_la_SOURCES = src/secp256k1.c -libsecp256k1_la_CPPFLAGS = -I$(top_srcdir)/include $(SECP_INCLUDES) -libsecp256k1_la_LIBADD = $(SECP_LIBS) +if USE_EXTERNAL_ASM +if USE_ASM_ARM +libsecp256k1_common_la_SOURCES = src/asm/field_10x26_arm.s +endif +endif +libsecp256k1_la_SOURCES = src/secp256k1.c +libsecp256k1_la_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES) +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 +libsecp256k1_jni_la_CPPFLAGS = -DSECP256K1_BUILD $(JNI_INCLUDES) noinst_PROGRAMS = if USE_BENCHMARK -noinst_PROGRAMS += bench_verify bench_recover bench_sign bench_internal +noinst_PROGRAMS += bench_verify bench_sign bench_internal bench_verify_SOURCES = src/bench_verify.c -bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) -bench_verify_LDFLAGS = -static -bench_recover_SOURCES = src/bench_recover.c -bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS) -bench_recover_LDFLAGS = -static +bench_verify_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) bench_sign_SOURCES = src/bench_sign.c -bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) -bench_sign_LDFLAGS = -static +bench_sign_LDADD = libsecp256k1.la $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) bench_internal_SOURCES = src/bench_internal.c -bench_internal_LDADD = $(SECP_LIBS) -bench_internal_LDFLAGS = -static -bench_internal_CPPFLAGS = $(SECP_INCLUDES) +bench_internal_LDADD = $(SECP_LIBS) $(COMMON_LIB) +bench_internal_CPPFLAGS = -DSECP256K1_BUILD $(SECP_INCLUDES) endif +TESTS = if USE_TESTS noinst_PROGRAMS += tests tests_SOURCES = src/tests.c -tests_CPPFLAGS = -DVERIFY $(SECP_INCLUDES) $(SECP_TEST_INCLUDES) -tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) -tests_LDFLAGS = -static -pthread -TESTS = tests +tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src -I$(top_srcdir)/include $(SECP_INCLUDES) $(SECP_TEST_INCLUDES) +if !ENABLE_COVERAGE +tests_CPPFLAGS += -DVERIFY +endif +tests_LDADD = $(SECP_LIBS) $(SECP_TEST_LIBS) $(COMMON_LIB) +tests_LDFLAGS = -static +TESTS += tests endif -EXTRA_DIST = autogen.sh +if USE_EXHAUSTIVE_TESTS +noinst_PROGRAMS += exhaustive_tests +exhaustive_tests_SOURCES = src/tests_exhaustive.c +exhaustive_tests_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/src $(SECP_INCLUDES) +if !ENABLE_COVERAGE +exhaustive_tests_CPPFLAGS += -DVERIFY +endif +exhaustive_tests_LDADD = $(SECP_LIBS) +exhaustive_tests_LDFLAGS = -static +TESTS += exhaustive_tests +endif + +JAVAROOT=src/java +JAVAORG=org/bitcoin +JAVA_GUAVA=$(srcdir)/$(JAVAROOT)/guava/guava-18.0.jar +CLASSPATH_ENV=CLASSPATH=$(JAVA_GUAVA) +JAVA_FILES= \ + $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1.java \ + $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Test.java \ + $(JAVAROOT)/$(JAVAORG)/NativeSecp256k1Util.java \ + $(JAVAROOT)/$(JAVAORG)/Secp256k1Context.java + +if USE_JNI + +$(JAVA_GUAVA): + @echo Guava is missing. Fetch it via: \ + wget https://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar -O $(@) + @false + +.stamp-java: $(JAVA_FILES) + @echo Compiling $^ + $(AM_V_at)$(CLASSPATH_ENV) javac $^ + @touch $@ + +if USE_TESTS + +check-java: libsecp256k1.la $(JAVA_GUAVA) .stamp-java + $(AM_V_at)java -Djava.library.path="./:./src:./src/.libs:.libs/" -cp "$(JAVA_GUAVA):$(JAVAROOT)" $(JAVAORG)/NativeSecp256k1Test + +endif +endif + +if USE_ECMULT_STATIC_PRECOMPUTATION +CPPFLAGS_FOR_BUILD +=-I$(top_srcdir) +CFLAGS_FOR_BUILD += -Wall -Wextra -Wno-unused-function + +gen_context_OBJECTS = gen_context.o +gen_context_BIN = gen_context$(BUILD_EXEEXT) +gen_%.o: src/gen_%.c + $(CC_FOR_BUILD) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD) -c $< -o $@ + +$(gen_context_BIN): $(gen_context_OBJECTS) + $(CC_FOR_BUILD) $^ -o $@ + +$(libsecp256k1_la_OBJECTS): src/ecmult_static_context.h +$(tests_OBJECTS): src/ecmult_static_context.h +$(bench_internal_OBJECTS): src/ecmult_static_context.h + +src/ecmult_static_context.h: $(gen_context_BIN) + ./$(gen_context_BIN) + +CLEANFILES = $(gen_context_BIN) src/ecmult_static_context.h $(JAVAROOT)/$(JAVAORG)/*.class .stamp-java +endif + +EXTRA_DIST = autogen.sh src/gen_context.c src/basic-config.h $(JAVA_FILES) + +if ENABLE_MODULE_ECDH +include src/modules/ecdh/Makefile.am.include +endif + +if ENABLE_MODULE_RECOVERY +include src/modules/recovery/Makefile.am.include +endif diff --git a/src/cryptoconditions/src/include/secp256k1/README.md b/src/cryptoconditions/src/include/secp256k1/README.md index 6095db422..8cd344ea8 100644 --- a/src/cryptoconditions/src/include/secp256k1/README.md +++ b/src/cryptoconditions/src/include/secp256k1/README.md @@ -1,7 +1,7 @@ libsecp256k1 ============ -[![Build Status](https://travis-ci.org/bitcoin/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin/secp256k1) +[![Build Status](https://travis-ci.org/bitcoin-core/secp256k1.svg?branch=master)](https://travis-ci.org/bitcoin-core/secp256k1) Optimized C library for EC operations on curve secp256k1. diff --git a/src/cryptoconditions/src/include/secp256k1/build-aux/m4/ax_jni_include_dir.m4 b/src/cryptoconditions/src/include/secp256k1/build-aux/m4/ax_jni_include_dir.m4 new file mode 100644 index 000000000..1fc362761 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/build-aux/m4/ax_jni_include_dir.m4 @@ -0,0 +1,140 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_jni_include_dir.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_JNI_INCLUDE_DIR +# +# DESCRIPTION +# +# AX_JNI_INCLUDE_DIR finds include directories needed for compiling +# programs using the JNI interface. +# +# JNI include directories are usually in the Java distribution. This is +# deduced from the value of $JAVA_HOME, $JAVAC, or the path to "javac", in +# that order. When this macro completes, a list of directories is left in +# the variable JNI_INCLUDE_DIRS. +# +# Example usage follows: +# +# AX_JNI_INCLUDE_DIR +# +# for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS +# do +# CPPFLAGS="$CPPFLAGS -I$JNI_INCLUDE_DIR" +# done +# +# If you want to force a specific compiler: +# +# - at the configure.in level, set JAVAC=yourcompiler before calling +# AX_JNI_INCLUDE_DIR +# +# - at the configure level, setenv JAVAC +# +# Note: This macro can work with the autoconf M4 macros for Java programs. +# This particular macro is not part of the original set of macros. +# +# LICENSE +# +# Copyright (c) 2008 Don Anderson +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 10 + +AU_ALIAS([AC_JNI_INCLUDE_DIR], [AX_JNI_INCLUDE_DIR]) +AC_DEFUN([AX_JNI_INCLUDE_DIR],[ + +JNI_INCLUDE_DIRS="" + +if test "x$JAVA_HOME" != x; then + _JTOPDIR="$JAVA_HOME" +else + if test "x$JAVAC" = x; then + JAVAC=javac + fi + AC_PATH_PROG([_ACJNI_JAVAC], [$JAVAC], [no]) + if test "x$_ACJNI_JAVAC" = xno; then + AC_MSG_WARN([cannot find JDK; try setting \$JAVAC or \$JAVA_HOME]) + fi + _ACJNI_FOLLOW_SYMLINKS("$_ACJNI_JAVAC") + _JTOPDIR=`echo "$_ACJNI_FOLLOWED" | sed -e 's://*:/:g' -e 's:/[[^/]]*$::'` +fi + +case "$host_os" in + darwin*) _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'` + _JINC="$_JTOPDIR/Headers";; + *) _JINC="$_JTOPDIR/include";; +esac +_AS_ECHO_LOG([_JTOPDIR=$_JTOPDIR]) +_AS_ECHO_LOG([_JINC=$_JINC]) + +# On Mac OS X 10.6.4, jni.h is a symlink: +# /System/Library/Frameworks/JavaVM.framework/Versions/Current/Headers/jni.h +# -> ../../CurrentJDK/Headers/jni.h. + +AC_CACHE_CHECK(jni headers, ac_cv_jni_header_path, +[ +if test -f "$_JINC/jni.h"; then + ac_cv_jni_header_path="$_JINC" + JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path" +else + _JTOPDIR=`echo "$_JTOPDIR" | sed -e 's:/[[^/]]*$::'` + if test -f "$_JTOPDIR/include/jni.h"; then + ac_cv_jni_header_path="$_JTOPDIR/include" + JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $ac_cv_jni_header_path" + else + ac_cv_jni_header_path=none + fi +fi +]) + + + +# get the likely subdirectories for system specific java includes +case "$host_os" in +bsdi*) _JNI_INC_SUBDIRS="bsdos";; +darwin*) _JNI_INC_SUBDIRS="darwin";; +freebsd*) _JNI_INC_SUBDIRS="freebsd";; +linux*) _JNI_INC_SUBDIRS="linux genunix";; +osf*) _JNI_INC_SUBDIRS="alpha";; +solaris*) _JNI_INC_SUBDIRS="solaris";; +mingw*) _JNI_INC_SUBDIRS="win32";; +cygwin*) _JNI_INC_SUBDIRS="win32";; +*) _JNI_INC_SUBDIRS="genunix";; +esac + +if test "x$ac_cv_jni_header_path" != "xnone"; then + # add any subdirectories that are present + for JINCSUBDIR in $_JNI_INC_SUBDIRS + do + if test -d "$_JTOPDIR/include/$JINCSUBDIR"; then + JNI_INCLUDE_DIRS="$JNI_INCLUDE_DIRS $_JTOPDIR/include/$JINCSUBDIR" + fi + done +fi +]) + +# _ACJNI_FOLLOW_SYMLINKS +# Follows symbolic links on , +# finally setting variable _ACJNI_FOLLOWED +# ---------------------------------------- +AC_DEFUN([_ACJNI_FOLLOW_SYMLINKS],[ +# find the include directory relative to the javac executable +_cur="$1" +while ls -ld "$_cur" 2>/dev/null | grep " -> " >/dev/null; do + AC_MSG_CHECKING([symlink for $_cur]) + _slink=`ls -ld "$_cur" | sed 's/.* -> //'` + case "$_slink" in + /*) _cur="$_slink";; + # 'X' avoids triggering unwanted echo options. + *) _cur=`echo "X$_cur" | sed -e 's/^X//' -e 's:[[^/]]*$::'`"$_slink";; + esac + AC_MSG_RESULT([$_cur]) +done +_ACJNI_FOLLOWED="$_cur" +])# _ACJNI diff --git a/src/cryptoconditions/src/include/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4 b/src/cryptoconditions/src/include/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4 new file mode 100644 index 000000000..77fd346a7 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/build-aux/m4/ax_prog_cc_for_build.m4 @@ -0,0 +1,125 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_prog_cc_for_build.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PROG_CC_FOR_BUILD +# +# DESCRIPTION +# +# This macro searches for a C compiler that generates native executables, +# that is a C compiler that surely is not a cross-compiler. This can be +# useful if you have to generate source code at compile-time like for +# example GCC does. +# +# The macro sets the CC_FOR_BUILD and CPP_FOR_BUILD macros to anything +# needed to compile or link (CC_FOR_BUILD) and preprocess (CPP_FOR_BUILD). +# The value of these variables can be overridden by the user by specifying +# a compiler with an environment variable (like you do for standard CC). +# +# It also sets BUILD_EXEEXT and BUILD_OBJEXT to the executable and object +# file extensions for the build platform, and GCC_FOR_BUILD to `yes' if +# the compiler we found is GCC. All these variables but GCC_FOR_BUILD are +# substituted in the Makefile. +# +# LICENSE +# +# Copyright (c) 2008 Paolo Bonzini +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 8 + +AU_ALIAS([AC_PROG_CC_FOR_BUILD], [AX_PROG_CC_FOR_BUILD]) +AC_DEFUN([AX_PROG_CC_FOR_BUILD], [dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_CPP])dnl +AC_REQUIRE([AC_EXEEXT])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl + +dnl Use the standard macros, but make them use other variable names +dnl +pushdef([ac_cv_prog_CPP], ac_cv_build_prog_CPP)dnl +pushdef([ac_cv_prog_gcc], ac_cv_build_prog_gcc)dnl +pushdef([ac_cv_prog_cc_works], ac_cv_build_prog_cc_works)dnl +pushdef([ac_cv_prog_cc_cross], ac_cv_build_prog_cc_cross)dnl +pushdef([ac_cv_prog_cc_g], ac_cv_build_prog_cc_g)dnl +pushdef([ac_cv_exeext], ac_cv_build_exeext)dnl +pushdef([ac_cv_objext], ac_cv_build_objext)dnl +pushdef([ac_exeext], ac_build_exeext)dnl +pushdef([ac_objext], ac_build_objext)dnl +pushdef([CC], CC_FOR_BUILD)dnl +pushdef([CPP], CPP_FOR_BUILD)dnl +pushdef([CFLAGS], CFLAGS_FOR_BUILD)dnl +pushdef([CPPFLAGS], CPPFLAGS_FOR_BUILD)dnl +pushdef([LDFLAGS], LDFLAGS_FOR_BUILD)dnl +pushdef([host], build)dnl +pushdef([host_alias], build_alias)dnl +pushdef([host_cpu], build_cpu)dnl +pushdef([host_vendor], build_vendor)dnl +pushdef([host_os], build_os)dnl +pushdef([ac_cv_host], ac_cv_build)dnl +pushdef([ac_cv_host_alias], ac_cv_build_alias)dnl +pushdef([ac_cv_host_cpu], ac_cv_build_cpu)dnl +pushdef([ac_cv_host_vendor], ac_cv_build_vendor)dnl +pushdef([ac_cv_host_os], ac_cv_build_os)dnl +pushdef([ac_cpp], ac_build_cpp)dnl +pushdef([ac_compile], ac_build_compile)dnl +pushdef([ac_link], ac_build_link)dnl + +save_cross_compiling=$cross_compiling +save_ac_tool_prefix=$ac_tool_prefix +cross_compiling=no +ac_tool_prefix= + +AC_PROG_CC +AC_PROG_CPP +AC_EXEEXT + +ac_tool_prefix=$save_ac_tool_prefix +cross_compiling=$save_cross_compiling + +dnl Restore the old definitions +dnl +popdef([ac_link])dnl +popdef([ac_compile])dnl +popdef([ac_cpp])dnl +popdef([ac_cv_host_os])dnl +popdef([ac_cv_host_vendor])dnl +popdef([ac_cv_host_cpu])dnl +popdef([ac_cv_host_alias])dnl +popdef([ac_cv_host])dnl +popdef([host_os])dnl +popdef([host_vendor])dnl +popdef([host_cpu])dnl +popdef([host_alias])dnl +popdef([host])dnl +popdef([LDFLAGS])dnl +popdef([CPPFLAGS])dnl +popdef([CFLAGS])dnl +popdef([CPP])dnl +popdef([CC])dnl +popdef([ac_objext])dnl +popdef([ac_exeext])dnl +popdef([ac_cv_objext])dnl +popdef([ac_cv_exeext])dnl +popdef([ac_cv_prog_cc_g])dnl +popdef([ac_cv_prog_cc_cross])dnl +popdef([ac_cv_prog_cc_works])dnl +popdef([ac_cv_prog_gcc])dnl +popdef([ac_cv_prog_CPP])dnl + +dnl Finally, set Makefile variables +dnl +BUILD_EXEEXT=$ac_build_exeext +BUILD_OBJEXT=$ac_build_objext +AC_SUBST(BUILD_EXEEXT)dnl +AC_SUBST(BUILD_OBJEXT)dnl +AC_SUBST([CFLAGS_FOR_BUILD])dnl +AC_SUBST([CPPFLAGS_FOR_BUILD])dnl +AC_SUBST([LDFLAGS_FOR_BUILD])dnl +]) diff --git a/src/cryptoconditions/src/include/secp256k1/build-aux/m4/bitcoin_secp.m4 b/src/cryptoconditions/src/include/secp256k1/build-aux/m4/bitcoin_secp.m4 new file mode 100644 index 000000000..b74acb8c1 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/build-aux/m4/bitcoin_secp.m4 @@ -0,0 +1,69 @@ +dnl libsecp25k1 helper checks +AC_DEFUN([SECP_INT128_CHECK],[ +has_int128=$ac_cv_type___int128 +]) + +dnl escape "$0x" below using the m4 quadrigaph @S|@, and escape it again with a \ for the shell. +AC_DEFUN([SECP_64BIT_ASM_CHECK],[ +AC_MSG_CHECKING(for x86_64 assembly availability) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include ]],[[ + uint64_t a = 11, tmp; + __asm__ __volatile__("movq \@S|@0x100000000,%1; mulq %%rsi" : "+a"(a) : "S"(tmp) : "cc", "%rdx"); + ]])],[has_64bit_asm=yes],[has_64bit_asm=no]) +AC_MSG_RESULT([$has_64bit_asm]) +]) + +dnl +AC_DEFUN([SECP_OPENSSL_CHECK],[ + has_libcrypto=no + m4_ifdef([PKG_CHECK_MODULES],[ + PKG_CHECK_MODULES([CRYPTO], [libcrypto], [has_libcrypto=yes],[has_libcrypto=no]) + if test x"$has_libcrypto" = x"yes"; then + TEMP_LIBS="$LIBS" + LIBS="$LIBS $CRYPTO_LIBS" + AC_CHECK_LIB(crypto, main,[AC_DEFINE(HAVE_LIBCRYPTO,1,[Define this symbol if libcrypto is installed])],[has_libcrypto=no]) + LIBS="$TEMP_LIBS" + fi + ]) + if test x$has_libcrypto = xno; then + AC_CHECK_HEADER(openssl/crypto.h,[ + AC_CHECK_LIB(crypto, main,[ + has_libcrypto=yes + CRYPTO_LIBS=-lcrypto + AC_DEFINE(HAVE_LIBCRYPTO,1,[Define this symbol if libcrypto is installed]) + ]) + ]) + LIBS= + fi +if test x"$has_libcrypto" = x"yes" && test x"$has_openssl_ec" = x; then + AC_MSG_CHECKING(for EC functions in libcrypto) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ + #include + #include + #include ]],[[ + EC_KEY *eckey = EC_KEY_new_by_curve_name(NID_secp256k1); + ECDSA_sign(0, NULL, 0, NULL, NULL, eckey); + ECDSA_verify(0, NULL, 0, NULL, 0, eckey); + EC_KEY_free(eckey); + ECDSA_SIG *sig_openssl; + sig_openssl = ECDSA_SIG_new(); + (void)sig_openssl->r; + ECDSA_SIG_free(sig_openssl); + ]])],[has_openssl_ec=yes],[has_openssl_ec=no]) + AC_MSG_RESULT([$has_openssl_ec]) +fi +]) + +dnl +AC_DEFUN([SECP_GMP_CHECK],[ +if test x"$has_gmp" != x"yes"; then + CPPFLAGS_TEMP="$CPPFLAGS" + CPPFLAGS="$GMP_CPPFLAGS $CPPFLAGS" + LIBS_TEMP="$LIBS" + LIBS="$GMP_LIBS $LIBS" + AC_CHECK_HEADER(gmp.h,[AC_CHECK_LIB(gmp, __gmpz_init,[has_gmp=yes; GMP_LIBS="$GMP_LIBS -lgmp"; AC_DEFINE(HAVE_LIBGMP,1,[Define this symbol if libgmp is installed])])]) + CPPFLAGS="$CPPFLAGS_TEMP" + LIBS="$LIBS_TEMP" +fi +]) diff --git a/src/cryptoconditions/src/include/secp256k1/configure.ac b/src/cryptoconditions/src/include/secp256k1/configure.ac index 3dc182951..e5fcbcb4e 100644 --- a/src/cryptoconditions/src/include/secp256k1/configure.ac +++ b/src/cryptoconditions/src/include/secp256k1/configure.ac @@ -17,24 +17,19 @@ PKG_PROG_PKG_CONFIG AC_PATH_TOOL(AR, ar) AC_PATH_TOOL(RANLIB, ranlib) AC_PATH_TOOL(STRIP, strip) +AX_PROG_CC_FOR_BUILD if test "x$CFLAGS" = "x"; then - CFLAGS="-O3 -g" + CFLAGS="-g" fi +AM_PROG_CC_C_O + AC_PROG_CC_C89 if test x"$ac_cv_prog_cc_c89" = x"no"; then AC_MSG_ERROR([c89 compiler support required]) fi - -case $host in - *mingw*) - use_pkgconfig=no - ;; - *) - use_pkgconfig=yes - ;; -esac +AM_PROG_AS case $host_os in *darwin*) @@ -80,22 +75,70 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], CFLAGS="$saved_CFLAGS" ]) +saved_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -fvisibility=hidden" +AC_MSG_CHECKING([if ${CC} supports -fvisibility=hidden]) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([[char foo;]])], + [ AC_MSG_RESULT([yes]) ], + [ AC_MSG_RESULT([no]) + CFLAGS="$saved_CFLAGS" + ]) AC_ARG_ENABLE(benchmark, AS_HELP_STRING([--enable-benchmark],[compile benchmark (default is no)]), [use_benchmark=$enableval], [use_benchmark=no]) +AC_ARG_ENABLE(coverage, + AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis]), + [enable_coverage=$enableval], + [enable_coverage=no]) + AC_ARG_ENABLE(tests, AS_HELP_STRING([--enable-tests],[compile tests (default is yes)]), [use_tests=$enableval], [use_tests=yes]) +AC_ARG_ENABLE(openssl_tests, + AS_HELP_STRING([--enable-openssl-tests],[enable OpenSSL tests, if OpenSSL is available (default is auto)]), + [enable_openssl_tests=$enableval], + [enable_openssl_tests=auto]) + +AC_ARG_ENABLE(experimental, + AS_HELP_STRING([--enable-experimental],[allow experimental configure options (default is no)]), + [use_experimental=$enableval], + [use_experimental=no]) + +AC_ARG_ENABLE(exhaustive_tests, + AS_HELP_STRING([--enable-exhaustive-tests],[compile exhaustive tests (default is yes)]), + [use_exhaustive_tests=$enableval], + [use_exhaustive_tests=yes]) + AC_ARG_ENABLE(endomorphism, AS_HELP_STRING([--enable-endomorphism],[enable endomorphism (default is no)]), [use_endomorphism=$enableval], [use_endomorphism=no]) +AC_ARG_ENABLE(ecmult_static_precomputation, + AS_HELP_STRING([--enable-ecmult-static-precomputation],[enable precomputed ecmult table for signing (default is yes)]), + [use_ecmult_static_precomputation=$enableval], + [use_ecmult_static_precomputation=auto]) + +AC_ARG_ENABLE(module_ecdh, + AS_HELP_STRING([--enable-module-ecdh],[enable ECDH shared secret computation (experimental)]), + [enable_module_ecdh=$enableval], + [enable_module_ecdh=no]) + +AC_ARG_ENABLE(module_recovery, + AS_HELP_STRING([--enable-module-recovery],[enable ECDSA pubkey recovery module (default is no)]), + [enable_module_recovery=$enableval], + [enable_module_recovery=no]) + +AC_ARG_ENABLE(jni, + AS_HELP_STRING([--enable-jni],[enable libsecp256k1_jni (default is auto)]), + [use_jni=$enableval], + [use_jni=auto]) + AC_ARG_WITH([field], [AS_HELP_STRING([--with-field=64bit|32bit|auto], [Specify Field Implementation. Default is auto])],[req_field=$withval], [req_field=auto]) @@ -105,8 +148,8 @@ AC_ARG_WITH([bignum], [AS_HELP_STRING([--with-bignum=gmp|no|auto], AC_ARG_WITH([scalar], [AS_HELP_STRING([--with-scalar=64bit|32bit|auto], [Specify scalar implementation. Default is auto])],[req_scalar=$withval], [req_scalar=auto]) -AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|no|auto] -[Specify assembly optimizations to use. Default is auto])],[req_asm=$withval], [req_asm=auto]) +AC_ARG_WITH([asm], [AS_HELP_STRING([--with-asm=x86_64|arm|no|auto] +[Specify assembly optimizations to use. Default is auto (experimental: arm)])],[req_asm=$withval], [req_asm=auto]) AC_CHECK_TYPES([__int128]) @@ -116,6 +159,42 @@ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[void myfunc() {__builtin_expect(0,0);}]])], [ AC_MSG_RESULT([no]) ]) +if test x"$enable_coverage" = x"yes"; then + AC_DEFINE(COVERAGE, 1, [Define this symbol to compile out all VERIFY code]) + CFLAGS="$CFLAGS -O0 --coverage" + LDFLAGS="--coverage" +else + CFLAGS="$CFLAGS -O3" +fi + +if test x"$use_ecmult_static_precomputation" != x"no"; then + save_cross_compiling=$cross_compiling + cross_compiling=no + TEMP_CC="$CC" + CC="$CC_FOR_BUILD" + AC_MSG_CHECKING([native compiler: ${CC_FOR_BUILD}]) + AC_RUN_IFELSE( + [AC_LANG_PROGRAM([], [return 0])], + [working_native_cc=yes], + [working_native_cc=no],[dnl]) + CC="$TEMP_CC" + cross_compiling=$save_cross_compiling + + if test x"$working_native_cc" = x"no"; then + set_precomp=no + if test x"$use_ecmult_static_precomputation" = x"yes"; then + AC_MSG_ERROR([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD]) + else + AC_MSG_RESULT([${CC_FOR_BUILD} does not produce working binaries. Please set CC_FOR_BUILD]) + fi + else + AC_MSG_RESULT([ok]) + set_precomp=yes + fi +else + set_precomp=no +fi + if test x"$req_asm" = x"auto"; then SECP_64BIT_ASM_CHECK if test x"$has_64bit_asm" = x"yes"; then @@ -133,6 +212,8 @@ else AC_MSG_ERROR([x86_64 assembly optimization requested but not available]) fi ;; + arm) + ;; no) ;; *) @@ -225,10 +306,15 @@ else fi # select assembly optimization +use_external_asm=no + case $set_asm in x86_64) AC_DEFINE(USE_ASM_X86_64, 1, [Define this symbol to enable x86_64 assembly optimizations]) ;; +arm) + use_external_asm=yes + ;; no) ;; *) @@ -283,16 +369,48 @@ esac if test x"$use_tests" = x"yes"; then SECP_OPENSSL_CHECK if test x"$has_openssl_ec" = x"yes"; then - AC_DEFINE(ENABLE_OPENSSL_TESTS, 1, [Define this symbol if OpenSSL EC functions are available]) - SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS" - SECP_TEST_LIBS="$CRYPTO_LIBS" + if test x"$enable_openssl_tests" != x"no"; then + AC_DEFINE(ENABLE_OPENSSL_TESTS, 1, [Define this symbol if OpenSSL EC functions are available]) + SECP_TEST_INCLUDES="$SSL_CFLAGS $CRYPTO_CFLAGS" + SECP_TEST_LIBS="$CRYPTO_LIBS" - case $host in - *mingw*) - SECP_TEST_LIBS="$SECP_TEST_LIBS -lgdi32" - ;; - esac + case $host in + *mingw*) + SECP_TEST_LIBS="$SECP_TEST_LIBS -lgdi32" + ;; + esac + fi + else + if test x"$enable_openssl_tests" = x"yes"; then + AC_MSG_ERROR([OpenSSL tests requested but OpenSSL with EC support is not available]) + fi + fi +else + if test x"$enable_openssl_tests" = x"yes"; then + AC_MSG_ERROR([OpenSSL tests requested but tests are not enabled]) + fi +fi +if test x"$use_jni" != x"no"; then + AX_JNI_INCLUDE_DIR + have_jni_dependencies=yes + if test x"$enable_module_ecdh" = x"no"; then + have_jni_dependencies=no + fi + if test "x$JNI_INCLUDE_DIRS" = "x"; then + have_jni_dependencies=no + fi + if test "x$have_jni_dependencies" = "xno"; then + if test x"$use_jni" = x"yes"; then + AC_MSG_ERROR([jni support explicitly requested but headers/dependencies were not found. Enable ECDH and try again.]) + fi + AC_MSG_WARN([jni headers/dependencies not found. jni support disabled]) + use_jni=no + else + use_jni=yes + for JNI_INCLUDE_DIR in $JNI_INCLUDE_DIRS; do + JNI_INCLUDES="$JNI_INCLUDES -I$JNI_INCLUDE_DIR" + done fi fi @@ -305,22 +423,67 @@ if test x"$use_endomorphism" = x"yes"; then AC_DEFINE(USE_ENDOMORPHISM, 1, [Define this symbol to use endomorphism optimization]) fi +if test x"$set_precomp" = x"yes"; then + AC_DEFINE(USE_ECMULT_STATIC_PRECOMPUTATION, 1, [Define this symbol to use a statically generated ecmult table]) +fi + +if test x"$enable_module_ecdh" = x"yes"; then + AC_DEFINE(ENABLE_MODULE_ECDH, 1, [Define this symbol to enable the ECDH module]) +fi + +if test x"$enable_module_recovery" = x"yes"; then + AC_DEFINE(ENABLE_MODULE_RECOVERY, 1, [Define this symbol to enable the ECDSA pubkey recovery module]) +fi + AC_C_BIGENDIAN() +if test x"$use_external_asm" = x"yes"; then + AC_DEFINE(USE_EXTERNAL_ASM, 1, [Define this symbol if an external (non-inline) assembly implementation is used]) +fi + +AC_MSG_NOTICE([Using static precomputation: $set_precomp]) AC_MSG_NOTICE([Using assembly optimizations: $set_asm]) AC_MSG_NOTICE([Using field implementation: $set_field]) AC_MSG_NOTICE([Using bignum implementation: $set_bignum]) AC_MSG_NOTICE([Using scalar implementation: $set_scalar]) AC_MSG_NOTICE([Using endomorphism optimizations: $use_endomorphism]) +AC_MSG_NOTICE([Building for coverage analysis: $enable_coverage]) +AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh]) +AC_MSG_NOTICE([Building ECDSA pubkey recovery module: $enable_module_recovery]) +AC_MSG_NOTICE([Using jni: $use_jni]) + +if test x"$enable_experimental" = x"yes"; then + AC_MSG_NOTICE([******]) + AC_MSG_NOTICE([WARNING: experimental build]) + AC_MSG_NOTICE([Experimental features do not have stable APIs or properties, and may not be safe for production use.]) + AC_MSG_NOTICE([Building ECDH module: $enable_module_ecdh]) + AC_MSG_NOTICE([******]) +else + if test x"$enable_module_ecdh" = x"yes"; then + AC_MSG_ERROR([ECDH module is experimental. Use --enable-experimental to allow.]) + fi + if test x"$set_asm" = x"arm"; then + AC_MSG_ERROR([ARM assembly optimization is experimental. Use --enable-experimental to allow.]) + fi +fi AC_CONFIG_HEADERS([src/libsecp256k1-config.h]) AC_CONFIG_FILES([Makefile libsecp256k1.pc]) +AC_SUBST(JNI_INCLUDES) AC_SUBST(SECP_INCLUDES) AC_SUBST(SECP_LIBS) AC_SUBST(SECP_TEST_LIBS) AC_SUBST(SECP_TEST_INCLUDES) +AM_CONDITIONAL([ENABLE_COVERAGE], [test x"$enable_coverage" = x"yes"]) AM_CONDITIONAL([USE_TESTS], [test x"$use_tests" != x"no"]) +AM_CONDITIONAL([USE_EXHAUSTIVE_TESTS], [test x"$use_exhaustive_tests" != x"no"]) AM_CONDITIONAL([USE_BENCHMARK], [test x"$use_benchmark" = x"yes"]) +AM_CONDITIONAL([USE_ECMULT_STATIC_PRECOMPUTATION], [test x"$set_precomp" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_ECDH], [test x"$enable_module_ecdh" = x"yes"]) +AM_CONDITIONAL([ENABLE_MODULE_RECOVERY], [test x"$enable_module_recovery" = x"yes"]) +AM_CONDITIONAL([USE_JNI], [test x"$use_jni" == x"yes"]) +AM_CONDITIONAL([USE_EXTERNAL_ASM], [test x"$use_external_asm" = x"yes"]) +AM_CONDITIONAL([USE_ASM_ARM], [test x"$set_asm" = x"arm"]) dnl make sure nothing new is exported so that we don't break the cache PKGCONFIG_PATH_TEMP="$PKG_CONFIG_PATH" diff --git a/src/cryptoconditions/src/include/secp256k1/contrib/lax_der_parsing.c b/src/cryptoconditions/src/include/secp256k1/contrib/lax_der_parsing.c new file mode 100644 index 000000000..5b141a994 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/contrib/lax_der_parsing.c @@ -0,0 +1,150 @@ +/********************************************************************** + * Copyright (c) 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include + +#include "lax_der_parsing.h" + +int ecdsa_signature_parse_der_lax(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) { + size_t rpos, rlen, spos, slen; + size_t pos = 0; + size_t lenbyte; + unsigned char tmpsig[64] = {0}; + int overflow = 0; + + /* Hack to initialize sig with a correctly-parsed but invalid signature. */ + secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + + /* Sequence tag byte */ + if (pos == inputlen || input[pos] != 0x30) { + return 0; + } + pos++; + + /* Sequence length bytes */ + if (pos == inputlen) { + return 0; + } + lenbyte = input[pos++]; + if (lenbyte & 0x80) { + lenbyte -= 0x80; + if (pos + lenbyte > inputlen) { + return 0; + } + pos += lenbyte; + } + + /* Integer tag byte for R */ + if (pos == inputlen || input[pos] != 0x02) { + return 0; + } + pos++; + + /* Integer length for R */ + if (pos == inputlen) { + return 0; + } + lenbyte = input[pos++]; + if (lenbyte & 0x80) { + lenbyte -= 0x80; + if (pos + lenbyte > inputlen) { + return 0; + } + while (lenbyte > 0 && input[pos] == 0) { + pos++; + lenbyte--; + } + if (lenbyte >= sizeof(size_t)) { + return 0; + } + rlen = 0; + while (lenbyte > 0) { + rlen = (rlen << 8) + input[pos]; + pos++; + lenbyte--; + } + } else { + rlen = lenbyte; + } + if (rlen > inputlen - pos) { + return 0; + } + rpos = pos; + pos += rlen; + + /* Integer tag byte for S */ + if (pos == inputlen || input[pos] != 0x02) { + return 0; + } + pos++; + + /* Integer length for S */ + if (pos == inputlen) { + return 0; + } + lenbyte = input[pos++]; + if (lenbyte & 0x80) { + lenbyte -= 0x80; + if (pos + lenbyte > inputlen) { + return 0; + } + while (lenbyte > 0 && input[pos] == 0) { + pos++; + lenbyte--; + } + if (lenbyte >= sizeof(size_t)) { + return 0; + } + slen = 0; + while (lenbyte > 0) { + slen = (slen << 8) + input[pos]; + pos++; + lenbyte--; + } + } else { + slen = lenbyte; + } + if (slen > inputlen - pos) { + return 0; + } + spos = pos; + pos += slen; + + /* Ignore leading zeroes in R */ + while (rlen > 0 && input[rpos] == 0) { + rlen--; + rpos++; + } + /* Copy R value */ + if (rlen > 32) { + overflow = 1; + } else { + memcpy(tmpsig + 32 - rlen, input + rpos, rlen); + } + + /* Ignore leading zeroes in S */ + while (slen > 0 && input[spos] == 0) { + slen--; + spos++; + } + /* Copy S value */ + if (slen > 32) { + overflow = 1; + } else { + memcpy(tmpsig + 64 - slen, input + spos, slen); + } + + if (!overflow) { + overflow = !secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + } + if (overflow) { + memset(tmpsig, 0, 64); + secp256k1_ecdsa_signature_parse_compact(ctx, sig, tmpsig); + } + return 1; +} + diff --git a/src/cryptoconditions/src/include/secp256k1/contrib/lax_der_parsing.h b/src/cryptoconditions/src/include/secp256k1/contrib/lax_der_parsing.h new file mode 100644 index 000000000..7eaf63bf6 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/contrib/lax_der_parsing.h @@ -0,0 +1,91 @@ +/********************************************************************** + * Copyright (c) 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +/**** + * Please do not link this file directly. It is not part of the libsecp256k1 + * project and does not promise any stability in its API, functionality or + * presence. Projects which use this code should instead copy this header + * and its accompanying .c file directly into their codebase. + ****/ + +/* This file defines a function that parses DER with various errors and + * violations. This is not a part of the library itself, because the allowed + * violations are chosen arbitrarily and do not follow or establish any + * standard. + * + * In many places it matters that different implementations do not only accept + * the same set of valid signatures, but also reject the same set of signatures. + * The only means to accomplish that is by strictly obeying a standard, and not + * accepting anything else. + * + * Nonetheless, sometimes there is a need for compatibility with systems that + * use signatures which do not strictly obey DER. The snippet below shows how + * certain violations are easily supported. You may need to adapt it. + * + * Do not use this for new systems. Use well-defined DER or compact signatures + * instead if you have the choice (see secp256k1_ecdsa_signature_parse_der and + * secp256k1_ecdsa_signature_parse_compact). + * + * The supported violations are: + * - All numbers are parsed as nonnegative integers, even though X.609-0207 + * section 8.3.3 specifies that integers are always encoded as two's + * complement. + * - Integers can have length 0, even though section 8.3.1 says they can't. + * - Integers with overly long padding are accepted, violation section + * 8.3.2. + * - 127-byte long length descriptors are accepted, even though section + * 8.1.3.5.c says that they are not. + * - Trailing garbage data inside or after the signature is ignored. + * - The length descriptor of the sequence is ignored. + * + * Compared to for example OpenSSL, many violations are NOT supported: + * - Using overly long tag descriptors for the sequence or integers inside, + * violating section 8.1.2.2. + * - Encoding primitive integers as constructed values, violating section + * 8.3.1. + */ + +#ifndef SECP256K1_CONTRIB_LAX_DER_PARSING_H +#define SECP256K1_CONTRIB_LAX_DER_PARSING_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Parse a signature in "lax DER" format + * + * Returns: 1 when the signature could be parsed, 0 otherwise. + * Args: ctx: a secp256k1 context object + * Out: sig: a pointer to a signature object + * In: input: a pointer to the signature to be parsed + * inputlen: the length of the array pointed to be input + * + * This function will accept any valid DER encoded signature, even if the + * encoded numbers are out of range. In addition, it will accept signatures + * which violate the DER spec in various ways. Its purpose is to allow + * validation of the Bitcoin blockchain, which includes non-DER signatures + * from before the network rules were updated to enforce DER. Note that + * the set of supported violations is a strict subset of what OpenSSL will + * accept. + * + * After the call, sig will always be initialized. If parsing failed or the + * encoded numbers are out of range, signature validation with it is + * guaranteed to fail for every message and public key. + */ +int ecdsa_signature_parse_der_lax( + const secp256k1_context* ctx, + secp256k1_ecdsa_signature* sig, + const unsigned char *input, + size_t inputlen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_CONTRIB_LAX_DER_PARSING_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/contrib/lax_der_privatekey_parsing.c b/src/cryptoconditions/src/include/secp256k1/contrib/lax_der_privatekey_parsing.c new file mode 100644 index 000000000..c2e63b4b8 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/contrib/lax_der_privatekey_parsing.c @@ -0,0 +1,113 @@ +/********************************************************************** + * Copyright (c) 2014, 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include +#include + +#include "lax_der_privatekey_parsing.h" + +int ec_privkey_import_der(const secp256k1_context* ctx, unsigned char *out32, const unsigned char *privkey, size_t privkeylen) { + const unsigned char *end = privkey + privkeylen; + int lenb = 0; + int len = 0; + memset(out32, 0, 32); + /* sequence header */ + if (end < privkey+1 || *privkey != 0x30) { + return 0; + } + privkey++; + /* sequence length constructor */ + if (end < privkey+1 || !(*privkey & 0x80)) { + return 0; + } + lenb = *privkey & ~0x80; privkey++; + if (lenb < 1 || lenb > 2) { + return 0; + } + if (end < privkey+lenb) { + return 0; + } + /* sequence length */ + len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0); + privkey += lenb; + if (end < privkey+len) { + return 0; + } + /* sequence element 0: version number (=1) */ + if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01) { + return 0; + } + privkey += 3; + /* sequence element 1: octet string, up to 32 bytes */ + if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) { + return 0; + } + memcpy(out32 + 32 - privkey[1], privkey + 2, privkey[1]); + if (!secp256k1_ec_seckey_verify(ctx, out32)) { + memset(out32, 0, 32); + return 0; + } + return 1; +} + +int ec_privkey_export_der(const secp256k1_context *ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *key32, int compressed) { + secp256k1_pubkey pubkey; + size_t pubkeylen = 0; + if (!secp256k1_ec_pubkey_create(ctx, &pubkey, key32)) { + *privkeylen = 0; + return 0; + } + if (compressed) { + static const unsigned char begin[] = { + 0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20 + }; + static const unsigned char middle[] = { + 0xA0,0x81,0x85,0x30,0x81,0x82,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, + 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, + 0x21,0x02,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, + 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, + 0x17,0x98,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, + 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x24,0x03,0x22,0x00 + }; + unsigned char *ptr = privkey; + memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); + memcpy(ptr, key32, 32); ptr += 32; + memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); + pubkeylen = 33; + secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED); + ptr += pubkeylen; + *privkeylen = ptr - privkey; + } else { + static const unsigned char begin[] = { + 0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20 + }; + static const unsigned char middle[] = { + 0xA0,0x81,0xA5,0x30,0x81,0xA2,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, + 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, + 0x41,0x04,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, + 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, + 0x17,0x98,0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,0x5D,0xA4,0xFB,0xFC,0x0E,0x11, + 0x08,0xA8,0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,0x9C,0x47,0xD0,0x8F,0xFB,0x10, + 0xD4,0xB8,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, + 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x44,0x03,0x42,0x00 + }; + unsigned char *ptr = privkey; + memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); + memcpy(ptr, key32, 32); ptr += 32; + memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); + pubkeylen = 65; + secp256k1_ec_pubkey_serialize(ctx, ptr, &pubkeylen, &pubkey, SECP256K1_EC_UNCOMPRESSED); + ptr += pubkeylen; + *privkeylen = ptr - privkey; + } + return 1; +} diff --git a/src/cryptoconditions/src/include/secp256k1/contrib/lax_der_privatekey_parsing.h b/src/cryptoconditions/src/include/secp256k1/contrib/lax_der_privatekey_parsing.h new file mode 100644 index 000000000..fece261fb --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/contrib/lax_der_privatekey_parsing.h @@ -0,0 +1,90 @@ +/********************************************************************** + * Copyright (c) 2014, 2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +/**** + * Please do not link this file directly. It is not part of the libsecp256k1 + * project and does not promise any stability in its API, functionality or + * presence. Projects which use this code should instead copy this header + * and its accompanying .c file directly into their codebase. + ****/ + +/* This file contains code snippets that parse DER private keys with + * various errors and violations. This is not a part of the library + * itself, because the allowed violations are chosen arbitrarily and + * do not follow or establish any standard. + * + * It also contains code to serialize private keys in a compatible + * manner. + * + * These functions are meant for compatibility with applications + * that require BER encoded keys. When working with secp256k1-specific + * code, the simple 32-byte private keys normally used by the + * library are sufficient. + */ + +#ifndef SECP256K1_CONTRIB_BER_PRIVATEKEY_H +#define SECP256K1_CONTRIB_BER_PRIVATEKEY_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** Export a private key in DER format. + * + * Returns: 1 if the private key was valid. + * Args: ctx: pointer to a context object, initialized for signing (cannot + * be NULL) + * Out: privkey: pointer to an array for storing the private key in BER. + * Should have space for 279 bytes, and cannot be NULL. + * privkeylen: Pointer to an int where the length of the private key in + * privkey will be stored. + * In: seckey: pointer to a 32-byte secret key to export. + * compressed: 1 if the key should be exported in + * compressed format, 0 otherwise + * + * This function is purely meant for compatibility with applications that + * require BER encoded keys. When working with secp256k1-specific code, the + * simple 32-byte private keys are sufficient. + * + * Note that this function does not guarantee correct DER output. It is + * guaranteed to be parsable by secp256k1_ec_privkey_import_der + */ +SECP256K1_WARN_UNUSED_RESULT int ec_privkey_export_der( + const secp256k1_context* ctx, + unsigned char *privkey, + size_t *privkeylen, + const unsigned char *seckey, + int compressed +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Import a private key in DER format. + * Returns: 1 if a private key was extracted. + * Args: ctx: pointer to a context object (cannot be NULL). + * Out: seckey: pointer to a 32-byte array for storing the private key. + * (cannot be NULL). + * In: privkey: pointer to a private key in DER format (cannot be NULL). + * privkeylen: length of the DER private key pointed to be privkey. + * + * This function will accept more than just strict DER, and even allow some BER + * violations. The public key stored inside the DER-encoded private key is not + * verified for correctness, nor are the curve parameters. Use this function + * only if you know in advance it is supposed to contain a secp256k1 private + * key. + */ +SECP256K1_WARN_UNUSED_RESULT int ec_privkey_import_der( + const secp256k1_context* ctx, + unsigned char *seckey, + const unsigned char *privkey, + size_t privkeylen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_CONTRIB_BER_PRIVATEKEY_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/include/secp256k1.h b/src/cryptoconditions/src/include/secp256k1/include/secp256k1.h index 9db5cf3a8..3e9c098d1 100644 --- a/src/cryptoconditions/src/include/secp256k1/include/secp256k1.h +++ b/src/cryptoconditions/src/include/secp256k1/include/secp256k1.h @@ -1,9 +1,96 @@ -#ifndef _SECP256K1_ -# define _SECP256K1_ +#ifndef SECP256K1_H +#define SECP256K1_H -# ifdef __cplusplus +#ifdef __cplusplus extern "C" { -# endif +#endif + +#include + +/* These rules specify the order of arguments in API calls: + * + * 1. Context pointers go first, followed by output arguments, combined + * output/input arguments, and finally input-only arguments. + * 2. Array lengths always immediately the follow the argument whose length + * they describe, even if this violates rule 1. + * 3. Within the OUT/OUTIN/IN groups, pointers to data that is typically generated + * later go first. This means: signatures, public nonces, private nonces, + * messages, public keys, secret keys, tweaks. + * 4. Arguments that are not data pointers go last, from more complex to less + * complex: function pointers, algorithm names, messages, void pointers, + * counts, flags, booleans. + * 5. Opaque data pointers follow the function pointer they are to be passed to. + */ + +/** Opaque data structure that holds context information (precomputed tables etc.). + * + * The purpose of context structures is to cache large precomputed data tables + * that are expensive to construct, and also to maintain the randomization data + * for blinding. + * + * Do not create a new context object for each operation, as construction is + * far slower than all other API calls (~100 times slower than an ECDSA + * verification). + * + * A constructed context can safely be used from multiple threads + * simultaneously, but API call that take a non-const pointer to a context + * need exclusive access to it. In particular this is the case for + * secp256k1_context_destroy and secp256k1_context_randomize. + * + * Regarding randomization, either do it once at creation time (in which case + * you do not need any locking for the other calls), or use a read-write lock. + */ +typedef struct secp256k1_context_struct secp256k1_context; + +/** Opaque data structure that holds a parsed and valid public key. + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is + * however guaranteed to be 64 bytes in size, and can be safely copied/moved. + * If you need to convert to a format suitable for storage, transmission, or + * comparison, use secp256k1_ec_pubkey_serialize and secp256k1_ec_pubkey_parse. + */ +typedef struct { + unsigned char data[64]; +} secp256k1_pubkey; + +/** Opaque data structured that holds a parsed ECDSA signature. + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is + * however guaranteed to be 64 bytes in size, and can be safely copied/moved. + * If you need to convert to a format suitable for storage, transmission, or + * comparison, use the secp256k1_ecdsa_signature_serialize_* and + * secp256k1_ecdsa_signature_parse_* functions. + */ +typedef struct { + unsigned char data[64]; +} secp256k1_ecdsa_signature; + +/** A pointer to a function to deterministically generate a nonce. + * + * Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail. + * Out: nonce32: pointer to a 32-byte array to be filled by the function. + * In: msg32: the 32-byte message hash being verified (will not be NULL) + * key32: pointer to a 32-byte secret key (will not be NULL) + * algo16: pointer to a 16-byte array describing the signature + * algorithm (will be NULL for ECDSA for compatibility). + * data: Arbitrary data pointer that is passed through. + * attempt: how many iterations we have tried to find a nonce. + * This will almost always be 0, but different attempt values + * are required to result in a different nonce. + * + * Except for test cases, this function should compute some cryptographic hash of + * the message, the algorithm, the key and the attempt. + */ +typedef int (*secp256k1_nonce_function)( + unsigned char *nonce32, + const unsigned char *msg32, + const unsigned char *key32, + const unsigned char *algo16, + void *data, + unsigned int attempt +); # if !defined(SECP256K1_GNUC_PREREQ) # if defined(__GNUC__)&&defined(__GNUC_MINOR__) @@ -26,6 +113,20 @@ extern "C" { # define SECP256K1_INLINE inline # endif +#ifndef SECP256K1_API +# if defined(_WIN32) +# ifdef SECP256K1_BUILD +# define SECP256K1_API __declspec(dllexport) +# else +# define SECP256K1_API +# endif +# elif defined(__GNUC__) && defined(SECP256K1_BUILD) +# define SECP256K1_API __attribute__ ((visibility ("default"))) +# else +# define SECP256K1_API +# endif +#endif + /**Warning attributes * NONNULL is not used if SECP256K1_BUILD is set to avoid the compiler optimizing out * some paranoid null checks. */ @@ -40,320 +141,481 @@ extern "C" { # define SECP256K1_ARG_NONNULL(_x) # endif -/** Opaque data structure that holds context information (precomputed tables etc.). - * Only functions that take a pointer to a non-const context require exclusive - * access to it. Multiple functions that take a pointer to a const context may - * run simultaneously. - */ -typedef struct secp256k1_context_struct secp256k1_context_t; +/** All flags' lower 8 bits indicate what they're for. Do not use directly. */ +#define SECP256K1_FLAGS_TYPE_MASK ((1 << 8) - 1) +#define SECP256K1_FLAGS_TYPE_CONTEXT (1 << 0) +#define SECP256K1_FLAGS_TYPE_COMPRESSION (1 << 1) +/** The higher bits contain the actual data. Do not use directly. */ +#define SECP256K1_FLAGS_BIT_CONTEXT_VERIFY (1 << 8) +#define SECP256K1_FLAGS_BIT_CONTEXT_SIGN (1 << 9) +#define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8) /** Flags to pass to secp256k1_context_create. */ -# define SECP256K1_CONTEXT_VERIFY (1 << 0) -# define SECP256K1_CONTEXT_SIGN (1 << 1) +#define SECP256K1_CONTEXT_VERIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) +#define SECP256K1_CONTEXT_SIGN (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN) +#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT) + +/** Flag to pass to secp256k1_ec_pubkey_serialize and secp256k1_ec_privkey_export. */ +#define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION) +#define SECP256K1_EC_UNCOMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION) + +/** Prefix byte used to tag various encoded curvepoints for specific purposes */ +#define SECP256K1_TAG_PUBKEY_EVEN 0x02 +#define SECP256K1_TAG_PUBKEY_ODD 0x03 +#define SECP256K1_TAG_PUBKEY_UNCOMPRESSED 0x04 +#define SECP256K1_TAG_PUBKEY_HYBRID_EVEN 0x06 +#define SECP256K1_TAG_PUBKEY_HYBRID_ODD 0x07 /** Create a secp256k1 context object. + * * Returns: a newly created context object. * In: flags: which parts of the context to initialize. + * + * See also secp256k1_context_randomize. */ -secp256k1_context_t* secp256k1_context_create( - int flags +SECP256K1_API secp256k1_context* secp256k1_context_create( + unsigned int flags ) SECP256K1_WARN_UNUSED_RESULT; /** Copies a secp256k1 context object. + * * Returns: a newly created context object. - * In: ctx: an existing context to copy + * Args: ctx: an existing context to copy (cannot be NULL) */ -secp256k1_context_t* secp256k1_context_clone( - const secp256k1_context_t* ctx -) SECP256K1_WARN_UNUSED_RESULT; +SECP256K1_API secp256k1_context* secp256k1_context_clone( + const secp256k1_context* ctx +) SECP256K1_ARG_NONNULL(1) SECP256K1_WARN_UNUSED_RESULT; /** Destroy a secp256k1 context object. + * * The context pointer may not be used afterwards. + * Args: ctx: an existing context to destroy (cannot be NULL) */ -void secp256k1_context_destroy( - secp256k1_context_t* ctx +SECP256K1_API void secp256k1_context_destroy( + secp256k1_context* ctx +); + +/** Set a callback function to be called when an illegal argument is passed to + * an API call. It will only trigger for violations that are mentioned + * explicitly in the header. + * + * The philosophy is that these shouldn't be dealt with through a + * specific return value, as calling code should not have branches to deal with + * the case that this code itself is broken. + * + * On the other hand, during debug stage, one would want to be informed about + * such mistakes, and the default (crashing) may be inadvisable. + * When this callback is triggered, the API function called is guaranteed not + * to cause a crash, though its return value and output arguments are + * undefined. + * + * Args: ctx: an existing context object (cannot be NULL) + * In: fun: a pointer to a function to call when an illegal argument is + * passed to the API, taking a message and an opaque pointer + * (NULL restores a default handler that calls abort). + * data: the opaque pointer to pass to fun above. + */ +SECP256K1_API void secp256k1_context_set_illegal_callback( + secp256k1_context* ctx, + void (*fun)(const char* message, void* data), + const void* data ) SECP256K1_ARG_NONNULL(1); +/** Set a callback function to be called when an internal consistency check + * fails. The default is crashing. + * + * This can only trigger in case of a hardware failure, miscompilation, + * memory corruption, serious bug in the library, or other error would can + * otherwise result in undefined behaviour. It will not trigger due to mere + * incorrect usage of the API (see secp256k1_context_set_illegal_callback + * for that). After this callback returns, anything may happen, including + * crashing. + * + * Args: ctx: an existing context object (cannot be NULL) + * In: fun: a pointer to a function to call when an internal error occurs, + * taking a message and an opaque pointer (NULL restores a default + * handler that calls abort). + * data: the opaque pointer to pass to fun above. + */ +SECP256K1_API void secp256k1_context_set_error_callback( + secp256k1_context* ctx, + void (*fun)(const char* message, void* data), + const void* data +) SECP256K1_ARG_NONNULL(1); + +/** Parse a variable-length public key into the pubkey object. + * + * Returns: 1 if the public key was fully valid. + * 0 if the public key could not be parsed or is invalid. + * Args: ctx: a secp256k1 context object. + * Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a + * parsed version of input. If not, its value is undefined. + * In: input: pointer to a serialized public key + * inputlen: length of the array pointed to by input + * + * This function supports parsing compressed (33 bytes, header byte 0x02 or + * 0x03), uncompressed (65 bytes, header byte 0x04), or hybrid (65 bytes, header + * byte 0x06 or 0x07) format public keys. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse( + const secp256k1_context* ctx, + secp256k1_pubkey* pubkey, + const unsigned char *input, + size_t inputlen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize a pubkey object into a serialized byte sequence. + * + * Returns: 1 always. + * Args: ctx: a secp256k1 context object. + * Out: output: a pointer to a 65-byte (if compressed==0) or 33-byte (if + * compressed==1) byte array to place the serialized key + * in. + * In/Out: outputlen: a pointer to an integer which is initially set to the + * size of output, and is overwritten with the written + * size. + * In: pubkey: a pointer to a secp256k1_pubkey containing an + * initialized public key. + * flags: SECP256K1_EC_COMPRESSED if serialization should be in + * compressed format, otherwise SECP256K1_EC_UNCOMPRESSED. + */ +SECP256K1_API int secp256k1_ec_pubkey_serialize( + const secp256k1_context* ctx, + unsigned char *output, + size_t *outputlen, + const secp256k1_pubkey* pubkey, + unsigned int flags +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Parse an ECDSA signature in compact (64 bytes) format. + * + * Returns: 1 when the signature could be parsed, 0 otherwise. + * Args: ctx: a secp256k1 context object + * Out: sig: a pointer to a signature object + * In: input64: a pointer to the 64-byte array to parse + * + * The signature must consist of a 32-byte big endian R value, followed by a + * 32-byte big endian S value. If R or S fall outside of [0..order-1], the + * encoding is invalid. R and S with value 0 are allowed in the encoding. + * + * After the call, sig will always be initialized. If parsing failed or R or + * S are zero, the resulting sig value is guaranteed to fail validation for any + * message and public key. + */ +SECP256K1_API int secp256k1_ecdsa_signature_parse_compact( + const secp256k1_context* ctx, + secp256k1_ecdsa_signature* sig, + const unsigned char *input64 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Parse a DER ECDSA signature. + * + * Returns: 1 when the signature could be parsed, 0 otherwise. + * Args: ctx: a secp256k1 context object + * Out: sig: a pointer to a signature object + * In: input: a pointer to the signature to be parsed + * inputlen: the length of the array pointed to be input + * + * This function will accept any valid DER encoded signature, even if the + * encoded numbers are out of range. + * + * After the call, sig will always be initialized. If parsing failed or the + * encoded numbers are out of range, signature validation with it is + * guaranteed to fail for every message and public key. + */ +SECP256K1_API int secp256k1_ecdsa_signature_parse_der( + const secp256k1_context* ctx, + secp256k1_ecdsa_signature* sig, + const unsigned char *input, + size_t inputlen +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize an ECDSA signature in DER format. + * + * Returns: 1 if enough space was available to serialize, 0 otherwise + * Args: ctx: a secp256k1 context object + * Out: output: a pointer to an array to store the DER serialization + * In/Out: outputlen: a pointer to a length integer. Initially, this integer + * should be set to the length of output. After the call + * it will be set to the length of the serialization (even + * if 0 was returned). + * In: sig: a pointer to an initialized signature object + */ +SECP256K1_API int secp256k1_ecdsa_signature_serialize_der( + const secp256k1_context* ctx, + unsigned char *output, + size_t *outputlen, + const secp256k1_ecdsa_signature* sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Serialize an ECDSA signature in compact (64 byte) format. + * + * Returns: 1 + * Args: ctx: a secp256k1 context object + * Out: output64: a pointer to a 64-byte array to store the compact serialization + * In: sig: a pointer to an initialized signature object + * + * See secp256k1_ecdsa_signature_parse_compact for details about the encoding. + */ +SECP256K1_API int secp256k1_ecdsa_signature_serialize_compact( + const secp256k1_context* ctx, + unsigned char *output64, + const secp256k1_ecdsa_signature* sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + /** Verify an ECDSA signature. + * * Returns: 1: correct signature - * 0: incorrect signature - * -1: invalid public key - * -2: invalid signature - * In: ctx: a secp256k1 context object, initialized for verification. + * 0: incorrect or unparseable signature + * Args: ctx: a secp256k1 context object, initialized for verification. + * In: sig: the signature being verified (cannot be NULL) * msg32: the 32-byte message hash being verified (cannot be NULL) - * sig: the signature being verified (cannot be NULL) - * siglen: the length of the signature - * pubkey: the public key to verify with (cannot be NULL) - * pubkeylen: the length of pubkey + * pubkey: pointer to an initialized public key to verify with (cannot be NULL) + * + * To avoid accepting malleable signatures, only ECDSA signatures in lower-S + * form are accepted. + * + * If you need to accept ECDSA signatures from sources that do not obey this + * rule, apply secp256k1_ecdsa_signature_normalize to the signature prior to + * validation, but be aware that doing so results in malleable signatures. + * + * For details, see the comments for that function. */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify( - const secp256k1_context_t* ctx, - const unsigned char *msg32, - const unsigned char *sig, - int siglen, - const unsigned char *pubkey, - int pubkeylen -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5); +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify( + const secp256k1_context* ctx, + const secp256k1_ecdsa_signature *sig, + const unsigned char *msg32, + const secp256k1_pubkey *pubkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); -/** Check that signature is in canonical form - * Returns: 1: In canonical form - * 0: Non canonical - * -1: invalid signature - * In: sig: the signature being verified (cannot be NULL) - * siglen: the length of the signature +/** Convert a signature to a normalized lower-S form. + * + * Returns: 1 if sigin was not normalized, 0 if it already was. + * Args: ctx: a secp256k1 context object + * Out: sigout: a pointer to a signature to fill with the normalized form, + * or copy if the input was already normalized. (can be NULL if + * you're only interested in whether the input was already + * normalized). + * In: sigin: a pointer to a signature to check/normalize (cannot be NULL, + * can be identical to sigout) + * + * With ECDSA a third-party can forge a second distinct signature of the same + * message, given a single initial signature, but without knowing the key. This + * is done by negating the S value modulo the order of the curve, 'flipping' + * the sign of the random point R which is not included in the signature. + * + * Forgery of the same message isn't universally problematic, but in systems + * where message malleability or uniqueness of signatures is important this can + * cause issues. This forgery can be blocked by all verifiers forcing signers + * to use a normalized form. + * + * The lower-S form reduces the size of signatures slightly on average when + * variable length encodings (such as DER) are used and is cheap to verify, + * making it a good choice. Security of always using lower-S is assured because + * anyone can trivially modify a signature after the fact to enforce this + * property anyway. + * + * The lower S value is always between 0x1 and + * 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, + * inclusive. + * + * No other forms of ECDSA malleability are known and none seem likely, but + * there is no formal proof that ECDSA, even with this additional restriction, + * is free of other malleability. Commonly used serialization schemes will also + * accept various non-unique encodings, so care should be taken when this + * property is required for an application. + * + * The secp256k1_ecdsa_sign function will by default create signatures in the + * lower-S form, and secp256k1_ecdsa_verify will not accept others. In case + * signatures come from a system that cannot enforce this property, + * secp256k1_ecdsa_signature_normalize must be called before verification. */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_check_canonical_sig( - const unsigned char *sig, - int siglen -) SECP256K1_ARG_NONNULL(1); - -/** A pointer to a function to deterministically generate a nonce. - * Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail. - * In: msg32: the 32-byte message hash being verified (will not be NULL) - * key32: pointer to a 32-byte secret key (will not be NULL) - * attempt: how many iterations we have tried to find a nonce. - * This will almost always be 0, but different attempt values - * are required to result in a different nonce. - * data: Arbitrary data pointer that is passed through. - * Out: nonce32: pointer to a 32-byte array to be filled by the function. - * Except for test cases, this function should compute some cryptographic hash of - * the message, the key and the attempt. - */ -typedef int (*secp256k1_nonce_function_t)( - unsigned char *nonce32, - const unsigned char *msg32, - const unsigned char *key32, - unsigned int attempt, - const void *data -); +SECP256K1_API int secp256k1_ecdsa_signature_normalize( + const secp256k1_context* ctx, + secp256k1_ecdsa_signature *sigout, + const secp256k1_ecdsa_signature *sigin +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(3); /** An implementation of RFC6979 (using HMAC-SHA256) as nonce generation function. * If a data pointer is passed, it is assumed to be a pointer to 32 bytes of * extra entropy. */ -extern const secp256k1_nonce_function_t secp256k1_nonce_function_rfc6979; +SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_rfc6979; /** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */ -extern const secp256k1_nonce_function_t secp256k1_nonce_function_default; - +SECP256K1_API extern const secp256k1_nonce_function secp256k1_nonce_function_default; /** Create an ECDSA signature. - * Returns: 1: signature created - * 0: the nonce generation function failed, the private key was invalid, or there is not - * enough space in the signature (as indicated by siglen). - * In: ctx: pointer to a context object, initialized for signing (cannot be NULL) - * msg32: the 32-byte message hash being signed (cannot be NULL) - * seckey: pointer to a 32-byte secret key (cannot be NULL) - * noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used - * ndata: pointer to arbitrary data used by the nonce generation function (can be NULL) - * Out: sig: pointer to an array where the signature will be placed (cannot be NULL) - * In/Out: siglen: pointer to an int with the length of sig, which will be updated - * to contain the actual signature length (<=72). * - * The sig always has an s value in the lower half of the range (From 0x1 - * to 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, - * inclusive), unlike many other implementations. - * With ECDSA a third-party can can forge a second distinct signature - * of the same message given a single initial signature without knowing - * the key by setting s to its additive inverse mod-order, 'flipping' the - * sign of the random point R which is not included in the signature. - * Since the forgery is of the same message this isn't universally - * problematic, but in systems where message malleability or uniqueness - * of signatures is important this can cause issues. This forgery can be - * blocked by all verifiers forcing signers to use a canonical form. The - * lower-S form reduces the size of signatures slightly on average when - * variable length encodings (such as DER) are used and is cheap to - * verify, making it a good choice. Security of always using lower-S is - * assured because anyone can trivially modify a signature after the - * fact to enforce this property. Adjusting it inside the signing - * function avoids the need to re-serialize or have curve specific - * constants outside of the library. By always using a canonical form - * even in applications where it isn't needed it becomes possible to - * impose a requirement later if a need is discovered. - * No other forms of ECDSA malleability are known and none seem likely, - * but there is no formal proof that ECDSA, even with this additional - * restriction, is free of other malleability. Commonly used serialization - * schemes will also accept various non-unique encodings, so care should - * be taken when this property is required for an application. - */ -int secp256k1_ecdsa_sign( - const secp256k1_context_t* ctx, - const unsigned char *msg32, - unsigned char *sig, - int *siglen, - const unsigned char *seckey, - secp256k1_nonce_function_t noncefp, - const void *ndata -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); - -/** Create a compact ECDSA signature (64 byte + recovery id). * Returns: 1: signature created - * 0: the nonce generation function failed, or the secret key was invalid. - * In: ctx: pointer to a context object, initialized for signing (cannot be NULL) - * msg32: the 32-byte message hash being signed (cannot be NULL) + * 0: the nonce generation function failed, or the private key was invalid. + * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) + * Out: sig: pointer to an array where the signature will be placed (cannot be NULL) + * In: msg32: the 32-byte message hash being signed (cannot be NULL) * seckey: pointer to a 32-byte secret key (cannot be NULL) * noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used * ndata: pointer to arbitrary data used by the nonce generation function (can be NULL) - * Out: sig: pointer to a 64-byte array where the signature will be placed (cannot be NULL) - * In case 0 is returned, the returned signature length will be zero. - * recid: pointer to an int, which will be updated to contain the recovery id (can be NULL) + * + * The created signature is always in lower-S form. See + * secp256k1_ecdsa_signature_normalize for more details. */ -int secp256k1_ecdsa_sign_compact( - const secp256k1_context_t* ctx, - const unsigned char *msg32, - unsigned char *sig64, - const unsigned char *seckey, - secp256k1_nonce_function_t noncefp, - const void *ndata, - int *recid +SECP256K1_API int secp256k1_ecdsa_sign( + const secp256k1_context* ctx, + secp256k1_ecdsa_signature *sig, + const unsigned char *msg32, + const unsigned char *seckey, + secp256k1_nonce_function noncefp, + const void *ndata ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); -/** Recover an ECDSA public key from a compact signature. - * Returns: 1: public key successfully recovered (which guarantees a correct signature). - * 0: otherwise. - * In: ctx: pointer to a context object, initialized for verification (cannot be NULL) - * msg32: the 32-byte message hash assumed to be signed (cannot be NULL) - * sig64: signature as 64 byte array (cannot be NULL) - * compressed: whether to recover a compressed or uncompressed pubkey - * recid: the recovery id (0-3, as returned by ecdsa_sign_compact) - * Out: pubkey: pointer to a 33 or 65 byte array to put the pubkey (cannot be NULL) - * pubkeylen: pointer to an int that will contain the pubkey length (cannot be NULL) - */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover_compact( - const secp256k1_context_t* ctx, - const unsigned char *msg32, - const unsigned char *sig64, - unsigned char *pubkey, - int *pubkeylen, - int compressed, - int recid -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5); - /** Verify an ECDSA secret key. + * * Returns: 1: secret key is valid * 0: secret key is invalid - * In: ctx: pointer to a context object (cannot be NULL) - * seckey: pointer to a 32-byte secret key (cannot be NULL) + * Args: ctx: pointer to a context object (cannot be NULL) + * In: seckey: pointer to a 32-byte secret key (cannot be NULL) */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify( - const secp256k1_context_t* ctx, - const unsigned char *seckey -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); - -/** Just validate a public key. - * Returns: 1: public key is valid - * 0: public key is invalid - * In: ctx: pointer to a context object (cannot be NULL) - * pubkey: pointer to a 33-byte or 65-byte public key (cannot be NULL). - * pubkeylen: length of pubkey - */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_verify( - const secp256k1_context_t* ctx, - const unsigned char *pubkey, - int pubkeylen +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify( + const secp256k1_context* ctx, + const unsigned char *seckey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); /** Compute the public key for a secret key. - * In: ctx: pointer to a context object, initialized for signing (cannot be NULL) - * compressed: whether the computed public key should be compressed - * seckey: pointer to a 32-byte private key (cannot be NULL) - * Out: pubkey: pointer to a 33-byte (if compressed) or 65-byte (if uncompressed) - * area to store the public key (cannot be NULL) - * pubkeylen: pointer to int that will be updated to contains the pubkey's - * length (cannot be NULL) + * * Returns: 1: secret was valid, public key stores * 0: secret was invalid, try again + * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) + * Out: pubkey: pointer to the created public key (cannot be NULL) + * In: seckey: pointer to a 32-byte private key (cannot be NULL) */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create( - const secp256k1_context_t* ctx, - unsigned char *pubkey, - int *pubkeylen, - const unsigned char *seckey, - int compressed -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); - -/** Decompress a public key. - * In: ctx: pointer to a context object (cannot be NULL) - * In/Out: pubkey: pointer to a 65-byte array to put the decompressed public key. - * It must contain a 33-byte or 65-byte public key already (cannot be NULL) - * pubkeylen: pointer to the size of the public key pointed to by pubkey (cannot be NULL) - * It will be updated to reflect the new size. - * Returns: 0: pubkey was invalid - * 1: pubkey was valid, and was replaced with its decompressed version - */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_decompress( - const secp256k1_context_t* ctx, - unsigned char *pubkey, - int *pubkeylen +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create( + const secp256k1_context* ctx, + secp256k1_pubkey *pubkey, + const unsigned char *seckey ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Export a private key in DER format. - * In: ctx: pointer to a context object, initialized for signing (cannot be NULL) +/** Negates a private key in place. + * + * Returns: 1 always + * Args: ctx: pointer to a context object + * In/Out: pubkey: pointer to the public key to be negated (cannot be NULL) */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_export( - const secp256k1_context_t* ctx, - const unsigned char *seckey, - unsigned char *privkey, - int *privkeylen, - int compressed -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_negate( + const secp256k1_context* ctx, + unsigned char *seckey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); -/** Import a private key in DER format. */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_import( - const secp256k1_context_t* ctx, - unsigned char *seckey, - const unsigned char *privkey, - int privkeylen -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); +/** Negates a public key in place. + * + * Returns: 1 always + * Args: ctx: pointer to a context object + * In/Out: pubkey: pointer to the public key to be negated (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_negate( + const secp256k1_context* ctx, + secp256k1_pubkey *pubkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); -/** Tweak a private key by adding tweak to it. */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add( - const secp256k1_context_t* ctx, - unsigned char *seckey, - const unsigned char *tweak +/** Tweak a private key by adding tweak to it. + * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for + * uniformly random 32-byte arrays, or if the resulting private key + * would be invalid (only when the tweak is the complement of the + * private key). 1 otherwise. + * Args: ctx: pointer to a context object (cannot be NULL). + * In/Out: seckey: pointer to a 32-byte private key. + * In: tweak: pointer to a 32-byte tweak. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add( + const secp256k1_context* ctx, + unsigned char *seckey, + const unsigned char *tweak ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); /** Tweak a public key by adding tweak times the generator to it. - * In: ctx: pointer to a context object, initialized for verification (cannot be NULL) + * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for + * uniformly random 32-byte arrays, or if the resulting public key + * would be invalid (only when the tweak is the complement of the + * corresponding private key). 1 otherwise. + * Args: ctx: pointer to a context object initialized for validation + * (cannot be NULL). + * In/Out: pubkey: pointer to a public key object. + * In: tweak: pointer to a 32-byte tweak. */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add( - const secp256k1_context_t* ctx, - unsigned char *pubkey, - int pubkeylen, - const unsigned char *tweak -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); - -/** Tweak a private key by multiplying it with tweak. */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul( - const secp256k1_context_t* ctx, - unsigned char *seckey, - const unsigned char *tweak +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add( + const secp256k1_context* ctx, + secp256k1_pubkey *pubkey, + const unsigned char *tweak ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Tweak a public key by multiplying it with tweak. - * In: ctx: pointer to a context object, initialized for verification (cannot be NULL) +/** Tweak a private key by multiplying it by a tweak. + * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for + * uniformly random 32-byte arrays, or equal to zero. 1 otherwise. + * Args: ctx: pointer to a context object (cannot be NULL). + * In/Out: seckey: pointer to a 32-byte private key. + * In: tweak: pointer to a 32-byte tweak. */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul( - const secp256k1_context_t* ctx, - unsigned char *pubkey, - int pubkeylen, - const unsigned char *tweak -) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul( + const secp256k1_context* ctx, + unsigned char *seckey, + const unsigned char *tweak +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -/** Updates the context randomization. +/** Tweak a public key by multiplying it by a tweak value. + * Returns: 0 if the tweak was out of range (chance of around 1 in 2^128 for + * uniformly random 32-byte arrays, or equal to zero. 1 otherwise. + * Args: ctx: pointer to a context object initialized for validation + * (cannot be NULL). + * In/Out: pubkey: pointer to a public key obkect. + * In: tweak: pointer to a 32-byte tweak. + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul( + const secp256k1_context* ctx, + secp256k1_pubkey *pubkey, + const unsigned char *tweak +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Updates the context randomization to protect against side-channel leakage. * Returns: 1: randomization successfully updated * 0: error - * In: ctx: pointer to a context object (cannot be NULL) - * seed32: pointer to a 32-byte random seed (NULL resets to initial state) + * Args: ctx: pointer to a context object (cannot be NULL) + * In: seed32: pointer to a 32-byte random seed (NULL resets to initial state) + * + * While secp256k1 code is written to be constant-time no matter what secret + * values are, it's possible that a future compiler may output code which isn't, + * and also that the CPU may not emit the same radio frequencies or draw the same + * amount power for all values. + * + * This function provides a seed which is combined into the blinding value: that + * blinding value is added before each multiplication (and removed afterwards) so + * that it does not affect function results, but shields against attacks which + * rely on any input-dependent behaviour. + * + * You should call this after secp256k1_context_create or + * secp256k1_context_clone, and may call this repeatedly afterwards. */ -SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize( - secp256k1_context_t* ctx, - const unsigned char *seed32 +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_context_randomize( + secp256k1_context* ctx, + const unsigned char *seed32 ) SECP256K1_ARG_NONNULL(1); +/** Add a number of public keys together. + * Returns: 1: the sum of the public keys is valid. + * 0: the sum of the public keys is not valid. + * Args: ctx: pointer to a context object + * Out: out: pointer to a public key object for placing the resulting public key + * (cannot be NULL) + * In: ins: pointer to array of pointers to public keys (cannot be NULL) + * n: the number of public keys to add together (must be at least 1) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine( + const secp256k1_context* ctx, + secp256k1_pubkey *out, + const secp256k1_pubkey * const * ins, + size_t n +) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); -# ifdef __cplusplus +#ifdef __cplusplus } -# endif - #endif + +#endif /* SECP256K1_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/include/secp256k1_ecdh.h b/src/cryptoconditions/src/include/secp256k1/include/secp256k1_ecdh.h new file mode 100644 index 000000000..88492dc1a --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/include/secp256k1_ecdh.h @@ -0,0 +1,31 @@ +#ifndef SECP256K1_ECDH_H +#define SECP256K1_ECDH_H + +#include "secp256k1.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Compute an EC Diffie-Hellman secret in constant time + * Returns: 1: exponentiation was successful + * 0: scalar was invalid (zero or overflow) + * Args: ctx: pointer to a context object (cannot be NULL) + * Out: result: a 32-byte array which will be populated by an ECDH + * secret computed from the point and scalar + * In: pubkey: a pointer to a secp256k1_pubkey containing an + * initialized public key + * privkey: a 32-byte scalar with which to multiply the point + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdh( + const secp256k1_context* ctx, + unsigned char *result, + const secp256k1_pubkey *pubkey, + const unsigned char *privkey +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_ECDH_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/include/secp256k1_recovery.h b/src/cryptoconditions/src/include/secp256k1/include/secp256k1_recovery.h new file mode 100644 index 000000000..cf6c5ed7f --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/include/secp256k1_recovery.h @@ -0,0 +1,110 @@ +#ifndef SECP256K1_RECOVERY_H +#define SECP256K1_RECOVERY_H + +#include "secp256k1.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Opaque data structured that holds a parsed ECDSA signature, + * supporting pubkey recovery. + * + * The exact representation of data inside is implementation defined and not + * guaranteed to be portable between different platforms or versions. It is + * however guaranteed to be 65 bytes in size, and can be safely copied/moved. + * If you need to convert to a format suitable for storage or transmission, use + * the secp256k1_ecdsa_signature_serialize_* and + * secp256k1_ecdsa_signature_parse_* functions. + * + * Furthermore, it is guaranteed that identical signatures (including their + * recoverability) will have identical representation, so they can be + * memcmp'ed. + */ +typedef struct { + unsigned char data[65]; +} secp256k1_ecdsa_recoverable_signature; + +/** Parse a compact ECDSA signature (64 bytes + recovery id). + * + * Returns: 1 when the signature could be parsed, 0 otherwise + * Args: ctx: a secp256k1 context object + * Out: sig: a pointer to a signature object + * In: input64: a pointer to a 64-byte compact signature + * recid: the recovery id (0, 1, 2 or 3) + */ +SECP256K1_API int secp256k1_ecdsa_recoverable_signature_parse_compact( + const secp256k1_context* ctx, + secp256k1_ecdsa_recoverable_signature* sig, + const unsigned char *input64, + int recid +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Convert a recoverable signature into a normal signature. + * + * Returns: 1 + * Out: sig: a pointer to a normal signature (cannot be NULL). + * In: sigin: a pointer to a recoverable signature (cannot be NULL). + */ +SECP256K1_API int secp256k1_ecdsa_recoverable_signature_convert( + const secp256k1_context* ctx, + secp256k1_ecdsa_signature* sig, + const secp256k1_ecdsa_recoverable_signature* sigin +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3); + +/** Serialize an ECDSA signature in compact format (64 bytes + recovery id). + * + * Returns: 1 + * Args: ctx: a secp256k1 context object + * Out: output64: a pointer to a 64-byte array of the compact signature (cannot be NULL) + * recid: a pointer to an integer to hold the recovery id (can be NULL). + * In: sig: a pointer to an initialized signature object (cannot be NULL) + */ +SECP256K1_API int secp256k1_ecdsa_recoverable_signature_serialize_compact( + const secp256k1_context* ctx, + unsigned char *output64, + int *recid, + const secp256k1_ecdsa_recoverable_signature* sig +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Create a recoverable ECDSA signature. + * + * Returns: 1: signature created + * 0: the nonce generation function failed, or the private key was invalid. + * Args: ctx: pointer to a context object, initialized for signing (cannot be NULL) + * Out: sig: pointer to an array where the signature will be placed (cannot be NULL) + * In: msg32: the 32-byte message hash being signed (cannot be NULL) + * seckey: pointer to a 32-byte secret key (cannot be NULL) + * noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used + * ndata: pointer to arbitrary data used by the nonce generation function (can be NULL) + */ +SECP256K1_API int secp256k1_ecdsa_sign_recoverable( + const secp256k1_context* ctx, + secp256k1_ecdsa_recoverable_signature *sig, + const unsigned char *msg32, + const unsigned char *seckey, + secp256k1_nonce_function noncefp, + const void *ndata +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +/** Recover an ECDSA public key from a signature. + * + * Returns: 1: public key successfully recovered (which guarantees a correct signature). + * 0: otherwise. + * Args: ctx: pointer to a context object, initialized for verification (cannot be NULL) + * Out: pubkey: pointer to the recovered public key (cannot be NULL) + * In: sig: pointer to initialized signature that supports pubkey recovery (cannot be NULL) + * msg32: the 32-byte message hash assumed to be signed (cannot be NULL) + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover( + const secp256k1_context* ctx, + secp256k1_pubkey *pubkey, + const secp256k1_ecdsa_recoverable_signature *sig, + const unsigned char *msg32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4); + +#ifdef __cplusplus +} +#endif + +#endif /* SECP256K1_RECOVERY_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/libsecp256k1.pc.in b/src/cryptoconditions/src/include/secp256k1/libsecp256k1.pc.in index 1c72dd000..a0d006f11 100644 --- a/src/cryptoconditions/src/include/secp256k1/libsecp256k1.pc.in +++ b/src/cryptoconditions/src/include/secp256k1/libsecp256k1.pc.in @@ -5,7 +5,7 @@ includedir=@includedir@ Name: libsecp256k1 Description: Optimized C library for EC operations on curve secp256k1 -URL: https://github.com/bitcoin/secp256k1 +URL: https://github.com/bitcoin-core/secp256k1 Version: @PACKAGE_VERSION@ Cflags: -I${includedir} Libs.private: @SECP_LIBS@ diff --git a/src/cryptoconditions/src/include/secp256k1/sage/group_prover.sage b/src/cryptoconditions/src/include/secp256k1/sage/group_prover.sage new file mode 100644 index 000000000..8521f0799 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/sage/group_prover.sage @@ -0,0 +1,322 @@ +# This code supports verifying group implementations which have branches +# or conditional statements (like cmovs), by allowing each execution path +# to independently set assumptions on input or intermediary variables. +# +# The general approach is: +# * A constraint is a tuple of two sets of symbolic expressions: +# the first of which are required to evaluate to zero, the second of which +# are required to evaluate to nonzero. +# - A constraint is said to be conflicting if any of its nonzero expressions +# is in the ideal with basis the zero expressions (in other words: when the +# zero expressions imply that one of the nonzero expressions are zero). +# * There is a list of laws that describe the intended behaviour, including +# laws for addition and doubling. Each law is called with the symbolic point +# coordinates as arguments, and returns: +# - A constraint describing the assumptions under which it is applicable, +# called "assumeLaw" +# - A constraint describing the requirements of the law, called "require" +# * Implementations are transliterated into functions that operate as well on +# algebraic input points, and are called once per combination of branches +# executed. Each execution returns: +# - A constraint describing the assumptions this implementation requires +# (such as Z1=1), called "assumeFormula" +# - A constraint describing the assumptions this specific branch requires, +# but which is by construction guaranteed to cover the entire space by +# merging the results from all branches, called "assumeBranch" +# - The result of the computation +# * All combinations of laws with implementation branches are tried, and: +# - If the combination of assumeLaw, assumeFormula, and assumeBranch results +# in a conflict, it means this law does not apply to this branch, and it is +# skipped. +# - For others, we try to prove the require constraints hold, assuming the +# information in assumeLaw + assumeFormula + assumeBranch, and if this does +# not succeed, we fail. +# + To prove an expression is zero, we check whether it belongs to the +# ideal with the assumed zero expressions as basis. This test is exact. +# + To prove an expression is nonzero, we check whether each of its +# factors is contained in the set of nonzero assumptions' factors. +# This test is not exact, so various combinations of original and +# reduced expressions' factors are tried. +# - If we succeed, we print out the assumptions from assumeFormula that +# weren't implied by assumeLaw already. Those from assumeBranch are skipped, +# as we assume that all constraints in it are complementary with each other. +# +# Based on the sage verification scripts used in the Explicit-Formulas Database +# by Tanja Lange and others, see http://hyperelliptic.org/EFD + +class fastfrac: + """Fractions over rings.""" + + def __init__(self,R,top,bot=1): + """Construct a fractional, given a ring, a numerator, and denominator.""" + self.R = R + if parent(top) == ZZ or parent(top) == R: + self.top = R(top) + self.bot = R(bot) + elif top.__class__ == fastfrac: + self.top = top.top + self.bot = top.bot * bot + else: + self.top = R(numerator(top)) + self.bot = R(denominator(top)) * bot + + def iszero(self,I): + """Return whether this fraction is zero given an ideal.""" + return self.top in I and self.bot not in I + + def reduce(self,assumeZero): + zero = self.R.ideal(map(numerator, assumeZero)) + return fastfrac(self.R, zero.reduce(self.top)) / fastfrac(self.R, zero.reduce(self.bot)) + + def __add__(self,other): + """Add two fractions.""" + if parent(other) == ZZ: + return fastfrac(self.R,self.top + self.bot * other,self.bot) + if other.__class__ == fastfrac: + return fastfrac(self.R,self.top * other.bot + self.bot * other.top,self.bot * other.bot) + return NotImplemented + + def __sub__(self,other): + """Subtract two fractions.""" + if parent(other) == ZZ: + return fastfrac(self.R,self.top - self.bot * other,self.bot) + if other.__class__ == fastfrac: + return fastfrac(self.R,self.top * other.bot - self.bot * other.top,self.bot * other.bot) + return NotImplemented + + def __neg__(self): + """Return the negation of a fraction.""" + return fastfrac(self.R,-self.top,self.bot) + + def __mul__(self,other): + """Multiply two fractions.""" + if parent(other) == ZZ: + return fastfrac(self.R,self.top * other,self.bot) + if other.__class__ == fastfrac: + return fastfrac(self.R,self.top * other.top,self.bot * other.bot) + return NotImplemented + + def __rmul__(self,other): + """Multiply something else with a fraction.""" + return self.__mul__(other) + + def __div__(self,other): + """Divide two fractions.""" + if parent(other) == ZZ: + return fastfrac(self.R,self.top,self.bot * other) + if other.__class__ == fastfrac: + return fastfrac(self.R,self.top * other.bot,self.bot * other.top) + return NotImplemented + + def __pow__(self,other): + """Compute a power of a fraction.""" + if parent(other) == ZZ: + if other < 0: + # Negative powers require flipping top and bottom + return fastfrac(self.R,self.bot ^ (-other),self.top ^ (-other)) + else: + return fastfrac(self.R,self.top ^ other,self.bot ^ other) + return NotImplemented + + def __str__(self): + return "fastfrac((" + str(self.top) + ") / (" + str(self.bot) + "))" + def __repr__(self): + return "%s" % self + + def numerator(self): + return self.top + +class constraints: + """A set of constraints, consisting of zero and nonzero expressions. + + Constraints can either be used to express knowledge or a requirement. + + Both the fields zero and nonzero are maps from expressions to description + strings. The expressions that are the keys in zero are required to be zero, + and the expressions that are the keys in nonzero are required to be nonzero. + + Note that (a != 0) and (b != 0) is the same as (a*b != 0), so all keys in + nonzero could be multiplied into a single key. This is often much less + efficient to work with though, so we keep them separate inside the + constraints. This allows higher-level code to do fast checks on the individual + nonzero elements, or combine them if needed for stronger checks. + + We can't multiply the different zero elements, as it would suffice for one of + the factors to be zero, instead of all of them. Instead, the zero elements are + typically combined into an ideal first. + """ + + def __init__(self, **kwargs): + if 'zero' in kwargs: + self.zero = dict(kwargs['zero']) + else: + self.zero = dict() + if 'nonzero' in kwargs: + self.nonzero = dict(kwargs['nonzero']) + else: + self.nonzero = dict() + + def negate(self): + return constraints(zero=self.nonzero, nonzero=self.zero) + + def __add__(self, other): + zero = self.zero.copy() + zero.update(other.zero) + nonzero = self.nonzero.copy() + nonzero.update(other.nonzero) + return constraints(zero=zero, nonzero=nonzero) + + def __str__(self): + return "constraints(zero=%s,nonzero=%s)" % (self.zero, self.nonzero) + + def __repr__(self): + return "%s" % self + + +def conflicts(R, con): + """Check whether any of the passed non-zero assumptions is implied by the zero assumptions""" + zero = R.ideal(map(numerator, con.zero)) + if 1 in zero: + return True + # First a cheap check whether any of the individual nonzero terms conflict on + # their own. + for nonzero in con.nonzero: + if nonzero.iszero(zero): + return True + # It can be the case that entries in the nonzero set do not individually + # conflict with the zero set, but their combination does. For example, knowing + # that either x or y is zero is equivalent to having x*y in the zero set. + # Having x or y individually in the nonzero set is not a conflict, but both + # simultaneously is, so that is the right thing to check for. + if reduce(lambda a,b: a * b, con.nonzero, fastfrac(R, 1)).iszero(zero): + return True + return False + + +def get_nonzero_set(R, assume): + """Calculate a simple set of nonzero expressions""" + zero = R.ideal(map(numerator, assume.zero)) + nonzero = set() + for nz in map(numerator, assume.nonzero): + for (f,n) in nz.factor(): + nonzero.add(f) + rnz = zero.reduce(nz) + for (f,n) in rnz.factor(): + nonzero.add(f) + return nonzero + + +def prove_nonzero(R, exprs, assume): + """Check whether an expression is provably nonzero, given assumptions""" + zero = R.ideal(map(numerator, assume.zero)) + nonzero = get_nonzero_set(R, assume) + expl = set() + ok = True + for expr in exprs: + if numerator(expr) in zero: + return (False, [exprs[expr]]) + allexprs = reduce(lambda a,b: numerator(a)*numerator(b), exprs, 1) + for (f, n) in allexprs.factor(): + if f not in nonzero: + ok = False + if ok: + return (True, None) + ok = True + for (f, n) in zero.reduce(numerator(allexprs)).factor(): + if f not in nonzero: + ok = False + if ok: + return (True, None) + ok = True + for expr in exprs: + for (f,n) in numerator(expr).factor(): + if f not in nonzero: + ok = False + if ok: + return (True, None) + ok = True + for expr in exprs: + for (f,n) in zero.reduce(numerator(expr)).factor(): + if f not in nonzero: + expl.add(exprs[expr]) + if expl: + return (False, list(expl)) + else: + return (True, None) + + +def prove_zero(R, exprs, assume): + """Check whether all of the passed expressions are provably zero, given assumptions""" + r, e = prove_nonzero(R, dict(map(lambda x: (fastfrac(R, x.bot, 1), exprs[x]), exprs)), assume) + if not r: + return (False, map(lambda x: "Possibly zero denominator: %s" % x, e)) + zero = R.ideal(map(numerator, assume.zero)) + nonzero = prod(x for x in assume.nonzero) + expl = [] + for expr in exprs: + if not expr.iszero(zero): + expl.append(exprs[expr]) + if not expl: + return (True, None) + return (False, expl) + + +def describe_extra(R, assume, assumeExtra): + """Describe what assumptions are added, given existing assumptions""" + zerox = assume.zero.copy() + zerox.update(assumeExtra.zero) + zero = R.ideal(map(numerator, assume.zero)) + zeroextra = R.ideal(map(numerator, zerox)) + nonzero = get_nonzero_set(R, assume) + ret = set() + # Iterate over the extra zero expressions + for base in assumeExtra.zero: + if base not in zero: + add = [] + for (f, n) in numerator(base).factor(): + if f not in nonzero: + add += ["%s" % f] + if add: + ret.add((" * ".join(add)) + " = 0 [%s]" % assumeExtra.zero[base]) + # Iterate over the extra nonzero expressions + for nz in assumeExtra.nonzero: + nzr = zeroextra.reduce(numerator(nz)) + if nzr not in zeroextra: + for (f,n) in nzr.factor(): + if zeroextra.reduce(f) not in nonzero: + ret.add("%s != 0" % zeroextra.reduce(f)) + return ", ".join(x for x in ret) + + +def check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require): + """Check a set of zero and nonzero requirements, given a set of zero and nonzero assumptions""" + assume = assumeLaw + assumeAssert + assumeBranch + + if conflicts(R, assume): + # This formula does not apply + return None + + describe = describe_extra(R, assumeLaw + assumeBranch, assumeAssert) + + ok, msg = prove_zero(R, require.zero, assume) + if not ok: + return "FAIL, %s fails (assuming %s)" % (str(msg), describe) + + res, expl = prove_nonzero(R, require.nonzero, assume) + if not res: + return "FAIL, %s fails (assuming %s)" % (str(expl), describe) + + if describe != "": + return "OK (assuming %s)" % describe + else: + return "OK" + + +def concrete_verify(c): + for k in c.zero: + if k != 0: + return (False, c.zero[k]) + for k in c.nonzero: + if k == 0: + return (False, c.nonzero[k]) + return (True, None) diff --git a/src/cryptoconditions/src/include/secp256k1/sage/secp256k1.sage b/src/cryptoconditions/src/include/secp256k1/sage/secp256k1.sage new file mode 100644 index 000000000..a97e732f7 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/sage/secp256k1.sage @@ -0,0 +1,306 @@ +# Test libsecp256k1' group operation implementations using prover.sage + +import sys + +load("group_prover.sage") +load("weierstrass_prover.sage") + +def formula_secp256k1_gej_double_var(a): + """libsecp256k1's secp256k1_gej_double_var, used by various addition functions""" + rz = a.Z * a.Y + rz = rz * 2 + t1 = a.X^2 + t1 = t1 * 3 + t2 = t1^2 + t3 = a.Y^2 + t3 = t3 * 2 + t4 = t3^2 + t4 = t4 * 2 + t3 = t3 * a.X + rx = t3 + rx = rx * 4 + rx = -rx + rx = rx + t2 + t2 = -t2 + t3 = t3 * 6 + t3 = t3 + t2 + ry = t1 * t3 + t2 = -t4 + ry = ry + t2 + return jacobianpoint(rx, ry, rz) + +def formula_secp256k1_gej_add_var(branch, a, b): + """libsecp256k1's secp256k1_gej_add_var""" + if branch == 0: + return (constraints(), constraints(nonzero={a.Infinity : 'a_infinite'}), b) + if branch == 1: + return (constraints(), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a) + z22 = b.Z^2 + z12 = a.Z^2 + u1 = a.X * z22 + u2 = b.X * z12 + s1 = a.Y * z22 + s1 = s1 * b.Z + s2 = b.Y * z12 + s2 = s2 * a.Z + h = -u1 + h = h + u2 + i = -s1 + i = i + s2 + if branch == 2: + r = formula_secp256k1_gej_double_var(a) + return (constraints(), constraints(zero={h : 'h=0', i : 'i=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}), r) + if branch == 3: + return (constraints(), constraints(zero={h : 'h=0', a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={i : 'i!=0'}), point_at_infinity()) + i2 = i^2 + h2 = h^2 + h3 = h2 * h + h = h * b.Z + rz = a.Z * h + t = u1 * h2 + rx = t + rx = rx * 2 + rx = rx + h3 + rx = -rx + rx = rx + i2 + ry = -rx + ry = ry + t + ry = ry * i + h3 = h3 * s1 + h3 = -h3 + ry = ry + h3 + return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) + +def formula_secp256k1_gej_add_ge_var(branch, a, b): + """libsecp256k1's secp256k1_gej_add_ge_var, which assume bz==1""" + if branch == 0: + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(nonzero={a.Infinity : 'a_infinite'}), b) + if branch == 1: + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite'}, nonzero={b.Infinity : 'b_infinite'}), a) + z12 = a.Z^2 + u1 = a.X + u2 = b.X * z12 + s1 = a.Y + s2 = b.Y * z12 + s2 = s2 * a.Z + h = -u1 + h = h + u2 + i = -s1 + i = i + s2 + if (branch == 2): + r = formula_secp256k1_gej_double_var(a) + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r) + if (branch == 3): + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity()) + i2 = i^2 + h2 = h^2 + h3 = h * h2 + rz = a.Z * h + t = u1 * h2 + rx = t + rx = rx * 2 + rx = rx + h3 + rx = -rx + rx = rx + i2 + ry = -rx + ry = ry + t + ry = ry * i + h3 = h3 * s1 + h3 = -h3 + ry = ry + h3 + return (constraints(zero={b.Z - 1 : 'b.z=1'}), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) + +def formula_secp256k1_gej_add_zinv_var(branch, a, b): + """libsecp256k1's secp256k1_gej_add_zinv_var""" + bzinv = b.Z^(-1) + if branch == 0: + return (constraints(), constraints(nonzero={b.Infinity : 'b_infinite'}), a) + if branch == 1: + bzinv2 = bzinv^2 + bzinv3 = bzinv2 * bzinv + rx = b.X * bzinv2 + ry = b.Y * bzinv3 + rz = 1 + return (constraints(), constraints(zero={b.Infinity : 'b_finite'}, nonzero={a.Infinity : 'a_infinite'}), jacobianpoint(rx, ry, rz)) + azz = a.Z * bzinv + z12 = azz^2 + u1 = a.X + u2 = b.X * z12 + s1 = a.Y + s2 = b.Y * z12 + s2 = s2 * azz + h = -u1 + h = h + u2 + i = -s1 + i = i + s2 + if branch == 2: + r = formula_secp256k1_gej_double_var(a) + return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0', i : 'i=0'}), r) + if branch == 3: + return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite', h : 'h=0'}, nonzero={i : 'i!=0'}), point_at_infinity()) + i2 = i^2 + h2 = h^2 + h3 = h * h2 + rz = a.Z + rz = rz * h + t = u1 * h2 + rx = t + rx = rx * 2 + rx = rx + h3 + rx = -rx + rx = rx + i2 + ry = -rx + ry = ry + t + ry = ry * i + h3 = h3 * s1 + h3 = -h3 + ry = ry + h3 + return (constraints(), constraints(zero={a.Infinity : 'a_finite', b.Infinity : 'b_finite'}, nonzero={h : 'h!=0'}), jacobianpoint(rx, ry, rz)) + +def formula_secp256k1_gej_add_ge(branch, a, b): + """libsecp256k1's secp256k1_gej_add_ge""" + zeroes = {} + nonzeroes = {} + a_infinity = False + if (branch & 4) != 0: + nonzeroes.update({a.Infinity : 'a_infinite'}) + a_infinity = True + else: + zeroes.update({a.Infinity : 'a_finite'}) + zz = a.Z^2 + u1 = a.X + u2 = b.X * zz + s1 = a.Y + s2 = b.Y * zz + s2 = s2 * a.Z + t = u1 + t = t + u2 + m = s1 + m = m + s2 + rr = t^2 + m_alt = -u2 + tt = u1 * m_alt + rr = rr + tt + degenerate = (branch & 3) == 3 + if (branch & 1) != 0: + zeroes.update({m : 'm_zero'}) + else: + nonzeroes.update({m : 'm_nonzero'}) + if (branch & 2) != 0: + zeroes.update({rr : 'rr_zero'}) + else: + nonzeroes.update({rr : 'rr_nonzero'}) + rr_alt = s1 + rr_alt = rr_alt * 2 + m_alt = m_alt + u1 + if not degenerate: + rr_alt = rr + m_alt = m + n = m_alt^2 + q = n * t + n = n^2 + if degenerate: + n = m + t = rr_alt^2 + rz = a.Z * m_alt + infinity = False + if (branch & 8) != 0: + if not a_infinity: + infinity = True + zeroes.update({rz : 'r.z=0'}) + else: + nonzeroes.update({rz : 'r.z!=0'}) + rz = rz * 2 + q = -q + t = t + q + rx = t + t = t * 2 + t = t + q + t = t * rr_alt + t = t + n + ry = -t + rx = rx * 4 + ry = ry * 4 + if a_infinity: + rx = b.X + ry = b.Y + rz = 1 + if infinity: + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), point_at_infinity()) + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zeroes, nonzero=nonzeroes), jacobianpoint(rx, ry, rz)) + +def formula_secp256k1_gej_add_ge_old(branch, a, b): + """libsecp256k1's old secp256k1_gej_add_ge, which fails when ay+by=0 but ax!=bx""" + a_infinity = (branch & 1) != 0 + zero = {} + nonzero = {} + if a_infinity: + nonzero.update({a.Infinity : 'a_infinite'}) + else: + zero.update({a.Infinity : 'a_finite'}) + zz = a.Z^2 + u1 = a.X + u2 = b.X * zz + s1 = a.Y + s2 = b.Y * zz + s2 = s2 * a.Z + z = a.Z + t = u1 + t = t + u2 + m = s1 + m = m + s2 + n = m^2 + q = n * t + n = n^2 + rr = t^2 + t = u1 * u2 + t = -t + rr = rr + t + t = rr^2 + rz = m * z + infinity = False + if (branch & 2) != 0: + if not a_infinity: + infinity = True + else: + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(nonzero={z : 'conflict_a'}, zero={z : 'conflict_b'}), point_at_infinity()) + zero.update({rz : 'r.z=0'}) + else: + nonzero.update({rz : 'r.z!=0'}) + rz = rz * (0 if a_infinity else 2) + rx = t + q = -q + rx = rx + q + q = q * 3 + t = t * 2 + t = t + q + t = t * rr + t = t + n + ry = -t + rx = rx * (0 if a_infinity else 4) + ry = ry * (0 if a_infinity else 4) + t = b.X + t = t * (1 if a_infinity else 0) + rx = rx + t + t = b.Y + t = t * (1 if a_infinity else 0) + ry = ry + t + t = (1 if a_infinity else 0) + rz = rz + t + if infinity: + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), point_at_infinity()) + return (constraints(zero={b.Z - 1 : 'b.z=1', b.Infinity : 'b_finite'}), constraints(zero=zero, nonzero=nonzero), jacobianpoint(rx, ry, rz)) + +if __name__ == "__main__": + check_symbolic_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var) + check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var) + check_symbolic_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var) + check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge) + check_symbolic_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old) + + if len(sys.argv) >= 2 and sys.argv[1] == "--exhaustive": + check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_var", 0, 7, 5, formula_secp256k1_gej_add_var, 43) + check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_var", 0, 7, 5, formula_secp256k1_gej_add_ge_var, 43) + check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_zinv_var", 0, 7, 5, formula_secp256k1_gej_add_zinv_var, 43) + check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge", 0, 7, 16, formula_secp256k1_gej_add_ge, 43) + check_exhaustive_jacobian_weierstrass("secp256k1_gej_add_ge_old [should fail]", 0, 7, 4, formula_secp256k1_gej_add_ge_old, 43) diff --git a/src/cryptoconditions/src/include/secp256k1/sage/weierstrass_prover.sage b/src/cryptoconditions/src/include/secp256k1/sage/weierstrass_prover.sage new file mode 100644 index 000000000..03ef2ec90 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/sage/weierstrass_prover.sage @@ -0,0 +1,264 @@ +# Prover implementation for Weierstrass curves of the form +# y^2 = x^3 + A * x + B, specifically with a = 0 and b = 7, with group laws +# operating on affine and Jacobian coordinates, including the point at infinity +# represented by a 4th variable in coordinates. + +load("group_prover.sage") + + +class affinepoint: + def __init__(self, x, y, infinity=0): + self.x = x + self.y = y + self.infinity = infinity + def __str__(self): + return "affinepoint(x=%s,y=%s,inf=%s)" % (self.x, self.y, self.infinity) + + +class jacobianpoint: + def __init__(self, x, y, z, infinity=0): + self.X = x + self.Y = y + self.Z = z + self.Infinity = infinity + def __str__(self): + return "jacobianpoint(X=%s,Y=%s,Z=%s,inf=%s)" % (self.X, self.Y, self.Z, self.Infinity) + + +def point_at_infinity(): + return jacobianpoint(1, 1, 1, 1) + + +def negate(p): + if p.__class__ == affinepoint: + return affinepoint(p.x, -p.y) + if p.__class__ == jacobianpoint: + return jacobianpoint(p.X, -p.Y, p.Z) + assert(False) + + +def on_weierstrass_curve(A, B, p): + """Return a set of zero-expressions for an affine point to be on the curve""" + return constraints(zero={p.x^3 + A*p.x + B - p.y^2: 'on_curve'}) + + +def tangential_to_weierstrass_curve(A, B, p12, p3): + """Return a set of zero-expressions for ((x12,y12),(x3,y3)) to be a line that is tangential to the curve at (x12,y12)""" + return constraints(zero={ + (p12.y - p3.y) * (p12.y * 2) - (p12.x^2 * 3 + A) * (p12.x - p3.x): 'tangential_to_curve' + }) + + +def colinear(p1, p2, p3): + """Return a set of zero-expressions for ((x1,y1),(x2,y2),(x3,y3)) to be collinear""" + return constraints(zero={ + (p1.y - p2.y) * (p1.x - p3.x) - (p1.y - p3.y) * (p1.x - p2.x): 'colinear_1', + (p2.y - p3.y) * (p2.x - p1.x) - (p2.y - p1.y) * (p2.x - p3.x): 'colinear_2', + (p3.y - p1.y) * (p3.x - p2.x) - (p3.y - p2.y) * (p3.x - p1.x): 'colinear_3' + }) + + +def good_affine_point(p): + return constraints(nonzero={p.x : 'nonzero_x', p.y : 'nonzero_y'}) + + +def good_jacobian_point(p): + return constraints(nonzero={p.X : 'nonzero_X', p.Y : 'nonzero_Y', p.Z^6 : 'nonzero_Z'}) + + +def good_point(p): + return constraints(nonzero={p.Z^6 : 'nonzero_X'}) + + +def finite(p, *affine_fns): + con = good_point(p) + constraints(zero={p.Infinity : 'finite_point'}) + if p.Z != 0: + return con + reduce(lambda a, b: a + b, (f(affinepoint(p.X / p.Z^2, p.Y / p.Z^3)) for f in affine_fns), con) + else: + return con + +def infinite(p): + return constraints(nonzero={p.Infinity : 'infinite_point'}) + + +def law_jacobian_weierstrass_add(A, B, pa, pb, pA, pB, pC): + """Check whether the passed set of coordinates is a valid Jacobian add, given assumptions""" + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + on_weierstrass_curve(A, B, pa) + + on_weierstrass_curve(A, B, pb) + + finite(pA) + + finite(pB) + + constraints(nonzero={pa.x - pb.x : 'different_x'})) + require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) + + colinear(pa, pb, negate(pc)))) + return (assumeLaw, require) + + +def law_jacobian_weierstrass_double(A, B, pa, pb, pA, pB, pC): + """Check whether the passed set of coordinates is a valid Jacobian doubling, given assumptions""" + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + on_weierstrass_curve(A, B, pa) + + on_weierstrass_curve(A, B, pb) + + finite(pA) + + finite(pB) + + constraints(zero={pa.x - pb.x : 'equal_x', pa.y - pb.y : 'equal_y'})) + require = (finite(pC, lambda pc: on_weierstrass_curve(A, B, pc) + + tangential_to_weierstrass_curve(A, B, pa, negate(pc)))) + return (assumeLaw, require) + + +def law_jacobian_weierstrass_add_opposites(A, B, pa, pb, pA, pB, pC): + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + on_weierstrass_curve(A, B, pa) + + on_weierstrass_curve(A, B, pb) + + finite(pA) + + finite(pB) + + constraints(zero={pa.x - pb.x : 'equal_x', pa.y + pb.y : 'opposite_y'})) + require = infinite(pC) + return (assumeLaw, require) + + +def law_jacobian_weierstrass_add_infinite_a(A, B, pa, pb, pA, pB, pC): + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + on_weierstrass_curve(A, B, pb) + + infinite(pA) + + finite(pB)) + require = finite(pC, lambda pc: constraints(zero={pc.x - pb.x : 'c.x=b.x', pc.y - pb.y : 'c.y=b.y'})) + return (assumeLaw, require) + + +def law_jacobian_weierstrass_add_infinite_b(A, B, pa, pb, pA, pB, pC): + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + on_weierstrass_curve(A, B, pa) + + infinite(pB) + + finite(pA)) + require = finite(pC, lambda pc: constraints(zero={pc.x - pa.x : 'c.x=a.x', pc.y - pa.y : 'c.y=a.y'})) + return (assumeLaw, require) + + +def law_jacobian_weierstrass_add_infinite_ab(A, B, pa, pb, pA, pB, pC): + assumeLaw = (good_affine_point(pa) + + good_affine_point(pb) + + good_jacobian_point(pA) + + good_jacobian_point(pB) + + infinite(pA) + + infinite(pB)) + require = infinite(pC) + return (assumeLaw, require) + + +laws_jacobian_weierstrass = { + 'add': law_jacobian_weierstrass_add, + 'double': law_jacobian_weierstrass_double, + 'add_opposite': law_jacobian_weierstrass_add_opposites, + 'add_infinite_a': law_jacobian_weierstrass_add_infinite_a, + 'add_infinite_b': law_jacobian_weierstrass_add_infinite_b, + 'add_infinite_ab': law_jacobian_weierstrass_add_infinite_ab +} + + +def check_exhaustive_jacobian_weierstrass(name, A, B, branches, formula, p): + """Verify an implementation of addition of Jacobian points on a Weierstrass curve, by executing and validating the result for every possible addition in a prime field""" + F = Integers(p) + print "Formula %s on Z%i:" % (name, p) + points = [] + for x in xrange(0, p): + for y in xrange(0, p): + point = affinepoint(F(x), F(y)) + r, e = concrete_verify(on_weierstrass_curve(A, B, point)) + if r: + points.append(point) + + for za in xrange(1, p): + for zb in xrange(1, p): + for pa in points: + for pb in points: + for ia in xrange(2): + for ib in xrange(2): + pA = jacobianpoint(pa.x * F(za)^2, pa.y * F(za)^3, F(za), ia) + pB = jacobianpoint(pb.x * F(zb)^2, pb.y * F(zb)^3, F(zb), ib) + for branch in xrange(0, branches): + assumeAssert, assumeBranch, pC = formula(branch, pA, pB) + pC.X = F(pC.X) + pC.Y = F(pC.Y) + pC.Z = F(pC.Z) + pC.Infinity = F(pC.Infinity) + r, e = concrete_verify(assumeAssert + assumeBranch) + if r: + match = False + for key in laws_jacobian_weierstrass: + assumeLaw, require = laws_jacobian_weierstrass[key](A, B, pa, pb, pA, pB, pC) + r, e = concrete_verify(assumeLaw) + if r: + if match: + print " multiple branches for (%s,%s,%s,%s) + (%s,%s,%s,%s)" % (pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity) + else: + match = True + r, e = concrete_verify(require) + if not r: + print " failure in branch %i for (%s,%s,%s,%s) + (%s,%s,%s,%s) = (%s,%s,%s,%s): %s" % (branch, pA.X, pA.Y, pA.Z, pA.Infinity, pB.X, pB.Y, pB.Z, pB.Infinity, pC.X, pC.Y, pC.Z, pC.Infinity, e) + print + + +def check_symbolic_function(R, assumeAssert, assumeBranch, f, A, B, pa, pb, pA, pB, pC): + assumeLaw, require = f(A, B, pa, pb, pA, pB, pC) + return check_symbolic(R, assumeLaw, assumeAssert, assumeBranch, require) + +def check_symbolic_jacobian_weierstrass(name, A, B, branches, formula): + """Verify an implementation of addition of Jacobian points on a Weierstrass curve symbolically""" + R. = PolynomialRing(QQ,8,order='invlex') + lift = lambda x: fastfrac(R,x) + ax = lift(ax) + ay = lift(ay) + Az = lift(Az) + bx = lift(bx) + by = lift(by) + Bz = lift(Bz) + Ai = lift(Ai) + Bi = lift(Bi) + + pa = affinepoint(ax, ay, Ai) + pb = affinepoint(bx, by, Bi) + pA = jacobianpoint(ax * Az^2, ay * Az^3, Az, Ai) + pB = jacobianpoint(bx * Bz^2, by * Bz^3, Bz, Bi) + + res = {} + + for key in laws_jacobian_weierstrass: + res[key] = [] + + print ("Formula " + name + ":") + count = 0 + for branch in xrange(branches): + assumeFormula, assumeBranch, pC = formula(branch, pA, pB) + pC.X = lift(pC.X) + pC.Y = lift(pC.Y) + pC.Z = lift(pC.Z) + pC.Infinity = lift(pC.Infinity) + + for key in laws_jacobian_weierstrass: + res[key].append((check_symbolic_function(R, assumeFormula, assumeBranch, laws_jacobian_weierstrass[key], A, B, pa, pb, pA, pB, pC), branch)) + + for key in res: + print " %s:" % key + val = res[key] + for x in val: + if x[0] is not None: + print " branch %i: %s" % (x[1], x[0]) + + print diff --git a/src/cryptoconditions/src/include/secp256k1/src/asm/field_10x26_arm.s b/src/cryptoconditions/src/include/secp256k1/src/asm/field_10x26_arm.s new file mode 100644 index 000000000..5a9cc3ffc --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/asm/field_10x26_arm.s @@ -0,0 +1,919 @@ +@ vim: set tabstop=8 softtabstop=8 shiftwidth=8 noexpandtab syntax=armasm: +/********************************************************************** + * Copyright (c) 2014 Wladimir J. van der Laan * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ +/* +ARM implementation of field_10x26 inner loops. + +Note: + +- To avoid unnecessary loads and make use of available registers, two + 'passes' have every time been interleaved, with the odd passes accumulating c' and d' + which will be added to c and d respectively in the even passes + +*/ + + .syntax unified + .arch armv7-a + @ eabi attributes - see readelf -A + .eabi_attribute 8, 1 @ Tag_ARM_ISA_use = yes + .eabi_attribute 9, 0 @ Tag_Thumb_ISA_use = no + .eabi_attribute 10, 0 @ Tag_FP_arch = none + .eabi_attribute 24, 1 @ Tag_ABI_align_needed = 8-byte + .eabi_attribute 25, 1 @ Tag_ABI_align_preserved = 8-byte, except leaf SP + .eabi_attribute 30, 2 @ Tag_ABI_optimization_goals = Aggressive Speed + .eabi_attribute 34, 1 @ Tag_CPU_unaligned_access = v6 + .text + + @ Field constants + .set field_R0, 0x3d10 + .set field_R1, 0x400 + .set field_not_M, 0xfc000000 @ ~M = ~0x3ffffff + + .align 2 + .global secp256k1_fe_mul_inner + .type secp256k1_fe_mul_inner, %function + @ Arguments: + @ r0 r Restrict: can overlap with a, not with b + @ r1 a + @ r2 b + @ Stack (total 4+10*4 = 44) + @ sp + #0 saved 'r' pointer + @ sp + #4 + 4*X t0,t1,t2,t3,t4,t5,t6,t7,u8,t9 +secp256k1_fe_mul_inner: + stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14} + sub sp, sp, #48 @ frame=44 + alignment + str r0, [sp, #0] @ save result address, we need it only at the end + + /****************************************** + * Main computation code. + ****************************************** + + Allocation: + r0,r14,r7,r8 scratch + r1 a (pointer) + r2 b (pointer) + r3:r4 c + r5:r6 d + r11:r12 c' + r9:r10 d' + + Note: do not write to r[] here, it may overlap with a[] + */ + + /* A - interleaved with B */ + ldr r7, [r1, #0*4] @ a[0] + ldr r8, [r2, #9*4] @ b[9] + ldr r0, [r1, #1*4] @ a[1] + umull r5, r6, r7, r8 @ d = a[0] * b[9] + ldr r14, [r2, #8*4] @ b[8] + umull r9, r10, r0, r8 @ d' = a[1] * b[9] + ldr r7, [r1, #2*4] @ a[2] + umlal r5, r6, r0, r14 @ d += a[1] * b[8] + ldr r8, [r2, #7*4] @ b[7] + umlal r9, r10, r7, r14 @ d' += a[2] * b[8] + ldr r0, [r1, #3*4] @ a[3] + umlal r5, r6, r7, r8 @ d += a[2] * b[7] + ldr r14, [r2, #6*4] @ b[6] + umlal r9, r10, r0, r8 @ d' += a[3] * b[7] + ldr r7, [r1, #4*4] @ a[4] + umlal r5, r6, r0, r14 @ d += a[3] * b[6] + ldr r8, [r2, #5*4] @ b[5] + umlal r9, r10, r7, r14 @ d' += a[4] * b[6] + ldr r0, [r1, #5*4] @ a[5] + umlal r5, r6, r7, r8 @ d += a[4] * b[5] + ldr r14, [r2, #4*4] @ b[4] + umlal r9, r10, r0, r8 @ d' += a[5] * b[5] + ldr r7, [r1, #6*4] @ a[6] + umlal r5, r6, r0, r14 @ d += a[5] * b[4] + ldr r8, [r2, #3*4] @ b[3] + umlal r9, r10, r7, r14 @ d' += a[6] * b[4] + ldr r0, [r1, #7*4] @ a[7] + umlal r5, r6, r7, r8 @ d += a[6] * b[3] + ldr r14, [r2, #2*4] @ b[2] + umlal r9, r10, r0, r8 @ d' += a[7] * b[3] + ldr r7, [r1, #8*4] @ a[8] + umlal r5, r6, r0, r14 @ d += a[7] * b[2] + ldr r8, [r2, #1*4] @ b[1] + umlal r9, r10, r7, r14 @ d' += a[8] * b[2] + ldr r0, [r1, #9*4] @ a[9] + umlal r5, r6, r7, r8 @ d += a[8] * b[1] + ldr r14, [r2, #0*4] @ b[0] + umlal r9, r10, r0, r8 @ d' += a[9] * b[1] + ldr r7, [r1, #0*4] @ a[0] + umlal r5, r6, r0, r14 @ d += a[9] * b[0] + @ r7,r14 used in B + + bic r0, r5, field_not_M @ t9 = d & M + str r0, [sp, #4 + 4*9] + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + + /* B */ + umull r3, r4, r7, r14 @ c = a[0] * b[0] + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u0 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u0 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t0 = c & M + str r14, [sp, #4 + 0*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u0 * R1 + umlal r3, r4, r0, r14 + + /* C - interleaved with D */ + ldr r7, [r1, #0*4] @ a[0] + ldr r8, [r2, #2*4] @ b[2] + ldr r14, [r2, #1*4] @ b[1] + umull r11, r12, r7, r8 @ c' = a[0] * b[2] + ldr r0, [r1, #1*4] @ a[1] + umlal r3, r4, r7, r14 @ c += a[0] * b[1] + ldr r8, [r2, #0*4] @ b[0] + umlal r11, r12, r0, r14 @ c' += a[1] * b[1] + ldr r7, [r1, #2*4] @ a[2] + umlal r3, r4, r0, r8 @ c += a[1] * b[0] + ldr r14, [r2, #9*4] @ b[9] + umlal r11, r12, r7, r8 @ c' += a[2] * b[0] + ldr r0, [r1, #3*4] @ a[3] + umlal r5, r6, r7, r14 @ d += a[2] * b[9] + ldr r8, [r2, #8*4] @ b[8] + umull r9, r10, r0, r14 @ d' = a[3] * b[9] + ldr r7, [r1, #4*4] @ a[4] + umlal r5, r6, r0, r8 @ d += a[3] * b[8] + ldr r14, [r2, #7*4] @ b[7] + umlal r9, r10, r7, r8 @ d' += a[4] * b[8] + ldr r0, [r1, #5*4] @ a[5] + umlal r5, r6, r7, r14 @ d += a[4] * b[7] + ldr r8, [r2, #6*4] @ b[6] + umlal r9, r10, r0, r14 @ d' += a[5] * b[7] + ldr r7, [r1, #6*4] @ a[6] + umlal r5, r6, r0, r8 @ d += a[5] * b[6] + ldr r14, [r2, #5*4] @ b[5] + umlal r9, r10, r7, r8 @ d' += a[6] * b[6] + ldr r0, [r1, #7*4] @ a[7] + umlal r5, r6, r7, r14 @ d += a[6] * b[5] + ldr r8, [r2, #4*4] @ b[4] + umlal r9, r10, r0, r14 @ d' += a[7] * b[5] + ldr r7, [r1, #8*4] @ a[8] + umlal r5, r6, r0, r8 @ d += a[7] * b[4] + ldr r14, [r2, #3*4] @ b[3] + umlal r9, r10, r7, r8 @ d' += a[8] * b[4] + ldr r0, [r1, #9*4] @ a[9] + umlal r5, r6, r7, r14 @ d += a[8] * b[3] + ldr r8, [r2, #2*4] @ b[2] + umlal r9, r10, r0, r14 @ d' += a[9] * b[3] + umlal r5, r6, r0, r8 @ d += a[9] * b[2] + + bic r0, r5, field_not_M @ u1 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u1 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t1 = c & M + str r14, [sp, #4 + 1*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u1 * R1 + umlal r3, r4, r0, r14 + + /* D */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u2 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u2 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t2 = c & M + str r14, [sp, #4 + 2*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u2 * R1 + umlal r3, r4, r0, r14 + + /* E - interleaved with F */ + ldr r7, [r1, #0*4] @ a[0] + ldr r8, [r2, #4*4] @ b[4] + umull r11, r12, r7, r8 @ c' = a[0] * b[4] + ldr r8, [r2, #3*4] @ b[3] + umlal r3, r4, r7, r8 @ c += a[0] * b[3] + ldr r7, [r1, #1*4] @ a[1] + umlal r11, r12, r7, r8 @ c' += a[1] * b[3] + ldr r8, [r2, #2*4] @ b[2] + umlal r3, r4, r7, r8 @ c += a[1] * b[2] + ldr r7, [r1, #2*4] @ a[2] + umlal r11, r12, r7, r8 @ c' += a[2] * b[2] + ldr r8, [r2, #1*4] @ b[1] + umlal r3, r4, r7, r8 @ c += a[2] * b[1] + ldr r7, [r1, #3*4] @ a[3] + umlal r11, r12, r7, r8 @ c' += a[3] * b[1] + ldr r8, [r2, #0*4] @ b[0] + umlal r3, r4, r7, r8 @ c += a[3] * b[0] + ldr r7, [r1, #4*4] @ a[4] + umlal r11, r12, r7, r8 @ c' += a[4] * b[0] + ldr r8, [r2, #9*4] @ b[9] + umlal r5, r6, r7, r8 @ d += a[4] * b[9] + ldr r7, [r1, #5*4] @ a[5] + umull r9, r10, r7, r8 @ d' = a[5] * b[9] + ldr r8, [r2, #8*4] @ b[8] + umlal r5, r6, r7, r8 @ d += a[5] * b[8] + ldr r7, [r1, #6*4] @ a[6] + umlal r9, r10, r7, r8 @ d' += a[6] * b[8] + ldr r8, [r2, #7*4] @ b[7] + umlal r5, r6, r7, r8 @ d += a[6] * b[7] + ldr r7, [r1, #7*4] @ a[7] + umlal r9, r10, r7, r8 @ d' += a[7] * b[7] + ldr r8, [r2, #6*4] @ b[6] + umlal r5, r6, r7, r8 @ d += a[7] * b[6] + ldr r7, [r1, #8*4] @ a[8] + umlal r9, r10, r7, r8 @ d' += a[8] * b[6] + ldr r8, [r2, #5*4] @ b[5] + umlal r5, r6, r7, r8 @ d += a[8] * b[5] + ldr r7, [r1, #9*4] @ a[9] + umlal r9, r10, r7, r8 @ d' += a[9] * b[5] + ldr r8, [r2, #4*4] @ b[4] + umlal r5, r6, r7, r8 @ d += a[9] * b[4] + + bic r0, r5, field_not_M @ u3 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u3 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t3 = c & M + str r14, [sp, #4 + 3*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u3 * R1 + umlal r3, r4, r0, r14 + + /* F */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u4 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u4 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t4 = c & M + str r14, [sp, #4 + 4*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u4 * R1 + umlal r3, r4, r0, r14 + + /* G - interleaved with H */ + ldr r7, [r1, #0*4] @ a[0] + ldr r8, [r2, #6*4] @ b[6] + ldr r14, [r2, #5*4] @ b[5] + umull r11, r12, r7, r8 @ c' = a[0] * b[6] + ldr r0, [r1, #1*4] @ a[1] + umlal r3, r4, r7, r14 @ c += a[0] * b[5] + ldr r8, [r2, #4*4] @ b[4] + umlal r11, r12, r0, r14 @ c' += a[1] * b[5] + ldr r7, [r1, #2*4] @ a[2] + umlal r3, r4, r0, r8 @ c += a[1] * b[4] + ldr r14, [r2, #3*4] @ b[3] + umlal r11, r12, r7, r8 @ c' += a[2] * b[4] + ldr r0, [r1, #3*4] @ a[3] + umlal r3, r4, r7, r14 @ c += a[2] * b[3] + ldr r8, [r2, #2*4] @ b[2] + umlal r11, r12, r0, r14 @ c' += a[3] * b[3] + ldr r7, [r1, #4*4] @ a[4] + umlal r3, r4, r0, r8 @ c += a[3] * b[2] + ldr r14, [r2, #1*4] @ b[1] + umlal r11, r12, r7, r8 @ c' += a[4] * b[2] + ldr r0, [r1, #5*4] @ a[5] + umlal r3, r4, r7, r14 @ c += a[4] * b[1] + ldr r8, [r2, #0*4] @ b[0] + umlal r11, r12, r0, r14 @ c' += a[5] * b[1] + ldr r7, [r1, #6*4] @ a[6] + umlal r3, r4, r0, r8 @ c += a[5] * b[0] + ldr r14, [r2, #9*4] @ b[9] + umlal r11, r12, r7, r8 @ c' += a[6] * b[0] + ldr r0, [r1, #7*4] @ a[7] + umlal r5, r6, r7, r14 @ d += a[6] * b[9] + ldr r8, [r2, #8*4] @ b[8] + umull r9, r10, r0, r14 @ d' = a[7] * b[9] + ldr r7, [r1, #8*4] @ a[8] + umlal r5, r6, r0, r8 @ d += a[7] * b[8] + ldr r14, [r2, #7*4] @ b[7] + umlal r9, r10, r7, r8 @ d' += a[8] * b[8] + ldr r0, [r1, #9*4] @ a[9] + umlal r5, r6, r7, r14 @ d += a[8] * b[7] + ldr r8, [r2, #6*4] @ b[6] + umlal r9, r10, r0, r14 @ d' += a[9] * b[7] + umlal r5, r6, r0, r8 @ d += a[9] * b[6] + + bic r0, r5, field_not_M @ u5 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u5 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t5 = c & M + str r14, [sp, #4 + 5*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u5 * R1 + umlal r3, r4, r0, r14 + + /* H */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u6 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u6 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t6 = c & M + str r14, [sp, #4 + 6*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u6 * R1 + umlal r3, r4, r0, r14 + + /* I - interleaved with J */ + ldr r8, [r2, #8*4] @ b[8] + ldr r7, [r1, #0*4] @ a[0] + ldr r14, [r2, #7*4] @ b[7] + umull r11, r12, r7, r8 @ c' = a[0] * b[8] + ldr r0, [r1, #1*4] @ a[1] + umlal r3, r4, r7, r14 @ c += a[0] * b[7] + ldr r8, [r2, #6*4] @ b[6] + umlal r11, r12, r0, r14 @ c' += a[1] * b[7] + ldr r7, [r1, #2*4] @ a[2] + umlal r3, r4, r0, r8 @ c += a[1] * b[6] + ldr r14, [r2, #5*4] @ b[5] + umlal r11, r12, r7, r8 @ c' += a[2] * b[6] + ldr r0, [r1, #3*4] @ a[3] + umlal r3, r4, r7, r14 @ c += a[2] * b[5] + ldr r8, [r2, #4*4] @ b[4] + umlal r11, r12, r0, r14 @ c' += a[3] * b[5] + ldr r7, [r1, #4*4] @ a[4] + umlal r3, r4, r0, r8 @ c += a[3] * b[4] + ldr r14, [r2, #3*4] @ b[3] + umlal r11, r12, r7, r8 @ c' += a[4] * b[4] + ldr r0, [r1, #5*4] @ a[5] + umlal r3, r4, r7, r14 @ c += a[4] * b[3] + ldr r8, [r2, #2*4] @ b[2] + umlal r11, r12, r0, r14 @ c' += a[5] * b[3] + ldr r7, [r1, #6*4] @ a[6] + umlal r3, r4, r0, r8 @ c += a[5] * b[2] + ldr r14, [r2, #1*4] @ b[1] + umlal r11, r12, r7, r8 @ c' += a[6] * b[2] + ldr r0, [r1, #7*4] @ a[7] + umlal r3, r4, r7, r14 @ c += a[6] * b[1] + ldr r8, [r2, #0*4] @ b[0] + umlal r11, r12, r0, r14 @ c' += a[7] * b[1] + ldr r7, [r1, #8*4] @ a[8] + umlal r3, r4, r0, r8 @ c += a[7] * b[0] + ldr r14, [r2, #9*4] @ b[9] + umlal r11, r12, r7, r8 @ c' += a[8] * b[0] + ldr r0, [r1, #9*4] @ a[9] + umlal r5, r6, r7, r14 @ d += a[8] * b[9] + ldr r8, [r2, #8*4] @ b[8] + umull r9, r10, r0, r14 @ d' = a[9] * b[9] + umlal r5, r6, r0, r8 @ d += a[9] * b[8] + + bic r0, r5, field_not_M @ u7 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u7 * R0 + umlal r3, r4, r0, r14 + + bic r14, r3, field_not_M @ t7 = c & M + str r14, [sp, #4 + 7*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u7 * R1 + umlal r3, r4, r0, r14 + + /* J */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u8 = d & M + str r0, [sp, #4 + 8*4] + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u8 * R0 + umlal r3, r4, r0, r14 + + /****************************************** + * compute and write back result + ****************************************** + Allocation: + r0 r + r3:r4 c + r5:r6 d + r7 t0 + r8 t1 + r9 t2 + r11 u8 + r12 t9 + r1,r2,r10,r14 scratch + + Note: do not read from a[] after here, it may overlap with r[] + */ + ldr r0, [sp, #0] + add r1, sp, #4 + 3*4 @ r[3..7] = t3..7, r11=u8, r12=t9 + ldmia r1, {r2,r7,r8,r9,r10,r11,r12} + add r1, r0, #3*4 + stmia r1, {r2,r7,r8,r9,r10} + + bic r2, r3, field_not_M @ r[8] = c & M + str r2, [r0, #8*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u8 * R1 + umlal r3, r4, r11, r14 + movw r14, field_R0 @ c += d * R0 + umlal r3, r4, r5, r14 + adds r3, r3, r12 @ c += t9 + adc r4, r4, #0 + + add r1, sp, #4 + 0*4 @ r7,r8,r9 = t0,t1,t2 + ldmia r1, {r7,r8,r9} + + ubfx r2, r3, #0, #22 @ r[9] = c & (M >> 4) + str r2, [r0, #9*4] + mov r3, r3, lsr #22 @ c >>= 22 + orr r3, r3, r4, asl #10 + mov r4, r4, lsr #22 + movw r14, field_R1 << 4 @ c += d * (R1 << 4) + umlal r3, r4, r5, r14 + + movw r14, field_R0 >> 4 @ d = c * (R0 >> 4) + t0 (64x64 multiply+add) + umull r5, r6, r3, r14 @ d = c.lo * (R0 >> 4) + adds r5, r5, r7 @ d.lo += t0 + mla r6, r14, r4, r6 @ d.hi += c.hi * (R0 >> 4) + adc r6, r6, 0 @ d.hi += carry + + bic r2, r5, field_not_M @ r[0] = d & M + str r2, [r0, #0*4] + + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + + movw r14, field_R1 >> 4 @ d += c * (R1 >> 4) + t1 (64x64 multiply+add) + umull r1, r2, r3, r14 @ tmp = c.lo * (R1 >> 4) + adds r5, r5, r8 @ d.lo += t1 + adc r6, r6, #0 @ d.hi += carry + adds r5, r5, r1 @ d.lo += tmp.lo + mla r2, r14, r4, r2 @ tmp.hi += c.hi * (R1 >> 4) + adc r6, r6, r2 @ d.hi += carry + tmp.hi + + bic r2, r5, field_not_M @ r[1] = d & M + str r2, [r0, #1*4] + mov r5, r5, lsr #26 @ d >>= 26 (ignore hi) + orr r5, r5, r6, asl #6 + + add r5, r5, r9 @ d += t2 + str r5, [r0, #2*4] @ r[2] = d + + add sp, sp, #48 + ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc} + .size secp256k1_fe_mul_inner, .-secp256k1_fe_mul_inner + + .align 2 + .global secp256k1_fe_sqr_inner + .type secp256k1_fe_sqr_inner, %function + @ Arguments: + @ r0 r Can overlap with a + @ r1 a + @ Stack (total 4+10*4 = 44) + @ sp + #0 saved 'r' pointer + @ sp + #4 + 4*X t0,t1,t2,t3,t4,t5,t6,t7,u8,t9 +secp256k1_fe_sqr_inner: + stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r14} + sub sp, sp, #48 @ frame=44 + alignment + str r0, [sp, #0] @ save result address, we need it only at the end + /****************************************** + * Main computation code. + ****************************************** + + Allocation: + r0,r14,r2,r7,r8 scratch + r1 a (pointer) + r3:r4 c + r5:r6 d + r11:r12 c' + r9:r10 d' + + Note: do not write to r[] here, it may overlap with a[] + */ + /* A interleaved with B */ + ldr r0, [r1, #1*4] @ a[1]*2 + ldr r7, [r1, #0*4] @ a[0] + mov r0, r0, asl #1 + ldr r14, [r1, #9*4] @ a[9] + umull r3, r4, r7, r7 @ c = a[0] * a[0] + ldr r8, [r1, #8*4] @ a[8] + mov r7, r7, asl #1 + umull r5, r6, r7, r14 @ d = a[0]*2 * a[9] + ldr r7, [r1, #2*4] @ a[2]*2 + umull r9, r10, r0, r14 @ d' = a[1]*2 * a[9] + ldr r14, [r1, #7*4] @ a[7] + umlal r5, r6, r0, r8 @ d += a[1]*2 * a[8] + mov r7, r7, asl #1 + ldr r0, [r1, #3*4] @ a[3]*2 + umlal r9, r10, r7, r8 @ d' += a[2]*2 * a[8] + ldr r8, [r1, #6*4] @ a[6] + umlal r5, r6, r7, r14 @ d += a[2]*2 * a[7] + mov r0, r0, asl #1 + ldr r7, [r1, #4*4] @ a[4]*2 + umlal r9, r10, r0, r14 @ d' += a[3]*2 * a[7] + ldr r14, [r1, #5*4] @ a[5] + mov r7, r7, asl #1 + umlal r5, r6, r0, r8 @ d += a[3]*2 * a[6] + umlal r9, r10, r7, r8 @ d' += a[4]*2 * a[6] + umlal r5, r6, r7, r14 @ d += a[4]*2 * a[5] + umlal r9, r10, r14, r14 @ d' += a[5] * a[5] + + bic r0, r5, field_not_M @ t9 = d & M + str r0, [sp, #4 + 9*4] + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + + /* B */ + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u0 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u0 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t0 = c & M + str r14, [sp, #4 + 0*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u0 * R1 + umlal r3, r4, r0, r14 + + /* C interleaved with D */ + ldr r0, [r1, #0*4] @ a[0]*2 + ldr r14, [r1, #1*4] @ a[1] + mov r0, r0, asl #1 + ldr r8, [r1, #2*4] @ a[2] + umlal r3, r4, r0, r14 @ c += a[0]*2 * a[1] + mov r7, r8, asl #1 @ a[2]*2 + umull r11, r12, r14, r14 @ c' = a[1] * a[1] + ldr r14, [r1, #9*4] @ a[9] + umlal r11, r12, r0, r8 @ c' += a[0]*2 * a[2] + ldr r0, [r1, #3*4] @ a[3]*2 + ldr r8, [r1, #8*4] @ a[8] + umlal r5, r6, r7, r14 @ d += a[2]*2 * a[9] + mov r0, r0, asl #1 + ldr r7, [r1, #4*4] @ a[4]*2 + umull r9, r10, r0, r14 @ d' = a[3]*2 * a[9] + ldr r14, [r1, #7*4] @ a[7] + umlal r5, r6, r0, r8 @ d += a[3]*2 * a[8] + mov r7, r7, asl #1 + ldr r0, [r1, #5*4] @ a[5]*2 + umlal r9, r10, r7, r8 @ d' += a[4]*2 * a[8] + ldr r8, [r1, #6*4] @ a[6] + mov r0, r0, asl #1 + umlal r5, r6, r7, r14 @ d += a[4]*2 * a[7] + umlal r9, r10, r0, r14 @ d' += a[5]*2 * a[7] + umlal r5, r6, r0, r8 @ d += a[5]*2 * a[6] + umlal r9, r10, r8, r8 @ d' += a[6] * a[6] + + bic r0, r5, field_not_M @ u1 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u1 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t1 = c & M + str r14, [sp, #4 + 1*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u1 * R1 + umlal r3, r4, r0, r14 + + /* D */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u2 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u2 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t2 = c & M + str r14, [sp, #4 + 2*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u2 * R1 + umlal r3, r4, r0, r14 + + /* E interleaved with F */ + ldr r7, [r1, #0*4] @ a[0]*2 + ldr r0, [r1, #1*4] @ a[1]*2 + ldr r14, [r1, #2*4] @ a[2] + mov r7, r7, asl #1 + ldr r8, [r1, #3*4] @ a[3] + ldr r2, [r1, #4*4] + umlal r3, r4, r7, r8 @ c += a[0]*2 * a[3] + mov r0, r0, asl #1 + umull r11, r12, r7, r2 @ c' = a[0]*2 * a[4] + mov r2, r2, asl #1 @ a[4]*2 + umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[3] + ldr r8, [r1, #9*4] @ a[9] + umlal r3, r4, r0, r14 @ c += a[1]*2 * a[2] + ldr r0, [r1, #5*4] @ a[5]*2 + umlal r11, r12, r14, r14 @ c' += a[2] * a[2] + ldr r14, [r1, #8*4] @ a[8] + mov r0, r0, asl #1 + umlal r5, r6, r2, r8 @ d += a[4]*2 * a[9] + ldr r7, [r1, #6*4] @ a[6]*2 + umull r9, r10, r0, r8 @ d' = a[5]*2 * a[9] + mov r7, r7, asl #1 + ldr r8, [r1, #7*4] @ a[7] + umlal r5, r6, r0, r14 @ d += a[5]*2 * a[8] + umlal r9, r10, r7, r14 @ d' += a[6]*2 * a[8] + umlal r5, r6, r7, r8 @ d += a[6]*2 * a[7] + umlal r9, r10, r8, r8 @ d' += a[7] * a[7] + + bic r0, r5, field_not_M @ u3 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u3 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t3 = c & M + str r14, [sp, #4 + 3*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u3 * R1 + umlal r3, r4, r0, r14 + + /* F */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u4 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u4 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t4 = c & M + str r14, [sp, #4 + 4*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u4 * R1 + umlal r3, r4, r0, r14 + + /* G interleaved with H */ + ldr r7, [r1, #0*4] @ a[0]*2 + ldr r0, [r1, #1*4] @ a[1]*2 + mov r7, r7, asl #1 + ldr r8, [r1, #5*4] @ a[5] + ldr r2, [r1, #6*4] @ a[6] + umlal r3, r4, r7, r8 @ c += a[0]*2 * a[5] + ldr r14, [r1, #4*4] @ a[4] + mov r0, r0, asl #1 + umull r11, r12, r7, r2 @ c' = a[0]*2 * a[6] + ldr r7, [r1, #2*4] @ a[2]*2 + umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[5] + mov r7, r7, asl #1 + ldr r8, [r1, #3*4] @ a[3] + umlal r3, r4, r0, r14 @ c += a[1]*2 * a[4] + mov r0, r2, asl #1 @ a[6]*2 + umlal r11, r12, r7, r14 @ c' += a[2]*2 * a[4] + ldr r14, [r1, #9*4] @ a[9] + umlal r3, r4, r7, r8 @ c += a[2]*2 * a[3] + ldr r7, [r1, #7*4] @ a[7]*2 + umlal r11, r12, r8, r8 @ c' += a[3] * a[3] + mov r7, r7, asl #1 + ldr r8, [r1, #8*4] @ a[8] + umlal r5, r6, r0, r14 @ d += a[6]*2 * a[9] + umull r9, r10, r7, r14 @ d' = a[7]*2 * a[9] + umlal r5, r6, r7, r8 @ d += a[7]*2 * a[8] + umlal r9, r10, r8, r8 @ d' += a[8] * a[8] + + bic r0, r5, field_not_M @ u5 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u5 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t5 = c & M + str r14, [sp, #4 + 5*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u5 * R1 + umlal r3, r4, r0, r14 + + /* H */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + adds r5, r5, r9 @ d += d' + adc r6, r6, r10 + + bic r0, r5, field_not_M @ u6 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u6 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t6 = c & M + str r14, [sp, #4 + 6*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u6 * R1 + umlal r3, r4, r0, r14 + + /* I interleaved with J */ + ldr r7, [r1, #0*4] @ a[0]*2 + ldr r0, [r1, #1*4] @ a[1]*2 + mov r7, r7, asl #1 + ldr r8, [r1, #7*4] @ a[7] + ldr r2, [r1, #8*4] @ a[8] + umlal r3, r4, r7, r8 @ c += a[0]*2 * a[7] + ldr r14, [r1, #6*4] @ a[6] + mov r0, r0, asl #1 + umull r11, r12, r7, r2 @ c' = a[0]*2 * a[8] + ldr r7, [r1, #2*4] @ a[2]*2 + umlal r11, r12, r0, r8 @ c' += a[1]*2 * a[7] + ldr r8, [r1, #5*4] @ a[5] + umlal r3, r4, r0, r14 @ c += a[1]*2 * a[6] + ldr r0, [r1, #3*4] @ a[3]*2 + mov r7, r7, asl #1 + umlal r11, r12, r7, r14 @ c' += a[2]*2 * a[6] + ldr r14, [r1, #4*4] @ a[4] + mov r0, r0, asl #1 + umlal r3, r4, r7, r8 @ c += a[2]*2 * a[5] + mov r2, r2, asl #1 @ a[8]*2 + umlal r11, r12, r0, r8 @ c' += a[3]*2 * a[5] + umlal r3, r4, r0, r14 @ c += a[3]*2 * a[4] + umlal r11, r12, r14, r14 @ c' += a[4] * a[4] + ldr r8, [r1, #9*4] @ a[9] + umlal r5, r6, r2, r8 @ d += a[8]*2 * a[9] + @ r8 will be used in J + + bic r0, r5, field_not_M @ u7 = d & M + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u7 * R0 + umlal r3, r4, r0, r14 + bic r14, r3, field_not_M @ t7 = c & M + str r14, [sp, #4 + 7*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u7 * R1 + umlal r3, r4, r0, r14 + + /* J */ + adds r3, r3, r11 @ c += c' + adc r4, r4, r12 + umlal r5, r6, r8, r8 @ d += a[9] * a[9] + + bic r0, r5, field_not_M @ u8 = d & M + str r0, [sp, #4 + 8*4] + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + movw r14, field_R0 @ c += u8 * R0 + umlal r3, r4, r0, r14 + + /****************************************** + * compute and write back result + ****************************************** + Allocation: + r0 r + r3:r4 c + r5:r6 d + r7 t0 + r8 t1 + r9 t2 + r11 u8 + r12 t9 + r1,r2,r10,r14 scratch + + Note: do not read from a[] after here, it may overlap with r[] + */ + ldr r0, [sp, #0] + add r1, sp, #4 + 3*4 @ r[3..7] = t3..7, r11=u8, r12=t9 + ldmia r1, {r2,r7,r8,r9,r10,r11,r12} + add r1, r0, #3*4 + stmia r1, {r2,r7,r8,r9,r10} + + bic r2, r3, field_not_M @ r[8] = c & M + str r2, [r0, #8*4] + mov r3, r3, lsr #26 @ c >>= 26 + orr r3, r3, r4, asl #6 + mov r4, r4, lsr #26 + mov r14, field_R1 @ c += u8 * R1 + umlal r3, r4, r11, r14 + movw r14, field_R0 @ c += d * R0 + umlal r3, r4, r5, r14 + adds r3, r3, r12 @ c += t9 + adc r4, r4, #0 + + add r1, sp, #4 + 0*4 @ r7,r8,r9 = t0,t1,t2 + ldmia r1, {r7,r8,r9} + + ubfx r2, r3, #0, #22 @ r[9] = c & (M >> 4) + str r2, [r0, #9*4] + mov r3, r3, lsr #22 @ c >>= 22 + orr r3, r3, r4, asl #10 + mov r4, r4, lsr #22 + movw r14, field_R1 << 4 @ c += d * (R1 << 4) + umlal r3, r4, r5, r14 + + movw r14, field_R0 >> 4 @ d = c * (R0 >> 4) + t0 (64x64 multiply+add) + umull r5, r6, r3, r14 @ d = c.lo * (R0 >> 4) + adds r5, r5, r7 @ d.lo += t0 + mla r6, r14, r4, r6 @ d.hi += c.hi * (R0 >> 4) + adc r6, r6, 0 @ d.hi += carry + + bic r2, r5, field_not_M @ r[0] = d & M + str r2, [r0, #0*4] + + mov r5, r5, lsr #26 @ d >>= 26 + orr r5, r5, r6, asl #6 + mov r6, r6, lsr #26 + + movw r14, field_R1 >> 4 @ d += c * (R1 >> 4) + t1 (64x64 multiply+add) + umull r1, r2, r3, r14 @ tmp = c.lo * (R1 >> 4) + adds r5, r5, r8 @ d.lo += t1 + adc r6, r6, #0 @ d.hi += carry + adds r5, r5, r1 @ d.lo += tmp.lo + mla r2, r14, r4, r2 @ tmp.hi += c.hi * (R1 >> 4) + adc r6, r6, r2 @ d.hi += carry + tmp.hi + + bic r2, r5, field_not_M @ r[1] = d & M + str r2, [r0, #1*4] + mov r5, r5, lsr #26 @ d >>= 26 (ignore hi) + orr r5, r5, r6, asl #6 + + add r5, r5, r9 @ d += t2 + str r5, [r0, #2*4] @ r[2] = d + + add sp, sp, #48 + ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc} + .size secp256k1_fe_sqr_inner, .-secp256k1_fe_sqr_inner + diff --git a/src/cryptoconditions/src/include/secp256k1/src/basic-config.h b/src/cryptoconditions/src/include/secp256k1/src/basic-config.h new file mode 100644 index 000000000..fc588061c --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/basic-config.h @@ -0,0 +1,33 @@ +/********************************************************************** + * Copyright (c) 2013, 2014 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_BASIC_CONFIG_H +#define SECP256K1_BASIC_CONFIG_H + +#ifdef USE_BASIC_CONFIG + +#undef USE_ASM_X86_64 +#undef USE_ENDOMORPHISM +#undef USE_FIELD_10X26 +#undef USE_FIELD_5X52 +#undef USE_FIELD_INV_BUILTIN +#undef USE_FIELD_INV_NUM +#undef USE_NUM_GMP +#undef USE_NUM_NONE +#undef USE_SCALAR_4X64 +#undef USE_SCALAR_8X32 +#undef USE_SCALAR_INV_BUILTIN +#undef USE_SCALAR_INV_NUM + +#define USE_NUM_NONE 1 +#define USE_FIELD_INV_BUILTIN 1 +#define USE_SCALAR_INV_BUILTIN 1 +#define USE_FIELD_10X26 1 +#define USE_SCALAR_8X32 1 + +#endif /* USE_BASIC_CONFIG */ + +#endif /* SECP256K1_BASIC_CONFIG_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/bench.h b/src/cryptoconditions/src/include/secp256k1/src/bench.h index db5f68cee..d5ebe0130 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/bench.h +++ b/src/cryptoconditions/src/include/secp256k1/src/bench.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_BENCH_H_ -#define _SECP256K1_BENCH_H_ +#ifndef SECP256K1_BENCH_H +#define SECP256K1_BENCH_H #include #include @@ -20,8 +20,10 @@ static double gettimedouble(void) { void print_number(double x) { double y = x; int c = 0; - if (y < 0.0) y = -y; - while (y < 100.0) { + if (y < 0.0) { + y = -y; + } + while (y > 0 && y < 100.0) { y *= 10.0; c++; } @@ -35,13 +37,21 @@ void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), v double max = 0.0; for (i = 0; i < count; i++) { double begin, total; - if (setup) setup(data); + if (setup != NULL) { + setup(data); + } begin = gettimedouble(); benchmark(data); total = gettimedouble() - begin; - if (teardown) teardown(data); - if (total < min) min = total; - if (total > max) max = total; + if (teardown != NULL) { + teardown(data); + } + if (total < min) { + min = total; + } + if (total > max) { + max = total; + } sum += total; } printf("%s: min ", name); @@ -53,4 +63,4 @@ void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), v printf("us\n"); } -#endif +#endif /* SECP256K1_BENCH_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/bench_ecdh.c b/src/cryptoconditions/src/include/secp256k1/src/bench_ecdh.c new file mode 100644 index 000000000..2de5126d6 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/bench_ecdh.c @@ -0,0 +1,54 @@ +/********************************************************************** + * Copyright (c) 2015 Pieter Wuille, Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#include + +#include "include/secp256k1.h" +#include "include/secp256k1_ecdh.h" +#include "util.h" +#include "bench.h" + +typedef struct { + secp256k1_context *ctx; + secp256k1_pubkey point; + unsigned char scalar[32]; +} bench_ecdh; + +static void bench_ecdh_setup(void* arg) { + int i; + bench_ecdh *data = (bench_ecdh*)arg; + const unsigned char point[] = { + 0x03, + 0x54, 0x94, 0xc1, 0x5d, 0x32, 0x09, 0x97, 0x06, + 0xc2, 0x39, 0x5f, 0x94, 0x34, 0x87, 0x45, 0xfd, + 0x75, 0x7c, 0xe3, 0x0e, 0x4e, 0x8c, 0x90, 0xfb, + 0xa2, 0xba, 0xd1, 0x84, 0xf8, 0x83, 0xc6, 0x9f + }; + + /* create a context with no capabilities */ + data->ctx = secp256k1_context_create(SECP256K1_FLAGS_TYPE_CONTEXT); + for (i = 0; i < 32; i++) { + data->scalar[i] = i + 1; + } + CHECK(secp256k1_ec_pubkey_parse(data->ctx, &data->point, point, sizeof(point)) == 1); +} + +static void bench_ecdh(void* arg) { + int i; + unsigned char res[32]; + bench_ecdh *data = (bench_ecdh*)arg; + + for (i = 0; i < 20000; i++) { + CHECK(secp256k1_ecdh(data->ctx, res, &data->point, data->scalar) == 1); + } +} + +int main(void) { + bench_ecdh data; + + run_benchmark("ecdh", bench_ecdh, bench_ecdh_setup, NULL, &data, 10, 20000); + return 0; +} diff --git a/src/cryptoconditions/src/include/secp256k1/src/bench_internal.c b/src/cryptoconditions/src/include/secp256k1/src/bench_internal.c index a960549b9..9b30c50d0 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/bench_internal.c +++ b/src/cryptoconditions/src/include/secp256k1/src/bench_internal.c @@ -13,20 +13,22 @@ #include "field_impl.h" #include "group_impl.h" #include "scalar_impl.h" +#include "ecmult_const_impl.h" #include "ecmult_impl.h" #include "bench.h" +#include "secp256k1.c" typedef struct { - secp256k1_scalar_t scalar_x, scalar_y; - secp256k1_fe_t fe_x, fe_y; - secp256k1_ge_t ge_x, ge_y; - secp256k1_gej_t gej_x, gej_y; - unsigned char data[32]; + secp256k1_scalar scalar_x, scalar_y; + secp256k1_fe fe_x, fe_y; + secp256k1_ge ge_x, ge_y; + secp256k1_gej gej_x, gej_y; + unsigned char data[64]; int wnaf[256]; -} bench_inv_t; +} bench_inv; void bench_setup(void* arg) { - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; static const unsigned char init_x[32] = { 0x02, 0x03, 0x05, 0x07, 0x0b, 0x0d, 0x11, 0x13, @@ -51,11 +53,12 @@ void bench_setup(void* arg) { secp256k1_gej_set_ge(&data->gej_x, &data->ge_x); secp256k1_gej_set_ge(&data->gej_y, &data->ge_y); memcpy(data->data, init_x, 32); + memcpy(data->data + 32, init_y, 32); } void bench_scalar_add(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 2000000; i++) { secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); @@ -64,7 +67,7 @@ void bench_scalar_add(void* arg) { void bench_scalar_negate(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 2000000; i++) { secp256k1_scalar_negate(&data->scalar_x, &data->scalar_x); @@ -73,7 +76,7 @@ void bench_scalar_negate(void* arg) { void bench_scalar_sqr(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 200000; i++) { secp256k1_scalar_sqr(&data->scalar_x, &data->scalar_x); @@ -82,7 +85,7 @@ void bench_scalar_sqr(void* arg) { void bench_scalar_mul(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 200000; i++) { secp256k1_scalar_mul(&data->scalar_x, &data->scalar_x, &data->scalar_y); @@ -92,11 +95,11 @@ void bench_scalar_mul(void* arg) { #ifdef USE_ENDOMORPHISM void bench_scalar_split(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 20000; i++) { - secp256k1_scalar_t l, r; - secp256k1_scalar_split_lambda_var(&l, &r, &data->scalar_x); + secp256k1_scalar l, r; + secp256k1_scalar_split_lambda(&l, &r, &data->scalar_x); secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); } } @@ -104,7 +107,7 @@ void bench_scalar_split(void* arg) { void bench_scalar_inverse(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 2000; i++) { secp256k1_scalar_inverse(&data->scalar_x, &data->scalar_x); @@ -114,7 +117,7 @@ void bench_scalar_inverse(void* arg) { void bench_scalar_inverse_var(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 2000; i++) { secp256k1_scalar_inverse_var(&data->scalar_x, &data->scalar_x); @@ -124,7 +127,7 @@ void bench_scalar_inverse_var(void* arg) { void bench_field_normalize(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 2000000; i++) { secp256k1_fe_normalize(&data->fe_x); @@ -133,7 +136,7 @@ void bench_field_normalize(void* arg) { void bench_field_normalize_weak(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 2000000; i++) { secp256k1_fe_normalize_weak(&data->fe_x); @@ -142,7 +145,7 @@ void bench_field_normalize_weak(void* arg) { void bench_field_mul(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 200000; i++) { secp256k1_fe_mul(&data->fe_x, &data->fe_x, &data->fe_y); @@ -151,7 +154,7 @@ void bench_field_mul(void* arg) { void bench_field_sqr(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 200000; i++) { secp256k1_fe_sqr(&data->fe_x, &data->fe_x); @@ -160,7 +163,7 @@ void bench_field_sqr(void* arg) { void bench_field_inverse(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 20000; i++) { secp256k1_fe_inv(&data->fe_x, &data->fe_x); @@ -170,7 +173,7 @@ void bench_field_inverse(void* arg) { void bench_field_inverse_var(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 20000; i++) { secp256k1_fe_inv_var(&data->fe_x, &data->fe_x); @@ -178,37 +181,37 @@ void bench_field_inverse_var(void* arg) { } } -void bench_field_sqrt_var(void* arg) { +void bench_field_sqrt(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 20000; i++) { - secp256k1_fe_sqrt_var(&data->fe_x, &data->fe_x); + secp256k1_fe_sqrt(&data->fe_x, &data->fe_x); secp256k1_fe_add(&data->fe_x, &data->fe_y); } } void bench_group_double_var(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 200000; i++) { - secp256k1_gej_double_var(&data->gej_x, &data->gej_x); + secp256k1_gej_double_var(&data->gej_x, &data->gej_x, NULL); } } void bench_group_add_var(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 200000; i++) { - secp256k1_gej_add_var(&data->gej_x, &data->gej_x, &data->gej_y); + secp256k1_gej_add_var(&data->gej_x, &data->gej_x, &data->gej_y, NULL); } } void bench_group_add_affine(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 200000; i++) { secp256k1_gej_add_ge(&data->gej_x, &data->gej_x, &data->ge_y); @@ -217,19 +220,38 @@ void bench_group_add_affine(void* arg) { void bench_group_add_affine_var(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 200000; i++) { - secp256k1_gej_add_ge_var(&data->gej_x, &data->gej_x, &data->ge_y); + secp256k1_gej_add_ge_var(&data->gej_x, &data->gej_x, &data->ge_y, NULL); + } +} + +void bench_group_jacobi_var(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_gej_has_quad_y_var(&data->gej_x); } } void bench_ecmult_wnaf(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; + bench_inv *data = (bench_inv*)arg; for (i = 0; i < 20000; i++) { - secp256k1_ecmult_wnaf(data->wnaf, &data->scalar_x, WINDOW_A); + secp256k1_ecmult_wnaf(data->wnaf, 256, &data->scalar_x, WINDOW_A); + secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); + } +} + +void bench_wnaf_const(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + + for (i = 0; i < 20000; i++) { + secp256k1_wnaf_const(data->wnaf, data->scalar_x, WINDOW_A); secp256k1_scalar_add(&data->scalar_x, &data->scalar_x, &data->scalar_y); } } @@ -237,8 +259,8 @@ void bench_ecmult_wnaf(void* arg) { void bench_sha256(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; - secp256k1_sha256_t sha; + bench_inv *data = (bench_inv*)arg; + secp256k1_sha256 sha; for (i = 0; i < 20000; i++) { secp256k1_sha256_initialize(&sha); @@ -249,8 +271,8 @@ void bench_sha256(void* arg) { void bench_hmac_sha256(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; - secp256k1_hmac_sha256_t hmac; + bench_inv *data = (bench_inv*)arg; + secp256k1_hmac_sha256 hmac; for (i = 0; i < 20000; i++) { secp256k1_hmac_sha256_initialize(&hmac, data->data, 32); @@ -261,15 +283,46 @@ void bench_hmac_sha256(void* arg) { void bench_rfc6979_hmac_sha256(void* arg) { int i; - bench_inv_t *data = (bench_inv_t*)arg; - secp256k1_rfc6979_hmac_sha256_t rng; + bench_inv *data = (bench_inv*)arg; + secp256k1_rfc6979_hmac_sha256 rng; for (i = 0; i < 20000; i++) { - secp256k1_rfc6979_hmac_sha256_initialize(&rng, data->data, 32, data->data, 32, NULL, 0); + secp256k1_rfc6979_hmac_sha256_initialize(&rng, data->data, 64); secp256k1_rfc6979_hmac_sha256_generate(&rng, data->data, 32); } } +void bench_context_verify(void* arg) { + int i; + (void)arg; + for (i = 0; i < 20; i++) { + secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_VERIFY)); + } +} + +void bench_context_sign(void* arg) { + int i; + (void)arg; + for (i = 0; i < 200; i++) { + secp256k1_context_destroy(secp256k1_context_create(SECP256K1_CONTEXT_SIGN)); + } +} + +#ifndef USE_NUM_NONE +void bench_num_jacobi(void* arg) { + int i; + bench_inv *data = (bench_inv*)arg; + secp256k1_num nx, norder; + + secp256k1_scalar_get_num(&nx, &data->scalar_x); + secp256k1_scalar_order_get_num(&norder); + secp256k1_scalar_get_num(&norder, &data->scalar_y); + + for (i = 0; i < 200000; i++) { + secp256k1_num_jacobi(&nx, &norder); + } +} +#endif int have_flag(int argc, char** argv, char *flag) { char** argm = argv + argc; @@ -278,14 +331,16 @@ int have_flag(int argc, char** argv, char *flag) { return 1; } while (argv != NULL && argv != argm) { - if (strcmp(*argv, flag) == 0) return 1; + if (strcmp(*argv, flag) == 0) { + return 1; + } argv++; } return 0; } int main(int argc, char **argv) { - bench_inv_t data; + bench_inv data; if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "add")) run_benchmark("scalar_add", bench_scalar_add, bench_setup, NULL, &data, 10, 2000000); if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "negate")) run_benchmark("scalar_negate", bench_scalar_negate, bench_setup, NULL, &data, 10, 2000000); if (have_flag(argc, argv, "scalar") || have_flag(argc, argv, "sqr")) run_benchmark("scalar_sqr", bench_scalar_sqr, bench_setup, NULL, &data, 10, 200000); @@ -302,17 +357,26 @@ int main(int argc, char **argv) { if (have_flag(argc, argv, "field") || have_flag(argc, argv, "mul")) run_benchmark("field_mul", bench_field_mul, bench_setup, NULL, &data, 10, 200000); if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse", bench_field_inverse, bench_setup, NULL, &data, 10, 20000); if (have_flag(argc, argv, "field") || have_flag(argc, argv, "inverse")) run_benchmark("field_inverse_var", bench_field_inverse_var, bench_setup, NULL, &data, 10, 20000); - if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt_var", bench_field_sqrt_var, bench_setup, NULL, &data, 10, 20000); + if (have_flag(argc, argv, "field") || have_flag(argc, argv, "sqrt")) run_benchmark("field_sqrt", bench_field_sqrt, bench_setup, NULL, &data, 10, 20000); if (have_flag(argc, argv, "group") || have_flag(argc, argv, "double")) run_benchmark("group_double_var", bench_group_double_var, bench_setup, NULL, &data, 10, 200000); if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_var", bench_group_add_var, bench_setup, NULL, &data, 10, 200000); if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine", bench_group_add_affine, bench_setup, NULL, &data, 10, 200000); if (have_flag(argc, argv, "group") || have_flag(argc, argv, "add")) run_benchmark("group_add_affine_var", bench_group_add_affine_var, bench_setup, NULL, &data, 10, 200000); + if (have_flag(argc, argv, "group") || have_flag(argc, argv, "jacobi")) run_benchmark("group_jacobi_var", bench_group_jacobi_var, bench_setup, NULL, &data, 10, 20000); + if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("wnaf_const", bench_wnaf_const, bench_setup, NULL, &data, 10, 20000); if (have_flag(argc, argv, "ecmult") || have_flag(argc, argv, "wnaf")) run_benchmark("ecmult_wnaf", bench_ecmult_wnaf, bench_setup, NULL, &data, 10, 20000); if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "sha256")) run_benchmark("hash_sha256", bench_sha256, bench_setup, NULL, &data, 10, 20000); if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "hmac")) run_benchmark("hash_hmac_sha256", bench_hmac_sha256, bench_setup, NULL, &data, 10, 20000); if (have_flag(argc, argv, "hash") || have_flag(argc, argv, "rng6979")) run_benchmark("hash_rfc6979_hmac_sha256", bench_rfc6979_hmac_sha256, bench_setup, NULL, &data, 10, 20000); + + if (have_flag(argc, argv, "context") || have_flag(argc, argv, "verify")) run_benchmark("context_verify", bench_context_verify, bench_setup, NULL, &data, 10, 20); + if (have_flag(argc, argv, "context") || have_flag(argc, argv, "sign")) run_benchmark("context_sign", bench_context_sign, bench_setup, NULL, &data, 10, 200); + +#ifndef USE_NUM_NONE + if (have_flag(argc, argv, "num") || have_flag(argc, argv, "jacobi")) run_benchmark("num_jacobi", bench_num_jacobi, bench_setup, NULL, &data, 10, 200000); +#endif return 0; } diff --git a/src/cryptoconditions/src/include/secp256k1/src/bench_recover.c b/src/cryptoconditions/src/include/secp256k1/src/bench_recover.c index 56faed11a..506fc1880 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/bench_recover.c +++ b/src/cryptoconditions/src/include/secp256k1/src/bench_recover.c @@ -1,46 +1,55 @@ /********************************************************************** - * Copyright (c) 2014 Pieter Wuille * + * Copyright (c) 2014-2015 Pieter Wuille * * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ #include "include/secp256k1.h" +#include "include/secp256k1_recovery.h" #include "util.h" #include "bench.h" typedef struct { - secp256k1_context_t *ctx; + secp256k1_context *ctx; unsigned char msg[32]; unsigned char sig[64]; -} bench_recover_t; +} bench_recover; void bench_recover(void* arg) { int i; - bench_recover_t *data = (bench_recover_t*)arg; - unsigned char pubkey[33]; + bench_recover *data = (bench_recover*)arg; + secp256k1_pubkey pubkey; + unsigned char pubkeyc[33]; for (i = 0; i < 20000; i++) { int j; - int pubkeylen = 33; - CHECK(secp256k1_ecdsa_recover_compact(data->ctx, data->msg, data->sig, pubkey, &pubkeylen, 1, i % 2)); + size_t pubkeylen = 33; + secp256k1_ecdsa_recoverable_signature sig; + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(data->ctx, &sig, data->sig, i % 2)); + CHECK(secp256k1_ecdsa_recover(data->ctx, &pubkey, &sig, data->msg)); + CHECK(secp256k1_ec_pubkey_serialize(data->ctx, pubkeyc, &pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED)); for (j = 0; j < 32; j++) { data->sig[j + 32] = data->msg[j]; /* Move former message to S. */ data->msg[j] = data->sig[j]; /* Move former R to message. */ - data->sig[j] = pubkey[j + 1]; /* Move recovered pubkey X coordinate to R (which must be a valid X coordinate). */ + data->sig[j] = pubkeyc[j + 1]; /* Move recovered pubkey X coordinate to R (which must be a valid X coordinate). */ } } } void bench_recover_setup(void* arg) { int i; - bench_recover_t *data = (bench_recover_t*)arg; + bench_recover *data = (bench_recover*)arg; - for (i = 0; i < 32; i++) data->msg[i] = 1 + i; - for (i = 0; i < 64; i++) data->sig[i] = 65 + i; + for (i = 0; i < 32; i++) { + data->msg[i] = 1 + i; + } + for (i = 0; i < 64; i++) { + data->sig[i] = 65 + i; + } } int main(void) { - bench_recover_t data; + bench_recover data; data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); diff --git a/src/cryptoconditions/src/include/secp256k1/src/bench_sign.c b/src/cryptoconditions/src/include/secp256k1/src/bench_sign.c index 072a37af5..544b43963 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/bench_sign.c +++ b/src/cryptoconditions/src/include/secp256k1/src/bench_sign.c @@ -9,41 +9,47 @@ #include "bench.h" typedef struct { - secp256k1_context_t* ctx; + secp256k1_context* ctx; unsigned char msg[32]; unsigned char key[32]; -} bench_sign_t; +} bench_sign; static void bench_sign_setup(void* arg) { int i; - bench_sign_t *data = (bench_sign_t*)arg; + bench_sign *data = (bench_sign*)arg; - for (i = 0; i < 32; i++) data->msg[i] = i + 1; - for (i = 0; i < 32; i++) data->key[i] = i + 65; + for (i = 0; i < 32; i++) { + data->msg[i] = i + 1; + } + for (i = 0; i < 32; i++) { + data->key[i] = i + 65; + } } -static void bench_sign(void* arg) { +static void bench_sign_run(void* arg) { int i; - bench_sign_t *data = (bench_sign_t*)arg; + bench_sign *data = (bench_sign*)arg; - unsigned char sig[64]; + unsigned char sig[74]; for (i = 0; i < 20000; i++) { + size_t siglen = 74; int j; - int recid = 0; - CHECK(secp256k1_ecdsa_sign_compact(data->ctx, data->msg, sig, data->key, NULL, NULL, &recid)); + secp256k1_ecdsa_signature signature; + CHECK(secp256k1_ecdsa_sign(data->ctx, &signature, data->msg, data->key, NULL, NULL)); + CHECK(secp256k1_ecdsa_signature_serialize_der(data->ctx, sig, &siglen, &signature)); for (j = 0; j < 32; j++) { - data->msg[j] = sig[j]; /* Move former R to message. */ - data->key[j] = sig[j + 32]; /* Move former S to key. */ + data->msg[j] = sig[j]; + data->key[j] = sig[j + 32]; } } } int main(void) { - bench_sign_t data; + bench_sign data; data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); - run_benchmark("ecdsa_sign", bench_sign, bench_sign_setup, NULL, &data, 10, 20000); + run_benchmark("ecdsa_sign", bench_sign_run, bench_sign_setup, NULL, &data, 10, 20000); secp256k1_context_destroy(data.ctx); return 0; diff --git a/src/cryptoconditions/src/include/secp256k1/src/bench_verify.c b/src/cryptoconditions/src/include/secp256k1/src/bench_verify.c index c8c82752c..418defa0a 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/bench_verify.c +++ b/src/cryptoconditions/src/include/secp256k1/src/bench_verify.c @@ -11,14 +11,23 @@ #include "util.h" #include "bench.h" +#ifdef ENABLE_OPENSSL_TESTS +#include +#include +#include +#endif + typedef struct { - secp256k1_context_t *ctx; + secp256k1_context *ctx; unsigned char msg[32]; unsigned char key[32]; unsigned char sig[72]; - int siglen; + size_t siglen; unsigned char pubkey[33]; - int pubkeylen; + size_t pubkeylen; +#ifdef ENABLE_OPENSSL_TESTS + EC_GROUP* ec_group; +#endif } benchmark_verify_t; static void benchmark_verify(void* arg) { @@ -26,30 +35,77 @@ static void benchmark_verify(void* arg) { benchmark_verify_t* data = (benchmark_verify_t*)arg; for (i = 0; i < 20000; i++) { + secp256k1_pubkey pubkey; + secp256k1_ecdsa_signature sig; data->sig[data->siglen - 1] ^= (i & 0xFF); data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); - CHECK(secp256k1_ecdsa_verify(data->ctx, data->msg, data->sig, data->siglen, data->pubkey, data->pubkeylen) == (i == 0)); + CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->pubkey, data->pubkeylen) == 1); + CHECK(secp256k1_ecdsa_signature_parse_der(data->ctx, &sig, data->sig, data->siglen) == 1); + CHECK(secp256k1_ecdsa_verify(data->ctx, &sig, data->msg, &pubkey) == (i == 0)); data->sig[data->siglen - 1] ^= (i & 0xFF); data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); } } +#ifdef ENABLE_OPENSSL_TESTS +static void benchmark_verify_openssl(void* arg) { + int i; + benchmark_verify_t* data = (benchmark_verify_t*)arg; + + for (i = 0; i < 20000; i++) { + data->sig[data->siglen - 1] ^= (i & 0xFF); + data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); + data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); + { + EC_KEY *pkey = EC_KEY_new(); + const unsigned char *pubkey = &data->pubkey[0]; + int result; + + CHECK(pkey != NULL); + result = EC_KEY_set_group(pkey, data->ec_group); + CHECK(result); + result = (o2i_ECPublicKey(&pkey, &pubkey, data->pubkeylen)) != NULL; + CHECK(result); + result = ECDSA_verify(0, &data->msg[0], sizeof(data->msg), &data->sig[0], data->siglen, pkey) == (i == 0); + CHECK(result); + EC_KEY_free(pkey); + } + data->sig[data->siglen - 1] ^= (i & 0xFF); + data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); + data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); + } +} +#endif + int main(void) { int i; + secp256k1_pubkey pubkey; + secp256k1_ecdsa_signature sig; benchmark_verify_t data; data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - for (i = 0; i < 32; i++) data.msg[i] = 1 + i; - for (i = 0; i < 32; i++) data.key[i] = 33 + i; + for (i = 0; i < 32; i++) { + data.msg[i] = 1 + i; + } + for (i = 0; i < 32; i++) { + data.key[i] = 33 + i; + } data.siglen = 72; - secp256k1_ecdsa_sign(data.ctx, data.msg, data.sig, &data.siglen, data.key, NULL, NULL); + CHECK(secp256k1_ecdsa_sign(data.ctx, &sig, data.msg, data.key, NULL, NULL)); + CHECK(secp256k1_ecdsa_signature_serialize_der(data.ctx, data.sig, &data.siglen, &sig)); + CHECK(secp256k1_ec_pubkey_create(data.ctx, &pubkey, data.key)); data.pubkeylen = 33; - CHECK(secp256k1_ec_pubkey_create(data.ctx, data.pubkey, &data.pubkeylen, data.key, 1)); + CHECK(secp256k1_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED) == 1); run_benchmark("ecdsa_verify", benchmark_verify, NULL, NULL, &data, 10, 20000); +#ifdef ENABLE_OPENSSL_TESTS + data.ec_group = EC_GROUP_new_by_curve_name(NID_secp256k1); + run_benchmark("ecdsa_verify_openssl", benchmark_verify_openssl, NULL, NULL, &data, 10, 20000); + EC_GROUP_free(data.ec_group); +#endif secp256k1_context_destroy(data.ctx); return 0; diff --git a/src/cryptoconditions/src/include/secp256k1/src/ecdsa.h b/src/cryptoconditions/src/include/secp256k1/src/ecdsa.h index 4ef78e8af..80590c7cc 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/ecdsa.h +++ b/src/cryptoconditions/src/include/secp256k1/src/ecdsa.h @@ -4,21 +4,18 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_ECDSA_ -#define _SECP256K1_ECDSA_ +#ifndef SECP256K1_ECDSA_H +#define SECP256K1_ECDSA_H + +#include #include "scalar.h" #include "group.h" #include "ecmult.h" -typedef struct { - secp256k1_scalar_t r, s; -} secp256k1_ecdsa_sig_t; +static int secp256k1_ecdsa_sig_parse(secp256k1_scalar *r, secp256k1_scalar *s, const unsigned char *sig, size_t size); +static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const secp256k1_scalar *r, const secp256k1_scalar *s); +static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const secp256k1_scalar* r, const secp256k1_scalar* s, const secp256k1_ge *pubkey, const secp256k1_scalar *message); +static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid); -static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size); -static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a); -static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message); -static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *seckey, const secp256k1_scalar_t *message, const secp256k1_scalar_t *nonce, int *recid); -static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid); - -#endif +#endif /* SECP256K1_ECDSA_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/ecdsa_impl.h b/src/cryptoconditions/src/include/secp256k1/src/ecdsa_impl.h index 8d97db946..c3400042d 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/ecdsa_impl.h +++ b/src/cryptoconditions/src/include/secp256k1/src/ecdsa_impl.h @@ -1,12 +1,12 @@ /********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * + * Copyright (c) 2013-2015 Pieter Wuille * * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_ECDSA_IMPL_H_ -#define _SECP256K1_ECDSA_IMPL_H_ +#ifndef SECP256K1_ECDSA_IMPL_H +#define SECP256K1_ECDSA_IMPL_H #include "scalar.h" #include "field.h" @@ -28,7 +28,7 @@ * sage: '%x' % (EllipticCurve ([F (a), F (b)]).order()) * 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141' */ -static const secp256k1_fe_t secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CONST( +static const secp256k1_fe secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CONST( 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, 0xBAAEDCE6UL, 0xAF48A03BUL, 0xBFD25E8CUL, 0xD0364141UL ); @@ -42,90 +42,148 @@ static const secp256k1_fe_t secp256k1_ecdsa_const_order_as_fe = SECP256K1_FE_CON * sage: '%x' % (p - EllipticCurve ([F (a), F (b)]).order()) * '14551231950b75fc4402da1722fc9baee' */ -static const secp256k1_fe_t secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_CONST( +static const secp256k1_fe secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_CONST( 0, 0, 0, 1, 0x45512319UL, 0x50B75FC4UL, 0x402DA172UL, 0x2FC9BAEEUL ); -static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size) { +static int secp256k1_der_read_len(const unsigned char **sigp, const unsigned char *sigend) { + int lenleft, b1; + size_t ret = 0; + if (*sigp >= sigend) { + return -1; + } + b1 = *((*sigp)++); + if (b1 == 0xFF) { + /* X.690-0207 8.1.3.5.c the value 0xFF shall not be used. */ + return -1; + } + if ((b1 & 0x80) == 0) { + /* X.690-0207 8.1.3.4 short form length octets */ + return b1; + } + if (b1 == 0x80) { + /* Indefinite length is not allowed in DER. */ + return -1; + } + /* X.690-207 8.1.3.5 long form length octets */ + lenleft = b1 & 0x7F; + if (lenleft > sigend - *sigp) { + return -1; + } + if (**sigp == 0) { + /* Not the shortest possible length encoding. */ + return -1; + } + if ((size_t)lenleft > sizeof(size_t)) { + /* The resulting length would exceed the range of a size_t, so + * certainly longer than the passed array size. + */ + return -1; + } + while (lenleft > 0) { + ret = (ret << 8) | **sigp; + if (ret + lenleft > (size_t)(sigend - *sigp)) { + /* Result exceeds the length of the passed array. */ + return -1; + } + (*sigp)++; + lenleft--; + } + if (ret < 128) { + /* Not the shortest possible length encoding. */ + return -1; + } + return ret; +} - /* libscott had to add this to get this version of the library to read compact sigs */ +static int secp256k1_der_parse_integer(secp256k1_scalar *r, const unsigned char **sig, const unsigned char *sigend) { int overflow = 0; - if (size == 64) { - secp256k1_scalar_set_b32(&r->r, sig, &overflow); - secp256k1_scalar_set_b32(&r->s, sig+32, &overflow); - return 1; - } + unsigned char ra[32] = {0}; + int rlen; - unsigned char ra[32] = {0}, sa[32] = {0}; - const unsigned char *rp; - const unsigned char *sp; - int lenr; - int lens; - if (sig[0] != 0x30) { + if (*sig == sigend || **sig != 0x02) { + /* Not a primitive integer (X.690-0207 8.3.1). */ return 0; } - lenr = sig[3]; - if (5+lenr >= size) { + (*sig)++; + rlen = secp256k1_der_read_len(sig, sigend); + if (rlen <= 0 || (*sig) + rlen > sigend) { + /* Exceeds bounds or not at least length 1 (X.690-0207 8.3.1). */ return 0; } - lens = sig[lenr+5]; - if (sig[1] != lenr+lens+4) { + if (**sig == 0x00 && rlen > 1 && (((*sig)[1]) & 0x80) == 0x00) { + /* Excessive 0x00 padding. */ return 0; } - if (lenr+lens+6 > size) { + if (**sig == 0xFF && rlen > 1 && (((*sig)[1]) & 0x80) == 0x80) { + /* Excessive 0xFF padding. */ return 0; } - if (sig[2] != 0x02) { - return 0; + if ((**sig & 0x80) == 0x80) { + /* Negative. */ + overflow = 1; } - if (lenr == 0) { - return 0; + while (rlen > 0 && **sig == 0) { + /* Skip leading zero bytes */ + rlen--; + (*sig)++; } - if (sig[lenr+4] != 0x02) { - return 0; + if (rlen > 32) { + overflow = 1; } - if (lens == 0) { - return 0; + if (!overflow) { + memcpy(ra + 32 - rlen, *sig, rlen); + secp256k1_scalar_set_b32(r, ra, &overflow); } - sp = sig + 6 + lenr; - while (lens > 0 && sp[0] == 0) { - lens--; - sp++; - } - if (lens > 32) { - return 0; - } - rp = sig + 4; - while (lenr > 0 && rp[0] == 0) { - lenr--; - rp++; - } - if (lenr > 32) { - return 0; - } - memcpy(ra + 32 - lenr, rp, lenr); - memcpy(sa + 32 - lens, sp, lens); - overflow = 0; - secp256k1_scalar_set_b32(&r->r, ra, &overflow); if (overflow) { - return 0; - } - secp256k1_scalar_set_b32(&r->s, sa, &overflow); - if (overflow) { - return 0; + secp256k1_scalar_set_int(r, 0); } + (*sig) += rlen; return 1; } -static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a) { +static int secp256k1_ecdsa_sig_parse(secp256k1_scalar *rr, secp256k1_scalar *rs, const unsigned char *sig, size_t size) { + const unsigned char *sigend = sig + size; + int rlen; + if (sig == sigend || *(sig++) != 0x30) { + /* The encoding doesn't start with a constructed sequence (X.690-0207 8.9.1). */ + return 0; + } + rlen = secp256k1_der_read_len(&sig, sigend); + if (rlen < 0 || sig + rlen > sigend) { + /* Tuple exceeds bounds */ + return 0; + } + if (sig + rlen != sigend) { + /* Garbage after tuple. */ + return 0; + } + + if (!secp256k1_der_parse_integer(rr, &sig, sigend)) { + return 0; + } + if (!secp256k1_der_parse_integer(rs, &sig, sigend)) { + return 0; + } + + if (sig != sigend) { + /* Trailing garbage inside tuple. */ + return 0; + } + + return 1; +} + +static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, size_t *size, const secp256k1_scalar* ar, const secp256k1_scalar* as) { unsigned char r[33] = {0}, s[33] = {0}; unsigned char *rp = r, *sp = s; - int lenR = 33, lenS = 33; - secp256k1_scalar_get_b32(&r[1], &a->r); - secp256k1_scalar_get_b32(&s[1], &a->s); + size_t lenR = 33, lenS = 33; + secp256k1_scalar_get_b32(&r[1], ar); + secp256k1_scalar_get_b32(&s[1], as); while (lenR > 1 && rp[0] == 0 && rp[1] < 0x80) { lenR--; rp++; } while (lenS > 1 && sp[0] == 0 && sp[1] < 0x80) { lenS--; sp++; } if (*size < 6+lenS+lenR) { + *size = 6 + lenS + lenR; return 0; } *size = 6 + lenS + lenR; @@ -140,26 +198,41 @@ static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const se return 1; } -static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message) { +static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context *ctx, const secp256k1_scalar *sigr, const secp256k1_scalar *sigs, const secp256k1_ge *pubkey, const secp256k1_scalar *message) { unsigned char c[32]; - secp256k1_scalar_t sn, u1, u2; - secp256k1_fe_t xr; - secp256k1_gej_t pubkeyj; - secp256k1_gej_t pr; + secp256k1_scalar sn, u1, u2; +#if !defined(EXHAUSTIVE_TEST_ORDER) + secp256k1_fe xr; +#endif + secp256k1_gej pubkeyj; + secp256k1_gej pr; - if (secp256k1_scalar_is_zero(&sig->r) || secp256k1_scalar_is_zero(&sig->s)) { + if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) { return 0; } - secp256k1_scalar_inverse_var(&sn, &sig->s); + secp256k1_scalar_inverse_var(&sn, sigs); secp256k1_scalar_mul(&u1, &sn, message); - secp256k1_scalar_mul(&u2, &sn, &sig->r); + secp256k1_scalar_mul(&u2, &sn, sigr); secp256k1_gej_set_ge(&pubkeyj, pubkey); secp256k1_ecmult(ctx, &pr, &pubkeyj, &u2, &u1); if (secp256k1_gej_is_infinity(&pr)) { return 0; } - secp256k1_scalar_get_b32(c, &sig->r); + +#if defined(EXHAUSTIVE_TEST_ORDER) +{ + secp256k1_scalar computed_r; + secp256k1_ge pr_ge; + secp256k1_ge_set_gej(&pr_ge, &pr); + secp256k1_fe_normalize(&pr_ge.x); + + secp256k1_fe_get_b32(c, &pr_ge.x); + secp256k1_scalar_set_b32(&computed_r, c, NULL); + return secp256k1_scalar_eq(sigr, &computed_r); +} +#else + secp256k1_scalar_get_b32(c, sigr); secp256k1_fe_set_b32(&xr, c); /** We now have the recomputed R point in pr, and its claimed x coordinate (modulo n) @@ -179,11 +252,11 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, con * secp256k1_gej_eq_x implements the (xr * pr.z^2 mod p == pr.x) test. */ if (secp256k1_gej_eq_x_var(&xr, &pr)) { - /* xr.x == xr * xr.z^2 mod p, so the signature is valid. */ + /* xr * pr.z^2 mod p == pr.x, so the signature is valid. */ return 1; } if (secp256k1_fe_cmp_var(&xr, &secp256k1_ecdsa_const_p_minus_order) >= 0) { - /* xr + p >= n, so we can skip testing the second case. */ + /* xr + n >= p, so we can skip testing the second case. */ return 0; } secp256k1_fe_add(&xr, &secp256k1_ecdsa_const_order_as_fe); @@ -192,46 +265,14 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, con return 1; } return 0; +#endif } -static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid) { - unsigned char brx[32]; - secp256k1_fe_t fx; - secp256k1_ge_t x; - secp256k1_gej_t xj; - secp256k1_scalar_t rn, u1, u2; - secp256k1_gej_t qj; - - if (secp256k1_scalar_is_zero(&sig->r) || secp256k1_scalar_is_zero(&sig->s)) { - return 0; - } - - secp256k1_scalar_get_b32(brx, &sig->r); - VERIFY_CHECK(secp256k1_fe_set_b32(&fx, brx)); /* brx comes from a scalar, so is less than the order; certainly less than p */ - if (recid & 2) { - if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_const_p_minus_order) >= 0) { - return 0; - } - secp256k1_fe_add(&fx, &secp256k1_ecdsa_const_order_as_fe); - } - if (!secp256k1_ge_set_xo_var(&x, &fx, recid & 1)) { - return 0; - } - secp256k1_gej_set_ge(&xj, &x); - secp256k1_scalar_inverse_var(&rn, &sig->r); - secp256k1_scalar_mul(&u1, &rn, message); - secp256k1_scalar_negate(&u1, &u1); - secp256k1_scalar_mul(&u2, &rn, &sig->s); - secp256k1_ecmult(ctx, &qj, &xj, &u2, &u1); - secp256k1_ge_set_gej_var(pubkey, &qj); - return !secp256k1_gej_is_infinity(&qj); -} - -static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *seckey, const secp256k1_scalar_t *message, const secp256k1_scalar_t *nonce, int *recid) { +static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context *ctx, secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *seckey, const secp256k1_scalar *message, const secp256k1_scalar *nonce, int *recid) { unsigned char b[32]; - secp256k1_gej_t rp; - secp256k1_ge_t r; - secp256k1_scalar_t n; + secp256k1_gej rp; + secp256k1_ge r; + secp256k1_scalar n; int overflow = 0; secp256k1_ecmult_gen(ctx, &rp, nonce); @@ -239,28 +280,29 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, s secp256k1_fe_normalize(&r.x); secp256k1_fe_normalize(&r.y); secp256k1_fe_get_b32(b, &r.x); - secp256k1_scalar_set_b32(&sig->r, b, &overflow); - if (secp256k1_scalar_is_zero(&sig->r)) { - /* P.x = order is on the curve, so technically sig->r could end up zero, which would be an invalid signature. */ - secp256k1_gej_clear(&rp); - secp256k1_ge_clear(&r); - return 0; - } + secp256k1_scalar_set_b32(sigr, b, &overflow); + /* These two conditions should be checked before calling */ + VERIFY_CHECK(!secp256k1_scalar_is_zero(sigr)); + VERIFY_CHECK(overflow == 0); + if (recid) { + /* The overflow condition is cryptographically unreachable as hitting it requires finding the discrete log + * of some P where P.x >= order, and only 1 in about 2^127 points meet this criteria. + */ *recid = (overflow ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0); } - secp256k1_scalar_mul(&n, &sig->r, seckey); + secp256k1_scalar_mul(&n, sigr, seckey); secp256k1_scalar_add(&n, &n, message); - secp256k1_scalar_inverse(&sig->s, nonce); - secp256k1_scalar_mul(&sig->s, &sig->s, &n); + secp256k1_scalar_inverse(sigs, nonce); + secp256k1_scalar_mul(sigs, sigs, &n); secp256k1_scalar_clear(&n); secp256k1_gej_clear(&rp); secp256k1_ge_clear(&r); - if (secp256k1_scalar_is_zero(&sig->s)) { + if (secp256k1_scalar_is_zero(sigs)) { return 0; } - if (secp256k1_scalar_is_high(&sig->s)) { - secp256k1_scalar_negate(&sig->s, &sig->s); + if (secp256k1_scalar_is_high(sigs)) { + secp256k1_scalar_negate(sigs, sigs); if (recid) { *recid ^= 1; } @@ -268,4 +310,4 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, s return 1; } -#endif +#endif /* SECP256K1_ECDSA_IMPL_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/eckey.h b/src/cryptoconditions/src/include/secp256k1/src/eckey.h index 53b818485..b621f1e6c 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/eckey.h +++ b/src/cryptoconditions/src/include/secp256k1/src/eckey.h @@ -4,23 +4,22 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_ECKEY_ -#define _SECP256K1_ECKEY_ +#ifndef SECP256K1_ECKEY_H +#define SECP256K1_ECKEY_H + +#include #include "group.h" #include "scalar.h" #include "ecmult.h" #include "ecmult_gen.h" -static int secp256k1_eckey_pubkey_parse(secp256k1_ge_t *elem, const unsigned char *pub, int size); -static int secp256k1_eckey_pubkey_serialize(secp256k1_ge_t *elem, unsigned char *pub, int *size, int compressed); +static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size); +static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed); -static int secp256k1_eckey_privkey_parse(secp256k1_scalar_t *key, const unsigned char *privkey, int privkeylen); -static int secp256k1_eckey_privkey_serialize(const secp256k1_ecmult_gen_context_t *ctx, unsigned char *privkey, int *privkeylen, const secp256k1_scalar_t *key, int compressed); +static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak); +static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak); +static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak); +static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak); -static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak); -static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context_t *ctx, secp256k1_ge_t *key, const secp256k1_scalar_t *tweak); -static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak); -static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context_t *ctx, secp256k1_ge_t *key, const secp256k1_scalar_t *tweak); - -#endif +#endif /* SECP256K1_ECKEY_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/eckey_impl.h b/src/cryptoconditions/src/include/secp256k1/src/eckey_impl.h index a332bd34e..1ab9a68ec 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/eckey_impl.h +++ b/src/cryptoconditions/src/include/secp256k1/src/eckey_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_ECKEY_IMPL_H_ -#define _SECP256K1_ECKEY_IMPL_H_ +#ifndef SECP256K1_ECKEY_IMPL_H +#define SECP256K1_ECKEY_IMPL_H #include "eckey.h" @@ -14,17 +14,18 @@ #include "group.h" #include "ecmult_gen.h" -static int secp256k1_eckey_pubkey_parse(secp256k1_ge_t *elem, const unsigned char *pub, int size) { - if (size == 33 && (pub[0] == 0x02 || pub[0] == 0x03)) { - secp256k1_fe_t x; - return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == 0x03); +static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size) { + if (size == 33 && (pub[0] == SECP256K1_TAG_PUBKEY_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_ODD)) { + secp256k1_fe x; + return secp256k1_fe_set_b32(&x, pub+1) && secp256k1_ge_set_xo_var(elem, &x, pub[0] == SECP256K1_TAG_PUBKEY_ODD); } else if (size == 65 && (pub[0] == 0x04 || pub[0] == 0x06 || pub[0] == 0x07)) { - secp256k1_fe_t x, y; + secp256k1_fe x, y; if (!secp256k1_fe_set_b32(&x, pub+1) || !secp256k1_fe_set_b32(&y, pub+33)) { return 0; } secp256k1_ge_set_xy(elem, &x, &y); - if ((pub[0] == 0x06 || pub[0] == 0x07) && secp256k1_fe_is_odd(&y) != (pub[0] == 0x07)) { + if ((pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_EVEN || pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD) && + secp256k1_fe_is_odd(&y) != (pub[0] == SECP256K1_TAG_PUBKEY_HYBRID_ODD)) { return 0; } return secp256k1_ge_is_valid_var(elem); @@ -33,7 +34,7 @@ static int secp256k1_eckey_pubkey_parse(secp256k1_ge_t *elem, const unsigned cha } } -static int secp256k1_eckey_pubkey_serialize(secp256k1_ge_t *elem, unsigned char *pub, int *size, int compressed) { +static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed) { if (secp256k1_ge_is_infinity(elem)) { return 0; } @@ -42,119 +43,16 @@ static int secp256k1_eckey_pubkey_serialize(secp256k1_ge_t *elem, unsigned char secp256k1_fe_get_b32(&pub[1], &elem->x); if (compressed) { *size = 33; - pub[0] = 0x02 | (secp256k1_fe_is_odd(&elem->y) ? 0x01 : 0x00); + pub[0] = secp256k1_fe_is_odd(&elem->y) ? SECP256K1_TAG_PUBKEY_ODD : SECP256K1_TAG_PUBKEY_EVEN; } else { *size = 65; - pub[0] = 0x04; + pub[0] = SECP256K1_TAG_PUBKEY_UNCOMPRESSED; secp256k1_fe_get_b32(&pub[33], &elem->y); } return 1; } -static int secp256k1_eckey_privkey_parse(secp256k1_scalar_t *key, const unsigned char *privkey, int privkeylen) { - unsigned char c[32] = {0}; - const unsigned char *end = privkey + privkeylen; - int lenb = 0; - int len = 0; - int overflow = 0; - /* sequence header */ - if (end < privkey+1 || *privkey != 0x30) { - return 0; - } - privkey++; - /* sequence length constructor */ - if (end < privkey+1 || !(*privkey & 0x80)) { - return 0; - } - lenb = *privkey & ~0x80; privkey++; - if (lenb < 1 || lenb > 2) { - return 0; - } - if (end < privkey+lenb) { - return 0; - } - /* sequence length */ - len = privkey[lenb-1] | (lenb > 1 ? privkey[lenb-2] << 8 : 0); - privkey += lenb; - if (end < privkey+len) { - return 0; - } - /* sequence element 0: version number (=1) */ - if (end < privkey+3 || privkey[0] != 0x02 || privkey[1] != 0x01 || privkey[2] != 0x01) { - return 0; - } - privkey += 3; - /* sequence element 1: octet string, up to 32 bytes */ - if (end < privkey+2 || privkey[0] != 0x04 || privkey[1] > 0x20 || end < privkey+2+privkey[1]) { - return 0; - } - memcpy(c + 32 - privkey[1], privkey + 2, privkey[1]); - secp256k1_scalar_set_b32(key, c, &overflow); - memset(c, 0, 32); - return !overflow; -} - -static int secp256k1_eckey_privkey_serialize(const secp256k1_ecmult_gen_context_t *ctx, unsigned char *privkey, int *privkeylen, const secp256k1_scalar_t *key, int compressed) { - secp256k1_gej_t rp; - secp256k1_ge_t r; - int pubkeylen = 0; - secp256k1_ecmult_gen(ctx, &rp, key); - secp256k1_ge_set_gej(&r, &rp); - if (compressed) { - static const unsigned char begin[] = { - 0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20 - }; - static const unsigned char middle[] = { - 0xA0,0x81,0x85,0x30,0x81,0x82,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, - 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, - 0x21,0x02,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, - 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, - 0x17,0x98,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, - 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x24,0x03,0x22,0x00 - }; - unsigned char *ptr = privkey; - memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); - secp256k1_scalar_get_b32(ptr, key); ptr += 32; - memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); - if (!secp256k1_eckey_pubkey_serialize(&r, ptr, &pubkeylen, 1)) { - return 0; - } - ptr += pubkeylen; - *privkeylen = ptr - privkey; - } else { - static const unsigned char begin[] = { - 0x30,0x82,0x01,0x13,0x02,0x01,0x01,0x04,0x20 - }; - static const unsigned char middle[] = { - 0xA0,0x81,0xA5,0x30,0x81,0xA2,0x02,0x01,0x01,0x30,0x2C,0x06,0x07,0x2A,0x86,0x48, - 0xCE,0x3D,0x01,0x01,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F,0x30,0x06,0x04,0x01,0x00,0x04,0x01,0x07,0x04, - 0x41,0x04,0x79,0xBE,0x66,0x7E,0xF9,0xDC,0xBB,0xAC,0x55,0xA0,0x62,0x95,0xCE,0x87, - 0x0B,0x07,0x02,0x9B,0xFC,0xDB,0x2D,0xCE,0x28,0xD9,0x59,0xF2,0x81,0x5B,0x16,0xF8, - 0x17,0x98,0x48,0x3A,0xDA,0x77,0x26,0xA3,0xC4,0x65,0x5D,0xA4,0xFB,0xFC,0x0E,0x11, - 0x08,0xA8,0xFD,0x17,0xB4,0x48,0xA6,0x85,0x54,0x19,0x9C,0x47,0xD0,0x8F,0xFB,0x10, - 0xD4,0xB8,0x02,0x21,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFE,0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,0xBF,0xD2,0x5E, - 0x8C,0xD0,0x36,0x41,0x41,0x02,0x01,0x01,0xA1,0x44,0x03,0x42,0x00 - }; - unsigned char *ptr = privkey; - memcpy(ptr, begin, sizeof(begin)); ptr += sizeof(begin); - secp256k1_scalar_get_b32(ptr, key); ptr += 32; - memcpy(ptr, middle, sizeof(middle)); ptr += sizeof(middle); - if (!secp256k1_eckey_pubkey_serialize(&r, ptr, &pubkeylen, 0)) { - return 0; - } - ptr += pubkeylen; - *privkeylen = ptr - privkey; - } - return 1; -} - -static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak) { +static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak) { secp256k1_scalar_add(key, key, tweak); if (secp256k1_scalar_is_zero(key)) { return 0; @@ -162,9 +60,9 @@ static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar_t *key, const secp return 1; } -static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context_t *ctx, secp256k1_ge_t *key, const secp256k1_scalar_t *tweak) { - secp256k1_gej_t pt; - secp256k1_scalar_t one; +static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak) { + secp256k1_gej pt; + secp256k1_scalar one; secp256k1_gej_set_ge(&pt, key); secp256k1_scalar_set_int(&one, 1); secp256k1_ecmult(ctx, &pt, &pt, &one, tweak); @@ -176,7 +74,7 @@ static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context_t *ct return 1; } -static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar_t *key, const secp256k1_scalar_t *tweak) { +static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar *key, const secp256k1_scalar *tweak) { if (secp256k1_scalar_is_zero(tweak)) { return 0; } @@ -185,9 +83,9 @@ static int secp256k1_eckey_privkey_tweak_mul(secp256k1_scalar_t *key, const secp return 1; } -static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context_t *ctx, secp256k1_ge_t *key, const secp256k1_scalar_t *tweak) { - secp256k1_scalar_t zero; - secp256k1_gej_t pt; +static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak) { + secp256k1_scalar zero; + secp256k1_gej pt; if (secp256k1_scalar_is_zero(tweak)) { return 0; } @@ -199,4 +97,4 @@ static int secp256k1_eckey_pubkey_tweak_mul(const secp256k1_ecmult_context_t *ct return 1; } -#endif +#endif /* SECP256K1_ECKEY_IMPL_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/ecmult.h b/src/cryptoconditions/src/include/secp256k1/src/ecmult.h index bab9e4ef5..6d44aba60 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/ecmult.h +++ b/src/cryptoconditions/src/include/secp256k1/src/ecmult.h @@ -4,28 +4,28 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_ECMULT_ -#define _SECP256K1_ECMULT_ +#ifndef SECP256K1_ECMULT_H +#define SECP256K1_ECMULT_H #include "num.h" #include "group.h" typedef struct { /* For accelerating the computation of a*P + b*G: */ - secp256k1_ge_storage_t (*pre_g)[]; /* odd multiples of the generator */ + secp256k1_ge_storage (*pre_g)[]; /* odd multiples of the generator */ #ifdef USE_ENDOMORPHISM - secp256k1_ge_storage_t (*pre_g_128)[]; /* odd multiples of 2^128*generator */ + secp256k1_ge_storage (*pre_g_128)[]; /* odd multiples of 2^128*generator */ #endif -} secp256k1_ecmult_context_t; +} secp256k1_ecmult_context; -static void secp256k1_ecmult_context_init(secp256k1_ecmult_context_t *ctx); -static void secp256k1_ecmult_context_build(secp256k1_ecmult_context_t *ctx); -static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context_t *dst, - const secp256k1_ecmult_context_t *src); -static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context_t *ctx); -static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context_t *ctx); +static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx); +static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_callback *cb); +static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context *dst, + const secp256k1_ecmult_context *src, const secp256k1_callback *cb); +static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx); +static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx); /** Double multiply: R = na*A + ng*G */ -static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_scalar_t *na, const secp256k1_scalar_t *ng); +static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng); -#endif +#endif /* SECP256K1_ECMULT_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/ecmult_const.h b/src/cryptoconditions/src/include/secp256k1/src/ecmult_const.h new file mode 100644 index 000000000..72bf7d758 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/ecmult_const.h @@ -0,0 +1,15 @@ +/********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_ECMULT_CONST_H +#define SECP256K1_ECMULT_CONST_H + +#include "scalar.h" +#include "group.h" + +static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *q); + +#endif /* SECP256K1_ECMULT_CONST_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/ecmult_const_impl.h b/src/cryptoconditions/src/include/secp256k1/src/ecmult_const_impl.h new file mode 100644 index 000000000..7d7a172b7 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/ecmult_const_impl.h @@ -0,0 +1,240 @@ +/********************************************************************** + * Copyright (c) 2015 Pieter Wuille, Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_ECMULT_CONST_IMPL_H +#define SECP256K1_ECMULT_CONST_IMPL_H + +#include "scalar.h" +#include "group.h" +#include "ecmult_const.h" +#include "ecmult_impl.h" + +#ifdef USE_ENDOMORPHISM + #define WNAF_BITS 128 +#else + #define WNAF_BITS 256 +#endif +#define WNAF_SIZE(w) ((WNAF_BITS + (w) - 1) / (w)) + +/* This is like `ECMULT_TABLE_GET_GE` but is constant time */ +#define ECMULT_CONST_TABLE_GET_GE(r,pre,n,w) do { \ + int m; \ + int abs_n = (n) * (((n) > 0) * 2 - 1); \ + int idx_n = abs_n / 2; \ + secp256k1_fe neg_y; \ + VERIFY_CHECK(((n) & 1) == 1); \ + VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \ + VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \ + VERIFY_SETUP(secp256k1_fe_clear(&(r)->x)); \ + VERIFY_SETUP(secp256k1_fe_clear(&(r)->y)); \ + for (m = 0; m < ECMULT_TABLE_SIZE(w); m++) { \ + /* This loop is used to avoid secret data in array indices. See + * the comment in ecmult_gen_impl.h for rationale. */ \ + secp256k1_fe_cmov(&(r)->x, &(pre)[m].x, m == idx_n); \ + secp256k1_fe_cmov(&(r)->y, &(pre)[m].y, m == idx_n); \ + } \ + (r)->infinity = 0; \ + secp256k1_fe_negate(&neg_y, &(r)->y, 1); \ + secp256k1_fe_cmov(&(r)->y, &neg_y, (n) != abs_n); \ +} while(0) + + +/** Convert a number to WNAF notation. + * The number becomes represented by sum(2^{wi} * wnaf[i], i=0..WNAF_SIZE(w)+1) - return_val. + * It has the following guarantees: + * - each wnaf[i] an odd integer between -(1 << w) and (1 << w) + * - each wnaf[i] is nonzero + * - the number of words set is always WNAF_SIZE(w) + 1 + * + * Adapted from `The Width-w NAF Method Provides Small Memory and Fast Elliptic Scalar + * Multiplications Secure against Side Channel Attacks`, Okeya and Tagaki. M. Joye (Ed.) + * CT-RSA 2003, LNCS 2612, pp. 328-443, 2003. Springer-Verlagy Berlin Heidelberg 2003 + * + * Numbers reference steps of `Algorithm SPA-resistant Width-w NAF with Odd Scalar` on pp. 335 + */ +static int secp256k1_wnaf_const(int *wnaf, secp256k1_scalar s, int w) { + int global_sign; + int skew = 0; + int word = 0; + + /* 1 2 3 */ + int u_last; + int u; + + int flip; + int bit; + secp256k1_scalar neg_s; + int not_neg_one; + /* Note that we cannot handle even numbers by negating them to be odd, as is + * done in other implementations, since if our scalars were specified to have + * width < 256 for performance reasons, their negations would have width 256 + * and we'd lose any performance benefit. Instead, we use a technique from + * Section 4.2 of the Okeya/Tagaki paper, which is to add either 1 (for even) + * or 2 (for odd) to the number we are encoding, returning a skew value indicating + * this, and having the caller compensate after doing the multiplication. */ + + /* Negative numbers will be negated to keep their bit representation below the maximum width */ + flip = secp256k1_scalar_is_high(&s); + /* We add 1 to even numbers, 2 to odd ones, noting that negation flips parity */ + bit = flip ^ !secp256k1_scalar_is_even(&s); + /* We check for negative one, since adding 2 to it will cause an overflow */ + secp256k1_scalar_negate(&neg_s, &s); + not_neg_one = !secp256k1_scalar_is_one(&neg_s); + secp256k1_scalar_cadd_bit(&s, bit, not_neg_one); + /* If we had negative one, flip == 1, s.d[0] == 0, bit == 1, so caller expects + * that we added two to it and flipped it. In fact for -1 these operations are + * identical. We only flipped, but since skewing is required (in the sense that + * the skew must be 1 or 2, never zero) and flipping is not, we need to change + * our flags to claim that we only skewed. */ + global_sign = secp256k1_scalar_cond_negate(&s, flip); + global_sign *= not_neg_one * 2 - 1; + skew = 1 << bit; + + /* 4 */ + u_last = secp256k1_scalar_shr_int(&s, w); + while (word * w < WNAF_BITS) { + int sign; + int even; + + /* 4.1 4.4 */ + u = secp256k1_scalar_shr_int(&s, w); + /* 4.2 */ + even = ((u & 1) == 0); + sign = 2 * (u_last > 0) - 1; + u += sign * even; + u_last -= sign * even * (1 << w); + + /* 4.3, adapted for global sign change */ + wnaf[word++] = u_last * global_sign; + + u_last = u; + } + wnaf[word] = u * global_sign; + + VERIFY_CHECK(secp256k1_scalar_is_zero(&s)); + VERIFY_CHECK(word == WNAF_SIZE(w)); + return skew; +} + + +static void secp256k1_ecmult_const(secp256k1_gej *r, const secp256k1_ge *a, const secp256k1_scalar *scalar) { + secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; + secp256k1_ge tmpa; + secp256k1_fe Z; + + int skew_1; + int wnaf_1[1 + WNAF_SIZE(WINDOW_A - 1)]; +#ifdef USE_ENDOMORPHISM + secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; + int wnaf_lam[1 + WNAF_SIZE(WINDOW_A - 1)]; + int skew_lam; + secp256k1_scalar q_1, q_lam; +#endif + + int i; + secp256k1_scalar sc = *scalar; + + /* build wnaf representation for q. */ +#ifdef USE_ENDOMORPHISM + /* split q into q_1 and q_lam (where q = q_1 + q_lam*lambda, and q_1 and q_lam are ~128 bit) */ + secp256k1_scalar_split_lambda(&q_1, &q_lam, &sc); + skew_1 = secp256k1_wnaf_const(wnaf_1, q_1, WINDOW_A - 1); + skew_lam = secp256k1_wnaf_const(wnaf_lam, q_lam, WINDOW_A - 1); +#else + skew_1 = secp256k1_wnaf_const(wnaf_1, sc, WINDOW_A - 1); +#endif + + /* Calculate odd multiples of a. + * All multiples are brought to the same Z 'denominator', which is stored + * in Z. Due to secp256k1' isomorphism we can do all operations pretending + * that the Z coordinate was 1, use affine addition formulae, and correct + * the Z coordinate of the result once at the end. + */ + secp256k1_gej_set_ge(r, a); + secp256k1_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, r); + for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { + secp256k1_fe_normalize_weak(&pre_a[i].y); + } +#ifdef USE_ENDOMORPHISM + for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { + secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]); + } +#endif + + /* first loop iteration (separated out so we can directly set r, rather + * than having it start at infinity, get doubled several times, then have + * its new value added to it) */ + i = wnaf_1[WNAF_SIZE(WINDOW_A - 1)]; + VERIFY_CHECK(i != 0); + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, i, WINDOW_A); + secp256k1_gej_set_ge(r, &tmpa); +#ifdef USE_ENDOMORPHISM + i = wnaf_lam[WNAF_SIZE(WINDOW_A - 1)]; + VERIFY_CHECK(i != 0); + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, i, WINDOW_A); + secp256k1_gej_add_ge(r, r, &tmpa); +#endif + /* remaining loop iterations */ + for (i = WNAF_SIZE(WINDOW_A - 1) - 1; i >= 0; i--) { + int n; + int j; + for (j = 0; j < WINDOW_A - 1; ++j) { + secp256k1_gej_double_nonzero(r, r, NULL); + } + + n = wnaf_1[i]; + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); + VERIFY_CHECK(n != 0); + secp256k1_gej_add_ge(r, r, &tmpa); +#ifdef USE_ENDOMORPHISM + n = wnaf_lam[i]; + ECMULT_CONST_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A); + VERIFY_CHECK(n != 0); + secp256k1_gej_add_ge(r, r, &tmpa); +#endif + } + + secp256k1_fe_mul(&r->z, &r->z, &Z); + + { + /* Correct for wNAF skew */ + secp256k1_ge correction = *a; + secp256k1_ge_storage correction_1_stor; +#ifdef USE_ENDOMORPHISM + secp256k1_ge_storage correction_lam_stor; +#endif + secp256k1_ge_storage a2_stor; + secp256k1_gej tmpj; + secp256k1_gej_set_ge(&tmpj, &correction); + secp256k1_gej_double_var(&tmpj, &tmpj, NULL); + secp256k1_ge_set_gej(&correction, &tmpj); + secp256k1_ge_to_storage(&correction_1_stor, a); +#ifdef USE_ENDOMORPHISM + secp256k1_ge_to_storage(&correction_lam_stor, a); +#endif + secp256k1_ge_to_storage(&a2_stor, &correction); + + /* For odd numbers this is 2a (so replace it), for even ones a (so no-op) */ + secp256k1_ge_storage_cmov(&correction_1_stor, &a2_stor, skew_1 == 2); +#ifdef USE_ENDOMORPHISM + secp256k1_ge_storage_cmov(&correction_lam_stor, &a2_stor, skew_lam == 2); +#endif + + /* Apply the correction */ + secp256k1_ge_from_storage(&correction, &correction_1_stor); + secp256k1_ge_neg(&correction, &correction); + secp256k1_gej_add_ge(r, r, &correction); + +#ifdef USE_ENDOMORPHISM + secp256k1_ge_from_storage(&correction, &correction_lam_stor); + secp256k1_ge_neg(&correction, &correction); + secp256k1_ge_mul_lambda(&correction, &correction); + secp256k1_gej_add_ge(r, r, &correction); +#endif + } +} + +#endif /* SECP256K1_ECMULT_CONST_IMPL_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/ecmult_gen.h b/src/cryptoconditions/src/include/secp256k1/src/ecmult_gen.h index 3745633c4..7564b7015 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/ecmult_gen.h +++ b/src/cryptoconditions/src/include/secp256k1/src/ecmult_gen.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_ECMULT_GEN_ -#define _SECP256K1_ECMULT_GEN_ +#ifndef SECP256K1_ECMULT_GEN_H +#define SECP256K1_ECMULT_GEN_H #include "scalar.h" #include "group.h" @@ -23,21 +23,21 @@ typedef struct { * None of the resulting prec group elements have a known scalar, and neither do any of * the intermediate sums while computing a*G. */ - secp256k1_ge_storage_t (*prec)[64][16]; /* prec[j][i] = 16^j * i * G + U_i */ - secp256k1_scalar_t blind; - secp256k1_gej_t initial; -} secp256k1_ecmult_gen_context_t; + secp256k1_ge_storage (*prec)[64][16]; /* prec[j][i] = 16^j * i * G + U_i */ + secp256k1_scalar blind; + secp256k1_gej initial; +} secp256k1_ecmult_gen_context; -static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context_t* ctx); -static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context_t* ctx); -static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context_t *dst, - const secp256k1_ecmult_gen_context_t* src); -static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context_t* ctx); -static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context_t* ctx); +static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context* ctx); +static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context* ctx, const secp256k1_callback* cb); +static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context *dst, + const secp256k1_ecmult_gen_context* src, const secp256k1_callback* cb); +static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context* ctx); +static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context* ctx); /** Multiply with the generator: R = a*G */ -static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context_t* ctx, secp256k1_gej_t *r, const secp256k1_scalar_t *a); +static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context* ctx, secp256k1_gej *r, const secp256k1_scalar *a); -static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context_t *ctx, const unsigned char *seed32); +static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32); -#endif +#endif /* SECP256K1_ECMULT_GEN_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/ecmult_gen_impl.h b/src/cryptoconditions/src/include/secp256k1/src/ecmult_gen_impl.h index 4697753ac..714f02e94 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/ecmult_gen_impl.h +++ b/src/cryptoconditions/src/include/secp256k1/src/ecmult_gen_impl.h @@ -4,29 +4,33 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_ECMULT_GEN_IMPL_H_ -#define _SECP256K1_ECMULT_GEN_IMPL_H_ +#ifndef SECP256K1_ECMULT_GEN_IMPL_H +#define SECP256K1_ECMULT_GEN_IMPL_H #include "scalar.h" #include "group.h" #include "ecmult_gen.h" #include "hash_impl.h" - -static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context_t *ctx) { +#ifdef USE_ECMULT_STATIC_PRECOMPUTATION +#include "ecmult_static_context.h" +#endif +static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context *ctx) { ctx->prec = NULL; } -static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context_t *ctx) { - secp256k1_ge_t prec[1024]; - secp256k1_gej_t gj; - secp256k1_gej_t nums_gej; +static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context *ctx, const secp256k1_callback* cb) { +#ifndef USE_ECMULT_STATIC_PRECOMPUTATION + secp256k1_ge prec[1024]; + secp256k1_gej gj; + secp256k1_gej nums_gej; int i, j; +#endif if (ctx->prec != NULL) { return; } - - ctx->prec = (secp256k1_ge_storage_t (*)[64][16])checked_malloc(sizeof(*ctx->prec)); +#ifndef USE_ECMULT_STATIC_PRECOMPUTATION + ctx->prec = (secp256k1_ge_storage (*)[64][16])checked_malloc(cb, sizeof(*ctx->prec)); /* get the generator */ secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); @@ -34,77 +38,93 @@ static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context_t *c /* Construct a group element with no known corresponding scalar (nothing up my sleeve). */ { static const unsigned char nums_b32[33] = "The scalar for this x is unknown"; - secp256k1_fe_t nums_x; - secp256k1_ge_t nums_ge; - VERIFY_CHECK(secp256k1_fe_set_b32(&nums_x, nums_b32)); - VERIFY_CHECK(secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0)); + secp256k1_fe nums_x; + secp256k1_ge nums_ge; + int r; + r = secp256k1_fe_set_b32(&nums_x, nums_b32); + (void)r; + VERIFY_CHECK(r); + r = secp256k1_ge_set_xo_var(&nums_ge, &nums_x, 0); + (void)r; + VERIFY_CHECK(r); secp256k1_gej_set_ge(&nums_gej, &nums_ge); /* Add G to make the bits in x uniformly distributed. */ - secp256k1_gej_add_ge_var(&nums_gej, &nums_gej, &secp256k1_ge_const_g); + secp256k1_gej_add_ge_var(&nums_gej, &nums_gej, &secp256k1_ge_const_g, NULL); } /* compute prec. */ { - secp256k1_gej_t precj[1024]; /* Jacobian versions of prec. */ - secp256k1_gej_t gbase; - secp256k1_gej_t numsbase; + secp256k1_gej precj[1024]; /* Jacobian versions of prec. */ + secp256k1_gej gbase; + secp256k1_gej numsbase; gbase = gj; /* 16^j * G */ numsbase = nums_gej; /* 2^j * nums. */ for (j = 0; j < 64; j++) { /* Set precj[j*16 .. j*16+15] to (numsbase, numsbase + gbase, ..., numsbase + 15*gbase). */ precj[j*16] = numsbase; for (i = 1; i < 16; i++) { - secp256k1_gej_add_var(&precj[j*16 + i], &precj[j*16 + i - 1], &gbase); + secp256k1_gej_add_var(&precj[j*16 + i], &precj[j*16 + i - 1], &gbase, NULL); } /* Multiply gbase by 16. */ for (i = 0; i < 4; i++) { - secp256k1_gej_double_var(&gbase, &gbase); + secp256k1_gej_double_var(&gbase, &gbase, NULL); } /* Multiply numbase by 2. */ - secp256k1_gej_double_var(&numsbase, &numsbase); + secp256k1_gej_double_var(&numsbase, &numsbase, NULL); if (j == 62) { /* In the last iteration, numsbase is (1 - 2^j) * nums instead. */ secp256k1_gej_neg(&numsbase, &numsbase); - secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej); + secp256k1_gej_add_var(&numsbase, &numsbase, &nums_gej, NULL); } } - secp256k1_ge_set_all_gej_var(1024, prec, precj); + secp256k1_ge_set_all_gej_var(prec, precj, 1024, cb); } for (j = 0; j < 64; j++) { for (i = 0; i < 16; i++) { secp256k1_ge_to_storage(&(*ctx->prec)[j][i], &prec[j*16 + i]); } } +#else + (void)cb; + ctx->prec = (secp256k1_ge_storage (*)[64][16])secp256k1_ecmult_static_context; +#endif secp256k1_ecmult_gen_blind(ctx, NULL); } -static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context_t* ctx) { +static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context* ctx) { return ctx->prec != NULL; } -static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context_t *dst, - const secp256k1_ecmult_gen_context_t *src) { +static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context *dst, + const secp256k1_ecmult_gen_context *src, const secp256k1_callback* cb) { if (src->prec == NULL) { dst->prec = NULL; } else { - dst->prec = (secp256k1_ge_storage_t (*)[64][16])checked_malloc(sizeof(*dst->prec)); +#ifndef USE_ECMULT_STATIC_PRECOMPUTATION + dst->prec = (secp256k1_ge_storage (*)[64][16])checked_malloc(cb, sizeof(*dst->prec)); memcpy(dst->prec, src->prec, sizeof(*dst->prec)); +#else + (void)cb; + dst->prec = src->prec; +#endif dst->initial = src->initial; dst->blind = src->blind; } } -static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context_t *ctx) { +static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context *ctx) { +#ifndef USE_ECMULT_STATIC_PRECOMPUTATION free(ctx->prec); +#endif secp256k1_scalar_clear(&ctx->blind); secp256k1_gej_clear(&ctx->initial); ctx->prec = NULL; } -static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context_t *ctx, secp256k1_gej_t *r, const secp256k1_scalar_t *gn) { - secp256k1_ge_t add; - secp256k1_ge_storage_t adds; - secp256k1_scalar_t gnb; +static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context *ctx, secp256k1_gej *r, const secp256k1_scalar *gn) { + secp256k1_ge add; + secp256k1_ge_storage adds; + secp256k1_scalar gnb; int bits; int i, j; memset(&adds, 0, sizeof(adds)); @@ -136,14 +156,15 @@ static void secp256k1_ecmult_gen(const secp256k1_ecmult_gen_context_t *ctx, secp } /* Setup blinding values for secp256k1_ecmult_gen. */ -static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context_t *ctx, const unsigned char *seed32) { - secp256k1_scalar_t b; - secp256k1_gej_t gb; - secp256k1_fe_t s; +static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context *ctx, const unsigned char *seed32) { + secp256k1_scalar b; + secp256k1_gej gb; + secp256k1_fe s; unsigned char nonce32[32]; - secp256k1_rfc6979_hmac_sha256_t rng; + secp256k1_rfc6979_hmac_sha256 rng; int retry; - if (!seed32) { + unsigned char keydata[64] = {0}; + if (seed32 == NULL) { /* When seed is NULL, reset the initial point and blinding value. */ secp256k1_gej_set_ge(&ctx->initial, &secp256k1_ge_const_g); secp256k1_gej_neg(&ctx->initial, &ctx->initial); @@ -155,13 +176,18 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context_t *ctx, cons * and guards against weak or adversarial seeds. This is a simpler and safer interface than * asking the caller for blinding values directly and expecting them to retry on failure. */ - secp256k1_rfc6979_hmac_sha256_initialize(&rng, seed32 ? seed32 : nonce32, 32, nonce32, 32, NULL, 0); + memcpy(keydata, nonce32, 32); + if (seed32 != NULL) { + memcpy(keydata + 32, seed32, 32); + } + secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, seed32 ? 64 : 32); + memset(keydata, 0, sizeof(keydata)); /* Retry for out of range results to achieve uniformity. */ do { secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); retry = !secp256k1_fe_set_b32(&s, nonce32); retry |= secp256k1_fe_is_zero(&s); - } while (retry); + } while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > Fp. */ /* Randomize the projection to defend against multiplier sidechannels. */ secp256k1_gej_rescale(&ctx->initial, &s); secp256k1_fe_clear(&s); @@ -170,7 +196,7 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context_t *ctx, cons secp256k1_scalar_set_b32(&b, nonce32, &retry); /* A blinding value of 0 works, but would undermine the projection hardening. */ retry |= secp256k1_scalar_is_zero(&b); - } while (retry); + } while (retry); /* This branch true is cryptographically unreachable. Requires sha256_hmac output > order. */ secp256k1_rfc6979_hmac_sha256_finalize(&rng); memset(nonce32, 0, 32); secp256k1_ecmult_gen(ctx, &gb, &b); @@ -181,4 +207,4 @@ static void secp256k1_ecmult_gen_blind(secp256k1_ecmult_gen_context_t *ctx, cons secp256k1_gej_clear(&gb); } -#endif +#endif /* SECP256K1_ECMULT_GEN_IMPL_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/ecmult_impl.h b/src/cryptoconditions/src/include/secp256k1/src/ecmult_impl.h index 1b2856f83..93d3794cb 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/ecmult_impl.h +++ b/src/cryptoconditions/src/include/secp256k1/src/ecmult_impl.h @@ -4,16 +4,32 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_ECMULT_IMPL_H_ -#define _SECP256K1_ECMULT_IMPL_H_ +#ifndef SECP256K1_ECMULT_IMPL_H +#define SECP256K1_ECMULT_IMPL_H + +#include #include "group.h" #include "scalar.h" #include "ecmult.h" +#if defined(EXHAUSTIVE_TEST_ORDER) +/* We need to lower these values for exhaustive tests because + * the tables cannot have infinities in them (this breaks the + * affine-isomorphism stuff which tracks z-ratios) */ +# if EXHAUSTIVE_TEST_ORDER > 128 +# define WINDOW_A 5 +# define WINDOW_G 8 +# elif EXHAUSTIVE_TEST_ORDER > 8 +# define WINDOW_A 4 +# define WINDOW_G 4 +# else +# define WINDOW_A 2 +# define WINDOW_G 2 +# endif +#else /* optimal for 128-bit and 256-bit exponents. */ #define WINDOW_A 5 - /** larger numbers may result in slightly better performance, at the cost of exponentially larger precomputed tables. */ #ifdef USE_ENDOMORPHISM @@ -23,63 +39,109 @@ /** One table for window size 16: 1.375 MiB. */ #define WINDOW_G 16 #endif - -/** Fill a table 'pre' with precomputed odd multiples of a. W determines the size of the table. - * pre will contains the values [1*a,3*a,5*a,...,(2^(w-1)-1)*a], so it needs place for - * 2^(w-2) entries. - * - * There are two versions of this function: - * - secp256k1_ecmult_precomp_wnaf_gej, which operates on group elements in jacobian notation, - * fast to precompute, but slower to use in later additions. - * - secp256k1_ecmult_precomp_wnaf_ge, which operates on group elements in affine notations, - * (much) slower to precompute, but a bit faster to use in later additions. - * To compute a*P + b*G, we use the jacobian version for P, and the affine version for G, as - * G is constant, so it only needs to be done once in advance. - */ -static void secp256k1_ecmult_table_precomp_gej_var(secp256k1_gej_t *pre, const secp256k1_gej_t *a, int w) { - secp256k1_gej_t d; - int i; - pre[0] = *a; - secp256k1_gej_double_var(&d, &pre[0]); - for (i = 1; i < (1 << (w-2)); i++) { - secp256k1_gej_add_var(&pre[i], &d, &pre[i-1]); - } -} - -static void secp256k1_ecmult_table_precomp_ge_storage_var(secp256k1_ge_storage_t *pre, const secp256k1_gej_t *a, int w) { - secp256k1_gej_t d; - int i; - const int table_size = 1 << (w-2); - secp256k1_gej_t *prej = (secp256k1_gej_t *)checked_malloc(sizeof(secp256k1_gej_t) * table_size); - secp256k1_ge_t *prea = (secp256k1_ge_t *)checked_malloc(sizeof(secp256k1_ge_t) * table_size); - prej[0] = *a; - secp256k1_gej_double_var(&d, a); - for (i = 1; i < table_size; i++) { - secp256k1_gej_add_var(&prej[i], &d, &prej[i-1]); - } - secp256k1_ge_set_all_gej_var(table_size, prea, prej); - for (i = 0; i < table_size; i++) { - secp256k1_ge_to_storage(&pre[i], &prea[i]); - } - free(prej); - free(prea); -} +#endif /** The number of entries a table with precomputed multiples needs to have. */ #define ECMULT_TABLE_SIZE(w) (1 << ((w)-2)) +/** Fill a table 'prej' with precomputed odd multiples of a. Prej will contain + * the values [1*a,3*a,...,(2*n-1)*a], so it space for n values. zr[0] will + * contain prej[0].z / a.z. The other zr[i] values = prej[i].z / prej[i-1].z. + * Prej's Z values are undefined, except for the last value. + */ +static void secp256k1_ecmult_odd_multiples_table(int n, secp256k1_gej *prej, secp256k1_fe *zr, const secp256k1_gej *a) { + secp256k1_gej d; + secp256k1_ge a_ge, d_ge; + int i; + + VERIFY_CHECK(!a->infinity); + + secp256k1_gej_double_var(&d, a, NULL); + + /* + * Perform the additions on an isomorphism where 'd' is affine: drop the z coordinate + * of 'd', and scale the 1P starting value's x/y coordinates without changing its z. + */ + d_ge.x = d.x; + d_ge.y = d.y; + d_ge.infinity = 0; + + secp256k1_ge_set_gej_zinv(&a_ge, a, &d.z); + prej[0].x = a_ge.x; + prej[0].y = a_ge.y; + prej[0].z = a->z; + prej[0].infinity = 0; + + zr[0] = d.z; + for (i = 1; i < n; i++) { + secp256k1_gej_add_ge_var(&prej[i], &prej[i-1], &d_ge, &zr[i]); + } + + /* + * Each point in 'prej' has a z coordinate too small by a factor of 'd.z'. Only + * the final point's z coordinate is actually used though, so just update that. + */ + secp256k1_fe_mul(&prej[n-1].z, &prej[n-1].z, &d.z); +} + +/** Fill a table 'pre' with precomputed odd multiples of a. + * + * There are two versions of this function: + * - secp256k1_ecmult_odd_multiples_table_globalz_windowa which brings its + * resulting point set to a single constant Z denominator, stores the X and Y + * coordinates as ge_storage points in pre, and stores the global Z in rz. + * It only operates on tables sized for WINDOW_A wnaf multiples. + * - secp256k1_ecmult_odd_multiples_table_storage_var, which converts its + * resulting point set to actually affine points, and stores those in pre. + * It operates on tables of any size, but uses heap-allocated temporaries. + * + * To compute a*P + b*G, we compute a table for P using the first function, + * and for G using the second (which requires an inverse, but it only needs to + * happen once). + */ +static void secp256k1_ecmult_odd_multiples_table_globalz_windowa(secp256k1_ge *pre, secp256k1_fe *globalz, const secp256k1_gej *a) { + secp256k1_gej prej[ECMULT_TABLE_SIZE(WINDOW_A)]; + secp256k1_fe zr[ECMULT_TABLE_SIZE(WINDOW_A)]; + + /* Compute the odd multiples in Jacobian form. */ + secp256k1_ecmult_odd_multiples_table(ECMULT_TABLE_SIZE(WINDOW_A), prej, zr, a); + /* Bring them to the same Z denominator. */ + secp256k1_ge_globalz_set_table_gej(ECMULT_TABLE_SIZE(WINDOW_A), pre, globalz, prej, zr); +} + +static void secp256k1_ecmult_odd_multiples_table_storage_var(int n, secp256k1_ge_storage *pre, const secp256k1_gej *a, const secp256k1_callback *cb) { + secp256k1_gej *prej = (secp256k1_gej*)checked_malloc(cb, sizeof(secp256k1_gej) * n); + secp256k1_ge *prea = (secp256k1_ge*)checked_malloc(cb, sizeof(secp256k1_ge) * n); + secp256k1_fe *zr = (secp256k1_fe*)checked_malloc(cb, sizeof(secp256k1_fe) * n); + int i; + + /* Compute the odd multiples in Jacobian form. */ + secp256k1_ecmult_odd_multiples_table(n, prej, zr, a); + /* Convert them in batch to affine coordinates. */ + secp256k1_ge_set_table_gej_var(prea, prej, zr, n); + /* Convert them to compact storage form. */ + for (i = 0; i < n; i++) { + secp256k1_ge_to_storage(&pre[i], &prea[i]); + } + + free(prea); + free(prej); + free(zr); +} + /** The following two macro retrieves a particular odd multiple from a table * of precomputed multiples. */ -#define ECMULT_TABLE_GET_GEJ(r,pre,n,w) do { \ +#define ECMULT_TABLE_GET_GE(r,pre,n,w) do { \ VERIFY_CHECK(((n) & 1) == 1); \ VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \ VERIFY_CHECK((n) <= ((1 << ((w)-1)) - 1)); \ if ((n) > 0) { \ *(r) = (pre)[((n)-1)/2]; \ } else { \ - secp256k1_gej_neg((r), &(pre)[(-(n)-1)/2]); \ + secp256k1_ge_neg((r), &(pre)[(-(n)-1)/2]); \ } \ } while(0) + #define ECMULT_TABLE_GET_GE_STORAGE(r,pre,n,w) do { \ VERIFY_CHECK(((n) & 1) == 1); \ VERIFY_CHECK((n) >= -((1 << ((w)-1)) - 1)); \ @@ -92,15 +154,15 @@ static void secp256k1_ecmult_table_precomp_ge_storage_var(secp256k1_ge_storage_t } \ } while(0) -static void secp256k1_ecmult_context_init(secp256k1_ecmult_context_t *ctx) { +static void secp256k1_ecmult_context_init(secp256k1_ecmult_context *ctx) { ctx->pre_g = NULL; #ifdef USE_ENDOMORPHISM ctx->pre_g_128 = NULL; #endif } -static void secp256k1_ecmult_context_build(secp256k1_ecmult_context_t *ctx) { - secp256k1_gej_t gj; +static void secp256k1_ecmult_context_build(secp256k1_ecmult_context *ctx, const secp256k1_callback *cb) { + secp256k1_gej gj; if (ctx->pre_g != NULL) { return; @@ -109,35 +171,35 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context_t *ctx) { /* get the generator */ secp256k1_gej_set_ge(&gj, &secp256k1_ge_const_g); - ctx->pre_g = (secp256k1_ge_storage_t (*)[])checked_malloc(sizeof((*ctx->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); + ctx->pre_g = (secp256k1_ge_storage (*)[])checked_malloc(cb, sizeof((*ctx->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); /* precompute the tables with odd multiples */ - secp256k1_ecmult_table_precomp_ge_storage_var(*ctx->pre_g, &gj, WINDOW_G); + secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g, &gj, cb); #ifdef USE_ENDOMORPHISM { - secp256k1_gej_t g_128j; + secp256k1_gej g_128j; int i; - ctx->pre_g_128 = (secp256k1_ge_storage_t (*)[])checked_malloc(sizeof((*ctx->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); + ctx->pre_g_128 = (secp256k1_ge_storage (*)[])checked_malloc(cb, sizeof((*ctx->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G)); /* calculate 2^128*generator */ g_128j = gj; for (i = 0; i < 128; i++) { - secp256k1_gej_double_var(&g_128j, &g_128j); + secp256k1_gej_double_var(&g_128j, &g_128j, NULL); } - secp256k1_ecmult_table_precomp_ge_storage_var(*ctx->pre_g_128, &g_128j, WINDOW_G); + secp256k1_ecmult_odd_multiples_table_storage_var(ECMULT_TABLE_SIZE(WINDOW_G), *ctx->pre_g_128, &g_128j, cb); } #endif } -static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context_t *dst, - const secp256k1_ecmult_context_t *src) { +static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context *dst, + const secp256k1_ecmult_context *src, const secp256k1_callback *cb) { if (src->pre_g == NULL) { dst->pre_g = NULL; } else { size_t size = sizeof((*dst->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G); - dst->pre_g = (secp256k1_ge_storage_t (*)[])checked_malloc(size); + dst->pre_g = (secp256k1_ge_storage (*)[])checked_malloc(cb, size); memcpy(dst->pre_g, src->pre_g, size); } #ifdef USE_ENDOMORPHISM @@ -145,17 +207,17 @@ static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context_t *dst, dst->pre_g_128 = NULL; } else { size_t size = sizeof((*dst->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G); - dst->pre_g_128 = (secp256k1_ge_storage_t (*)[])checked_malloc(size); + dst->pre_g_128 = (secp256k1_ge_storage (*)[])checked_malloc(cb, size); memcpy(dst->pre_g_128, src->pre_g_128, size); } #endif } -static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context_t *ctx) { +static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context *ctx) { return ctx->pre_g != NULL; } -static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context_t *ctx) { +static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context *ctx) { free(ctx->pre_g); #ifdef USE_ENDOMORPHISM free(ctx->pre_g_128); @@ -168,54 +230,68 @@ static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context_t *ctx) { * - each wnaf[i] is either 0, or an odd integer between -(1<<(w-1) - 1) and (1<<(w-1) - 1) * - two non-zero entries in wnaf are separated by at least w-1 zeroes. * - the number of set values in wnaf is returned. This number is at most 256, and at most one more - * - than the number of bits in the (absolute value) of the input. + * than the number of bits in the (absolute value) of the input. */ -static int secp256k1_ecmult_wnaf(int *wnaf, const secp256k1_scalar_t *a, int w) { - secp256k1_scalar_t s = *a; - int set_bits = 0; +static int secp256k1_ecmult_wnaf(int *wnaf, int len, const secp256k1_scalar *a, int w) { + secp256k1_scalar s = *a; + int last_set_bit = -1; int bit = 0; int sign = 1; + int carry = 0; + + VERIFY_CHECK(wnaf != NULL); + VERIFY_CHECK(0 <= len && len <= 256); + VERIFY_CHECK(a != NULL); + VERIFY_CHECK(2 <= w && w <= 31); + + memset(wnaf, 0, len * sizeof(wnaf[0])); if (secp256k1_scalar_get_bits(&s, 255, 1)) { secp256k1_scalar_negate(&s, &s); sign = -1; } - while (bit < 256) { + while (bit < len) { int now; int word; - if (secp256k1_scalar_get_bits(&s, bit, 1) == 0) { + if (secp256k1_scalar_get_bits(&s, bit, 1) == (unsigned int)carry) { bit++; continue; } - while (set_bits < bit) { - wnaf[set_bits++] = 0; - } + now = w; - if (bit + now > 256) { - now = 256 - bit; - } - word = secp256k1_scalar_get_bits_var(&s, bit, now); - if (word & (1 << (w-1))) { - secp256k1_scalar_add_bit(&s, bit + w); - wnaf[set_bits++] = sign * (word - (1 << w)); - } else { - wnaf[set_bits++] = sign * word; + if (now > len - bit) { + now = len - bit; } + + word = secp256k1_scalar_get_bits_var(&s, bit, now) + carry; + + carry = (word >> (w-1)) & 1; + word -= carry << w; + + wnaf[bit] = sign * word; + last_set_bit = bit; + bit += now; } - return set_bits; +#ifdef VERIFY + CHECK(carry == 0); + while (bit < 256) { + CHECK(secp256k1_scalar_get_bits(&s, bit++, 1) == 0); + } +#endif + return last_set_bit + 1; } -static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_scalar_t *na, const secp256k1_scalar_t *ng) { - secp256k1_gej_t tmpj; - secp256k1_gej_t pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; - secp256k1_ge_t tmpa; +static void secp256k1_ecmult(const secp256k1_ecmult_context *ctx, secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_scalar *na, const secp256k1_scalar *ng) { + secp256k1_ge pre_a[ECMULT_TABLE_SIZE(WINDOW_A)]; + secp256k1_ge tmpa; + secp256k1_fe Z; #ifdef USE_ENDOMORPHISM - secp256k1_gej_t pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; - secp256k1_scalar_t na_1, na_lam; + secp256k1_ge pre_a_lam[ECMULT_TABLE_SIZE(WINDOW_A)]; + secp256k1_scalar na_1, na_lam; /* Splitted G factors. */ - secp256k1_scalar_t ng_1, ng_128; + secp256k1_scalar ng_1, ng_128; int wnaf_na_1[130]; int wnaf_na_lam[130]; int bits_na_1; @@ -227,7 +303,7 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge #else int wnaf_na[256]; int bits_na; - int wnaf_ng[257]; + int wnaf_ng[256]; int bits_ng; #endif int i; @@ -235,11 +311,11 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge #ifdef USE_ENDOMORPHISM /* split na into na_1 and na_lam (where na = na_1 + na_lam*lambda, and na_1 and na_lam are ~128 bit) */ - secp256k1_scalar_split_lambda_var(&na_1, &na_lam, na); + secp256k1_scalar_split_lambda(&na_1, &na_lam, na); /* build wnaf representation for na_1 and na_lam. */ - bits_na_1 = secp256k1_ecmult_wnaf(wnaf_na_1, &na_1, WINDOW_A); - bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, &na_lam, WINDOW_A); + bits_na_1 = secp256k1_ecmult_wnaf(wnaf_na_1, 130, &na_1, WINDOW_A); + bits_na_lam = secp256k1_ecmult_wnaf(wnaf_na_lam, 130, &na_lam, WINDOW_A); VERIFY_CHECK(bits_na_1 <= 130); VERIFY_CHECK(bits_na_lam <= 130); bits = bits_na_1; @@ -248,24 +324,33 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge } #else /* build wnaf representation for na. */ - bits_na = secp256k1_ecmult_wnaf(wnaf_na, na, WINDOW_A); + bits_na = secp256k1_ecmult_wnaf(wnaf_na, 256, na, WINDOW_A); bits = bits_na; #endif - /* calculate odd multiples of a */ - secp256k1_ecmult_table_precomp_gej_var(pre_a, a, WINDOW_A); + /* Calculate odd multiples of a. + * All multiples are brought to the same Z 'denominator', which is stored + * in Z. Due to secp256k1' isomorphism we can do all operations pretending + * that the Z coordinate was 1, use affine addition formulae, and correct + * the Z coordinate of the result once at the end. + * The exception is the precomputed G table points, which are actually + * affine. Compared to the base used for other points, they have a Z ratio + * of 1/Z, so we can use secp256k1_gej_add_zinv_var, which uses the same + * isomorphism to efficiently add with a known Z inverse. + */ + secp256k1_ecmult_odd_multiples_table_globalz_windowa(pre_a, &Z, a); #ifdef USE_ENDOMORPHISM for (i = 0; i < ECMULT_TABLE_SIZE(WINDOW_A); i++) { - secp256k1_gej_mul_lambda(&pre_a_lam[i], &pre_a[i]); + secp256k1_ge_mul_lambda(&pre_a_lam[i], &pre_a[i]); } /* split ng into ng_1 and ng_128 (where gn = gn_1 + gn_128*2^128, and gn_1 and gn_128 are ~128 bit) */ secp256k1_scalar_split_128(&ng_1, &ng_128, ng); /* Build wnaf representation for ng_1 and ng_128 */ - bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, &ng_1, WINDOW_G); - bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, &ng_128, WINDOW_G); + bits_ng_1 = secp256k1_ecmult_wnaf(wnaf_ng_1, 129, &ng_1, WINDOW_G); + bits_ng_128 = secp256k1_ecmult_wnaf(wnaf_ng_128, 129, &ng_128, WINDOW_G); if (bits_ng_1 > bits) { bits = bits_ng_1; } @@ -273,7 +358,7 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge bits = bits_ng_128; } #else - bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, ng, WINDOW_G); + bits_ng = secp256k1_ecmult_wnaf(wnaf_ng, 256, ng, WINDOW_G); if (bits_ng > bits) { bits = bits_ng; } @@ -281,37 +366,41 @@ static void secp256k1_ecmult(const secp256k1_ecmult_context_t *ctx, secp256k1_ge secp256k1_gej_set_infinity(r); - for (i = bits-1; i >= 0; i--) { + for (i = bits - 1; i >= 0; i--) { int n; - secp256k1_gej_double_var(r, r); + secp256k1_gej_double_var(r, r, NULL); #ifdef USE_ENDOMORPHISM if (i < bits_na_1 && (n = wnaf_na_1[i])) { - ECMULT_TABLE_GET_GEJ(&tmpj, pre_a, n, WINDOW_A); - secp256k1_gej_add_var(r, r, &tmpj); + ECMULT_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); + secp256k1_gej_add_ge_var(r, r, &tmpa, NULL); } if (i < bits_na_lam && (n = wnaf_na_lam[i])) { - ECMULT_TABLE_GET_GEJ(&tmpj, pre_a_lam, n, WINDOW_A); - secp256k1_gej_add_var(r, r, &tmpj); + ECMULT_TABLE_GET_GE(&tmpa, pre_a_lam, n, WINDOW_A); + secp256k1_gej_add_ge_var(r, r, &tmpa, NULL); } if (i < bits_ng_1 && (n = wnaf_ng_1[i])) { ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G); - secp256k1_gej_add_ge_var(r, r, &tmpa); + secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z); } if (i < bits_ng_128 && (n = wnaf_ng_128[i])) { ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g_128, n, WINDOW_G); - secp256k1_gej_add_ge_var(r, r, &tmpa); + secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z); } #else if (i < bits_na && (n = wnaf_na[i])) { - ECMULT_TABLE_GET_GEJ(&tmpj, pre_a, n, WINDOW_A); - secp256k1_gej_add_var(r, r, &tmpj); + ECMULT_TABLE_GET_GE(&tmpa, pre_a, n, WINDOW_A); + secp256k1_gej_add_ge_var(r, r, &tmpa, NULL); } if (i < bits_ng && (n = wnaf_ng[i])) { ECMULT_TABLE_GET_GE_STORAGE(&tmpa, *ctx->pre_g, n, WINDOW_G); - secp256k1_gej_add_ge_var(r, r, &tmpa); + secp256k1_gej_add_zinv_var(r, r, &tmpa, &Z); } #endif } + + if (!r->infinity) { + secp256k1_fe_mul(&r->z, &r->z, &Z); + } } -#endif +#endif /* SECP256K1_ECMULT_IMPL_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/field.h b/src/cryptoconditions/src/include/secp256k1/src/field.h index 41b280892..bb6692ad5 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/field.h +++ b/src/cryptoconditions/src/include/secp256k1/src/field.h @@ -4,13 +4,13 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_FIELD_ -#define _SECP256K1_FIELD_ +#ifndef SECP256K1_FIELD_H +#define SECP256K1_FIELD_H /** Field element module. * * Field elements can be represented in several ways, but code accessing - * it (and implementations) need to take certain properaties into account: + * it (and implementations) need to take certain properties into account: * - Each field element can be normalized or not. * - Each field element has a magnitude, which represents how far away * its representation is away from normalization. Normalized elements @@ -30,90 +30,103 @@ #error "Please select field implementation" #endif +#include "util.h" + /** Normalize a field element. */ -static void secp256k1_fe_normalize(secp256k1_fe_t *r); +static void secp256k1_fe_normalize(secp256k1_fe *r); /** Weakly normalize a field element: reduce it magnitude to 1, but don't fully normalize. */ -static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r); +static void secp256k1_fe_normalize_weak(secp256k1_fe *r); /** Normalize a field element, without constant-time guarantee. */ -static void secp256k1_fe_normalize_var(secp256k1_fe_t *r); +static void secp256k1_fe_normalize_var(secp256k1_fe *r); /** Verify whether a field element represents zero i.e. would normalize to a zero value. The field * implementation may optionally normalize the input, but this should not be relied upon. */ -static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r); +static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r); /** Verify whether a field element represents zero i.e. would normalize to a zero value. The field * implementation may optionally normalize the input, but this should not be relied upon. */ -static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r); +static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r); /** Set a field element equal to a small integer. Resulting field element is normalized. */ -static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a); +static void secp256k1_fe_set_int(secp256k1_fe *r, int a); + +/** Sets a field element equal to zero, initializing all fields. */ +static void secp256k1_fe_clear(secp256k1_fe *a); /** Verify whether a field element is zero. Requires the input to be normalized. */ -static int secp256k1_fe_is_zero(const secp256k1_fe_t *a); +static int secp256k1_fe_is_zero(const secp256k1_fe *a); /** Check the "oddness" of a field element. Requires the input to be normalized. */ -static int secp256k1_fe_is_odd(const secp256k1_fe_t *a); +static int secp256k1_fe_is_odd(const secp256k1_fe *a); /** Compare two field elements. Requires magnitude-1 inputs. */ -static int secp256k1_fe_equal_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b); +static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b); + +/** Same as secp256k1_fe_equal, but may be variable time. */ +static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b); /** Compare two field elements. Requires both inputs to be normalized */ -static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b); +static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b); -/** Set a field element equal to 32-byte big endian value. If succesful, the resulting field element is normalized. */ -static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a); +/** Set a field element equal to 32-byte big endian value. If successful, the resulting field element is normalized. */ +static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a); /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ -static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a); +static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a); /** Set a field element equal to the additive inverse of another. Takes a maximum magnitude of the input * as an argument. The magnitude of the output is one higher. */ -static void secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m); +static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m); /** Multiplies the passed field element with a small integer constant. Multiplies the magnitude by that * small integer. */ -static void secp256k1_fe_mul_int(secp256k1_fe_t *r, int a); +static void secp256k1_fe_mul_int(secp256k1_fe *r, int a); /** Adds a field element to another. The result has the sum of the inputs' magnitudes as magnitude. */ -static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a); +static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a); /** Sets a field element to be the product of two others. Requires the inputs' magnitudes to be at most 8. * The output magnitude is 1 (but not guaranteed to be normalized). */ -static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t * SECP256K1_RESTRICT b); +static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b); /** Sets a field element to be the square of another. Requires the input's magnitude to be at most 8. * The output magnitude is 1 (but not guaranteed to be normalized). */ -static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a); +static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a); -/** Sets a field element to be the (modular) square root (if any exist) of another. Requires the - * input's magnitude to be at most 8. The output magnitude is 1 (but not guaranteed to be - * normalized). Return value indicates whether a square root was found. */ -static int secp256k1_fe_sqrt_var(secp256k1_fe_t *r, const secp256k1_fe_t *a); +/** If a has a square root, it is computed in r and 1 is returned. If a does not + * have a square root, the root of its negation is computed and 0 is returned. + * The input's magnitude can be at most 8. The output magnitude is 1 (but not + * guaranteed to be normalized). The result in r will always be a square + * itself. */ +static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a); + +/** Checks whether a field element is a quadratic residue. */ +static int secp256k1_fe_is_quad_var(const secp256k1_fe *a); /** Sets a field element to be the (modular) inverse of another. Requires the input's magnitude to be * at most 8. The output magnitude is 1 (but not guaranteed to be normalized). */ -static void secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a); +static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a); /** Potentially faster version of secp256k1_fe_inv, without constant-time guarantee. */ -static void secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a); +static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a); /** Calculate the (modular) inverses of a batch of field elements. Requires the inputs' magnitudes to be * at most 8. The output magnitudes are 1 (but not guaranteed to be normalized). The inputs and * outputs must not overlap in memory. */ -static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe_t *r, const secp256k1_fe_t *a); +static void secp256k1_fe_inv_all_var(secp256k1_fe *r, const secp256k1_fe *a, size_t len); /** Convert a field element to the storage type. */ -static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_fe_t*); +static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a); /** Convert a field element back from the storage type. */ -static void secp256k1_fe_from_storage(secp256k1_fe_t *r, const secp256k1_fe_storage_t*); +static void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a); /** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */ -static void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r, const secp256k1_fe_storage_t *a, int flag); +static void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag); /** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */ -static void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag); +static void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag); -#endif +#endif /* SECP256K1_FIELD_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/field_10x26.h b/src/cryptoconditions/src/include/secp256k1/src/field_10x26.h index 44bce6525..727c5267f 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/field_10x26.h +++ b/src/cryptoconditions/src/include/secp256k1/src/field_10x26.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_FIELD_REPR_ -#define _SECP256K1_FIELD_REPR_ +#ifndef SECP256K1_FIELD_REPR_H +#define SECP256K1_FIELD_REPR_H #include @@ -16,20 +16,20 @@ typedef struct { int magnitude; int normalized; #endif -} secp256k1_fe_t; +} secp256k1_fe; /* Unpacks a constant into a overlapping multi-limbed FE element. */ #define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \ (d0) & 0x3FFFFFFUL, \ - ((d0) >> 26) | ((d1) & 0xFFFFFUL) << 6, \ - ((d1) >> 20) | ((d2) & 0x3FFFUL) << 12, \ - ((d2) >> 14) | ((d3) & 0xFFUL) << 18, \ - ((d3) >> 8) | ((d4) & 0x3) << 24, \ - ((d4) >> 2) & 0x3FFFFFFUL, \ - ((d4) >> 28) | ((d5) & 0x3FFFFFUL) << 4, \ - ((d5) >> 22) | ((d6) & 0xFFFF) << 10, \ - ((d6) >> 16) | ((d7) & 0x3FF) << 16, \ - ((d7) >> 10) \ + (((uint32_t)d0) >> 26) | (((uint32_t)(d1) & 0xFFFFFUL) << 6), \ + (((uint32_t)d1) >> 20) | (((uint32_t)(d2) & 0x3FFFUL) << 12), \ + (((uint32_t)d2) >> 14) | (((uint32_t)(d3) & 0xFFUL) << 18), \ + (((uint32_t)d3) >> 8) | (((uint32_t)(d4) & 0x3UL) << 24), \ + (((uint32_t)d4) >> 2) & 0x3FFFFFFUL, \ + (((uint32_t)d4) >> 28) | (((uint32_t)(d5) & 0x3FFFFFUL) << 4), \ + (((uint32_t)d5) >> 22) | (((uint32_t)(d6) & 0xFFFFUL) << 10), \ + (((uint32_t)d6) >> 16) | (((uint32_t)(d7) & 0x3FFUL) << 16), \ + (((uint32_t)d7) >> 10) \ } #ifdef VERIFY @@ -40,8 +40,9 @@ typedef struct { typedef struct { uint32_t n[8]; -} secp256k1_fe_storage_t; +} secp256k1_fe_storage; #define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }} +#define SECP256K1_FE_STORAGE_CONST_GET(d) d.n[7], d.n[6], d.n[5], d.n[4],d.n[3], d.n[2], d.n[1], d.n[0] -#endif +#endif /* SECP256K1_FIELD_REPR_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/field_10x26_impl.h b/src/cryptoconditions/src/include/secp256k1/src/field_10x26_impl.h index 871b91f91..94f8132fc 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/field_10x26_impl.h +++ b/src/cryptoconditions/src/include/secp256k1/src/field_10x26_impl.h @@ -4,17 +4,15 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_FIELD_REPR_IMPL_H_ -#define _SECP256K1_FIELD_REPR_IMPL_H_ +#ifndef SECP256K1_FIELD_REPR_IMPL_H +#define SECP256K1_FIELD_REPR_IMPL_H -#include -#include #include "util.h" #include "num.h" #include "field.h" #ifdef VERIFY -static void secp256k1_fe_verify(const secp256k1_fe_t *a) { +static void secp256k1_fe_verify(const secp256k1_fe *a) { const uint32_t *d = a->n; int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; r &= (d[0] <= 0x3FFFFFFUL * m); @@ -40,13 +38,9 @@ static void secp256k1_fe_verify(const secp256k1_fe_t *a) { } VERIFY_CHECK(r == 1); } -#else -static void secp256k1_fe_verify(const secp256k1_fe_t *a) { - (void)a; -} #endif -static void secp256k1_fe_normalize(secp256k1_fe_t *r) { +static void secp256k1_fe_normalize(secp256k1_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; @@ -101,7 +95,7 @@ static void secp256k1_fe_normalize(secp256k1_fe_t *r) { #endif } -static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r) { +static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; @@ -132,7 +126,7 @@ static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r) { #endif } -static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) { +static void secp256k1_fe_normalize_var(secp256k1_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; @@ -188,7 +182,7 @@ static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) { #endif } -static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r) { +static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r) { uint32_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4], t5 = r->n[5], t6 = r->n[6], t7 = r->n[7], t8 = r->n[8], t9 = r->n[9]; @@ -217,7 +211,7 @@ static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r) { return (z0 == 0) | (z1 == 0x3FFFFFFUL); } -static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) { +static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r) { uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9; uint32_t z0, z1; uint32_t x; @@ -252,7 +246,7 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) { t9 &= 0x03FFFFFUL; t1 += (x << 6); - t1 += (t0 >> 26); t0 = z0; + t1 += (t0 >> 26); t2 += (t1 >> 26); t1 &= 0x3FFFFFFUL; z0 |= t1; z1 &= t1 ^ 0x40UL; t3 += (t2 >> 26); t2 &= 0x3FFFFFFUL; z0 |= t2; z1 &= t2; t4 += (t3 >> 26); t3 &= 0x3FFFFFFUL; z0 |= t3; z1 &= t3; @@ -269,7 +263,7 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) { return (z0 == 0) | (z1 == 0x3FFFFFFUL); } -SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) { +SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) { r->n[0] = a; r->n[1] = r->n[2] = r->n[3] = r->n[4] = r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0; #ifdef VERIFY @@ -279,7 +273,7 @@ SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) { #endif } -SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe_t *a) { +SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) { const uint32_t *t = a->n; #ifdef VERIFY VERIFY_CHECK(a->normalized); @@ -288,7 +282,7 @@ SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe_t *a) { return (t[0] | t[1] | t[2] | t[3] | t[4] | t[5] | t[6] | t[7] | t[8] | t[9]) == 0; } -SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe_t *a) { +SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) { #ifdef VERIFY VERIFY_CHECK(a->normalized); secp256k1_fe_verify(a); @@ -296,7 +290,7 @@ SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe_t *a) { return a->n[0] & 1; } -SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe_t *a) { +SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) { int i; #ifdef VERIFY a->magnitude = 0; @@ -307,7 +301,7 @@ SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe_t *a) { } } -static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { +static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { int i; #ifdef VERIFY VERIFY_CHECK(a->normalized); @@ -326,18 +320,18 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b return 0; } -static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) { - int i; - r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; - r->n[5] = r->n[6] = r->n[7] = r->n[8] = r->n[9] = 0; - for (i=0; i<32; i++) { - int j; - for (j=0; j<4; j++) { - int limb = (8*i+2*j)/26; - int shift = (8*i+2*j)%26; - r->n[limb] |= (uint32_t)((a[31-i] >> (2*j)) & 0x3) << shift; - } - } +static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) { + r->n[0] = (uint32_t)a[31] | ((uint32_t)a[30] << 8) | ((uint32_t)a[29] << 16) | ((uint32_t)(a[28] & 0x3) << 24); + r->n[1] = (uint32_t)((a[28] >> 2) & 0x3f) | ((uint32_t)a[27] << 6) | ((uint32_t)a[26] << 14) | ((uint32_t)(a[25] & 0xf) << 22); + r->n[2] = (uint32_t)((a[25] >> 4) & 0xf) | ((uint32_t)a[24] << 4) | ((uint32_t)a[23] << 12) | ((uint32_t)(a[22] & 0x3f) << 20); + r->n[3] = (uint32_t)((a[22] >> 6) & 0x3) | ((uint32_t)a[21] << 2) | ((uint32_t)a[20] << 10) | ((uint32_t)a[19] << 18); + r->n[4] = (uint32_t)a[18] | ((uint32_t)a[17] << 8) | ((uint32_t)a[16] << 16) | ((uint32_t)(a[15] & 0x3) << 24); + r->n[5] = (uint32_t)((a[15] >> 2) & 0x3f) | ((uint32_t)a[14] << 6) | ((uint32_t)a[13] << 14) | ((uint32_t)(a[12] & 0xf) << 22); + r->n[6] = (uint32_t)((a[12] >> 4) & 0xf) | ((uint32_t)a[11] << 4) | ((uint32_t)a[10] << 12) | ((uint32_t)(a[9] & 0x3f) << 20); + r->n[7] = (uint32_t)((a[9] >> 6) & 0x3) | ((uint32_t)a[8] << 2) | ((uint32_t)a[7] << 10) | ((uint32_t)a[6] << 18); + r->n[8] = (uint32_t)a[5] | ((uint32_t)a[4] << 8) | ((uint32_t)a[3] << 16) | ((uint32_t)(a[2] & 0x3) << 24); + r->n[9] = (uint32_t)((a[2] >> 2) & 0x3f) | ((uint32_t)a[1] << 6) | ((uint32_t)a[0] << 14); + if (r->n[9] == 0x3FFFFFUL && (r->n[8] & r->n[7] & r->n[6] & r->n[5] & r->n[4] & r->n[3] & r->n[2]) == 0x3FFFFFFUL && (r->n[1] + 0x40UL + ((r->n[0] + 0x3D1UL) >> 26)) > 0x3FFFFFFUL) { return 0; } @@ -350,25 +344,46 @@ static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) { } /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ -static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) { - int i; +static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) { #ifdef VERIFY VERIFY_CHECK(a->normalized); secp256k1_fe_verify(a); #endif - for (i=0; i<32; i++) { - int j; - int c = 0; - for (j=0; j<4; j++) { - int limb = (8*i+2*j)/26; - int shift = (8*i+2*j)%26; - c |= ((a->n[limb] >> shift) & 0x3) << (2 * j); - } - r[31-i] = c; - } + r[0] = (a->n[9] >> 14) & 0xff; + r[1] = (a->n[9] >> 6) & 0xff; + r[2] = ((a->n[9] & 0x3F) << 2) | ((a->n[8] >> 24) & 0x3); + r[3] = (a->n[8] >> 16) & 0xff; + r[4] = (a->n[8] >> 8) & 0xff; + r[5] = a->n[8] & 0xff; + r[6] = (a->n[7] >> 18) & 0xff; + r[7] = (a->n[7] >> 10) & 0xff; + r[8] = (a->n[7] >> 2) & 0xff; + r[9] = ((a->n[7] & 0x3) << 6) | ((a->n[6] >> 20) & 0x3f); + r[10] = (a->n[6] >> 12) & 0xff; + r[11] = (a->n[6] >> 4) & 0xff; + r[12] = ((a->n[6] & 0xf) << 4) | ((a->n[5] >> 22) & 0xf); + r[13] = (a->n[5] >> 14) & 0xff; + r[14] = (a->n[5] >> 6) & 0xff; + r[15] = ((a->n[5] & 0x3f) << 2) | ((a->n[4] >> 24) & 0x3); + r[16] = (a->n[4] >> 16) & 0xff; + r[17] = (a->n[4] >> 8) & 0xff; + r[18] = a->n[4] & 0xff; + r[19] = (a->n[3] >> 18) & 0xff; + r[20] = (a->n[3] >> 10) & 0xff; + r[21] = (a->n[3] >> 2) & 0xff; + r[22] = ((a->n[3] & 0x3) << 6) | ((a->n[2] >> 20) & 0x3f); + r[23] = (a->n[2] >> 12) & 0xff; + r[24] = (a->n[2] >> 4) & 0xff; + r[25] = ((a->n[2] & 0xf) << 4) | ((a->n[1] >> 22) & 0xf); + r[26] = (a->n[1] >> 14) & 0xff; + r[27] = (a->n[1] >> 6) & 0xff; + r[28] = ((a->n[1] & 0x3f) << 2) | ((a->n[0] >> 24) & 0x3); + r[29] = (a->n[0] >> 16) & 0xff; + r[30] = (a->n[0] >> 8) & 0xff; + r[31] = a->n[0] & 0xff; } -SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m) { +SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) { #ifdef VERIFY VERIFY_CHECK(a->magnitude <= m); secp256k1_fe_verify(a); @@ -390,7 +405,7 @@ SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe_t *r, const secp25 #endif } -SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) { +SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { r->n[0] *= a; r->n[1] *= a; r->n[2] *= a; @@ -408,7 +423,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) { #endif } -SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a) { +SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { #ifdef VERIFY secp256k1_fe_verify(a); #endif @@ -429,6 +444,14 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1 #endif } +#if defined(USE_EXTERNAL_ASM) + +/* External assembler implementation */ +void secp256k1_fe_mul_inner(uint32_t *r, const uint32_t *a, const uint32_t * SECP256K1_RESTRICT b); +void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t *a); + +#else + #ifdef VERIFY #define VERIFY_BITS(x, n) VERIFY_CHECK(((x) >> (n)) == 0) #else @@ -1037,9 +1060,9 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint32_t *r, const uint32_t VERIFY_BITS(r[2], 27); /* [r9 r8 r7 r6 r5 r4 r3 r2 r1 r0] = [p18 p17 p16 p15 p14 p13 p12 p11 p10 p9 p8 p7 p6 p5 p4 p3 p2 p1 p0] */ } +#endif - -static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t * SECP256K1_RESTRICT b) { +static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { #ifdef VERIFY VERIFY_CHECK(a->magnitude <= 8); VERIFY_CHECK(b->magnitude <= 8); @@ -1055,7 +1078,7 @@ static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const s #endif } -static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) { +static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) { #ifdef VERIFY VERIFY_CHECK(a->magnitude <= 8); secp256k1_fe_verify(a); @@ -1068,7 +1091,7 @@ static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) { #endif } -static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag) { +static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { uint32_t mask0, mask1; mask0 = flag + ~((uint32_t)0); mask1 = ~mask0; @@ -1083,12 +1106,14 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k r->n[8] = (r->n[8] & mask0) | (a->n[8] & mask1); r->n[9] = (r->n[9] & mask0) | (a->n[9] & mask1); #ifdef VERIFY - r->magnitude = (r->magnitude & mask0) | (a->magnitude & mask1); - r->normalized = (r->normalized & mask0) | (a->normalized & mask1); + if (a->magnitude > r->magnitude) { + r->magnitude = a->magnitude; + } + r->normalized &= a->normalized; #endif } -static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r, const secp256k1_fe_storage_t *a, int flag) { +static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) { uint32_t mask0, mask1; mask0 = flag + ~((uint32_t)0); mask1 = ~mask0; @@ -1102,7 +1127,7 @@ static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r r->n[7] = (r->n[7] & mask0) | (a->n[7] & mask1); } -static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_fe_t *a) { +static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { #ifdef VERIFY VERIFY_CHECK(a->normalized); #endif @@ -1116,7 +1141,7 @@ static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_f r->n[7] = a->n[8] >> 16 | a->n[9] << 10; } -static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe_t *r, const secp256k1_fe_storage_t *a) { +static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { r->n[0] = a->n[0] & 0x3FFFFFFUL; r->n[1] = a->n[0] >> 26 | ((a->n[1] << 6) & 0x3FFFFFFUL); r->n[2] = a->n[1] >> 20 | ((a->n[2] << 12) & 0x3FFFFFFUL); @@ -1133,4 +1158,4 @@ static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe_t *r, const #endif } -#endif +#endif /* SECP256K1_FIELD_REPR_IMPL_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/field_5x52.h b/src/cryptoconditions/src/include/secp256k1/src/field_5x52.h index 4513d36f4..bccd8feb4 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/field_5x52.h +++ b/src/cryptoconditions/src/include/secp256k1/src/field_5x52.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_FIELD_REPR_ -#define _SECP256K1_FIELD_REPR_ +#ifndef SECP256K1_FIELD_REPR_H +#define SECP256K1_FIELD_REPR_H #include @@ -16,15 +16,15 @@ typedef struct { int magnitude; int normalized; #endif -} secp256k1_fe_t; +} secp256k1_fe; /* Unpacks a constant into a overlapping multi-limbed FE element. */ #define SECP256K1_FE_CONST_INNER(d7, d6, d5, d4, d3, d2, d1, d0) { \ - (d0) | ((uint64_t)(d1) & 0xFFFFFUL) << 32, \ - ((d1) >> 20) | ((uint64_t)(d2)) << 12 | ((uint64_t)(d3) & 0xFFUL) << 44, \ - ((d3) >> 8) | ((uint64_t)(d4) & 0xFFFFFFFUL) << 24, \ - ((d4) >> 28) | ((uint64_t)(d5)) << 4 | ((uint64_t)(d6) & 0xFFFFUL) << 36, \ - ((d6) >> 16) | ((uint64_t)(d7)) << 16 \ + (d0) | (((uint64_t)(d1) & 0xFFFFFUL) << 32), \ + ((uint64_t)(d1) >> 20) | (((uint64_t)(d2)) << 12) | (((uint64_t)(d3) & 0xFFUL) << 44), \ + ((uint64_t)(d3) >> 8) | (((uint64_t)(d4) & 0xFFFFFFFUL) << 24), \ + ((uint64_t)(d4) >> 28) | (((uint64_t)(d5)) << 4) | (((uint64_t)(d6) & 0xFFFFUL) << 36), \ + ((uint64_t)(d6) >> 16) | (((uint64_t)(d7)) << 16) \ } #ifdef VERIFY @@ -35,13 +35,13 @@ typedef struct { typedef struct { uint64_t n[4]; -} secp256k1_fe_storage_t; +} secp256k1_fe_storage; #define SECP256K1_FE_STORAGE_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{ \ - (d0) | ((uint64_t)(d1)) << 32, \ - (d2) | ((uint64_t)(d3)) << 32, \ - (d4) | ((uint64_t)(d5)) << 32, \ - (d6) | ((uint64_t)(d7)) << 32 \ + (d0) | (((uint64_t)(d1)) << 32), \ + (d2) | (((uint64_t)(d3)) << 32), \ + (d4) | (((uint64_t)(d5)) << 32), \ + (d6) | (((uint64_t)(d7)) << 32) \ }} -#endif +#endif /* SECP256K1_FIELD_REPR_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/field_5x52_asm_impl.h b/src/cryptoconditions/src/include/secp256k1/src/field_5x52_asm_impl.h index 98cc004bf..1fc3171f6 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/field_5x52_asm_impl.h +++ b/src/cryptoconditions/src/include/secp256k1/src/field_5x52_asm_impl.h @@ -11,8 +11,8 @@ * - December 2014, Pieter Wuille: converted from YASM to GCC inline assembly */ -#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_ -#define _SECP256K1_FIELD_INNER5X52_IMPL_H_ +#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H +#define SECP256K1_FIELD_INNER5X52_IMPL_H SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t *a, const uint64_t * SECP256K1_RESTRICT b) { /** @@ -499,4 +499,4 @@ __asm__ __volatile__( ); } -#endif +#endif /* SECP256K1_FIELD_INNER5X52_IMPL_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/field_5x52_impl.h b/src/cryptoconditions/src/include/secp256k1/src/field_5x52_impl.h index bda4c3dfc..957c61b01 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/field_5x52_impl.h +++ b/src/cryptoconditions/src/include/secp256k1/src/field_5x52_impl.h @@ -4,14 +4,13 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_FIELD_REPR_IMPL_H_ -#define _SECP256K1_FIELD_REPR_IMPL_H_ +#ifndef SECP256K1_FIELD_REPR_IMPL_H +#define SECP256K1_FIELD_REPR_IMPL_H #if defined HAVE_CONFIG_H #include "libsecp256k1-config.h" #endif -#include #include "util.h" #include "num.h" #include "field.h" @@ -31,7 +30,7 @@ */ #ifdef VERIFY -static void secp256k1_fe_verify(const secp256k1_fe_t *a) { +static void secp256k1_fe_verify(const secp256k1_fe *a) { const uint64_t *d = a->n; int m = a->normalized ? 1 : 2 * a->magnitude, r = 1; /* secp256k1 'p' value defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ @@ -50,13 +49,9 @@ static void secp256k1_fe_verify(const secp256k1_fe_t *a) { } VERIFY_CHECK(r == 1); } -#else -static void secp256k1_fe_verify(const secp256k1_fe_t *a) { - (void)a; -} #endif -static void secp256k1_fe_normalize(secp256k1_fe_t *r) { +static void secp256k1_fe_normalize(secp256k1_fe *r) { uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; /* Reduce t4 at the start so there will be at most a single carry from the first pass */ @@ -99,7 +94,7 @@ static void secp256k1_fe_normalize(secp256k1_fe_t *r) { #endif } -static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r) { +static void secp256k1_fe_normalize_weak(secp256k1_fe *r) { uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; /* Reduce t4 at the start so there will be at most a single carry from the first pass */ @@ -123,7 +118,7 @@ static void secp256k1_fe_normalize_weak(secp256k1_fe_t *r) { #endif } -static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) { +static void secp256k1_fe_normalize_var(secp256k1_fe *r) { uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; /* Reduce t4 at the start so there will be at most a single carry from the first pass */ @@ -167,7 +162,7 @@ static void secp256k1_fe_normalize_var(secp256k1_fe_t *r) { #endif } -static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r) { +static int secp256k1_fe_normalizes_to_zero(secp256k1_fe *r) { uint64_t t0 = r->n[0], t1 = r->n[1], t2 = r->n[2], t3 = r->n[3], t4 = r->n[4]; /* z0 tracks a possible raw value of 0, z1 tracks a possible raw value of P */ @@ -190,7 +185,7 @@ static int secp256k1_fe_normalizes_to_zero(secp256k1_fe_t *r) { return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); } -static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) { +static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe *r) { uint64_t t0, t1, t2, t3, t4; uint64_t z0, z1; uint64_t x; @@ -219,7 +214,7 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) { t4 &= 0x0FFFFFFFFFFFFULL; - t1 += (t0 >> 52); t0 = z0; + t1 += (t0 >> 52); t2 += (t1 >> 52); t1 &= 0xFFFFFFFFFFFFFULL; z0 |= t1; z1 &= t1; t3 += (t2 >> 52); t2 &= 0xFFFFFFFFFFFFFULL; z0 |= t2; z1 &= t2; t4 += (t3 >> 52); t3 &= 0xFFFFFFFFFFFFFULL; z0 |= t3; z1 &= t3; @@ -231,7 +226,7 @@ static int secp256k1_fe_normalizes_to_zero_var(secp256k1_fe_t *r) { return (z0 == 0) | (z1 == 0xFFFFFFFFFFFFFULL); } -SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) { +SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe *r, int a) { r->n[0] = a; r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; #ifdef VERIFY @@ -241,7 +236,7 @@ SECP256K1_INLINE static void secp256k1_fe_set_int(secp256k1_fe_t *r, int a) { #endif } -SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe_t *a) { +SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe *a) { const uint64_t *t = a->n; #ifdef VERIFY VERIFY_CHECK(a->normalized); @@ -250,7 +245,7 @@ SECP256K1_INLINE static int secp256k1_fe_is_zero(const secp256k1_fe_t *a) { return (t[0] | t[1] | t[2] | t[3] | t[4]) == 0; } -SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe_t *a) { +SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe *a) { #ifdef VERIFY VERIFY_CHECK(a->normalized); secp256k1_fe_verify(a); @@ -258,7 +253,7 @@ SECP256K1_INLINE static int secp256k1_fe_is_odd(const secp256k1_fe_t *a) { return a->n[0] & 1; } -SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe_t *a) { +SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe *a) { int i; #ifdef VERIFY a->magnitude = 0; @@ -269,7 +264,7 @@ SECP256K1_INLINE static void secp256k1_fe_clear(secp256k1_fe_t *a) { } } -static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { +static int secp256k1_fe_cmp_var(const secp256k1_fe *a, const secp256k1_fe *b) { int i; #ifdef VERIFY VERIFY_CHECK(a->normalized); @@ -288,17 +283,41 @@ static int secp256k1_fe_cmp_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b return 0; } -static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) { - int i; - r->n[0] = r->n[1] = r->n[2] = r->n[3] = r->n[4] = 0; - for (i=0; i<32; i++) { - int j; - for (j=0; j<2; j++) { - int limb = (8*i+4*j)/52; - int shift = (8*i+4*j)%52; - r->n[limb] |= (uint64_t)((a[31-i] >> (4*j)) & 0xF) << shift; - } - } +static int secp256k1_fe_set_b32(secp256k1_fe *r, const unsigned char *a) { + r->n[0] = (uint64_t)a[31] + | ((uint64_t)a[30] << 8) + | ((uint64_t)a[29] << 16) + | ((uint64_t)a[28] << 24) + | ((uint64_t)a[27] << 32) + | ((uint64_t)a[26] << 40) + | ((uint64_t)(a[25] & 0xF) << 48); + r->n[1] = (uint64_t)((a[25] >> 4) & 0xF) + | ((uint64_t)a[24] << 4) + | ((uint64_t)a[23] << 12) + | ((uint64_t)a[22] << 20) + | ((uint64_t)a[21] << 28) + | ((uint64_t)a[20] << 36) + | ((uint64_t)a[19] << 44); + r->n[2] = (uint64_t)a[18] + | ((uint64_t)a[17] << 8) + | ((uint64_t)a[16] << 16) + | ((uint64_t)a[15] << 24) + | ((uint64_t)a[14] << 32) + | ((uint64_t)a[13] << 40) + | ((uint64_t)(a[12] & 0xF) << 48); + r->n[3] = (uint64_t)((a[12] >> 4) & 0xF) + | ((uint64_t)a[11] << 4) + | ((uint64_t)a[10] << 12) + | ((uint64_t)a[9] << 20) + | ((uint64_t)a[8] << 28) + | ((uint64_t)a[7] << 36) + | ((uint64_t)a[6] << 44); + r->n[4] = (uint64_t)a[5] + | ((uint64_t)a[4] << 8) + | ((uint64_t)a[3] << 16) + | ((uint64_t)a[2] << 24) + | ((uint64_t)a[1] << 32) + | ((uint64_t)a[0] << 40); if (r->n[4] == 0x0FFFFFFFFFFFFULL && (r->n[3] & r->n[2] & r->n[1]) == 0xFFFFFFFFFFFFFULL && r->n[0] >= 0xFFFFEFFFFFC2FULL) { return 0; } @@ -311,25 +330,46 @@ static int secp256k1_fe_set_b32(secp256k1_fe_t *r, const unsigned char *a) { } /** Convert a field element to a 32-byte big endian value. Requires the input to be normalized */ -static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe_t *a) { - int i; +static void secp256k1_fe_get_b32(unsigned char *r, const secp256k1_fe *a) { #ifdef VERIFY VERIFY_CHECK(a->normalized); secp256k1_fe_verify(a); #endif - for (i=0; i<32; i++) { - int j; - int c = 0; - for (j=0; j<2; j++) { - int limb = (8*i+4*j)/52; - int shift = (8*i+4*j)%52; - c |= ((a->n[limb] >> shift) & 0xF) << (4 * j); - } - r[31-i] = c; - } + r[0] = (a->n[4] >> 40) & 0xFF; + r[1] = (a->n[4] >> 32) & 0xFF; + r[2] = (a->n[4] >> 24) & 0xFF; + r[3] = (a->n[4] >> 16) & 0xFF; + r[4] = (a->n[4] >> 8) & 0xFF; + r[5] = a->n[4] & 0xFF; + r[6] = (a->n[3] >> 44) & 0xFF; + r[7] = (a->n[3] >> 36) & 0xFF; + r[8] = (a->n[3] >> 28) & 0xFF; + r[9] = (a->n[3] >> 20) & 0xFF; + r[10] = (a->n[3] >> 12) & 0xFF; + r[11] = (a->n[3] >> 4) & 0xFF; + r[12] = ((a->n[2] >> 48) & 0xF) | ((a->n[3] & 0xF) << 4); + r[13] = (a->n[2] >> 40) & 0xFF; + r[14] = (a->n[2] >> 32) & 0xFF; + r[15] = (a->n[2] >> 24) & 0xFF; + r[16] = (a->n[2] >> 16) & 0xFF; + r[17] = (a->n[2] >> 8) & 0xFF; + r[18] = a->n[2] & 0xFF; + r[19] = (a->n[1] >> 44) & 0xFF; + r[20] = (a->n[1] >> 36) & 0xFF; + r[21] = (a->n[1] >> 28) & 0xFF; + r[22] = (a->n[1] >> 20) & 0xFF; + r[23] = (a->n[1] >> 12) & 0xFF; + r[24] = (a->n[1] >> 4) & 0xFF; + r[25] = ((a->n[0] >> 48) & 0xF) | ((a->n[1] & 0xF) << 4); + r[26] = (a->n[0] >> 40) & 0xFF; + r[27] = (a->n[0] >> 32) & 0xFF; + r[28] = (a->n[0] >> 24) & 0xFF; + r[29] = (a->n[0] >> 16) & 0xFF; + r[30] = (a->n[0] >> 8) & 0xFF; + r[31] = a->n[0] & 0xFF; } -SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe_t *r, const secp256k1_fe_t *a, int m) { +SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe *r, const secp256k1_fe *a, int m) { #ifdef VERIFY VERIFY_CHECK(a->magnitude <= m); secp256k1_fe_verify(a); @@ -346,7 +386,7 @@ SECP256K1_INLINE static void secp256k1_fe_negate(secp256k1_fe_t *r, const secp25 #endif } -SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) { +SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe *r, int a) { r->n[0] *= a; r->n[1] *= a; r->n[2] *= a; @@ -359,7 +399,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_int(secp256k1_fe_t *r, int a) { #endif } -SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1_fe_t *a) { +SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe *r, const secp256k1_fe *a) { #ifdef VERIFY secp256k1_fe_verify(a); #endif @@ -375,7 +415,7 @@ SECP256K1_INLINE static void secp256k1_fe_add(secp256k1_fe_t *r, const secp256k1 #endif } -static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const secp256k1_fe_t * SECP256K1_RESTRICT b) { +static void secp256k1_fe_mul(secp256k1_fe *r, const secp256k1_fe *a, const secp256k1_fe * SECP256K1_RESTRICT b) { #ifdef VERIFY VERIFY_CHECK(a->magnitude <= 8); VERIFY_CHECK(b->magnitude <= 8); @@ -391,7 +431,7 @@ static void secp256k1_fe_mul(secp256k1_fe_t *r, const secp256k1_fe_t *a, const s #endif } -static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) { +static void secp256k1_fe_sqr(secp256k1_fe *r, const secp256k1_fe *a) { #ifdef VERIFY VERIFY_CHECK(a->magnitude <= 8); secp256k1_fe_verify(a); @@ -404,7 +444,7 @@ static void secp256k1_fe_sqr(secp256k1_fe_t *r, const secp256k1_fe_t *a) { #endif } -static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k1_fe_t *a, int flag) { +static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe *r, const secp256k1_fe *a, int flag) { uint64_t mask0, mask1; mask0 = flag + ~((uint64_t)0); mask1 = ~mask0; @@ -414,12 +454,14 @@ static SECP256K1_INLINE void secp256k1_fe_cmov(secp256k1_fe_t *r, const secp256k r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); r->n[4] = (r->n[4] & mask0) | (a->n[4] & mask1); #ifdef VERIFY - r->magnitude = (r->magnitude & mask0) | (a->magnitude & mask1); - r->normalized = (r->normalized & mask0) | (a->normalized & mask1); + if (a->magnitude > r->magnitude) { + r->magnitude = a->magnitude; + } + r->normalized &= a->normalized; #endif } -static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r, const secp256k1_fe_storage_t *a, int flag) { +static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage *r, const secp256k1_fe_storage *a, int flag) { uint64_t mask0, mask1; mask0 = flag + ~((uint64_t)0); mask1 = ~mask0; @@ -429,7 +471,7 @@ static SECP256K1_INLINE void secp256k1_fe_storage_cmov(secp256k1_fe_storage_t *r r->n[3] = (r->n[3] & mask0) | (a->n[3] & mask1); } -static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_fe_t *a) { +static void secp256k1_fe_to_storage(secp256k1_fe_storage *r, const secp256k1_fe *a) { #ifdef VERIFY VERIFY_CHECK(a->normalized); #endif @@ -439,7 +481,7 @@ static void secp256k1_fe_to_storage(secp256k1_fe_storage_t *r, const secp256k1_f r->n[3] = a->n[3] >> 36 | a->n[4] << 16; } -static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe_t *r, const secp256k1_fe_storage_t *a) { +static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe *r, const secp256k1_fe_storage *a) { r->n[0] = a->n[0] & 0xFFFFFFFFFFFFFULL; r->n[1] = a->n[0] >> 52 | ((a->n[1] << 12) & 0xFFFFFFFFFFFFFULL); r->n[2] = a->n[1] >> 40 | ((a->n[2] << 24) & 0xFFFFFFFFFFFFFULL); @@ -451,4 +493,4 @@ static SECP256K1_INLINE void secp256k1_fe_from_storage(secp256k1_fe_t *r, const #endif } -#endif +#endif /* SECP256K1_FIELD_REPR_IMPL_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/field_5x52_int128_impl.h b/src/cryptoconditions/src/include/secp256k1/src/field_5x52_int128_impl.h index 9280bb5ea..95a0d1791 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/field_5x52_int128_impl.h +++ b/src/cryptoconditions/src/include/secp256k1/src/field_5x52_int128_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_FIELD_INNER5X52_IMPL_H_ -#define _SECP256K1_FIELD_INNER5X52_IMPL_H_ +#ifndef SECP256K1_FIELD_INNER5X52_IMPL_H +#define SECP256K1_FIELD_INNER5X52_IMPL_H #include @@ -137,7 +137,7 @@ SECP256K1_INLINE static void secp256k1_fe_mul_inner(uint64_t *r, const uint64_t VERIFY_BITS(r[2], 52); VERIFY_BITS(c, 63); /* [d 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += d * R + t3;; + c += d * R + t3; VERIFY_BITS(c, 100); /* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ r[3] = c & M; c >>= 52; @@ -259,7 +259,7 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t VERIFY_BITS(c, 63); /* [d 0 0 0 t4 t3+c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ - c += d * R + t3;; + c += d * R + t3; VERIFY_BITS(c, 100); /* [t4 c r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ r[3] = c & M; c >>= 52; @@ -274,4 +274,4 @@ SECP256K1_INLINE static void secp256k1_fe_sqr_inner(uint64_t *r, const uint64_t /* [r4 r3 r2 r1 r0] = [p8 p7 p6 p5 p4 p3 p2 p1 p0] */ } -#endif +#endif /* SECP256K1_FIELD_INNER5X52_IMPL_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/field_impl.h b/src/cryptoconditions/src/include/secp256k1/src/field_impl.h index e6ec11e8f..20428648a 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/field_impl.h +++ b/src/cryptoconditions/src/include/secp256k1/src/field_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_FIELD_IMPL_H_ -#define _SECP256K1_FIELD_IMPL_H_ +#ifndef SECP256K1_FIELD_IMPL_H +#define SECP256K1_FIELD_IMPL_H #if defined HAVE_CONFIG_H #include "libsecp256k1-config.h" @@ -21,15 +21,31 @@ #error "Please select field implementation" #endif -SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { - secp256k1_fe_t na; +SECP256K1_INLINE static int secp256k1_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) { + secp256k1_fe na; + secp256k1_fe_negate(&na, a, 1); + secp256k1_fe_add(&na, b); + return secp256k1_fe_normalizes_to_zero(&na); +} + +SECP256K1_INLINE static int secp256k1_fe_equal_var(const secp256k1_fe *a, const secp256k1_fe *b) { + secp256k1_fe na; secp256k1_fe_negate(&na, a, 1); secp256k1_fe_add(&na, b); return secp256k1_fe_normalizes_to_zero_var(&na); } -static int secp256k1_fe_sqrt_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) { - secp256k1_fe_t x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; +static int secp256k1_fe_sqrt(secp256k1_fe *r, const secp256k1_fe *a) { + /** Given that p is congruent to 3 mod 4, we can compute the square root of + * a mod p as the (p+1)/4'th power of a. + * + * As (p+1)/4 is an even number, it will have the same result for a and for + * (-a). Only one of these two numbers actually has a square root however, + * so we test at the end by squaring and comparing to the input. + * Also because (p+1)/4 is an even number, the computed square root is + * itself always a square (a ** ((p+1)/4) is the square of a ** ((p+1)/8)). + */ + secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; int j; /** The binary representation of (p + 1)/4 has 3 blocks of 1s, with lengths in @@ -114,11 +130,11 @@ static int secp256k1_fe_sqrt_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) { /* Check that a square root was actually calculated */ secp256k1_fe_sqr(&t1, r); - return secp256k1_fe_equal_var(&t1, a); + return secp256k1_fe_equal(&t1, a); } -static void secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a) { - secp256k1_fe_t x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; +static void secp256k1_fe_inv(secp256k1_fe *r, const secp256k1_fe *a) { + secp256k1_fe x2, x3, x6, x9, x11, x22, x44, x88, x176, x220, x223, t1; int j; /** The binary representation of (p - 2) has 5 blocks of 1s, with lengths in @@ -207,11 +223,15 @@ static void secp256k1_fe_inv(secp256k1_fe_t *r, const secp256k1_fe_t *a) { secp256k1_fe_mul(r, a, &t1); } -static void secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) { +static void secp256k1_fe_inv_var(secp256k1_fe *r, const secp256k1_fe *a) { #if defined(USE_FIELD_INV_BUILTIN) secp256k1_fe_inv(r, a); #elif defined(USE_FIELD_INV_NUM) - secp256k1_num_t n, m; + secp256k1_num n, m; + static const secp256k1_fe negone = SECP256K1_FE_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, 0xFFFFFC2EUL + ); /* secp256k1 field prime, value p defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ static const unsigned char prime[32] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, @@ -220,21 +240,28 @@ static void secp256k1_fe_inv_var(secp256k1_fe_t *r, const secp256k1_fe_t *a) { 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F }; unsigned char b[32]; - secp256k1_fe_t c = *a; + int res; + secp256k1_fe c = *a; secp256k1_fe_normalize_var(&c); secp256k1_fe_get_b32(b, &c); secp256k1_num_set_bin(&n, b, 32); secp256k1_num_set_bin(&m, prime, 32); secp256k1_num_mod_inverse(&n, &n, &m); secp256k1_num_get_bin(b, 32, &n); - VERIFY_CHECK(secp256k1_fe_set_b32(r, b)); + res = secp256k1_fe_set_b32(r, b); + (void)res; + VERIFY_CHECK(res); + /* Verify the result is the (unique) valid inverse using non-GMP code. */ + secp256k1_fe_mul(&c, &c, r); + secp256k1_fe_add(&c, &negone); + CHECK(secp256k1_fe_normalizes_to_zero_var(&c)); #else #error "Please select field inverse implementation" #endif } -static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe_t *r, const secp256k1_fe_t *a) { - secp256k1_fe_t u; +static void secp256k1_fe_inv_all_var(secp256k1_fe *r, const secp256k1_fe *a, size_t len) { + secp256k1_fe u; size_t i; if (len < 1) { return; @@ -252,7 +279,7 @@ static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe_t *r, const secp25 secp256k1_fe_inv_var(&u, &r[--i]); while (i > 0) { - int j = i--; + size_t j = i--; secp256k1_fe_mul(&r[j], &r[i], &u); secp256k1_fe_mul(&u, &u, &a[j]); } @@ -260,4 +287,29 @@ static void secp256k1_fe_inv_all_var(size_t len, secp256k1_fe_t *r, const secp25 r[0] = u; } +static int secp256k1_fe_is_quad_var(const secp256k1_fe *a) { +#ifndef USE_NUM_NONE + unsigned char b[32]; + secp256k1_num n; + secp256k1_num m; + /* secp256k1 field prime, value p defined in "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ + static const unsigned char prime[32] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFC,0x2F + }; + + secp256k1_fe c = *a; + secp256k1_fe_normalize_var(&c); + secp256k1_fe_get_b32(b, &c); + secp256k1_num_set_bin(&n, b, 32); + secp256k1_num_set_bin(&m, prime, 32); + return secp256k1_num_jacobi(&n, &m) >= 0; +#else + secp256k1_fe r; + return secp256k1_fe_sqrt(&r, a); #endif +} + +#endif /* SECP256K1_FIELD_IMPL_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/gen_context.c b/src/cryptoconditions/src/include/secp256k1/src/gen_context.c new file mode 100644 index 000000000..1835fd491 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/gen_context.c @@ -0,0 +1,74 @@ +/********************************************************************** + * Copyright (c) 2013, 2014, 2015 Thomas Daede, Cory Fields * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#define USE_BASIC_CONFIG 1 + +#include "basic-config.h" +#include "include/secp256k1.h" +#include "field_impl.h" +#include "scalar_impl.h" +#include "group_impl.h" +#include "ecmult_gen_impl.h" + +static void default_error_callback_fn(const char* str, void* data) { + (void)data; + fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str); + abort(); +} + +static const secp256k1_callback default_error_callback = { + default_error_callback_fn, + NULL +}; + +int main(int argc, char **argv) { + secp256k1_ecmult_gen_context ctx; + int inner; + int outer; + FILE* fp; + + (void)argc; + (void)argv; + + fp = fopen("src/ecmult_static_context.h","w"); + if (fp == NULL) { + fprintf(stderr, "Could not open src/ecmult_static_context.h for writing!\n"); + return -1; + } + + fprintf(fp, "#ifndef _SECP256K1_ECMULT_STATIC_CONTEXT_\n"); + fprintf(fp, "#define _SECP256K1_ECMULT_STATIC_CONTEXT_\n"); + fprintf(fp, "#include \"group.h\"\n"); + fprintf(fp, "#define SC SECP256K1_GE_STORAGE_CONST\n"); + fprintf(fp, "static const secp256k1_ge_storage secp256k1_ecmult_static_context[64][16] = {\n"); + + secp256k1_ecmult_gen_context_init(&ctx); + secp256k1_ecmult_gen_context_build(&ctx, &default_error_callback); + for(outer = 0; outer != 64; outer++) { + fprintf(fp,"{\n"); + for(inner = 0; inner != 16; inner++) { + fprintf(fp," SC(%uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu, %uu)", SECP256K1_GE_STORAGE_CONST_GET((*ctx.prec)[outer][inner])); + if (inner != 15) { + fprintf(fp,",\n"); + } else { + fprintf(fp,"\n"); + } + } + if (outer != 63) { + fprintf(fp,"},\n"); + } else { + fprintf(fp,"}\n"); + } + } + fprintf(fp,"};\n"); + secp256k1_ecmult_gen_context_clear(&ctx); + + fprintf(fp, "#undef SC\n"); + fprintf(fp, "#endif\n"); + fclose(fp); + + return 0; +} diff --git a/src/cryptoconditions/src/include/secp256k1/src/group.h b/src/cryptoconditions/src/include/secp256k1/src/group.h index 0b08b3b99..ea1302deb 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/group.h +++ b/src/cryptoconditions/src/include/secp256k1/src/group.h @@ -4,118 +4,141 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_GROUP_ -#define _SECP256K1_GROUP_ +#ifndef SECP256K1_GROUP_H +#define SECP256K1_GROUP_H #include "num.h" #include "field.h" /** A group element of the secp256k1 curve, in affine coordinates. */ typedef struct { - secp256k1_fe_t x; - secp256k1_fe_t y; + secp256k1_fe x; + secp256k1_fe y; int infinity; /* whether this represents the point at infinity */ -} secp256k1_ge_t; +} secp256k1_ge; #define SECP256K1_GE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), 0} #define SECP256K1_GE_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1} /** A group element of the secp256k1 curve, in jacobian coordinates. */ typedef struct { - secp256k1_fe_t x; /* actual X: x/z^2 */ - secp256k1_fe_t y; /* actual Y: y/z^3 */ - secp256k1_fe_t z; + secp256k1_fe x; /* actual X: x/z^2 */ + secp256k1_fe y; /* actual Y: y/z^3 */ + secp256k1_fe z; int infinity; /* whether this represents the point at infinity */ -} secp256k1_gej_t; +} secp256k1_gej; #define SECP256K1_GEJ_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_CONST((i),(j),(k),(l),(m),(n),(o),(p)), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1), 0} #define SECP256K1_GEJ_CONST_INFINITY {SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 0), 1} typedef struct { - secp256k1_fe_storage_t x; - secp256k1_fe_storage_t y; -} secp256k1_ge_storage_t; + secp256k1_fe_storage x; + secp256k1_fe_storage y; +} secp256k1_ge_storage; #define SECP256K1_GE_STORAGE_CONST(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) {SECP256K1_FE_STORAGE_CONST((a),(b),(c),(d),(e),(f),(g),(h)), SECP256K1_FE_STORAGE_CONST((i),(j),(k),(l),(m),(n),(o),(p))} -/** Set a group element equal to the point at infinity */ -static void secp256k1_ge_set_infinity(secp256k1_ge_t *r); +#define SECP256K1_GE_STORAGE_CONST_GET(t) SECP256K1_FE_STORAGE_CONST_GET(t.x), SECP256K1_FE_STORAGE_CONST_GET(t.y) /** Set a group element equal to the point with given X and Y coordinates */ -static void secp256k1_ge_set_xy(secp256k1_ge_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y); +static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y); + +/** Set a group element (affine) equal to the point with the given X coordinate + * and a Y coordinate that is a quadratic residue modulo p. The return value + * is true iff a coordinate with the given X coordinate exists. + */ +static int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x); /** Set a group element (affine) equal to the point with the given X coordinate, and given oddness * for Y. Return value indicates whether the result is valid. */ -static int secp256k1_ge_set_xo_var(secp256k1_ge_t *r, const secp256k1_fe_t *x, int odd); +static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd); /** Check whether a group element is the point at infinity. */ -static int secp256k1_ge_is_infinity(const secp256k1_ge_t *a); +static int secp256k1_ge_is_infinity(const secp256k1_ge *a); /** Check whether a group element is valid (i.e., on the curve). */ -static int secp256k1_ge_is_valid_var(const secp256k1_ge_t *a); +static int secp256k1_ge_is_valid_var(const secp256k1_ge *a); -static void secp256k1_ge_neg(secp256k1_ge_t *r, const secp256k1_ge_t *a); +static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a); /** Set a group element equal to another which is given in jacobian coordinates */ -static void secp256k1_ge_set_gej(secp256k1_ge_t *r, secp256k1_gej_t *a); +static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a); /** Set a batch of group elements equal to the inputs given in jacobian coordinates */ -static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge_t *r, const secp256k1_gej_t *a); +static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len, const secp256k1_callback *cb); +/** Set a batch of group elements equal to the inputs given in jacobian + * coordinates (with known z-ratios). zr must contain the known z-ratios such + * that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. */ +static void secp256k1_ge_set_table_gej_var(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr, size_t len); + +/** Bring a batch inputs given in jacobian coordinates (with known z-ratios) to + * the same global z "denominator". zr must contain the known z-ratios such + * that mul(a[i].z, zr[i+1]) == a[i+1].z. zr[0] is ignored. The x and y + * coordinates of the result are stored in r, the common z coordinate is + * stored in globalz. */ +static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp256k1_fe *globalz, const secp256k1_gej *a, const secp256k1_fe *zr); /** Set a group element (jacobian) equal to the point at infinity. */ -static void secp256k1_gej_set_infinity(secp256k1_gej_t *r); - -/** Set a group element (jacobian) equal to the point with given X and Y coordinates. */ -static void secp256k1_gej_set_xy(secp256k1_gej_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y); +static void secp256k1_gej_set_infinity(secp256k1_gej *r); /** Set a group element (jacobian) equal to another which is given in affine coordinates. */ -static void secp256k1_gej_set_ge(secp256k1_gej_t *r, const secp256k1_ge_t *a); +static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a); /** Compare the X coordinate of a group element (jacobian). */ -static int secp256k1_gej_eq_x_var(const secp256k1_fe_t *x, const secp256k1_gej_t *a); +static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a); /** Set r equal to the inverse of a (i.e., mirrored around the X axis) */ -static void secp256k1_gej_neg(secp256k1_gej_t *r, const secp256k1_gej_t *a); +static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a); /** Check whether a group element is the point at infinity. */ -static int secp256k1_gej_is_infinity(const secp256k1_gej_t *a); +static int secp256k1_gej_is_infinity(const secp256k1_gej *a); -/** Set r equal to the double of a. */ -static void secp256k1_gej_double_var(secp256k1_gej_t *r, const secp256k1_gej_t *a); +/** Check whether a group element's y coordinate is a quadratic residue. */ +static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a); -/** Set r equal to the sum of a and b. */ -static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_gej_t *b); +/** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0). + * a may not be zero. Constant time. */ +static void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr); + +/** Set r equal to the double of a. If rzr is not-NULL, r->z = a->z * *rzr (where infinity means an implicit z = 0). */ +static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr); + +/** Set r equal to the sum of a and b. If rzr is non-NULL, r->z = a->z * *rzr (a cannot be infinity in that case). */ +static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr); /** Set r equal to the sum of a and b (with b given in affine coordinates, and not infinity). */ -static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b); +static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b); /** Set r equal to the sum of a and b (with b given in affine coordinates). This is more efficient than secp256k1_gej_add_var. It is identical to secp256k1_gej_add_ge but without constant-time - guarantee, and b is allowed to be infinity. */ -static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b); + guarantee, and b is allowed to be infinity. If rzr is non-NULL, r->z = a->z * *rzr (a cannot be infinity in that case). */ +static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr); + +/** Set r equal to the sum of a and b (with the inverse of b's Z coordinate passed as bzinv). */ +static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv); #ifdef USE_ENDOMORPHISM /** Set r to be equal to lambda times a, where lambda is chosen in a way such that this is very fast. */ -static void secp256k1_gej_mul_lambda(secp256k1_gej_t *r, const secp256k1_gej_t *a); +static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a); #endif -/** Clear a secp256k1_gej_t to prevent leaking sensitive information. */ -static void secp256k1_gej_clear(secp256k1_gej_t *r); +/** Clear a secp256k1_gej to prevent leaking sensitive information. */ +static void secp256k1_gej_clear(secp256k1_gej *r); -/** Clear a secp256k1_ge_t to prevent leaking sensitive information. */ -static void secp256k1_ge_clear(secp256k1_ge_t *r); +/** Clear a secp256k1_ge to prevent leaking sensitive information. */ +static void secp256k1_ge_clear(secp256k1_ge *r); /** Convert a group element to the storage type. */ -static void secp256k1_ge_to_storage(secp256k1_ge_storage_t *r, const secp256k1_ge_t*); +static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a); /** Convert a group element back from the storage type. */ -static void secp256k1_ge_from_storage(secp256k1_ge_t *r, const secp256k1_ge_storage_t*); +static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storage *a); /** If flag is true, set *r equal to *a; otherwise leave it. Constant-time. */ -static void secp256k1_ge_storage_cmov(secp256k1_ge_storage_t *r, const secp256k1_ge_storage_t *a, int flag); +static void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag); /** Rescale a jacobian point by b which must be non-zero. Constant-time. */ -static void secp256k1_gej_rescale(secp256k1_gej_t *r, const secp256k1_fe_t *b); +static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *b); -#endif +#endif /* SECP256K1_GROUP_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/group_impl.h b/src/cryptoconditions/src/include/secp256k1/src/group_impl.h index 0f64576fb..b31b6c12e 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/group_impl.h +++ b/src/cryptoconditions/src/include/secp256k1/src/group_impl.h @@ -4,47 +4,101 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_GROUP_IMPL_H_ -#define _SECP256K1_GROUP_IMPL_H_ - -#include +#ifndef SECP256K1_GROUP_IMPL_H +#define SECP256K1_GROUP_IMPL_H #include "num.h" #include "field.h" #include "group.h" +/* These points can be generated in sage as follows: + * + * 0. Setup a worksheet with the following parameters. + * b = 4 # whatever CURVE_B will be set to + * F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F) + * C = EllipticCurve ([F (0), F (b)]) + * + * 1. Determine all the small orders available to you. (If there are + * no satisfactory ones, go back and change b.) + * print C.order().factor(limit=1000) + * + * 2. Choose an order as one of the prime factors listed in the above step. + * (You can also multiply some to get a composite order, though the + * tests will crash trying to invert scalars during signing.) We take a + * random point and scale it to drop its order to the desired value. + * There is some probability this won't work; just try again. + * order = 199 + * P = C.random_point() + * P = (int(P.order()) / int(order)) * P + * assert(P.order() == order) + * + * 3. Print the values. You'll need to use a vim macro or something to + * split the hex output into 4-byte chunks. + * print "%x %x" % P.xy() + */ +#if defined(EXHAUSTIVE_TEST_ORDER) +# if EXHAUSTIVE_TEST_ORDER == 199 +const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST( + 0xFA7CC9A7, 0x0737F2DB, 0xA749DD39, 0x2B4FB069, + 0x3B017A7D, 0xA808C2F1, 0xFB12940C, 0x9EA66C18, + 0x78AC123A, 0x5ED8AEF3, 0x8732BC91, 0x1F3A2868, + 0x48DF246C, 0x808DAE72, 0xCFE52572, 0x7F0501ED +); + +const int CURVE_B = 4; +# elif EXHAUSTIVE_TEST_ORDER == 13 +const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST( + 0xedc60018, 0xa51a786b, 0x2ea91f4d, 0x4c9416c0, + 0x9de54c3b, 0xa1316554, 0x6cf4345c, 0x7277ef15, + 0x54cb1b6b, 0xdc8c1273, 0x087844ea, 0x43f4603e, + 0x0eaf9a43, 0xf6effe55, 0x939f806d, 0x37adf8ac +); +const int CURVE_B = 2; +# else +# error No known generator for the specified exhaustive test group order. +# endif +#else /** Generator for secp256k1, value 'g' defined in * "Standards for Efficient Cryptography" (SEC2) 2.7.1. */ -static const secp256k1_ge_t secp256k1_ge_const_g = SECP256K1_GE_CONST( +static const secp256k1_ge secp256k1_ge_const_g = SECP256K1_GE_CONST( 0x79BE667EUL, 0xF9DCBBACUL, 0x55A06295UL, 0xCE870B07UL, 0x029BFCDBUL, 0x2DCE28D9UL, 0x59F2815BUL, 0x16F81798UL, 0x483ADA77UL, 0x26A3C465UL, 0x5DA4FBFCUL, 0x0E1108A8UL, 0xFD17B448UL, 0xA6855419UL, 0x9C47D08FUL, 0xFB10D4B8UL ); -static void secp256k1_ge_set_infinity(secp256k1_ge_t *r) { - r->infinity = 1; +const int CURVE_B = 7; +#endif + +static void secp256k1_ge_set_gej_zinv(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zi) { + secp256k1_fe zi2; + secp256k1_fe zi3; + secp256k1_fe_sqr(&zi2, zi); + secp256k1_fe_mul(&zi3, &zi2, zi); + secp256k1_fe_mul(&r->x, &a->x, &zi2); + secp256k1_fe_mul(&r->y, &a->y, &zi3); + r->infinity = a->infinity; } -static void secp256k1_ge_set_xy(secp256k1_ge_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y) { +static void secp256k1_ge_set_xy(secp256k1_ge *r, const secp256k1_fe *x, const secp256k1_fe *y) { r->infinity = 0; r->x = *x; r->y = *y; } -static int secp256k1_ge_is_infinity(const secp256k1_ge_t *a) { +static int secp256k1_ge_is_infinity(const secp256k1_ge *a) { return a->infinity; } -static void secp256k1_ge_neg(secp256k1_ge_t *r, const secp256k1_ge_t *a) { +static void secp256k1_ge_neg(secp256k1_ge *r, const secp256k1_ge *a) { *r = *a; secp256k1_fe_normalize_weak(&r->y); secp256k1_fe_negate(&r->y, &r->y, 1); } -static void secp256k1_ge_set_gej(secp256k1_ge_t *r, secp256k1_gej_t *a) { - secp256k1_fe_t z2, z3; +static void secp256k1_ge_set_gej(secp256k1_ge *r, secp256k1_gej *a) { + secp256k1_fe z2, z3; r->infinity = a->infinity; secp256k1_fe_inv(&a->z, &a->z); secp256k1_fe_sqr(&z2, &a->z); @@ -56,8 +110,8 @@ static void secp256k1_ge_set_gej(secp256k1_ge_t *r, secp256k1_gej_t *a) { r->y = a->y; } -static void secp256k1_ge_set_gej_var(secp256k1_ge_t *r, secp256k1_gej_t *a) { - secp256k1_fe_t z2, z3; +static void secp256k1_ge_set_gej_var(secp256k1_ge *r, secp256k1_gej *a) { + secp256k1_fe z2, z3; r->infinity = a->infinity; if (a->infinity) { return; @@ -72,73 +126,106 @@ static void secp256k1_ge_set_gej_var(secp256k1_ge_t *r, secp256k1_gej_t *a) { r->y = a->y; } -static void secp256k1_ge_set_all_gej_var(size_t len, secp256k1_ge_t *r, const secp256k1_gej_t *a) { - secp256k1_fe_t *az; - secp256k1_fe_t *azi; +static void secp256k1_ge_set_all_gej_var(secp256k1_ge *r, const secp256k1_gej *a, size_t len, const secp256k1_callback *cb) { + secp256k1_fe *az; + secp256k1_fe *azi; size_t i; size_t count = 0; - az = (secp256k1_fe_t *)checked_malloc(sizeof(secp256k1_fe_t) * len); + az = (secp256k1_fe *)checked_malloc(cb, sizeof(secp256k1_fe) * len); for (i = 0; i < len; i++) { if (!a[i].infinity) { az[count++] = a[i].z; } } - azi = (secp256k1_fe_t *)checked_malloc(sizeof(secp256k1_fe_t) * count); - secp256k1_fe_inv_all_var(count, azi, az); + azi = (secp256k1_fe *)checked_malloc(cb, sizeof(secp256k1_fe) * count); + secp256k1_fe_inv_all_var(azi, az, count); free(az); count = 0; for (i = 0; i < len; i++) { r[i].infinity = a[i].infinity; if (!a[i].infinity) { - secp256k1_fe_t zi2, zi3; - secp256k1_fe_t *zi = &azi[count++]; - secp256k1_fe_sqr(&zi2, zi); - secp256k1_fe_mul(&zi3, &zi2, zi); - secp256k1_fe_mul(&r[i].x, &a[i].x, &zi2); - secp256k1_fe_mul(&r[i].y, &a[i].y, &zi3); + secp256k1_ge_set_gej_zinv(&r[i], &a[i], &azi[count++]); } } free(azi); } -static void secp256k1_gej_set_infinity(secp256k1_gej_t *r) { +static void secp256k1_ge_set_table_gej_var(secp256k1_ge *r, const secp256k1_gej *a, const secp256k1_fe *zr, size_t len) { + size_t i = len - 1; + secp256k1_fe zi; + + if (len > 0) { + /* Compute the inverse of the last z coordinate, and use it to compute the last affine output. */ + secp256k1_fe_inv(&zi, &a[i].z); + secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zi); + + /* Work out way backwards, using the z-ratios to scale the x/y values. */ + while (i > 0) { + secp256k1_fe_mul(&zi, &zi, &zr[i]); + i--; + secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zi); + } + } +} + +static void secp256k1_ge_globalz_set_table_gej(size_t len, secp256k1_ge *r, secp256k1_fe *globalz, const secp256k1_gej *a, const secp256k1_fe *zr) { + size_t i = len - 1; + secp256k1_fe zs; + + if (len > 0) { + /* The z of the final point gives us the "global Z" for the table. */ + r[i].x = a[i].x; + r[i].y = a[i].y; + *globalz = a[i].z; + r[i].infinity = 0; + zs = zr[i]; + + /* Work our way backwards, using the z-ratios to scale the x/y values. */ + while (i > 0) { + if (i != len - 1) { + secp256k1_fe_mul(&zs, &zs, &zr[i]); + } + i--; + secp256k1_ge_set_gej_zinv(&r[i], &a[i], &zs); + } + } +} + +static void secp256k1_gej_set_infinity(secp256k1_gej *r) { r->infinity = 1; - secp256k1_fe_set_int(&r->x, 0); - secp256k1_fe_set_int(&r->y, 0); - secp256k1_fe_set_int(&r->z, 0); + secp256k1_fe_clear(&r->x); + secp256k1_fe_clear(&r->y); + secp256k1_fe_clear(&r->z); } -static void secp256k1_gej_set_xy(secp256k1_gej_t *r, const secp256k1_fe_t *x, const secp256k1_fe_t *y) { - r->infinity = 0; - r->x = *x; - r->y = *y; - secp256k1_fe_set_int(&r->z, 1); -} - -static void secp256k1_gej_clear(secp256k1_gej_t *r) { +static void secp256k1_gej_clear(secp256k1_gej *r) { r->infinity = 0; secp256k1_fe_clear(&r->x); secp256k1_fe_clear(&r->y); secp256k1_fe_clear(&r->z); } -static void secp256k1_ge_clear(secp256k1_ge_t *r) { +static void secp256k1_ge_clear(secp256k1_ge *r) { r->infinity = 0; secp256k1_fe_clear(&r->x); secp256k1_fe_clear(&r->y); } -static int secp256k1_ge_set_xo_var(secp256k1_ge_t *r, const secp256k1_fe_t *x, int odd) { - secp256k1_fe_t x2, x3, c; +static int secp256k1_ge_set_xquad(secp256k1_ge *r, const secp256k1_fe *x) { + secp256k1_fe x2, x3, c; r->x = *x; secp256k1_fe_sqr(&x2, x); secp256k1_fe_mul(&x3, x, &x2); r->infinity = 0; - secp256k1_fe_set_int(&c, 7); + secp256k1_fe_set_int(&c, CURVE_B); secp256k1_fe_add(&c, &x3); - if (!secp256k1_fe_sqrt_var(&r->y, &c)) { + return secp256k1_fe_sqrt(&r->y, &c); +} + +static int secp256k1_ge_set_xo_var(secp256k1_ge *r, const secp256k1_fe *x, int odd) { + if (!secp256k1_ge_set_xquad(r, x)) { return 0; } secp256k1_fe_normalize_var(&r->y); @@ -146,24 +233,25 @@ static int secp256k1_ge_set_xo_var(secp256k1_ge_t *r, const secp256k1_fe_t *x, i secp256k1_fe_negate(&r->y, &r->y, 1); } return 1; + } -static void secp256k1_gej_set_ge(secp256k1_gej_t *r, const secp256k1_ge_t *a) { +static void secp256k1_gej_set_ge(secp256k1_gej *r, const secp256k1_ge *a) { r->infinity = a->infinity; r->x = a->x; r->y = a->y; secp256k1_fe_set_int(&r->z, 1); } -static int secp256k1_gej_eq_x_var(const secp256k1_fe_t *x, const secp256k1_gej_t *a) { - secp256k1_fe_t r, r2; +static int secp256k1_gej_eq_x_var(const secp256k1_fe *x, const secp256k1_gej *a) { + secp256k1_fe r, r2; VERIFY_CHECK(!a->infinity); secp256k1_fe_sqr(&r, &a->z); secp256k1_fe_mul(&r, &r, x); r2 = a->x; secp256k1_fe_normalize_weak(&r2); return secp256k1_fe_equal_var(&r, &r2); } -static void secp256k1_gej_neg(secp256k1_gej_t *r, const secp256k1_gej_t *a) { +static void secp256k1_gej_neg(secp256k1_gej *r, const secp256k1_gej *a) { r->infinity = a->infinity; r->x = a->x; r->y = a->y; @@ -172,12 +260,12 @@ static void secp256k1_gej_neg(secp256k1_gej_t *r, const secp256k1_gej_t *a) { secp256k1_fe_negate(&r->y, &r->y, 1); } -static int secp256k1_gej_is_infinity(const secp256k1_gej_t *a) { +static int secp256k1_gej_is_infinity(const secp256k1_gej *a) { return a->infinity; } -static int secp256k1_gej_is_valid_var(const secp256k1_gej_t *a) { - secp256k1_fe_t y2, x3, z2, z6; +static int secp256k1_gej_is_valid_var(const secp256k1_gej *a) { + secp256k1_fe y2, x3, z2, z6; if (a->infinity) { return 0; } @@ -190,38 +278,59 @@ static int secp256k1_gej_is_valid_var(const secp256k1_gej_t *a) { secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x); secp256k1_fe_sqr(&z2, &a->z); secp256k1_fe_sqr(&z6, &z2); secp256k1_fe_mul(&z6, &z6, &z2); - secp256k1_fe_mul_int(&z6, 7); + secp256k1_fe_mul_int(&z6, CURVE_B); secp256k1_fe_add(&x3, &z6); secp256k1_fe_normalize_weak(&x3); return secp256k1_fe_equal_var(&y2, &x3); } -static int secp256k1_ge_is_valid_var(const secp256k1_ge_t *a) { - secp256k1_fe_t y2, x3, c; +static int secp256k1_ge_is_valid_var(const secp256k1_ge *a) { + secp256k1_fe y2, x3, c; if (a->infinity) { return 0; } /* y^2 = x^3 + 7 */ secp256k1_fe_sqr(&y2, &a->y); secp256k1_fe_sqr(&x3, &a->x); secp256k1_fe_mul(&x3, &x3, &a->x); - secp256k1_fe_set_int(&c, 7); + secp256k1_fe_set_int(&c, CURVE_B); secp256k1_fe_add(&x3, &c); secp256k1_fe_normalize_weak(&x3); return secp256k1_fe_equal_var(&y2, &x3); } -static void secp256k1_gej_double_var(secp256k1_gej_t *r, const secp256k1_gej_t *a) { - /* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate */ - secp256k1_fe_t t1,t2,t3,t4; +static void secp256k1_gej_double_var(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) { + /* Operations: 3 mul, 4 sqr, 0 normalize, 12 mul_int/add/negate. + * + * Note that there is an implementation described at + * https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l + * which trades a multiply for a square, but in practice this is actually slower, + * mainly because it requires more normalizations. + */ + secp256k1_fe t1,t2,t3,t4; /** For secp256k1, 2Q is infinity if and only if Q is infinity. This is because if 2Q = infinity, * Q must equal -Q, or that Q.y == -(Q.y), or Q.y is 0. For a point on y^2 = x^3 + 7 to have * y=0, x^3 must be -7 mod p. However, -7 has no cube root mod p. + * + * Having said this, if this function receives a point on a sextic twist, e.g. by + * a fault attack, it is possible for y to be 0. This happens for y^2 = x^3 + 6, + * since -6 does have a cube root mod p. For this point, this function will not set + * the infinity flag even though the point doubles to infinity, and the result + * point will be gibberish (z = 0 but infinity = 0). */ r->infinity = a->infinity; if (r->infinity) { + if (rzr != NULL) { + secp256k1_fe_set_int(rzr, 1); + } return; } + if (rzr != NULL) { + *rzr = a->y; + secp256k1_fe_normalize_weak(rzr); + secp256k1_fe_mul_int(rzr, 2); + } + secp256k1_fe_mul(&r->z, &a->z, &a->y); secp256k1_fe_mul_int(&r->z, 2); /* Z' = 2*Y*Z (2) */ secp256k1_fe_sqr(&t1, &a->x); @@ -244,17 +353,29 @@ static void secp256k1_gej_double_var(secp256k1_gej_t *r, const secp256k1_gej_t * secp256k1_fe_add(&r->y, &t2); /* Y' = 36*X^3*Y^2 - 27*X^6 - 8*Y^4 (4) */ } -static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_gej_t *b) { +static SECP256K1_INLINE void secp256k1_gej_double_nonzero(secp256k1_gej *r, const secp256k1_gej *a, secp256k1_fe *rzr) { + VERIFY_CHECK(!secp256k1_gej_is_infinity(a)); + secp256k1_gej_double_var(r, a, rzr); +} + +static void secp256k1_gej_add_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_gej *b, secp256k1_fe *rzr) { /* Operations: 12 mul, 4 sqr, 2 normalize, 12 mul_int/add/negate */ - secp256k1_fe_t z22, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; + secp256k1_fe z22, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; + if (a->infinity) { + VERIFY_CHECK(rzr == NULL); *r = *b; return; } + if (b->infinity) { + if (rzr != NULL) { + secp256k1_fe_set_int(rzr, 1); + } *r = *a; return; } + r->infinity = 0; secp256k1_fe_sqr(&z22, &b->z); secp256k1_fe_sqr(&z12, &a->z); @@ -266,8 +387,11 @@ static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2); if (secp256k1_fe_normalizes_to_zero_var(&h)) { if (secp256k1_fe_normalizes_to_zero_var(&i)) { - secp256k1_gej_double_var(r, a); + secp256k1_gej_double_var(r, a, rzr); } else { + if (rzr != NULL) { + secp256k1_fe_set_int(rzr, 0); + } r->infinity = 1; } return; @@ -275,7 +399,11 @@ static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, secp256k1_fe_sqr(&i2, &i); secp256k1_fe_sqr(&h2, &h); secp256k1_fe_mul(&h3, &h, &h2); - secp256k1_fe_mul(&r->z, &a->z, &b->z); secp256k1_fe_mul(&r->z, &r->z, &h); + secp256k1_fe_mul(&h, &h, &b->z); + if (rzr != NULL) { + *rzr = h; + } + secp256k1_fe_mul(&r->z, &a->z, &h); secp256k1_fe_mul(&t, &u1, &h2); r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2); secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i); @@ -283,21 +411,23 @@ static void secp256k1_gej_add_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, secp256k1_fe_add(&r->y, &h3); } -static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b) { +static void secp256k1_gej_add_ge_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, secp256k1_fe *rzr) { /* 8 mul, 3 sqr, 4 normalize, 12 mul_int/add/negate */ - secp256k1_fe_t z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; + secp256k1_fe z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; if (a->infinity) { - r->infinity = b->infinity; - r->x = b->x; - r->y = b->y; - secp256k1_fe_set_int(&r->z, 1); + VERIFY_CHECK(rzr == NULL); + secp256k1_gej_set_ge(r, b); return; } if (b->infinity) { + if (rzr != NULL) { + secp256k1_fe_set_int(rzr, 1); + } *r = *a; return; } r->infinity = 0; + secp256k1_fe_sqr(&z12, &a->z); u1 = a->x; secp256k1_fe_normalize_weak(&u1); secp256k1_fe_mul(&u2, &b->x, &z12); @@ -307,7 +437,69 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t * secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2); if (secp256k1_fe_normalizes_to_zero_var(&h)) { if (secp256k1_fe_normalizes_to_zero_var(&i)) { - secp256k1_gej_double_var(r, a); + secp256k1_gej_double_var(r, a, rzr); + } else { + if (rzr != NULL) { + secp256k1_fe_set_int(rzr, 0); + } + r->infinity = 1; + } + return; + } + secp256k1_fe_sqr(&i2, &i); + secp256k1_fe_sqr(&h2, &h); + secp256k1_fe_mul(&h3, &h, &h2); + if (rzr != NULL) { + *rzr = h; + } + secp256k1_fe_mul(&r->z, &a->z, &h); + secp256k1_fe_mul(&t, &u1, &h2); + r->x = t; secp256k1_fe_mul_int(&r->x, 2); secp256k1_fe_add(&r->x, &h3); secp256k1_fe_negate(&r->x, &r->x, 3); secp256k1_fe_add(&r->x, &i2); + secp256k1_fe_negate(&r->y, &r->x, 5); secp256k1_fe_add(&r->y, &t); secp256k1_fe_mul(&r->y, &r->y, &i); + secp256k1_fe_mul(&h3, &h3, &s1); secp256k1_fe_negate(&h3, &h3, 1); + secp256k1_fe_add(&r->y, &h3); +} + +static void secp256k1_gej_add_zinv_var(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b, const secp256k1_fe *bzinv) { + /* 9 mul, 3 sqr, 4 normalize, 12 mul_int/add/negate */ + secp256k1_fe az, z12, u1, u2, s1, s2, h, i, i2, h2, h3, t; + + if (b->infinity) { + *r = *a; + return; + } + if (a->infinity) { + secp256k1_fe bzinv2, bzinv3; + r->infinity = b->infinity; + secp256k1_fe_sqr(&bzinv2, bzinv); + secp256k1_fe_mul(&bzinv3, &bzinv2, bzinv); + secp256k1_fe_mul(&r->x, &b->x, &bzinv2); + secp256k1_fe_mul(&r->y, &b->y, &bzinv3); + secp256k1_fe_set_int(&r->z, 1); + return; + } + r->infinity = 0; + + /** We need to calculate (rx,ry,rz) = (ax,ay,az) + (bx,by,1/bzinv). Due to + * secp256k1's isomorphism we can multiply the Z coordinates on both sides + * by bzinv, and get: (rx,ry,rz*bzinv) = (ax,ay,az*bzinv) + (bx,by,1). + * This means that (rx,ry,rz) can be calculated as + * (ax,ay,az*bzinv) + (bx,by,1), when not applying the bzinv factor to rz. + * The variable az below holds the modified Z coordinate for a, which is used + * for the computation of rx and ry, but not for rz. + */ + secp256k1_fe_mul(&az, &a->z, bzinv); + + secp256k1_fe_sqr(&z12, &az); + u1 = a->x; secp256k1_fe_normalize_weak(&u1); + secp256k1_fe_mul(&u2, &b->x, &z12); + s1 = a->y; secp256k1_fe_normalize_weak(&s1); + secp256k1_fe_mul(&s2, &b->y, &z12); secp256k1_fe_mul(&s2, &s2, &az); + secp256k1_fe_negate(&h, &u1, 1); secp256k1_fe_add(&h, &u2); + secp256k1_fe_negate(&i, &s1, 1); secp256k1_fe_add(&i, &s2); + if (secp256k1_fe_normalizes_to_zero_var(&h)) { + if (secp256k1_fe_normalizes_to_zero_var(&i)) { + secp256k1_gej_double_var(r, a, NULL); } else { r->infinity = 1; } @@ -324,11 +516,13 @@ static void secp256k1_gej_add_ge_var(secp256k1_gej_t *r, const secp256k1_gej_t * secp256k1_fe_add(&r->y, &h3); } -static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, const secp256k1_ge_t *b) { - /* Operations: 7 mul, 5 sqr, 5 normalize, 17 mul_int/add/negate/cmov */ - static const secp256k1_fe_t fe_1 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); - secp256k1_fe_t zz, u1, u2, s1, s2, z, t, m, n, q, rr; - int infinity; + +static void secp256k1_gej_add_ge(secp256k1_gej *r, const secp256k1_gej *a, const secp256k1_ge *b) { + /* Operations: 7 mul, 5 sqr, 4 normalize, 21 mul_int/add/negate/cmov */ + static const secp256k1_fe fe_1 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); + secp256k1_fe zz, u1, u2, s1, s2, t, tt, m, n, q, rr; + secp256k1_fe m_alt, rr_alt; + int infinity, degenerate; VERIFY_CHECK(!b->infinity); VERIFY_CHECK(a->infinity == 0 || a->infinity == 1); @@ -352,53 +546,102 @@ static void secp256k1_gej_add_ge(secp256k1_gej_t *r, const secp256k1_gej_t *a, c * Y3 = 4*(R*(3*Q-2*R^2)-M^4) * Z3 = 2*M*Z * (Note that the paper uses xi = Xi / Zi and yi = Yi / Zi instead.) + * + * This formula has the benefit of being the same for both addition + * of distinct points and doubling. However, it breaks down in the + * case that either point is infinity, or that y1 = -y2. We handle + * these cases in the following ways: + * + * - If b is infinity we simply bail by means of a VERIFY_CHECK. + * + * - If a is infinity, we detect this, and at the end of the + * computation replace the result (which will be meaningless, + * but we compute to be constant-time) with b.x : b.y : 1. + * + * - If a = -b, we have y1 = -y2, which is a degenerate case. + * But here the answer is infinity, so we simply set the + * infinity flag of the result, overriding the computed values + * without even needing to cmov. + * + * - If y1 = -y2 but x1 != x2, which does occur thanks to certain + * properties of our curve (specifically, 1 has nontrivial cube + * roots in our field, and the curve equation has no x coefficient) + * then the answer is not infinity but also not given by the above + * equation. In this case, we cmov in place an alternate expression + * for lambda. Specifically (y1 - y2)/(x1 - x2). Where both these + * expressions for lambda are defined, they are equal, and can be + * obtained from each other by multiplication by (y1 + y2)/(y1 + y2) + * then substitution of x^3 + 7 for y^2 (using the curve equation). + * For all pairs of nonzero points (a, b) at least one is defined, + * so this covers everything. */ secp256k1_fe_sqr(&zz, &a->z); /* z = Z1^2 */ u1 = a->x; secp256k1_fe_normalize_weak(&u1); /* u1 = U1 = X1*Z2^2 (1) */ secp256k1_fe_mul(&u2, &b->x, &zz); /* u2 = U2 = X2*Z1^2 (1) */ s1 = a->y; secp256k1_fe_normalize_weak(&s1); /* s1 = S1 = Y1*Z2^3 (1) */ - secp256k1_fe_mul(&s2, &b->y, &zz); /* s2 = Y2*Z2^2 (1) */ + secp256k1_fe_mul(&s2, &b->y, &zz); /* s2 = Y2*Z1^2 (1) */ secp256k1_fe_mul(&s2, &s2, &a->z); /* s2 = S2 = Y2*Z1^3 (1) */ - z = a->z; /* z = Z = Z1*Z2 (8) */ t = u1; secp256k1_fe_add(&t, &u2); /* t = T = U1+U2 (2) */ m = s1; secp256k1_fe_add(&m, &s2); /* m = M = S1+S2 (2) */ - secp256k1_fe_sqr(&n, &m); /* n = M^2 (1) */ - secp256k1_fe_mul(&q, &n, &t); /* q = Q = T*M^2 (1) */ - secp256k1_fe_sqr(&n, &n); /* n = M^4 (1) */ secp256k1_fe_sqr(&rr, &t); /* rr = T^2 (1) */ - secp256k1_fe_mul(&t, &u1, &u2); secp256k1_fe_negate(&t, &t, 1); /* t = -U1*U2 (2) */ - secp256k1_fe_add(&rr, &t); /* rr = R = T^2-U1*U2 (3) */ - secp256k1_fe_sqr(&t, &rr); /* t = R^2 (1) */ - secp256k1_fe_mul(&r->z, &m, &z); /* r->z = M*Z (1) */ - infinity = secp256k1_fe_normalizes_to_zero(&r->z) * (1 - a->infinity); - secp256k1_fe_mul_int(&r->z, 2 * (1 - a->infinity)); /* r->z = Z3 = 2*M*Z (2) */ - r->x = t; /* r->x = R^2 (1) */ - secp256k1_fe_negate(&q, &q, 1); /* q = -Q (2) */ - secp256k1_fe_add(&r->x, &q); /* r->x = R^2-Q (3) */ - secp256k1_fe_normalize(&r->x); - secp256k1_fe_mul_int(&q, 3); /* q = -3*Q (6) */ - secp256k1_fe_mul_int(&t, 2); /* t = 2*R^2 (2) */ - secp256k1_fe_add(&t, &q); /* t = 2*R^2-3*Q (8) */ - secp256k1_fe_mul(&t, &t, &rr); /* t = R*(2*R^2-3*Q) (1) */ - secp256k1_fe_add(&t, &n); /* t = R*(2*R^2-3*Q)+M^4 (2) */ - secp256k1_fe_negate(&r->y, &t, 2); /* r->y = R*(3*Q-2*R^2)-M^4 (3) */ - secp256k1_fe_normalize_weak(&r->y); - secp256k1_fe_mul_int(&r->x, 4 * (1 - a->infinity)); /* r->x = X3 = 4*(R^2-Q) */ - secp256k1_fe_mul_int(&r->y, 4 * (1 - a->infinity)); /* r->y = Y3 = 4*R*(3*Q-2*R^2)-4*M^4 (4) */ + secp256k1_fe_negate(&m_alt, &u2, 1); /* Malt = -X2*Z1^2 */ + secp256k1_fe_mul(&tt, &u1, &m_alt); /* tt = -U1*U2 (2) */ + secp256k1_fe_add(&rr, &tt); /* rr = R = T^2-U1*U2 (3) */ + /** If lambda = R/M = 0/0 we have a problem (except in the "trivial" + * case that Z = z1z2 = 0, and this is special-cased later on). */ + degenerate = secp256k1_fe_normalizes_to_zero(&m) & + secp256k1_fe_normalizes_to_zero(&rr); + /* This only occurs when y1 == -y2 and x1^3 == x2^3, but x1 != x2. + * This means either x1 == beta*x2 or beta*x1 == x2, where beta is + * a nontrivial cube root of one. In either case, an alternate + * non-indeterminate expression for lambda is (y1 - y2)/(x1 - x2), + * so we set R/M equal to this. */ + rr_alt = s1; + secp256k1_fe_mul_int(&rr_alt, 2); /* rr = Y1*Z2^3 - Y2*Z1^3 (2) */ + secp256k1_fe_add(&m_alt, &u1); /* Malt = X1*Z2^2 - X2*Z1^2 */ - /** In case a->infinity == 1, the above code results in r->x, r->y, and r->z all equal to 0. - * Replace r with b->x, b->y, 1 in that case. - */ + secp256k1_fe_cmov(&rr_alt, &rr, !degenerate); + secp256k1_fe_cmov(&m_alt, &m, !degenerate); + /* Now Ralt / Malt = lambda and is guaranteed not to be 0/0. + * From here on out Ralt and Malt represent the numerator + * and denominator of lambda; R and M represent the explicit + * expressions x1^2 + x2^2 + x1x2 and y1 + y2. */ + secp256k1_fe_sqr(&n, &m_alt); /* n = Malt^2 (1) */ + secp256k1_fe_mul(&q, &n, &t); /* q = Q = T*Malt^2 (1) */ + /* These two lines use the observation that either M == Malt or M == 0, + * so M^3 * Malt is either Malt^4 (which is computed by squaring), or + * zero (which is "computed" by cmov). So the cost is one squaring + * versus two multiplications. */ + secp256k1_fe_sqr(&n, &n); + secp256k1_fe_cmov(&n, &m, degenerate); /* n = M^3 * Malt (2) */ + secp256k1_fe_sqr(&t, &rr_alt); /* t = Ralt^2 (1) */ + secp256k1_fe_mul(&r->z, &a->z, &m_alt); /* r->z = Malt*Z (1) */ + infinity = secp256k1_fe_normalizes_to_zero(&r->z) * (1 - a->infinity); + secp256k1_fe_mul_int(&r->z, 2); /* r->z = Z3 = 2*Malt*Z (2) */ + secp256k1_fe_negate(&q, &q, 1); /* q = -Q (2) */ + secp256k1_fe_add(&t, &q); /* t = Ralt^2-Q (3) */ + secp256k1_fe_normalize_weak(&t); + r->x = t; /* r->x = Ralt^2-Q (1) */ + secp256k1_fe_mul_int(&t, 2); /* t = 2*x3 (2) */ + secp256k1_fe_add(&t, &q); /* t = 2*x3 - Q: (4) */ + secp256k1_fe_mul(&t, &t, &rr_alt); /* t = Ralt*(2*x3 - Q) (1) */ + secp256k1_fe_add(&t, &n); /* t = Ralt*(2*x3 - Q) + M^3*Malt (3) */ + secp256k1_fe_negate(&r->y, &t, 3); /* r->y = Ralt*(Q - 2x3) - M^3*Malt (4) */ + secp256k1_fe_normalize_weak(&r->y); + secp256k1_fe_mul_int(&r->x, 4); /* r->x = X3 = 4*(Ralt^2-Q) */ + secp256k1_fe_mul_int(&r->y, 4); /* r->y = Y3 = 4*Ralt*(Q - 2x3) - 4*M^3*Malt (4) */ + + /** In case a->infinity == 1, replace r with (b->x, b->y, 1). */ secp256k1_fe_cmov(&r->x, &b->x, a->infinity); secp256k1_fe_cmov(&r->y, &b->y, a->infinity); secp256k1_fe_cmov(&r->z, &fe_1, a->infinity); r->infinity = infinity; } -static void secp256k1_gej_rescale(secp256k1_gej_t *r, const secp256k1_fe_t *s) { +static void secp256k1_gej_rescale(secp256k1_gej *r, const secp256k1_fe *s) { /* Operations: 4 mul, 1 sqr */ - secp256k1_fe_t zz; + secp256k1_fe zz; VERIFY_CHECK(!secp256k1_fe_is_zero(s)); secp256k1_fe_sqr(&zz, s); secp256k1_fe_mul(&r->x, &r->x, &zz); /* r->x *= s^2 */ @@ -407,8 +650,8 @@ static void secp256k1_gej_rescale(secp256k1_gej_t *r, const secp256k1_fe_t *s) { secp256k1_fe_mul(&r->z, &r->z, s); /* r->z *= s */ } -static void secp256k1_ge_to_storage(secp256k1_ge_storage_t *r, const secp256k1_ge_t *a) { - secp256k1_fe_t x, y; +static void secp256k1_ge_to_storage(secp256k1_ge_storage *r, const secp256k1_ge *a) { + secp256k1_fe x, y; VERIFY_CHECK(!a->infinity); x = a->x; secp256k1_fe_normalize(&x); @@ -418,20 +661,20 @@ static void secp256k1_ge_to_storage(secp256k1_ge_storage_t *r, const secp256k1_g secp256k1_fe_to_storage(&r->y, &y); } -static void secp256k1_ge_from_storage(secp256k1_ge_t *r, const secp256k1_ge_storage_t *a) { +static void secp256k1_ge_from_storage(secp256k1_ge *r, const secp256k1_ge_storage *a) { secp256k1_fe_from_storage(&r->x, &a->x); secp256k1_fe_from_storage(&r->y, &a->y); r->infinity = 0; } -static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage_t *r, const secp256k1_ge_storage_t *a, int flag) { +static SECP256K1_INLINE void secp256k1_ge_storage_cmov(secp256k1_ge_storage *r, const secp256k1_ge_storage *a, int flag) { secp256k1_fe_storage_cmov(&r->x, &a->x, flag); secp256k1_fe_storage_cmov(&r->y, &a->y, flag); } #ifdef USE_ENDOMORPHISM -static void secp256k1_gej_mul_lambda(secp256k1_gej_t *r, const secp256k1_gej_t *a) { - static const secp256k1_fe_t beta = SECP256K1_FE_CONST( +static void secp256k1_ge_mul_lambda(secp256k1_ge *r, const secp256k1_ge *a) { + static const secp256k1_fe beta = SECP256K1_FE_CONST( 0x7ae96a2bul, 0x657c0710ul, 0x6e64479eul, 0xac3434e9ul, 0x9cf04975ul, 0x12f58995ul, 0xc1396c28ul, 0x719501eeul ); @@ -440,4 +683,18 @@ static void secp256k1_gej_mul_lambda(secp256k1_gej_t *r, const secp256k1_gej_t * } #endif -#endif +static int secp256k1_gej_has_quad_y_var(const secp256k1_gej *a) { + secp256k1_fe yz; + + if (a->infinity) { + return 0; + } + + /* We rely on the fact that the Jacobi symbol of 1 / a->z^3 is the same as + * that of a->z. Thus a->y / a->z^3 is a quadratic residue iff a->y * a->z + is */ + secp256k1_fe_mul(&yz, &a->y, &a->z); + return secp256k1_fe_is_quad_var(&yz); +} + +#endif /* SECP256K1_GROUP_IMPL_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/hash.h b/src/cryptoconditions/src/include/secp256k1/src/hash.h index 843423d7f..de26e4b89 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/hash.h +++ b/src/cryptoconditions/src/include/secp256k1/src/hash.h @@ -4,38 +4,38 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_HASH_ -#define _SECP256K1_HASH_ +#ifndef SECP256K1_HASH_H +#define SECP256K1_HASH_H #include #include typedef struct { - uint32_t s[32]; + uint32_t s[8]; uint32_t buf[16]; /* In big endian */ size_t bytes; -} secp256k1_sha256_t; +} secp256k1_sha256; -static void secp256k1_sha256_initialize(secp256k1_sha256_t *hash); -static void secp256k1_sha256_write(secp256k1_sha256_t *hash, const unsigned char *data, size_t size); -static void secp256k1_sha256_finalize(secp256k1_sha256_t *hash, unsigned char *out32); +static void secp256k1_sha256_initialize(secp256k1_sha256 *hash); +static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t size); +static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32); typedef struct { - secp256k1_sha256_t inner, outer; -} secp256k1_hmac_sha256_t; + secp256k1_sha256 inner, outer; +} secp256k1_hmac_sha256; -static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, const unsigned char *key, size_t size); -static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256_t *hash, const unsigned char *data, size_t size); -static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsigned char *out32); +static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t size); +static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size); +static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256 *hash, unsigned char *out32); typedef struct { unsigned char v[32]; unsigned char k[32]; int retry; -} secp256k1_rfc6979_hmac_sha256_t; +} secp256k1_rfc6979_hmac_sha256; -static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen, const unsigned char *msg, size_t msglen, const unsigned char *rnd, size_t rndlen); -static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256_t *rng, unsigned char *out, size_t outlen); -static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256_t *rng); +static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen); +static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen); +static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 *rng); -#endif +#endif /* SECP256K1_HASH_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/hash_impl.h b/src/cryptoconditions/src/include/secp256k1/src/hash_impl.h index 9828827bc..c06db9e33 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/hash_impl.h +++ b/src/cryptoconditions/src/include/secp256k1/src/hash_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_HASH_IMPL_H_ -#define _SECP256K1_HASH_IMPL_H_ +#ifndef SECP256K1_HASH_IMPL_H +#define SECP256K1_HASH_IMPL_H #include "hash.h" @@ -33,7 +33,7 @@ #define BE32(p) ((((p) & 0xFF) << 24) | (((p) & 0xFF00) << 8) | (((p) & 0xFF0000) >> 8) | (((p) & 0xFF000000) >> 24)) #endif -static void secp256k1_sha256_initialize(secp256k1_sha256_t *hash) { +static void secp256k1_sha256_initialize(secp256k1_sha256 *hash) { hash->s[0] = 0x6a09e667ul; hash->s[1] = 0xbb67ae85ul; hash->s[2] = 0x3c6ef372ul; @@ -128,7 +128,7 @@ static void secp256k1_sha256_transform(uint32_t* s, const uint32_t* chunk) { s[7] += h; } -static void secp256k1_sha256_write(secp256k1_sha256_t *hash, const unsigned char *data, size_t len) { +static void secp256k1_sha256_write(secp256k1_sha256 *hash, const unsigned char *data, size_t len) { size_t bufsize = hash->bytes & 0x3F; hash->bytes += len; while (bufsize + len >= 64) { @@ -145,7 +145,7 @@ static void secp256k1_sha256_write(secp256k1_sha256_t *hash, const unsigned char } } -static void secp256k1_sha256_finalize(secp256k1_sha256_t *hash, unsigned char *out32) { +static void secp256k1_sha256_finalize(secp256k1_sha256 *hash, unsigned char *out32) { static const unsigned char pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint32_t sizedesc[2]; uint32_t out[8]; @@ -161,14 +161,14 @@ static void secp256k1_sha256_finalize(secp256k1_sha256_t *hash, unsigned char *o memcpy(out32, (const unsigned char*)out, 32); } -static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, const unsigned char *key, size_t keylen) { +static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256 *hash, const unsigned char *key, size_t keylen) { int n; unsigned char rkey[64]; if (keylen <= 64) { memcpy(rkey, key, keylen); memset(rkey + keylen, 0, 64 - keylen); } else { - secp256k1_sha256_t sha256; + secp256k1_sha256 sha256; secp256k1_sha256_initialize(&sha256); secp256k1_sha256_write(&sha256, key, keylen); secp256k1_sha256_finalize(&sha256, rkey); @@ -189,11 +189,11 @@ static void secp256k1_hmac_sha256_initialize(secp256k1_hmac_sha256_t *hash, cons memset(rkey, 0, 64); } -static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256_t *hash, const unsigned char *data, size_t size) { +static void secp256k1_hmac_sha256_write(secp256k1_hmac_sha256 *hash, const unsigned char *data, size_t size) { secp256k1_sha256_write(&hash->inner, data, size); } -static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsigned char *out32) { +static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256 *hash, unsigned char *out32) { unsigned char temp[32]; secp256k1_sha256_finalize(&hash->inner, temp); secp256k1_sha256_write(&hash->outer, temp, 32); @@ -202,8 +202,8 @@ static void secp256k1_hmac_sha256_finalize(secp256k1_hmac_sha256_t *hash, unsign } -static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256_t *rng, const unsigned char *key, size_t keylen, const unsigned char *msg, size_t msglen, const unsigned char *rnd, size_t rndlen) { - secp256k1_hmac_sha256_t hmac; +static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha256 *rng, const unsigned char *key, size_t keylen) { + secp256k1_hmac_sha256 hmac; static const unsigned char zero[1] = {0x00}; static const unsigned char one[1] = {0x01}; @@ -215,11 +215,6 @@ static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha2 secp256k1_hmac_sha256_write(&hmac, rng->v, 32); secp256k1_hmac_sha256_write(&hmac, zero, 1); secp256k1_hmac_sha256_write(&hmac, key, keylen); - secp256k1_hmac_sha256_write(&hmac, msg, msglen); - if (rnd && rndlen) { - /* RFC6979 3.6 "Additional data". */ - secp256k1_hmac_sha256_write(&hmac, rnd, rndlen); - } secp256k1_hmac_sha256_finalize(&hmac, rng->k); secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); secp256k1_hmac_sha256_write(&hmac, rng->v, 32); @@ -230,11 +225,6 @@ static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha2 secp256k1_hmac_sha256_write(&hmac, rng->v, 32); secp256k1_hmac_sha256_write(&hmac, one, 1); secp256k1_hmac_sha256_write(&hmac, key, keylen); - secp256k1_hmac_sha256_write(&hmac, msg, msglen); - if (rnd && rndlen) { - /* RFC6979 3.6 "Additional data". */ - secp256k1_hmac_sha256_write(&hmac, rnd, rndlen); - } secp256k1_hmac_sha256_finalize(&hmac, rng->k); secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); secp256k1_hmac_sha256_write(&hmac, rng->v, 32); @@ -242,11 +232,11 @@ static void secp256k1_rfc6979_hmac_sha256_initialize(secp256k1_rfc6979_hmac_sha2 rng->retry = 0; } -static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256_t *rng, unsigned char *out, size_t outlen) { +static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 *rng, unsigned char *out, size_t outlen) { /* RFC6979 3.2.h. */ static const unsigned char zero[1] = {0x00}; if (rng->retry) { - secp256k1_hmac_sha256_t hmac; + secp256k1_hmac_sha256 hmac; secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); secp256k1_hmac_sha256_write(&hmac, rng->v, 32); secp256k1_hmac_sha256_write(&hmac, zero, 1); @@ -257,7 +247,7 @@ static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 } while (outlen > 0) { - secp256k1_hmac_sha256_t hmac; + secp256k1_hmac_sha256 hmac; int now = outlen; secp256k1_hmac_sha256_initialize(&hmac, rng->k, 32); secp256k1_hmac_sha256_write(&hmac, rng->v, 32); @@ -273,21 +263,19 @@ static void secp256k1_rfc6979_hmac_sha256_generate(secp256k1_rfc6979_hmac_sha256 rng->retry = 1; } -static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256_t *rng) { +static void secp256k1_rfc6979_hmac_sha256_finalize(secp256k1_rfc6979_hmac_sha256 *rng) { memset(rng->k, 0, 32); memset(rng->v, 0, 32); rng->retry = 0; } - +#undef BE32 #undef Round -#undef sigma0 #undef sigma1 -#undef Sigma0 +#undef sigma0 #undef Sigma1 -#undef Ch +#undef Sigma0 #undef Maj -#undef ReadBE32 -#undef WriteBE32 +#undef Ch -#endif +#endif /* SECP256K1_HASH_IMPL_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java b/src/cryptoconditions/src/include/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java index 90a498eaa..1c67802fb 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java +++ b/src/cryptoconditions/src/include/secp256k1/src/java/org/bitcoin/NativeSecp256k1.java @@ -1,60 +1,446 @@ +/* + * Copyright 2013 Google Inc. + * Copyright 2014-2016 the libsecp256k1 contributors + * + * 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. + */ + package org.bitcoin; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.math.BigInteger; import com.google.common.base.Preconditions; - +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import static org.bitcoin.NativeSecp256k1Util.*; /** - * This class holds native methods to handle ECDSA verification. - * You can find an example library that can be used for this at - * https://github.com/sipa/secp256k1 + *

This class holds native methods to handle ECDSA verification.

+ * + *

You can find an example library that can be used for this at https://github.com/bitcoin/secp256k1

+ * + *

To build secp256k1 for use with bitcoinj, run + * `./configure --enable-jni --enable-experimental --enable-module-ecdh` + * and `make` then copy `.libs/libsecp256k1.so` to your system library path + * or point the JVM to the folder containing it with -Djava.library.path + *

*/ public class NativeSecp256k1 { - public static final boolean enabled; - static { - boolean isEnabled = true; - try { - System.loadLibrary("javasecp256k1"); - } catch (UnsatisfiedLinkError e) { - isEnabled = false; - } - enabled = isEnabled; - } - + + private static final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); + private static final Lock r = rwl.readLock(); + private static final Lock w = rwl.writeLock(); private static ThreadLocal nativeECDSABuffer = new ThreadLocal(); /** * Verifies the given secp256k1 signature in native code. * Calling when enabled == false is undefined (probably library not loaded) - * + * * @param data The data which was signed, must be exactly 32 bytes * @param signature The signature * @param pub The public key which did the signing */ - public static boolean verify(byte[] data, byte[] signature, byte[] pub) { + public static boolean verify(byte[] data, byte[] signature, byte[] pub) throws AssertFailException{ Preconditions.checkArgument(data.length == 32 && signature.length <= 520 && pub.length <= 520); ByteBuffer byteBuff = nativeECDSABuffer.get(); - if (byteBuff == null) { - byteBuff = ByteBuffer.allocateDirect(32 + 8 + 520 + 520); + if (byteBuff == null || byteBuff.capacity() < 520) { + byteBuff = ByteBuffer.allocateDirect(520); byteBuff.order(ByteOrder.nativeOrder()); nativeECDSABuffer.set(byteBuff); } byteBuff.rewind(); byteBuff.put(data); - byteBuff.putInt(signature.length); - byteBuff.putInt(pub.length); byteBuff.put(signature); byteBuff.put(pub); - return secp256k1_ecdsa_verify(byteBuff) == 1; + + byte[][] retByteArray; + + r.lock(); + try { + return secp256k1_ecdsa_verify(byteBuff, Secp256k1Context.getContext(), signature.length, pub.length) == 1; + } finally { + r.unlock(); + } } /** - * @param byteBuff signature format is byte[32] data, - * native-endian int signatureLength, native-endian int pubkeyLength, - * byte[signatureLength] signature, byte[pubkeyLength] pub - * @returns 1 for valid signature, anything else for invalid + * libsecp256k1 Create an ECDSA signature. + * + * @param data Message hash, 32 bytes + * @param key Secret key, 32 bytes + * + * Return values + * @param sig byte array of signature */ - private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff); + public static byte[] sign(byte[] data, byte[] sec) throws AssertFailException{ + Preconditions.checkArgument(data.length == 32 && sec.length <= 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < 32 + 32) { + byteBuff = ByteBuffer.allocateDirect(32 + 32); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(data); + byteBuff.put(sec); + + byte[][] retByteArray; + + r.lock(); + try { + retByteArray = secp256k1_ecdsa_sign(byteBuff, Secp256k1Context.getContext()); + } finally { + r.unlock(); + } + + byte[] sigArr = retByteArray[0]; + int sigLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(sigArr.length, sigLen, "Got bad signature length."); + + return retVal == 0 ? new byte[0] : sigArr; + } + + /** + * libsecp256k1 Seckey Verify - returns 1 if valid, 0 if invalid + * + * @param seckey ECDSA Secret key, 32 bytes + */ + public static boolean secKeyVerify(byte[] seckey) { + Preconditions.checkArgument(seckey.length == 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < seckey.length) { + byteBuff = ByteBuffer.allocateDirect(seckey.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(seckey); + + r.lock(); + try { + return secp256k1_ec_seckey_verify(byteBuff,Secp256k1Context.getContext()) == 1; + } finally { + r.unlock(); + } + } + + + /** + * libsecp256k1 Compute Pubkey - computes public key from secret key + * + * @param seckey ECDSA Secret key, 32 bytes + * + * Return values + * @param pubkey ECDSA Public key, 33 or 65 bytes + */ + //TODO add a 'compressed' arg + public static byte[] computePubkey(byte[] seckey) throws AssertFailException{ + Preconditions.checkArgument(seckey.length == 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < seckey.length) { + byteBuff = ByteBuffer.allocateDirect(seckey.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(seckey); + + byte[][] retByteArray; + + r.lock(); + try { + retByteArray = secp256k1_ec_pubkey_create(byteBuff, Secp256k1Context.getContext()); + } finally { + r.unlock(); + } + + byte[] pubArr = retByteArray[0]; + int pubLen = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(pubArr.length, pubLen, "Got bad pubkey length."); + + return retVal == 0 ? new byte[0]: pubArr; + } + + /** + * libsecp256k1 Cleanup - This destroys the secp256k1 context object + * This should be called at the end of the program for proper cleanup of the context. + */ + public static synchronized void cleanup() { + w.lock(); + try { + secp256k1_destroy_context(Secp256k1Context.getContext()); + } finally { + w.unlock(); + } + } + + public static long cloneContext() { + r.lock(); + try { + return secp256k1_ctx_clone(Secp256k1Context.getContext()); + } finally { r.unlock(); } + } + + /** + * libsecp256k1 PrivKey Tweak-Mul - Tweak privkey by multiplying to it + * + * @param tweak some bytes to tweak with + * @param seckey 32-byte seckey + */ + public static byte[] privKeyTweakMul(byte[] privkey, byte[] tweak) throws AssertFailException{ + Preconditions.checkArgument(privkey.length == 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) { + byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(privkey); + byteBuff.put(tweak); + + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_privkey_tweak_mul(byteBuff,Secp256k1Context.getContext()); + } finally { + r.unlock(); + } + + byte[] privArr = retByteArray[0]; + + int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(privArr.length, privLen, "Got bad pubkey length."); + + assertEquals(retVal, 1, "Failed return value check."); + + return privArr; + } + + /** + * libsecp256k1 PrivKey Tweak-Add - Tweak privkey by adding to it + * + * @param tweak some bytes to tweak with + * @param seckey 32-byte seckey + */ + public static byte[] privKeyTweakAdd(byte[] privkey, byte[] tweak) throws AssertFailException{ + Preconditions.checkArgument(privkey.length == 32); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < privkey.length + tweak.length) { + byteBuff = ByteBuffer.allocateDirect(privkey.length + tweak.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(privkey); + byteBuff.put(tweak); + + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_privkey_tweak_add(byteBuff,Secp256k1Context.getContext()); + } finally { + r.unlock(); + } + + byte[] privArr = retByteArray[0]; + + int privLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(privArr.length, privLen, "Got bad pubkey length."); + + assertEquals(retVal, 1, "Failed return value check."); + + return privArr; + } + + /** + * libsecp256k1 PubKey Tweak-Add - Tweak pubkey by adding to it + * + * @param tweak some bytes to tweak with + * @param pubkey 32-byte seckey + */ + public static byte[] pubKeyTweakAdd(byte[] pubkey, byte[] tweak) throws AssertFailException{ + Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) { + byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(pubkey); + byteBuff.put(tweak); + + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_pubkey_tweak_add(byteBuff,Secp256k1Context.getContext(), pubkey.length); + } finally { + r.unlock(); + } + + byte[] pubArr = retByteArray[0]; + + int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(pubArr.length, pubLen, "Got bad pubkey length."); + + assertEquals(retVal, 1, "Failed return value check."); + + return pubArr; + } + + /** + * libsecp256k1 PubKey Tweak-Mul - Tweak pubkey by multiplying to it + * + * @param tweak some bytes to tweak with + * @param pubkey 32-byte seckey + */ + public static byte[] pubKeyTweakMul(byte[] pubkey, byte[] tweak) throws AssertFailException{ + Preconditions.checkArgument(pubkey.length == 33 || pubkey.length == 65); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < pubkey.length + tweak.length) { + byteBuff = ByteBuffer.allocateDirect(pubkey.length + tweak.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(pubkey); + byteBuff.put(tweak); + + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_pubkey_tweak_mul(byteBuff,Secp256k1Context.getContext(), pubkey.length); + } finally { + r.unlock(); + } + + byte[] pubArr = retByteArray[0]; + + int pubLen = (byte) new BigInteger(new byte[] { retByteArray[1][0] }).intValue() & 0xFF; + int retVal = new BigInteger(new byte[] { retByteArray[1][1] }).intValue(); + + assertEquals(pubArr.length, pubLen, "Got bad pubkey length."); + + assertEquals(retVal, 1, "Failed return value check."); + + return pubArr; + } + + /** + * libsecp256k1 create ECDH secret - constant time ECDH calculation + * + * @param seckey byte array of secret key used in exponentiaion + * @param pubkey byte array of public key used in exponentiaion + */ + public static byte[] createECDHSecret(byte[] seckey, byte[] pubkey) throws AssertFailException{ + Preconditions.checkArgument(seckey.length <= 32 && pubkey.length <= 65); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < 32 + pubkey.length) { + byteBuff = ByteBuffer.allocateDirect(32 + pubkey.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(seckey); + byteBuff.put(pubkey); + + byte[][] retByteArray; + r.lock(); + try { + retByteArray = secp256k1_ecdh(byteBuff, Secp256k1Context.getContext(), pubkey.length); + } finally { + r.unlock(); + } + + byte[] resArr = retByteArray[0]; + int retVal = new BigInteger(new byte[] { retByteArray[1][0] }).intValue(); + + assertEquals(resArr.length, 32, "Got bad result length."); + assertEquals(retVal, 1, "Failed return value check."); + + return resArr; + } + + /** + * libsecp256k1 randomize - updates the context randomization + * + * @param seed 32-byte random seed + */ + public static synchronized boolean randomize(byte[] seed) throws AssertFailException{ + Preconditions.checkArgument(seed.length == 32 || seed == null); + + ByteBuffer byteBuff = nativeECDSABuffer.get(); + if (byteBuff == null || byteBuff.capacity() < seed.length) { + byteBuff = ByteBuffer.allocateDirect(seed.length); + byteBuff.order(ByteOrder.nativeOrder()); + nativeECDSABuffer.set(byteBuff); + } + byteBuff.rewind(); + byteBuff.put(seed); + + w.lock(); + try { + return secp256k1_context_randomize(byteBuff, Secp256k1Context.getContext()) == 1; + } finally { + w.unlock(); + } + } + + private static native long secp256k1_ctx_clone(long context); + + private static native int secp256k1_context_randomize(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_privkey_tweak_add(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_privkey_tweak_mul(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_pubkey_tweak_add(ByteBuffer byteBuff, long context, int pubLen); + + private static native byte[][] secp256k1_pubkey_tweak_mul(ByteBuffer byteBuff, long context, int pubLen); + + private static native void secp256k1_destroy_context(long context); + + private static native int secp256k1_ecdsa_verify(ByteBuffer byteBuff, long context, int sigLen, int pubLen); + + private static native byte[][] secp256k1_ecdsa_sign(ByteBuffer byteBuff, long context); + + private static native int secp256k1_ec_seckey_verify(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_ec_pubkey_create(ByteBuffer byteBuff, long context); + + private static native byte[][] secp256k1_ec_pubkey_parse(ByteBuffer byteBuff, long context, int inputLen); + + private static native byte[][] secp256k1_ecdh(ByteBuffer byteBuff, long context, int inputLen); + } diff --git a/src/cryptoconditions/src/include/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java b/src/cryptoconditions/src/include/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java new file mode 100644 index 000000000..c00d08899 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/java/org/bitcoin/NativeSecp256k1Test.java @@ -0,0 +1,226 @@ +package org.bitcoin; + +import com.google.common.io.BaseEncoding; +import java.util.Arrays; +import java.math.BigInteger; +import javax.xml.bind.DatatypeConverter; +import static org.bitcoin.NativeSecp256k1Util.*; + +/** + * This class holds test cases defined for testing this library. + */ +public class NativeSecp256k1Test { + + //TODO improve comments/add more tests + /** + * This tests verify() for a valid signature + */ + public static void testVerifyPos() throws AssertFailException{ + boolean result = false; + byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" + byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase()); + byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + + result = NativeSecp256k1.verify( data, sig, pub); + assertEquals( result, true , "testVerifyPos"); + } + + /** + * This tests verify() for a non-valid signature + */ + public static void testVerifyNeg() throws AssertFailException{ + boolean result = false; + byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A91".toLowerCase()); //sha256hash of "testing" + byte[] sig = BaseEncoding.base16().lowerCase().decode("3044022079BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F817980220294F14E883B3F525B5367756C2A11EF6CF84B730B36C17CB0C56F0AAB2C98589".toLowerCase()); + byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + + result = NativeSecp256k1.verify( data, sig, pub); + //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16)); + assertEquals( result, false , "testVerifyNeg"); + } + + /** + * This tests secret key verify() for a valid secretkey + */ + public static void testSecKeyVerifyPos() throws AssertFailException{ + boolean result = false; + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + + result = NativeSecp256k1.secKeyVerify( sec ); + //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16)); + assertEquals( result, true , "testSecKeyVerifyPos"); + } + + /** + * This tests secret key verify() for a invalid secretkey + */ + public static void testSecKeyVerifyNeg() throws AssertFailException{ + boolean result = false; + byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); + + result = NativeSecp256k1.secKeyVerify( sec ); + //System.out.println(" TEST " + new BigInteger(1, resultbytes).toString(16)); + assertEquals( result, false , "testSecKeyVerifyNeg"); + } + + /** + * This tests public key create() for a valid secretkey + */ + public static void testPubKeyCreatePos() throws AssertFailException{ + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.computePubkey( sec); + String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( pubkeyString , "04C591A8FF19AC9C4E4E5793673B83123437E975285E7B442F4EE2654DFFCA5E2D2103ED494718C697AC9AEBCFD19612E224DB46661011863ED2FC54E71861E2A6" , "testPubKeyCreatePos"); + } + + /** + * This tests public key create() for a invalid secretkey + */ + public static void testPubKeyCreateNeg() throws AssertFailException{ + byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.computePubkey( sec); + String pubkeyString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( pubkeyString, "" , "testPubKeyCreateNeg"); + } + + /** + * This tests sign() for a valid secretkey + */ + public static void testSignPos() throws AssertFailException{ + + byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.sign(data, sec); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString, "30440220182A108E1448DC8F1FB467D06A0F3BB8EA0533584CB954EF8DA112F1D60E39A202201C66F36DA211C087F3AF88B50EDF4F9BDAA6CF5FD6817E74DCA34DB12390C6E9" , "testSignPos"); + } + + /** + * This tests sign() for a invalid secretkey + */ + public static void testSignNeg() throws AssertFailException{ + byte[] data = BaseEncoding.base16().lowerCase().decode("CF80CD8AED482D5D1527D7DC72FCEFF84E6326592848447D2DC0B0E87DFC9A90".toLowerCase()); //sha256hash of "testing" + byte[] sec = BaseEncoding.base16().lowerCase().decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.sign(data, sec); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString, "" , "testSignNeg"); + } + + /** + * This tests private key tweak-add + */ + public static void testPrivKeyTweakAdd_1() throws AssertFailException { + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + + byte[] resultArr = NativeSecp256k1.privKeyTweakAdd( sec , data ); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "A168571E189E6F9A7E2D657A4B53AE99B909F7E712D1C23CED28093CD57C88F3" , "testPrivKeyAdd_1"); + } + + /** + * This tests private key tweak-mul + */ + public static void testPrivKeyTweakMul_1() throws AssertFailException { + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + + byte[] resultArr = NativeSecp256k1.privKeyTweakMul( sec , data ); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "97F8184235F101550F3C71C927507651BD3F1CDB4A5A33B8986ACF0DEE20FFFC" , "testPrivKeyMul_1"); + } + + /** + * This tests private key tweak-add uncompressed + */ + public static void testPrivKeyTweakAdd_2() throws AssertFailException { + byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + + byte[] resultArr = NativeSecp256k1.pubKeyTweakAdd( pub , data ); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "0411C6790F4B663CCE607BAAE08C43557EDC1A4D11D88DFCB3D841D0C6A941AF525A268E2A863C148555C48FB5FBA368E88718A46E205FABC3DBA2CCFFAB0796EF" , "testPrivKeyAdd_2"); + } + + /** + * This tests private key tweak-mul uncompressed + */ + public static void testPrivKeyTweakMul_2() throws AssertFailException { + byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + byte[] data = BaseEncoding.base16().lowerCase().decode("3982F19BEF1615BCCFBB05E321C10E1D4CBA3DF0E841C2E41EEB6016347653C3".toLowerCase()); //sha256hash of "tweak" + + byte[] resultArr = NativeSecp256k1.pubKeyTweakMul( pub , data ); + String sigString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( sigString , "04E0FE6FE55EBCA626B98A807F6CAF654139E14E5E3698F01A9A658E21DC1D2791EC060D4F412A794D5370F672BC94B722640B5F76914151CFCA6E712CA48CC589" , "testPrivKeyMul_2"); + } + + /** + * This tests seed randomization + */ + public static void testRandomize() throws AssertFailException { + byte[] seed = BaseEncoding.base16().lowerCase().decode("A441B15FE9A3CF56661190A0B93B9DEC7D04127288CC87250967CF3B52894D11".toLowerCase()); //sha256hash of "random" + boolean result = NativeSecp256k1.randomize(seed); + assertEquals( result, true, "testRandomize"); + } + + public static void testCreateECDHSecret() throws AssertFailException{ + + byte[] sec = BaseEncoding.base16().lowerCase().decode("67E56582298859DDAE725F972992A07C6C4FB9F62A8FFF58CE3CA926A1063530".toLowerCase()); + byte[] pub = BaseEncoding.base16().lowerCase().decode("040A629506E1B65CD9D2E0BA9C75DF9C4FED0DB16DC9625ED14397F0AFC836FAE595DC53F8B0EFE61E703075BD9B143BAC75EC0E19F82A2208CAEB32BE53414C40".toLowerCase()); + + byte[] resultArr = NativeSecp256k1.createECDHSecret(sec, pub); + String ecdhString = javax.xml.bind.DatatypeConverter.printHexBinary(resultArr); + assertEquals( ecdhString, "2A2A67007A926E6594AF3EB564FC74005B37A9C8AEF2033C4552051B5C87F043" , "testCreateECDHSecret"); + } + + public static void main(String[] args) throws AssertFailException{ + + + System.out.println("\n libsecp256k1 enabled: " + Secp256k1Context.isEnabled() + "\n"); + + assertEquals( Secp256k1Context.isEnabled(), true, "isEnabled" ); + + //Test verify() success/fail + testVerifyPos(); + testVerifyNeg(); + + //Test secKeyVerify() success/fail + testSecKeyVerifyPos(); + testSecKeyVerifyNeg(); + + //Test computePubkey() success/fail + testPubKeyCreatePos(); + testPubKeyCreateNeg(); + + //Test sign() success/fail + testSignPos(); + testSignNeg(); + + //Test privKeyTweakAdd() 1 + testPrivKeyTweakAdd_1(); + + //Test privKeyTweakMul() 2 + testPrivKeyTweakMul_1(); + + //Test privKeyTweakAdd() 3 + testPrivKeyTweakAdd_2(); + + //Test privKeyTweakMul() 4 + testPrivKeyTweakMul_2(); + + //Test randomize() + testRandomize(); + + //Test ECDH + testCreateECDHSecret(); + + NativeSecp256k1.cleanup(); + + System.out.println(" All tests passed." ); + + } +} diff --git a/src/cryptoconditions/src/include/secp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java b/src/cryptoconditions/src/include/secp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java new file mode 100644 index 000000000..04732ba04 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/java/org/bitcoin/NativeSecp256k1Util.java @@ -0,0 +1,45 @@ +/* + * Copyright 2014-2016 the libsecp256k1 contributors + * + * 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. + */ + +package org.bitcoin; + +public class NativeSecp256k1Util{ + + public static void assertEquals( int val, int val2, String message ) throws AssertFailException{ + if( val != val2 ) + throw new AssertFailException("FAIL: " + message); + } + + public static void assertEquals( boolean val, boolean val2, String message ) throws AssertFailException{ + if( val != val2 ) + throw new AssertFailException("FAIL: " + message); + else + System.out.println("PASS: " + message); + } + + public static void assertEquals( String val, String val2, String message ) throws AssertFailException{ + if( !val.equals(val2) ) + throw new AssertFailException("FAIL: " + message); + else + System.out.println("PASS: " + message); + } + + public static class AssertFailException extends Exception { + public AssertFailException(String message) { + super( message ); + } + } +} diff --git a/src/cryptoconditions/src/include/secp256k1/src/java/org/bitcoin/Secp256k1Context.java b/src/cryptoconditions/src/include/secp256k1/src/java/org/bitcoin/Secp256k1Context.java new file mode 100644 index 000000000..216c986a8 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/java/org/bitcoin/Secp256k1Context.java @@ -0,0 +1,51 @@ +/* + * Copyright 2014-2016 the libsecp256k1 contributors + * + * 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. + */ + +package org.bitcoin; + +/** + * This class holds the context reference used in native methods + * to handle ECDSA operations. + */ +public class Secp256k1Context { + private static final boolean enabled; //true if the library is loaded + private static final long context; //ref to pointer to context obj + + static { //static initializer + boolean isEnabled = true; + long contextRef = -1; + try { + System.loadLibrary("secp256k1"); + contextRef = secp256k1_init_context(); + } catch (UnsatisfiedLinkError e) { + System.out.println("UnsatisfiedLinkError: " + e.toString()); + isEnabled = false; + } + enabled = isEnabled; + context = contextRef; + } + + public static boolean isEnabled() { + return enabled; + } + + public static long getContext() { + if(!enabled) return -1; //sanity check + return context; + } + + private static native long secp256k1_init_context(); +} diff --git a/src/cryptoconditions/src/include/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c b/src/cryptoconditions/src/include/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c index bb4cd7072..bcef7b32c 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c +++ b/src/cryptoconditions/src/include/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c @@ -1,23 +1,377 @@ +#include +#include +#include #include "org_bitcoin_NativeSecp256k1.h" #include "include/secp256k1.h" +#include "include/secp256k1_ecdh.h" +#include "include/secp256k1_recovery.h" -JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify - (JNIEnv* env, jclass classObject, jobject byteBufferObject) + +SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone + (JNIEnv* env, jclass classObject, jlong ctx_l) { - unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); - int sigLen = *((int*)(data + 32)); - int pubLen = *((int*)(data + 32 + 4)); + const secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + + jlong ctx_clone_l = (uintptr_t) secp256k1_context_clone(ctx); + + (void)classObject;(void)env; + + return ctx_clone_l; - return secp256k1_ecdsa_verify(data, 32, data+32+8, sigLen, data+32+8+sigLen, pubLen); } -static void __javasecp256k1_attach(void) __attribute__((constructor)); -static void __javasecp256k1_detach(void) __attribute__((destructor)); +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + + const unsigned char* seed = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + + (void)classObject; + + return secp256k1_context_randomize(ctx, seed); -static void __javasecp256k1_attach(void) { - secp256k1_start(SECP256K1_START_VERIFY); } -static void __javasecp256k1_detach(void) { - secp256k1_stop(); +SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context + (JNIEnv* env, jclass classObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + + secp256k1_context_destroy(ctx); + + (void)classObject;(void)env; +} + +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint siglen, jint publen) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + + unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* sigdata = { (unsigned char*) (data + 32) }; + const unsigned char* pubdata = { (unsigned char*) (data + siglen + 32) }; + + secp256k1_ecdsa_signature sig; + secp256k1_pubkey pubkey; + + int ret = secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigdata, siglen); + + if( ret ) { + ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen); + + if( ret ) { + ret = secp256k1_ecdsa_verify(ctx, &sig, data, &pubkey); + } + } + + (void)classObject; + + return ret; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + unsigned char* data = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + unsigned char* secKey = (unsigned char*) (data + 32); + + jobjectArray retArray; + jbyteArray sigArray, intsByteArray; + unsigned char intsarray[2]; + + secp256k1_ecdsa_signature sig[72]; + + int ret = secp256k1_ecdsa_sign(ctx, sig, data, secKey, NULL, NULL ); + + unsigned char outputSer[72]; + size_t outputLen = 72; + + if( ret ) { + int ret2 = secp256k1_ecdsa_signature_serialize_der(ctx,outputSer, &outputLen, sig ); (void)ret2; + } + + intsarray[0] = outputLen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + sigArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, sigArray, 0, outputLen, (jbyte*)outputSer); + (*env)->SetObjectArrayElement(env, retArray, 0, sigArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + + (void)classObject; + + return secp256k1_ec_seckey_verify(ctx, secKey); +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + const unsigned char* secKey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + + secp256k1_pubkey pubkey; + + jobjectArray retArray; + jbyteArray pubkeyArray, intsByteArray; + unsigned char intsarray[2]; + + int ret = secp256k1_ec_pubkey_create(ctx, &pubkey, secKey); + + unsigned char outputSer[65]; + size_t outputLen = 65; + + if( ret ) { + int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; + } + + intsarray[0] = outputLen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + pubkeyArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, pubkeyArray, 0, outputLen, (jbyte*)outputSer); + (*env)->SetObjectArrayElement(env, retArray, 0, pubkeyArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; + +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* tweak = (unsigned char*) (privkey + 32); + + jobjectArray retArray; + jbyteArray privArray, intsByteArray; + unsigned char intsarray[2]; + + int privkeylen = 32; + + int ret = secp256k1_ec_privkey_tweak_add(ctx, privkey, tweak); + + intsarray[0] = privkeylen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + privArray = (*env)->NewByteArray(env, privkeylen); + (*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey); + (*env)->SetObjectArrayElement(env, retArray, 0, privArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + unsigned char* privkey = (unsigned char*) (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* tweak = (unsigned char*) (privkey + 32); + + jobjectArray retArray; + jbyteArray privArray, intsByteArray; + unsigned char intsarray[2]; + + int privkeylen = 32; + + int ret = secp256k1_ec_privkey_tweak_mul(ctx, privkey, tweak); + + intsarray[0] = privkeylen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + privArray = (*env)->NewByteArray(env, privkeylen); + (*env)->SetByteArrayRegion(env, privArray, 0, privkeylen, (jbyte*)privkey); + (*env)->SetObjectArrayElement(env, retArray, 0, privArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; +/* secp256k1_pubkey* pubkey = (secp256k1_pubkey*) (*env)->GetDirectBufferAddress(env, byteBufferObject);*/ + unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* tweak = (unsigned char*) (pkey + publen); + + jobjectArray retArray; + jbyteArray pubArray, intsByteArray; + unsigned char intsarray[2]; + unsigned char outputSer[65]; + size_t outputLen = 65; + + secp256k1_pubkey pubkey; + int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen); + + if( ret ) { + ret = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, tweak); + } + + if( ret ) { + int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; + } + + intsarray[0] = outputLen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + pubArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer); + (*env)->SetObjectArrayElement(env, retArray, 0, pubArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + unsigned char* pkey = (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* tweak = (unsigned char*) (pkey + publen); + + jobjectArray retArray; + jbyteArray pubArray, intsByteArray; + unsigned char intsarray[2]; + unsigned char outputSer[65]; + size_t outputLen = 65; + + secp256k1_pubkey pubkey; + int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pkey, publen); + + if ( ret ) { + ret = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, tweak); + } + + if( ret ) { + int ret2 = secp256k1_ec_pubkey_serialize(ctx,outputSer, &outputLen, &pubkey,SECP256K1_EC_UNCOMPRESSED );(void)ret2; + } + + intsarray[0] = outputLen; + intsarray[1] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + pubArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, pubArray, 0, outputLen, (jbyte*)outputSer); + (*env)->SetObjectArrayElement(env, retArray, 0, pubArray); + + intsByteArray = (*env)->NewByteArray(env, 2); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 2, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; +} + +SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1pubkey_1combine + (JNIEnv * env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint numkeys) +{ + (void)classObject;(void)env;(void)byteBufferObject;(void)ctx_l;(void)numkeys; + + return 0; +} + +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen) +{ + secp256k1_context *ctx = (secp256k1_context*)(uintptr_t)ctx_l; + const unsigned char* secdata = (*env)->GetDirectBufferAddress(env, byteBufferObject); + const unsigned char* pubdata = (const unsigned char*) (secdata + 32); + + jobjectArray retArray; + jbyteArray outArray, intsByteArray; + unsigned char intsarray[1]; + secp256k1_pubkey pubkey; + unsigned char nonce_res[32]; + size_t outputLen = 32; + + int ret = secp256k1_ec_pubkey_parse(ctx, &pubkey, pubdata, publen); + + if (ret) { + ret = secp256k1_ecdh( + ctx, + nonce_res, + &pubkey, + secdata + ); + } + + intsarray[0] = ret; + + retArray = (*env)->NewObjectArray(env, 2, + (*env)->FindClass(env, "[B"), + (*env)->NewByteArray(env, 1)); + + outArray = (*env)->NewByteArray(env, outputLen); + (*env)->SetByteArrayRegion(env, outArray, 0, 32, (jbyte*)nonce_res); + (*env)->SetObjectArrayElement(env, retArray, 0, outArray); + + intsByteArray = (*env)->NewByteArray(env, 1); + (*env)->SetByteArrayRegion(env, intsByteArray, 0, 1, (jbyte*)intsarray); + (*env)->SetObjectArrayElement(env, retArray, 1, intsByteArray); + + (void)classObject; + + return retArray; } diff --git a/src/cryptoconditions/src/include/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h b/src/cryptoconditions/src/include/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h index d7fb004fa..fe613c9e9 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h +++ b/src/cryptoconditions/src/include/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h @@ -1,5 +1,6 @@ /* DO NOT EDIT THIS FILE - it is machine generated */ #include +#include "include/secp256k1.h" /* Header for class org_bitcoin_NativeSecp256k1 */ #ifndef _Included_org_bitcoin_NativeSecp256k1 @@ -9,11 +10,108 @@ extern "C" { #endif /* * Class: org_bitcoin_NativeSecp256k1 - * Method: secp256k1_ecdsa_verify - * Signature: (Ljava/nio/ByteBuffer;)I + * Method: secp256k1_ctx_clone + * Signature: (J)J */ -JNIEXPORT jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify - (JNIEnv *, jclass, jobject); +SECP256K1_API jlong JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ctx_1clone + (JNIEnv *, jclass, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_context_randomize + * Signature: (Ljava/nio/ByteBuffer;J)I + */ +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1context_1randomize + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_privkey_tweak_add + * Signature: (Ljava/nio/ByteBuffer;J)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1add + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_privkey_tweak_mul + * Signature: (Ljava/nio/ByteBuffer;J)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1privkey_1tweak_1mul + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_pubkey_tweak_add + * Signature: (Ljava/nio/ByteBuffer;JI)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1add + (JNIEnv *, jclass, jobject, jlong, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_pubkey_tweak_mul + * Signature: (Ljava/nio/ByteBuffer;JI)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1pubkey_1tweak_1mul + (JNIEnv *, jclass, jobject, jlong, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_destroy_context + * Signature: (J)V + */ +SECP256K1_API void JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1destroy_1context + (JNIEnv *, jclass, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ecdsa_verify + * Signature: (Ljava/nio/ByteBuffer;JII)I + */ +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1verify + (JNIEnv *, jclass, jobject, jlong, jint, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ecdsa_sign + * Signature: (Ljava/nio/ByteBuffer;J)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdsa_1sign + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ec_seckey_verify + * Signature: (Ljava/nio/ByteBuffer;J)I + */ +SECP256K1_API jint JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1seckey_1verify + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ec_pubkey_create + * Signature: (Ljava/nio/ByteBuffer;J)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1create + (JNIEnv *, jclass, jobject, jlong); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ec_pubkey_parse + * Signature: (Ljava/nio/ByteBuffer;JI)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ec_1pubkey_1parse + (JNIEnv *, jclass, jobject, jlong, jint); + +/* + * Class: org_bitcoin_NativeSecp256k1 + * Method: secp256k1_ecdh + * Signature: (Ljava/nio/ByteBuffer;JI)[[B + */ +SECP256K1_API jobjectArray JNICALL Java_org_bitcoin_NativeSecp256k1_secp256k1_1ecdh + (JNIEnv* env, jclass classObject, jobject byteBufferObject, jlong ctx_l, jint publen); + #ifdef __cplusplus } diff --git a/src/cryptoconditions/src/include/secp256k1/src/java/org_bitcoin_Secp256k1Context.c b/src/cryptoconditions/src/include/secp256k1/src/java/org_bitcoin_Secp256k1Context.c new file mode 100644 index 000000000..a52939e7e --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/java/org_bitcoin_Secp256k1Context.c @@ -0,0 +1,15 @@ +#include +#include +#include "org_bitcoin_Secp256k1Context.h" +#include "include/secp256k1.h" + +SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context + (JNIEnv* env, jclass classObject) +{ + secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + + (void)classObject;(void)env; + + return (uintptr_t)ctx; +} + diff --git a/src/cryptoconditions/src/include/secp256k1/src/java/org_bitcoin_Secp256k1Context.h b/src/cryptoconditions/src/include/secp256k1/src/java/org_bitcoin_Secp256k1Context.h new file mode 100644 index 000000000..0d2bc84b7 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/java/org_bitcoin_Secp256k1Context.h @@ -0,0 +1,22 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +#include "include/secp256k1.h" +/* Header for class org_bitcoin_Secp256k1Context */ + +#ifndef _Included_org_bitcoin_Secp256k1Context +#define _Included_org_bitcoin_Secp256k1Context +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_bitcoin_Secp256k1Context + * Method: secp256k1_init_context + * Signature: ()J + */ +SECP256K1_API jlong JNICALL Java_org_bitcoin_Secp256k1Context_secp256k1_1init_1context + (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/modules/ecdh/Makefile.am.include b/src/cryptoconditions/src/include/secp256k1/src/modules/ecdh/Makefile.am.include new file mode 100644 index 000000000..e3088b469 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/modules/ecdh/Makefile.am.include @@ -0,0 +1,8 @@ +include_HEADERS += include/secp256k1_ecdh.h +noinst_HEADERS += src/modules/ecdh/main_impl.h +noinst_HEADERS += src/modules/ecdh/tests_impl.h +if USE_BENCHMARK +noinst_PROGRAMS += bench_ecdh +bench_ecdh_SOURCES = src/bench_ecdh.c +bench_ecdh_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB) +endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/modules/ecdh/main_impl.h b/src/cryptoconditions/src/include/secp256k1/src/modules/ecdh/main_impl.h new file mode 100644 index 000000000..bd8739eeb --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/modules/ecdh/main_impl.h @@ -0,0 +1,54 @@ +/********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODULE_ECDH_MAIN_H +#define SECP256K1_MODULE_ECDH_MAIN_H + +#include "include/secp256k1_ecdh.h" +#include "ecmult_const_impl.h" + +int secp256k1_ecdh(const secp256k1_context* ctx, unsigned char *result, const secp256k1_pubkey *point, const unsigned char *scalar) { + int ret = 0; + int overflow = 0; + secp256k1_gej res; + secp256k1_ge pt; + secp256k1_scalar s; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(result != NULL); + ARG_CHECK(point != NULL); + ARG_CHECK(scalar != NULL); + + secp256k1_pubkey_load(ctx, &pt, point); + secp256k1_scalar_set_b32(&s, scalar, &overflow); + if (overflow || secp256k1_scalar_is_zero(&s)) { + ret = 0; + } else { + unsigned char x[32]; + unsigned char y[1]; + secp256k1_sha256 sha; + + secp256k1_ecmult_const(&res, &pt, &s); + secp256k1_ge_set_gej(&pt, &res); + /* Compute a hash of the point in compressed form + * Note we cannot use secp256k1_eckey_pubkey_serialize here since it does not + * expect its output to be secret and has a timing sidechannel. */ + secp256k1_fe_normalize(&pt.x); + secp256k1_fe_normalize(&pt.y); + secp256k1_fe_get_b32(x, &pt.x); + y[0] = 0x02 | secp256k1_fe_is_odd(&pt.y); + + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, y, sizeof(y)); + secp256k1_sha256_write(&sha, x, sizeof(x)); + secp256k1_sha256_finalize(&sha, result); + ret = 1; + } + + secp256k1_scalar_clear(&s); + return ret; +} + +#endif /* SECP256K1_MODULE_ECDH_MAIN_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/modules/ecdh/tests_impl.h b/src/cryptoconditions/src/include/secp256k1/src/modules/ecdh/tests_impl.h new file mode 100644 index 000000000..0c53f8ee0 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/modules/ecdh/tests_impl.h @@ -0,0 +1,105 @@ +/********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODULE_ECDH_TESTS_H +#define SECP256K1_MODULE_ECDH_TESTS_H + +void test_ecdh_api(void) { + /* Setup context that just counts errors */ + secp256k1_context *tctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_pubkey point; + unsigned char res[32]; + unsigned char s_one[32] = { 0 }; + int32_t ecount = 0; + s_one[31] = 1; + + secp256k1_context_set_error_callback(tctx, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(tctx, counting_illegal_callback_fn, &ecount); + CHECK(secp256k1_ec_pubkey_create(tctx, &point, s_one) == 1); + + /* Check all NULLs are detected */ + CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1); + CHECK(ecount == 0); + CHECK(secp256k1_ecdh(tctx, NULL, &point, s_one) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ecdh(tctx, res, NULL, s_one) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_ecdh(tctx, res, &point, NULL) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_ecdh(tctx, res, &point, s_one) == 1); + CHECK(ecount == 3); + + /* Cleanup */ + secp256k1_context_destroy(tctx); +} + +void test_ecdh_generator_basepoint(void) { + unsigned char s_one[32] = { 0 }; + secp256k1_pubkey point[2]; + int i; + + s_one[31] = 1; + /* Check against pubkey creation when the basepoint is the generator */ + for (i = 0; i < 100; ++i) { + secp256k1_sha256 sha; + unsigned char s_b32[32]; + unsigned char output_ecdh[32]; + unsigned char output_ser[32]; + unsigned char point_ser[33]; + size_t point_ser_len = sizeof(point_ser); + secp256k1_scalar s; + + random_scalar_order(&s); + secp256k1_scalar_get_b32(s_b32, &s); + + /* compute using ECDH function */ + CHECK(secp256k1_ec_pubkey_create(ctx, &point[0], s_one) == 1); + CHECK(secp256k1_ecdh(ctx, output_ecdh, &point[0], s_b32) == 1); + /* compute "explicitly" */ + CHECK(secp256k1_ec_pubkey_create(ctx, &point[1], s_b32) == 1); + CHECK(secp256k1_ec_pubkey_serialize(ctx, point_ser, &point_ser_len, &point[1], SECP256K1_EC_COMPRESSED) == 1); + CHECK(point_ser_len == sizeof(point_ser)); + secp256k1_sha256_initialize(&sha); + secp256k1_sha256_write(&sha, point_ser, point_ser_len); + secp256k1_sha256_finalize(&sha, output_ser); + /* compare */ + CHECK(memcmp(output_ecdh, output_ser, sizeof(output_ser)) == 0); + } +} + +void test_bad_scalar(void) { + unsigned char s_zero[32] = { 0 }; + unsigned char s_overflow[32] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41 + }; + unsigned char s_rand[32] = { 0 }; + unsigned char output[32]; + secp256k1_scalar rand; + secp256k1_pubkey point; + + /* Create random point */ + random_scalar_order(&rand); + secp256k1_scalar_get_b32(s_rand, &rand); + CHECK(secp256k1_ec_pubkey_create(ctx, &point, s_rand) == 1); + + /* Try to multiply it by bad values */ + CHECK(secp256k1_ecdh(ctx, output, &point, s_zero) == 0); + CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 0); + /* ...and a good one */ + s_overflow[31] -= 1; + CHECK(secp256k1_ecdh(ctx, output, &point, s_overflow) == 1); +} + +void run_ecdh_tests(void) { + test_ecdh_api(); + test_ecdh_generator_basepoint(); + test_bad_scalar(); +} + +#endif /* SECP256K1_MODULE_ECDH_TESTS_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/modules/recovery/Makefile.am.include b/src/cryptoconditions/src/include/secp256k1/src/modules/recovery/Makefile.am.include new file mode 100644 index 000000000..bf23c26e7 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/modules/recovery/Makefile.am.include @@ -0,0 +1,8 @@ +include_HEADERS += include/secp256k1_recovery.h +noinst_HEADERS += src/modules/recovery/main_impl.h +noinst_HEADERS += src/modules/recovery/tests_impl.h +if USE_BENCHMARK +noinst_PROGRAMS += bench_recover +bench_recover_SOURCES = src/bench_recover.c +bench_recover_LDADD = libsecp256k1.la $(SECP_LIBS) $(COMMON_LIB) +endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/modules/recovery/main_impl.h b/src/cryptoconditions/src/include/secp256k1/src/modules/recovery/main_impl.h new file mode 100755 index 000000000..2f6691c5a --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/modules/recovery/main_impl.h @@ -0,0 +1,193 @@ +/********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODULE_RECOVERY_MAIN_H +#define SECP256K1_MODULE_RECOVERY_MAIN_H + +#include "include/secp256k1_recovery.h" + +static void secp256k1_ecdsa_recoverable_signature_load(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, int* recid, const secp256k1_ecdsa_recoverable_signature* sig) { + (void)ctx; + if (sizeof(secp256k1_scalar) == 32) { + /* When the secp256k1_scalar type is exactly 32 byte, use its + * representation inside secp256k1_ecdsa_signature, as conversion is very fast. + * Note that secp256k1_ecdsa_signature_save must use the same representation. */ + memcpy(r, &sig->data[0], 32); + memcpy(s, &sig->data[32], 32); + } else { + secp256k1_scalar_set_b32(r, &sig->data[0], NULL); + secp256k1_scalar_set_b32(s, &sig->data[32], NULL); + } + *recid = sig->data[64]; +} + +static void secp256k1_ecdsa_recoverable_signature_save(secp256k1_ecdsa_recoverable_signature* sig, const secp256k1_scalar* r, const secp256k1_scalar* s, int recid) { + if (sizeof(secp256k1_scalar) == 32) { + memcpy(&sig->data[0], r, 32); + memcpy(&sig->data[32], s, 32); + } else { + secp256k1_scalar_get_b32(&sig->data[0], r); + secp256k1_scalar_get_b32(&sig->data[32], s); + } + sig->data[64] = recid; +} + +int secp256k1_ecdsa_recoverable_signature_parse_compact(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature* sig, const unsigned char *input64, int recid) { + secp256k1_scalar r, s; + int ret = 1; + int overflow = 0; + + (void)ctx; + ARG_CHECK(sig != NULL); + ARG_CHECK(input64 != NULL); + ARG_CHECK(recid >= 0 && recid <= 3); + + secp256k1_scalar_set_b32(&r, &input64[0], &overflow); + ret &= !overflow; + secp256k1_scalar_set_b32(&s, &input64[32], &overflow); + ret &= !overflow; + if (ret) { + secp256k1_ecdsa_recoverable_signature_save(sig, &r, &s, recid); + } else { + memset(sig, 0, sizeof(*sig)); + } + return ret; +} + +int secp256k1_ecdsa_recoverable_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, int *recid, const secp256k1_ecdsa_recoverable_signature* sig) { + secp256k1_scalar r, s; + + (void)ctx; + ARG_CHECK(output64 != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(recid != NULL); + + secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, recid, sig); + secp256k1_scalar_get_b32(&output64[0], &r); + secp256k1_scalar_get_b32(&output64[32], &s); + return 1; +} + +int secp256k1_ecdsa_recoverable_signature_convert(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const secp256k1_ecdsa_recoverable_signature* sigin) { + secp256k1_scalar r, s; + int recid; + + (void)ctx; + ARG_CHECK(sig != NULL); + ARG_CHECK(sigin != NULL); + + secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, sigin); + secp256k1_ecdsa_signature_save(sig, &r, &s); + return 1; +} + +static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context *ctx, const secp256k1_scalar *sigr, const secp256k1_scalar* sigs, secp256k1_ge *pubkey, const secp256k1_scalar *message, int recid) { + unsigned char brx[32]; + secp256k1_fe fx; + secp256k1_ge x; + secp256k1_gej xj; + secp256k1_scalar rn, u1, u2; + secp256k1_gej qj; + int r; + + if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) { + return 0; + } + + secp256k1_scalar_get_b32(brx, sigr); + r = secp256k1_fe_set_b32(&fx, brx); + (void)r; + VERIFY_CHECK(r); /* brx comes from a scalar, so is less than the order; certainly less than p */ + if (recid & 2) { + if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_const_p_minus_order) >= 0) { + return 0; + } + secp256k1_fe_add(&fx, &secp256k1_ecdsa_const_order_as_fe); + } + if (!secp256k1_ge_set_xo_var(&x, &fx, recid & 1)) { + return 0; + } + secp256k1_gej_set_ge(&xj, &x); + secp256k1_scalar_inverse_var(&rn, sigr); + secp256k1_scalar_mul(&u1, &rn, message); + secp256k1_scalar_negate(&u1, &u1); + secp256k1_scalar_mul(&u2, &rn, sigs); + secp256k1_ecmult(ctx, &qj, &xj, &u2, &u1); + secp256k1_ge_set_gej_var(pubkey, &qj); + return !secp256k1_gej_is_infinity(&qj); +} + +int secp256k1_ecdsa_sign_recoverable(const secp256k1_context* ctx, secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) { + secp256k1_scalar r, s; + secp256k1_scalar sec, non, msg; + int recid; + int ret = 0; + int overflow = 0; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(signature != NULL); + ARG_CHECK(seckey != NULL); + if (noncefp == NULL) { + noncefp = secp256k1_nonce_function_default; + } + + secp256k1_scalar_set_b32(&sec, seckey, &overflow); + /* Fail if the secret key is invalid. */ + if (!overflow && !secp256k1_scalar_is_zero(&sec)) { + unsigned char nonce32[32]; + unsigned int count = 0; + secp256k1_scalar_set_b32(&msg, msg32, NULL); + while (1) { + ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count); + if (!ret) { + break; + } + secp256k1_scalar_set_b32(&non, nonce32, &overflow); + if (!secp256k1_scalar_is_zero(&non) && !overflow) { + if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, &recid)) { + break; + } + } + count++; + } + memset(nonce32, 0, 32); + secp256k1_scalar_clear(&msg); + secp256k1_scalar_clear(&non); + secp256k1_scalar_clear(&sec); + } + if (ret) { + secp256k1_ecdsa_recoverable_signature_save(signature, &r, &s, recid); + } else { + memset(signature, 0, sizeof(*signature)); + } + return ret; +} + +int secp256k1_ecdsa_recover(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const secp256k1_ecdsa_recoverable_signature *signature, const unsigned char *msg32) { + secp256k1_ge q; + secp256k1_scalar r, s; + secp256k1_scalar m; + int recid; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(signature != NULL); + ARG_CHECK(pubkey != NULL); + + secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, signature); + VERIFY_CHECK(recid >= 0 && recid < 4); /* should have been caught in parse_compact */ + secp256k1_scalar_set_b32(&m, msg32, NULL); + if (secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &r, &s, &q, &m, recid)) { + secp256k1_pubkey_save(pubkey, &q); + return 1; + } else { + memset(pubkey, 0, sizeof(*pubkey)); + return 0; + } +} + +#endif /* SECP256K1_MODULE_RECOVERY_MAIN_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/modules/recovery/tests_impl.h b/src/cryptoconditions/src/include/secp256k1/src/modules/recovery/tests_impl.h new file mode 100644 index 000000000..5c9bbe861 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/modules/recovery/tests_impl.h @@ -0,0 +1,393 @@ +/********************************************************************** + * Copyright (c) 2013-2015 Pieter Wuille * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_MODULE_RECOVERY_TESTS_H +#define SECP256K1_MODULE_RECOVERY_TESTS_H + +static int recovery_test_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + (void) msg32; + (void) key32; + (void) algo16; + (void) data; + + /* On the first run, return 0 to force a second run */ + if (counter == 0) { + memset(nonce32, 0, 32); + return 1; + } + /* On the second run, return an overflow to force a third run */ + if (counter == 1) { + memset(nonce32, 0xff, 32); + return 1; + } + /* On the next run, return a valid nonce, but flip a coin as to whether or not to fail signing. */ + memset(nonce32, 1, 32); + return secp256k1_rand_bits(1); +} + +void test_ecdsa_recovery_api(void) { + /* Setup contexts that just count errors */ + secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + secp256k1_pubkey pubkey; + secp256k1_pubkey recpubkey; + secp256k1_ecdsa_signature normal_sig; + secp256k1_ecdsa_recoverable_signature recsig; + unsigned char privkey[32] = { 1 }; + unsigned char message[32] = { 2 }; + int32_t ecount = 0; + int recid = 0; + unsigned char sig[74]; + unsigned char zero_privkey[32] = { 0 }; + unsigned char over_privkey[32] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + + secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_error_callback(both, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount); + + /* Construct and verify corresponding public key. */ + CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); + + /* Check bad contexts and NULLs for signing */ + ecount = 0; + CHECK(secp256k1_ecdsa_sign_recoverable(none, &recsig, message, privkey, NULL, NULL) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ecdsa_sign_recoverable(sign, &recsig, message, privkey, NULL, NULL) == 1); + CHECK(ecount == 1); + CHECK(secp256k1_ecdsa_sign_recoverable(vrfy, &recsig, message, privkey, NULL, NULL) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_sign_recoverable(both, NULL, message, privkey, NULL, NULL) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, NULL, privkey, NULL, NULL) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, NULL, NULL, NULL) == 0); + CHECK(ecount == 5); + /* This will fail or succeed randomly, and in either case will not ARG_CHECK failure */ + secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, recovery_test_nonce_function, NULL); + CHECK(ecount == 5); + /* These will all fail, but not in ARG_CHECK way */ + CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, zero_privkey, NULL, NULL) == 0); + CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, over_privkey, NULL, NULL) == 0); + /* This one will succeed. */ + CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1); + CHECK(ecount == 5); + + /* Check signing with a goofy nonce function */ + + /* Check bad contexts and NULLs for recovery */ + ecount = 0; + CHECK(secp256k1_ecdsa_recover(none, &recpubkey, &recsig, message) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ecdsa_recover(sign, &recpubkey, &recsig, message) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_recover(vrfy, &recpubkey, &recsig, message) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_recover(both, &recpubkey, &recsig, message) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_recover(both, NULL, &recsig, message) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_ecdsa_recover(both, &recpubkey, NULL, message) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_ecdsa_recover(both, &recpubkey, &recsig, NULL) == 0); + CHECK(ecount == 5); + + /* Check NULLs for conversion */ + CHECK(secp256k1_ecdsa_sign(both, &normal_sig, message, privkey, NULL, NULL) == 1); + ecount = 0; + CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, NULL, &recsig) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, &normal_sig, NULL) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_recoverable_signature_convert(both, &normal_sig, &recsig) == 1); + + /* Check NULLs for de/serialization */ + CHECK(secp256k1_ecdsa_sign_recoverable(both, &recsig, message, privkey, NULL, NULL) == 1); + ecount = 0; + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, NULL, &recid, &recsig) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, NULL, &recsig) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, NULL) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(both, sig, &recid, &recsig) == 1); + + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, NULL, sig, recid) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, NULL, recid) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, -1) == 0); + CHECK(ecount == 6); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, 5) == 0); + CHECK(ecount == 7); + /* overflow in signature will fail but not affect ecount */ + memcpy(sig, over_privkey, 32); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(both, &recsig, sig, recid) == 0); + CHECK(ecount == 7); + + /* cleanup */ + secp256k1_context_destroy(none); + secp256k1_context_destroy(sign); + secp256k1_context_destroy(vrfy); + secp256k1_context_destroy(both); +} + +void test_ecdsa_recovery_end_to_end(void) { + unsigned char extra[32] = {0x00}; + unsigned char privkey[32]; + unsigned char message[32]; + secp256k1_ecdsa_signature signature[5]; + secp256k1_ecdsa_recoverable_signature rsignature[5]; + unsigned char sig[74]; + secp256k1_pubkey pubkey; + secp256k1_pubkey recpubkey; + int recid = 0; + + /* Generate a random key and message. */ + { + secp256k1_scalar msg, key; + random_scalar_order_test(&msg); + random_scalar_order_test(&key); + secp256k1_scalar_get_b32(privkey, &key); + secp256k1_scalar_get_b32(message, &msg); + } + + /* Construct and verify corresponding public key. */ + CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); + + /* Serialize/parse compact and verify/recover. */ + extra[0] = 0; + CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[0], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, &signature[0], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[4], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[1], message, privkey, NULL, extra) == 1); + extra[31] = 1; + CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[2], message, privkey, NULL, extra) == 1); + extra[31] = 0; + extra[0] = 1; + CHECK(secp256k1_ecdsa_sign_recoverable(ctx, &rsignature[3], message, privkey, NULL, extra) == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); + CHECK(memcmp(&signature[4], &signature[0], 64) == 0); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1); + memset(&rsignature[4], 0, sizeof(rsignature[4])); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 1); + /* Parse compact (with recovery id) and recover. */ + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 1); + CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0); + /* Serialize/destroy/parse signature and verify again. */ + CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &rsignature[4]) == 1); + sig[secp256k1_rand_bits(6)] += 1 + secp256k1_rand_int(255); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsignature[4], sig, recid) == 1); + CHECK(secp256k1_ecdsa_recoverable_signature_convert(ctx, &signature[4], &rsignature[4]) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[4], message, &pubkey) == 0); + /* Recover again */ + CHECK(secp256k1_ecdsa_recover(ctx, &recpubkey, &rsignature[4], message) == 0 || + memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0); +} + +/* Tests several edge cases. */ +void test_ecdsa_recovery_edge_cases(void) { + const unsigned char msg32[32] = { + 'T', 'h', 'i', 's', ' ', 'i', 's', ' ', + 'a', ' ', 'v', 'e', 'r', 'y', ' ', 's', + 'e', 'c', 'r', 'e', 't', ' ', 'm', 'e', + 's', 's', 'a', 'g', 'e', '.', '.', '.' + }; + const unsigned char sig64[64] = { + /* Generated by signing the above message with nonce 'This is the nonce we will use...' + * and secret key 0 (which is not valid), resulting in recid 0. */ + 0x67, 0xCB, 0x28, 0x5F, 0x9C, 0xD1, 0x94, 0xE8, + 0x40, 0xD6, 0x29, 0x39, 0x7A, 0xF5, 0x56, 0x96, + 0x62, 0xFD, 0xE4, 0x46, 0x49, 0x99, 0x59, 0x63, + 0x17, 0x9A, 0x7D, 0xD1, 0x7B, 0xD2, 0x35, 0x32, + 0x4B, 0x1B, 0x7D, 0xF3, 0x4C, 0xE1, 0xF6, 0x8E, + 0x69, 0x4F, 0xF6, 0xF1, 0x1A, 0xC7, 0x51, 0xDD, + 0x7D, 0xD7, 0x3E, 0x38, 0x7E, 0xE4, 0xFC, 0x86, + 0x6E, 0x1B, 0xE8, 0xEC, 0xC7, 0xDD, 0x95, 0x57 + }; + secp256k1_pubkey pubkey; + /* signature (r,s) = (4,4), which can be recovered with all 4 recids. */ + const unsigned char sigb64[64] = { + 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, 0x04, + 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, 0x04, + }; + secp256k1_pubkey pubkeyb; + secp256k1_ecdsa_recoverable_signature rsig; + secp256k1_ecdsa_signature sig; + int recid; + + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 0)); + CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 1)); + CHECK(secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 2)); + CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sig64, 3)); + CHECK(!secp256k1_ecdsa_recover(ctx, &pubkey, &rsig, msg32)); + + for (recid = 0; recid < 4; recid++) { + int i; + int recid2; + /* (4,4) encoded in DER. */ + unsigned char sigbder[8] = {0x30, 0x06, 0x02, 0x01, 0x04, 0x02, 0x01, 0x04}; + unsigned char sigcder_zr[7] = {0x30, 0x05, 0x02, 0x00, 0x02, 0x01, 0x01}; + unsigned char sigcder_zs[7] = {0x30, 0x05, 0x02, 0x01, 0x01, 0x02, 0x00}; + unsigned char sigbderalt1[39] = { + 0x30, 0x25, 0x02, 0x20, 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, 0x04, 0x02, 0x01, 0x04, + }; + unsigned char sigbderalt2[39] = { + 0x30, 0x25, 0x02, 0x01, 0x04, 0x02, 0x20, 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, 0x04, + }; + unsigned char sigbderalt3[40] = { + 0x30, 0x26, 0x02, 0x21, 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, 0x04, 0x02, 0x01, 0x04, + }; + unsigned char sigbderalt4[40] = { + 0x30, 0x26, 0x02, 0x01, 0x04, 0x02, 0x21, 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, 0x04, + }; + /* (order + r,4) encoded in DER. */ + unsigned char sigbderlong[40] = { + 0x30, 0x26, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, + 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, + 0x8C, 0xD0, 0x36, 0x41, 0x45, 0x02, 0x01, 0x04 + }; + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 1); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 1); + for (recid2 = 0; recid2 < 4; recid2++) { + secp256k1_pubkey pubkey2b; + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigb64, recid2) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, &pubkey2b, &rsig, msg32) == 1); + /* Verifying with (order + r,4) should always fail. */ + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderlong, sizeof(sigbderlong)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + } + /* DER parsing tests. */ + /* Zero length r/s. */ + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zr, sizeof(sigcder_zr)) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zs, sizeof(sigcder_zs)) == 0); + /* Leading zeros. */ + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt1, sizeof(sigbderalt1)) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt2, sizeof(sigbderalt2)) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 0); + sigbderalt3[4] = 1; + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + sigbderalt4[7] = 1; + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + /* Damage signature. */ + sigbder[7]++; + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + sigbder[7]--; + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, 6) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder) - 1) == 0); + for(i = 0; i < 8; i++) { + int c; + unsigned char orig = sigbder[i]; + /*Try every single-byte change.*/ + for (c = 0; c < 256; c++) { + if (c == orig ) { + continue; + } + sigbder[i] = c; + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 0 || secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyb) == 0); + } + sigbder[i] = orig; + } + } + + /* Test r/s equal to zero */ + { + /* (1,1) encoded in DER. */ + unsigned char sigcder[8] = {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01}; + unsigned char sigc64[64] = { + 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, 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, 0x01, + }; + secp256k1_pubkey pubkeyc; + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyc, &rsig, msg32) == 1); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 1); + sigcder[4] = 0; + sigc64[31] = 0; + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0); + sigcder[4] = 1; + sigcder[7] = 0; + sigc64[31] = 1; + sigc64[63] = 0; + CHECK(secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &rsig, sigc64, 0) == 1); + CHECK(secp256k1_ecdsa_recover(ctx, &pubkeyb, &rsig, msg32) == 0); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg32, &pubkeyc) == 0); + } +} + +void run_recovery_tests(void) { + int i; + for (i = 0; i < count; i++) { + test_ecdsa_recovery_api(); + } + for (i = 0; i < 64*count; i++) { + test_ecdsa_recovery_end_to_end(); + } + test_ecdsa_recovery_edge_cases(); +} + +#endif /* SECP256K1_MODULE_RECOVERY_TESTS_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/num.h b/src/cryptoconditions/src/include/secp256k1/src/num.h index 339b6bb6e..49f2dd791 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/num.h +++ b/src/cryptoconditions/src/include/secp256k1/src/num.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_NUM_ -#define _SECP256K1_NUM_ +#ifndef SECP256K1_NUM_H +#define SECP256K1_NUM_H #ifndef USE_NUM_NONE @@ -20,49 +20,55 @@ #endif /** Copy a number. */ -static void secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a); +static void secp256k1_num_copy(secp256k1_num *r, const secp256k1_num *a); /** Convert a number's absolute value to a binary big-endian string. * There must be enough place. */ -static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a); +static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num *a); /** Set a number to the value of a binary big-endian string. */ -static void secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen); +static void secp256k1_num_set_bin(secp256k1_num *r, const unsigned char *a, unsigned int alen); /** Compute a modular inverse. The input must be less than the modulus. */ -static void secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m); +static void secp256k1_num_mod_inverse(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *m); + +/** Compute the jacobi symbol (a|b). b must be positive and odd. */ +static int secp256k1_num_jacobi(const secp256k1_num *a, const secp256k1_num *b); /** Compare the absolute value of two numbers. */ -static int secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b); +static int secp256k1_num_cmp(const secp256k1_num *a, const secp256k1_num *b); /** Test whether two number are equal (including sign). */ -static int secp256k1_num_eq(const secp256k1_num_t *a, const secp256k1_num_t *b); +static int secp256k1_num_eq(const secp256k1_num *a, const secp256k1_num *b); /** Add two (signed) numbers. */ -static void secp256k1_num_add(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b); +static void secp256k1_num_add(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b); /** Subtract two (signed) numbers. */ -static void secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b); +static void secp256k1_num_sub(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b); /** Multiply two (signed) numbers. */ -static void secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b); +static void secp256k1_num_mul(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b); /** Replace a number by its remainder modulo m. M's sign is ignored. The result is a number between 0 and m-1, even if r was negative. */ -static void secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m); +static void secp256k1_num_mod(secp256k1_num *r, const secp256k1_num *m); /** Right-shift the passed number by bits bits. */ -static void secp256k1_num_shift(secp256k1_num_t *r, int bits); +static void secp256k1_num_shift(secp256k1_num *r, int bits); /** Check whether a number is zero. */ -static int secp256k1_num_is_zero(const secp256k1_num_t *a); +static int secp256k1_num_is_zero(const secp256k1_num *a); + +/** Check whether a number is one. */ +static int secp256k1_num_is_one(const secp256k1_num *a); /** Check whether a number is strictly negative. */ -static int secp256k1_num_is_neg(const secp256k1_num_t *a); +static int secp256k1_num_is_neg(const secp256k1_num *a); /** Change a number's sign. */ -static void secp256k1_num_negate(secp256k1_num_t *r); +static void secp256k1_num_negate(secp256k1_num *r); #endif -#endif +#endif /* SECP256K1_NUM_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/num_gmp.h b/src/cryptoconditions/src/include/secp256k1/src/num_gmp.h index baa1f2bf2..3619844bd 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/num_gmp.h +++ b/src/cryptoconditions/src/include/secp256k1/src/num_gmp.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_NUM_REPR_ -#define _SECP256K1_NUM_REPR_ +#ifndef SECP256K1_NUM_REPR_H +#define SECP256K1_NUM_REPR_H #include @@ -15,6 +15,6 @@ typedef struct { mp_limb_t data[2*NUM_LIMBS]; int neg; int limbs; -} secp256k1_num_t; +} secp256k1_num; -#endif +#endif /* SECP256K1_NUM_REPR_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/num_gmp_impl.h b/src/cryptoconditions/src/include/secp256k1/src/num_gmp_impl.h index dbbc458d5..0ae2a8ba0 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/num_gmp_impl.h +++ b/src/cryptoconditions/src/include/secp256k1/src/num_gmp_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_NUM_REPR_IMPL_H_ -#define _SECP256K1_NUM_REPR_IMPL_H_ +#ifndef SECP256K1_NUM_REPR_IMPL_H +#define SECP256K1_NUM_REPR_IMPL_H #include #include @@ -15,18 +15,18 @@ #include "num.h" #ifdef VERIFY -static void secp256k1_num_sanity(const secp256k1_num_t *a) { +static void secp256k1_num_sanity(const secp256k1_num *a) { VERIFY_CHECK(a->limbs == 1 || (a->limbs > 1 && a->data[a->limbs-1] != 0)); } #else #define secp256k1_num_sanity(a) do { } while(0) #endif -static void secp256k1_num_copy(secp256k1_num_t *r, const secp256k1_num_t *a) { +static void secp256k1_num_copy(secp256k1_num *r, const secp256k1_num *a) { *r = *a; } -static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num_t *a) { +static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const secp256k1_num *a) { unsigned char tmp[65]; int len = 0; int shift = 0; @@ -42,7 +42,7 @@ static void secp256k1_num_get_bin(unsigned char *r, unsigned int rlen, const sec memset(tmp, 0, sizeof(tmp)); } -static void secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, unsigned int alen) { +static void secp256k1_num_set_bin(secp256k1_num *r, const unsigned char *a, unsigned int alen) { int len; VERIFY_CHECK(alen > 0); VERIFY_CHECK(alen <= 64); @@ -59,7 +59,7 @@ static void secp256k1_num_set_bin(secp256k1_num_t *r, const unsigned char *a, un } } -static void secp256k1_num_add_abs(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { +static void secp256k1_num_add_abs(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { mp_limb_t c = mpn_add(r->data, a->data, a->limbs, b->data, b->limbs); r->limbs = a->limbs; if (c != 0) { @@ -68,8 +68,9 @@ static void secp256k1_num_add_abs(secp256k1_num_t *r, const secp256k1_num_t *a, } } -static void secp256k1_num_sub_abs(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { +static void secp256k1_num_sub_abs(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { mp_limb_t c = mpn_sub(r->data, a->data, a->limbs, b->data, b->limbs); + (void)c; VERIFY_CHECK(c == 0); r->limbs = a->limbs; while (r->limbs > 1 && r->data[r->limbs-1]==0) { @@ -77,7 +78,7 @@ static void secp256k1_num_sub_abs(secp256k1_num_t *r, const secp256k1_num_t *a, } } -static void secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m) { +static void secp256k1_num_mod(secp256k1_num *r, const secp256k1_num *m) { secp256k1_num_sanity(r); secp256k1_num_sanity(m); @@ -97,7 +98,7 @@ static void secp256k1_num_mod(secp256k1_num_t *r, const secp256k1_num_t *m) { } } -static void secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *m) { +static void secp256k1_num_mod_inverse(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *m) { int i; mp_limb_t g[NUM_LIMBS+1]; mp_limb_t u[NUM_LIMBS+1]; @@ -125,6 +126,7 @@ static void secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t } sn = NUM_LIMBS+1; gn = mpn_gcdext(g, r->data, &sn, u, m->limbs, v, m->limbs); + (void)gn; VERIFY_CHECK(gn == 1); VERIFY_CHECK(g[0] == 1); r->neg = a->neg ^ m->neg; @@ -142,15 +144,41 @@ static void secp256k1_num_mod_inverse(secp256k1_num_t *r, const secp256k1_num_t memset(v, 0, sizeof(v)); } -static int secp256k1_num_is_zero(const secp256k1_num_t *a) { +static int secp256k1_num_jacobi(const secp256k1_num *a, const secp256k1_num *b) { + int ret; + mpz_t ga, gb; + secp256k1_num_sanity(a); + secp256k1_num_sanity(b); + VERIFY_CHECK(!b->neg && (b->limbs > 0) && (b->data[0] & 1)); + + mpz_inits(ga, gb, NULL); + + mpz_import(gb, b->limbs, -1, sizeof(mp_limb_t), 0, 0, b->data); + mpz_import(ga, a->limbs, -1, sizeof(mp_limb_t), 0, 0, a->data); + if (a->neg) { + mpz_neg(ga, ga); + } + + ret = mpz_jacobi(ga, gb); + + mpz_clears(ga, gb, NULL); + + return ret; +} + +static int secp256k1_num_is_one(const secp256k1_num *a) { + return (a->limbs == 1 && a->data[0] == 1); +} + +static int secp256k1_num_is_zero(const secp256k1_num *a) { return (a->limbs == 1 && a->data[0] == 0); } -static int secp256k1_num_is_neg(const secp256k1_num_t *a) { +static int secp256k1_num_is_neg(const secp256k1_num *a) { return (a->limbs > 1 || a->data[0] != 0) && a->neg; } -static int secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b) { +static int secp256k1_num_cmp(const secp256k1_num *a, const secp256k1_num *b) { if (a->limbs > b->limbs) { return 1; } @@ -160,7 +188,7 @@ static int secp256k1_num_cmp(const secp256k1_num_t *a, const secp256k1_num_t *b) return mpn_cmp(a->data, b->data, a->limbs); } -static int secp256k1_num_eq(const secp256k1_num_t *a, const secp256k1_num_t *b) { +static int secp256k1_num_eq(const secp256k1_num *a, const secp256k1_num *b) { if (a->limbs > b->limbs) { return 0; } @@ -173,7 +201,7 @@ static int secp256k1_num_eq(const secp256k1_num_t *a, const secp256k1_num_t *b) return mpn_cmp(a->data, b->data, a->limbs) == 0; } -static void secp256k1_num_subadd(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b, int bneg) { +static void secp256k1_num_subadd(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b, int bneg) { if (!(b->neg ^ bneg ^ a->neg)) { /* a and b have the same sign */ r->neg = a->neg; if (a->limbs >= b->limbs) { @@ -192,19 +220,19 @@ static void secp256k1_num_subadd(secp256k1_num_t *r, const secp256k1_num_t *a, c } } -static void secp256k1_num_add(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { +static void secp256k1_num_add(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { secp256k1_num_sanity(a); secp256k1_num_sanity(b); secp256k1_num_subadd(r, a, b, 0); } -static void secp256k1_num_sub(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { +static void secp256k1_num_sub(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { secp256k1_num_sanity(a); secp256k1_num_sanity(b); secp256k1_num_subadd(r, a, b, 1); } -static void secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, const secp256k1_num_t *b) { +static void secp256k1_num_mul(secp256k1_num *r, const secp256k1_num *a, const secp256k1_num *b) { mp_limb_t tmp[2*NUM_LIMBS+1]; secp256k1_num_sanity(a); secp256k1_num_sanity(b); @@ -231,13 +259,13 @@ static void secp256k1_num_mul(secp256k1_num_t *r, const secp256k1_num_t *a, cons memset(tmp, 0, sizeof(tmp)); } -static void secp256k1_num_shift(secp256k1_num_t *r, int bits) { - int i; +static void secp256k1_num_shift(secp256k1_num *r, int bits) { if (bits % GMP_NUMB_BITS) { /* Shift within limbs. */ mpn_rshift(r->data, r->data, r->limbs, bits % GMP_NUMB_BITS); } if (bits >= GMP_NUMB_BITS) { + int i; /* Shift full limbs. */ for (i = 0; i < r->limbs; i++) { int index = i + (bits / GMP_NUMB_BITS); @@ -253,8 +281,8 @@ static void secp256k1_num_shift(secp256k1_num_t *r, int bits) { } } -static void secp256k1_num_negate(secp256k1_num_t *r) { +static void secp256k1_num_negate(secp256k1_num *r) { r->neg ^= 1; } -#endif +#endif /* SECP256K1_NUM_REPR_IMPL_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/num_impl.h b/src/cryptoconditions/src/include/secp256k1/src/num_impl.h index 0b0e3a072..c45193b03 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/num_impl.h +++ b/src/cryptoconditions/src/include/secp256k1/src/num_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_NUM_IMPL_H_ -#define _SECP256K1_NUM_IMPL_H_ +#ifndef SECP256K1_NUM_IMPL_H +#define SECP256K1_NUM_IMPL_H #if defined HAVE_CONFIG_H #include "libsecp256k1-config.h" @@ -21,4 +21,4 @@ #error "Please select num implementation" #endif -#endif +#endif /* SECP256K1_NUM_IMPL_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/scalar.h b/src/cryptoconditions/src/include/secp256k1/src/scalar.h index f5d09f8d4..59304cb66 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/scalar.h +++ b/src/cryptoconditions/src/include/secp256k1/src/scalar.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_SCALAR_ -#define _SECP256K1_SCALAR_ +#ifndef SECP256K1_SCALAR_H +#define SECP256K1_SCALAR_H #include "num.h" @@ -13,7 +13,9 @@ #include "libsecp256k1-config.h" #endif -#if defined(USE_SCALAR_4X64) +#if defined(EXHAUSTIVE_TEST_ORDER) +#include "scalar_low.h" +#elif defined(USE_SCALAR_4X64) #include "scalar_4x64.h" #elif defined(USE_SCALAR_8X32) #include "scalar_8x32.h" @@ -22,72 +24,83 @@ #endif /** Clear a scalar to prevent the leak of sensitive data. */ -static void secp256k1_scalar_clear(secp256k1_scalar_t *r); +static void secp256k1_scalar_clear(secp256k1_scalar *r); /** Access bits from a scalar. All requested bits must belong to the same 32-bit limb. */ -static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count); +static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count); /** Access bits from a scalar. Not constant time. */ -static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count); +static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count); /** Set a scalar from a big endian byte array. */ -static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *bin, int *overflow); +static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *bin, int *overflow); /** Set a scalar to an unsigned integer. */ -static void secp256k1_scalar_set_int(secp256k1_scalar_t *r, unsigned int v); +static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v); /** Convert a scalar to a byte array. */ -static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar_t* a); +static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a); /** Add two scalars together (modulo the group order). Returns whether it overflowed. */ -static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b); +static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b); -/** Add a power of two to a scalar. The result is not allowed to overflow. */ -static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit); +/** Conditionally add a power of two to a scalar. The result is not allowed to overflow. */ +static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag); /** Multiply two scalars (modulo the group order). */ -static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b); +static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b); + +/** Shift a scalar right by some amount strictly between 0 and 16, returning + * the low bits that were shifted off */ +static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n); /** Compute the square of a scalar (modulo the group order). */ -static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t *a); +static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a); /** Compute the inverse of a scalar (modulo the group order). */ -static void secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scalar_t *a); +static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *a); /** Compute the inverse of a scalar (modulo the group order), without constant-time guarantee. */ -static void secp256k1_scalar_inverse_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *a); +static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *a); /** Compute the complement of a scalar (modulo the group order). */ -static void secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scalar_t *a); +static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a); /** Check whether a scalar equals zero. */ -static int secp256k1_scalar_is_zero(const secp256k1_scalar_t *a); +static int secp256k1_scalar_is_zero(const secp256k1_scalar *a); /** Check whether a scalar equals one. */ -static int secp256k1_scalar_is_one(const secp256k1_scalar_t *a); +static int secp256k1_scalar_is_one(const secp256k1_scalar *a); + +/** Check whether a scalar, considered as an nonnegative integer, is even. */ +static int secp256k1_scalar_is_even(const secp256k1_scalar *a); /** Check whether a scalar is higher than the group order divided by 2. */ -static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a); +static int secp256k1_scalar_is_high(const secp256k1_scalar *a); + +/** Conditionally negate a number, in constant time. + * Returns -1 if the number was negated, 1 otherwise */ +static int secp256k1_scalar_cond_negate(secp256k1_scalar *a, int flag); #ifndef USE_NUM_NONE /** Convert a scalar to a number. */ -static void secp256k1_scalar_get_num(secp256k1_num_t *r, const secp256k1_scalar_t *a); +static void secp256k1_scalar_get_num(secp256k1_num *r, const secp256k1_scalar *a); /** Get the order of the group as a number. */ -static void secp256k1_scalar_order_get_num(secp256k1_num_t *r); +static void secp256k1_scalar_order_get_num(secp256k1_num *r); #endif /** Compare two scalars. */ -static int secp256k1_scalar_eq(const secp256k1_scalar_t *a, const secp256k1_scalar_t *b); +static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b); #ifdef USE_ENDOMORPHISM /** Find r1 and r2 such that r1+r2*2^128 = a. */ -static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a); +static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a); /** Find r1 and r2 such that r1+r2*lambda = a, and r1 and r2 are maximum 128 bits long (see secp256k1_gej_mul_lambda). */ -static void secp256k1_scalar_split_lambda_var(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a); +static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a); #endif /** Multiply a and b (without taking the modulus!), divide by 2**shift, and round to the nearest integer. Shift must be at least 256. */ -static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b, unsigned int shift); +static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift); -#endif +#endif /* SECP256K1_SCALAR_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/scalar_4x64.h b/src/cryptoconditions/src/include/secp256k1/src/scalar_4x64.h index 82899aa7b..19c7495d1 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/scalar_4x64.h +++ b/src/cryptoconditions/src/include/secp256k1/src/scalar_4x64.h @@ -4,16 +4,16 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_SCALAR_REPR_ -#define _SECP256K1_SCALAR_REPR_ +#ifndef SECP256K1_SCALAR_REPR_H +#define SECP256K1_SCALAR_REPR_H #include /** A scalar modulo the group order of the secp256k1 curve. */ typedef struct { uint64_t d[4]; -} secp256k1_scalar_t; +} secp256k1_scalar; #define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{((uint64_t)(d1)) << 32 | (d0), ((uint64_t)(d3)) << 32 | (d2), ((uint64_t)(d5)) << 32 | (d4), ((uint64_t)(d7)) << 32 | (d6)}} -#endif +#endif /* SECP256K1_SCALAR_REPR_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/scalar_4x64_impl.h b/src/cryptoconditions/src/include/secp256k1/src/scalar_4x64_impl.h index ff365292f..db1ebf94b 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/scalar_4x64_impl.h +++ b/src/cryptoconditions/src/include/secp256k1/src/scalar_4x64_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_ -#define _SECP256K1_SCALAR_REPR_IMPL_H_ +#ifndef SECP256K1_SCALAR_REPR_IMPL_H +#define SECP256K1_SCALAR_REPR_IMPL_H /* Limbs of the secp256k1 order. */ #define SECP256K1_N_0 ((uint64_t)0xBFD25E8CD0364141ULL) @@ -24,26 +24,26 @@ #define SECP256K1_N_H_2 ((uint64_t)0xFFFFFFFFFFFFFFFFULL) #define SECP256K1_N_H_3 ((uint64_t)0x7FFFFFFFFFFFFFFFULL) -SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar_t *r) { +SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { r->d[0] = 0; r->d[1] = 0; r->d[2] = 0; r->d[3] = 0; } -SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar_t *r, unsigned int v) { +SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { r->d[0] = v; r->d[1] = 0; r->d[2] = 0; r->d[3] = 0; } -SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count) { +SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { VERIFY_CHECK((offset + count - 1) >> 6 == offset >> 6); return (a->d[offset >> 6] >> (offset & 0x3F)) & ((((uint64_t)1) << count) - 1); } -SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count) { +SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { VERIFY_CHECK(count < 32); VERIFY_CHECK(offset + count <= 256); if ((offset + count - 1) >> 6 == offset >> 6) { @@ -54,7 +54,7 @@ SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256 } } -SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar_t *a) { +SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { int yes = 0; int no = 0; no |= (a->d[3] < SECP256K1_N_3); /* No need for a > check. */ @@ -66,7 +66,7 @@ SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scal return yes; } -SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar_t *r, unsigned int overflow) { +SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, unsigned int overflow) { uint128_t t; VERIFY_CHECK(overflow <= 1); t = (uint128_t)r->d[0] + overflow * SECP256K1_N_C_0; @@ -80,7 +80,7 @@ SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar_t *r, unsig return overflow; } -static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { +static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { int overflow; uint128_t t = (uint128_t)a->d[0] + b->d[0]; r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; @@ -96,9 +96,10 @@ static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t return overflow; } -static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit) { +static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { uint128_t t; VERIFY_CHECK(bit < 256); + bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 6) > 3 makes this a noop */ t = (uint128_t)r->d[0] + (((uint64_t)((bit >> 6) == 0)) << (bit & 0x3F)); r->d[0] = t & 0xFFFFFFFFFFFFFFFFULL; t >>= 64; t += (uint128_t)r->d[1] + (((uint64_t)((bit >> 6) == 1)) << (bit & 0x3F)); @@ -113,7 +114,7 @@ static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit) { #endif } -static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *b32, int *overflow) { +static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) { int over; r->d[0] = (uint64_t)b32[31] | (uint64_t)b32[30] << 8 | (uint64_t)b32[29] << 16 | (uint64_t)b32[28] << 24 | (uint64_t)b32[27] << 32 | (uint64_t)b32[26] << 40 | (uint64_t)b32[25] << 48 | (uint64_t)b32[24] << 56; r->d[1] = (uint64_t)b32[23] | (uint64_t)b32[22] << 8 | (uint64_t)b32[21] << 16 | (uint64_t)b32[20] << 24 | (uint64_t)b32[19] << 32 | (uint64_t)b32[18] << 40 | (uint64_t)b32[17] << 48 | (uint64_t)b32[16] << 56; @@ -125,18 +126,18 @@ static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char } } -static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar_t* a) { +static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) { bin[0] = a->d[3] >> 56; bin[1] = a->d[3] >> 48; bin[2] = a->d[3] >> 40; bin[3] = a->d[3] >> 32; bin[4] = a->d[3] >> 24; bin[5] = a->d[3] >> 16; bin[6] = a->d[3] >> 8; bin[7] = a->d[3]; bin[8] = a->d[2] >> 56; bin[9] = a->d[2] >> 48; bin[10] = a->d[2] >> 40; bin[11] = a->d[2] >> 32; bin[12] = a->d[2] >> 24; bin[13] = a->d[2] >> 16; bin[14] = a->d[2] >> 8; bin[15] = a->d[2]; bin[16] = a->d[1] >> 56; bin[17] = a->d[1] >> 48; bin[18] = a->d[1] >> 40; bin[19] = a->d[1] >> 32; bin[20] = a->d[1] >> 24; bin[21] = a->d[1] >> 16; bin[22] = a->d[1] >> 8; bin[23] = a->d[1]; bin[24] = a->d[0] >> 56; bin[25] = a->d[0] >> 48; bin[26] = a->d[0] >> 40; bin[27] = a->d[0] >> 32; bin[28] = a->d[0] >> 24; bin[29] = a->d[0] >> 16; bin[30] = a->d[0] >> 8; bin[31] = a->d[0]; } -SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar_t *a) { +SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) { return (a->d[0] | a->d[1] | a->d[2] | a->d[3]) == 0; } -static void secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) { +static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) { uint64_t nonzero = 0xFFFFFFFFFFFFFFFFULL * (secp256k1_scalar_is_zero(a) == 0); uint128_t t = (uint128_t)(~a->d[0]) + SECP256K1_N_0 + 1; r->d[0] = t & nonzero; t >>= 64; @@ -148,11 +149,11 @@ static void secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scala r->d[3] = t & nonzero; } -SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar_t *a) { +SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) { return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3]) == 0; } -static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) { +static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { int yes = 0; int no = 0; no |= (a->d[3] < SECP256K1_N_H_3); @@ -164,6 +165,22 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) { return yes; } +static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { + /* If we are flag = 0, mask = 00...00 and this is a no-op; + * if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */ + uint64_t mask = !flag - 1; + uint64_t nonzero = (secp256k1_scalar_is_zero(r) != 0) - 1; + uint128_t t = (uint128_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask); + r->d[0] = t & nonzero; t >>= 64; + t += (uint128_t)(r->d[1] ^ mask) + (SECP256K1_N_1 & mask); + r->d[1] = t & nonzero; t >>= 64; + t += (uint128_t)(r->d[2] ^ mask) + (SECP256K1_N_2 & mask); + r->d[2] = t & nonzero; t >>= 64; + t += (uint128_t)(r->d[3] ^ mask) + (SECP256K1_N_3 & mask); + r->d[3] = t & nonzero; + return 2 * (mask == 0) - 1; +} + /* Inspired by the macros in OpenSSL's crypto/bn/asm/x86_64-gcc.c. */ /** Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ @@ -250,7 +267,7 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) { VERIFY_CHECK(c2 == 0); \ } -static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint64_t *l) { +static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint64_t *l) { #ifdef USE_ASM_X86_64 /* Reduce 512 bits into 385. */ uint64_t m0, m1, m2, m3, m4, m5, m6; @@ -265,8 +282,8 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint64_t *l "movq 56(%%rsi), %%r14\n" /* Initialize r8,r9,r10 */ "movq 0(%%rsi), %%r8\n" - "movq $0, %%r9\n" - "movq $0, %%r10\n" + "xorq %%r9, %%r9\n" + "xorq %%r10, %%r10\n" /* (r8,r9) += n0 * c0 */ "movq %8, %%rax\n" "mulq %%r11\n" @@ -274,7 +291,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint64_t *l "adcq %%rdx, %%r9\n" /* extract m0 */ "movq %%r8, %q0\n" - "movq $0, %%r8\n" + "xorq %%r8, %%r8\n" /* (r9,r10) += l1 */ "addq 8(%%rsi), %%r9\n" "adcq $0, %%r10\n" @@ -292,7 +309,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint64_t *l "adcq $0, %%r8\n" /* extract m1 */ "movq %%r9, %q1\n" - "movq $0, %%r9\n" + "xorq %%r9, %%r9\n" /* (r10,r8,r9) += l2 */ "addq 16(%%rsi), %%r10\n" "adcq $0, %%r8\n" @@ -315,7 +332,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint64_t *l "adcq $0, %%r9\n" /* extract m2 */ "movq %%r10, %q2\n" - "movq $0, %%r10\n" + "xorq %%r10, %%r10\n" /* (r8,r9,r10) += l3 */ "addq 24(%%rsi), %%r8\n" "adcq $0, %%r9\n" @@ -338,7 +355,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint64_t *l "adcq $0, %%r10\n" /* extract m3 */ "movq %%r8, %q3\n" - "movq $0, %%r8\n" + "xorq %%r8, %%r8\n" /* (r9,r10,r8) += n3 * c1 */ "movq %9, %%rax\n" "mulq %%r14\n" @@ -370,8 +387,8 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint64_t *l "movq %q11, %%r13\n" /* Initialize (r8,r9,r10) */ "movq %q5, %%r8\n" - "movq $0, %%r9\n" - "movq $0, %%r10\n" + "xorq %%r9, %%r9\n" + "xorq %%r10, %%r10\n" /* (r8,r9) += m4 * c0 */ "movq %12, %%rax\n" "mulq %%r11\n" @@ -379,7 +396,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint64_t *l "adcq %%rdx, %%r9\n" /* extract p0 */ "movq %%r8, %q0\n" - "movq $0, %%r8\n" + "xorq %%r8, %%r8\n" /* (r9,r10) += m1 */ "addq %q6, %%r9\n" "adcq $0, %%r10\n" @@ -397,7 +414,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint64_t *l "adcq $0, %%r8\n" /* extract p1 */ "movq %%r9, %q1\n" - "movq $0, %%r9\n" + "xorq %%r9, %%r9\n" /* (r10,r8,r9) += m2 */ "addq %q7, %%r10\n" "adcq $0, %%r8\n" @@ -455,7 +472,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint64_t *l "movq %%rax, 0(%q6)\n" /* Move to (r8,r9) */ "movq %%rdx, %%r8\n" - "movq $0, %%r9\n" + "xorq %%r9, %%r9\n" /* (r8,r9) += p1 */ "addq %q2, %%r8\n" "adcq $0, %%r9\n" @@ -466,7 +483,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint64_t *l "adcq %%rdx, %%r9\n" /* Extract r1 */ "movq %%r8, 8(%q6)\n" - "movq $0, %%r8\n" + "xorq %%r8, %%r8\n" /* (r9,r8) += p4 */ "addq %%r10, %%r9\n" "adcq $0, %%r8\n" @@ -475,7 +492,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint64_t *l "adcq $0, %%r8\n" /* Extract r2 */ "movq %%r9, 16(%q6)\n" - "movq $0, %%r9\n" + "xorq %%r9, %%r9\n" /* (r8,r9) += p3 */ "addq %q4, %%r8\n" "adcq $0, %%r9\n" @@ -559,7 +576,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint64_t *l secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r)); } -static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { +static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar *a, const secp256k1_scalar *b) { #ifdef USE_ASM_X86_64 const uint64_t *pb = b->d; __asm__ __volatile__( @@ -721,12 +738,12 @@ static void secp256k1_scalar_mul_512(uint64_t l[8], const secp256k1_scalar_t *a, extract(l[5]); muladd_fast(a->d[3], b->d[3]); extract_fast(l[6]); - VERIFY_CHECK(c1 <= 0); + VERIFY_CHECK(c1 == 0); l[7] = c0; #endif } -static void secp256k1_scalar_sqr_512(uint64_t l[8], const secp256k1_scalar_t *a) { +static void secp256k1_scalar_sqr_512(uint64_t l[8], const secp256k1_scalar *a) { #ifdef USE_ASM_X86_64 __asm__ __volatile__( /* Preload */ @@ -871,19 +888,32 @@ static void secp256k1_scalar_sqr_512(uint64_t l[8], const secp256k1_scalar_t *a) #undef extract #undef extract_fast -static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { +static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { uint64_t l[8]; secp256k1_scalar_mul_512(l, a, b); secp256k1_scalar_reduce_512(r, l); } -static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) { +static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) { + int ret; + VERIFY_CHECK(n > 0); + VERIFY_CHECK(n < 16); + ret = r->d[0] & ((1 << n) - 1); + r->d[0] = (r->d[0] >> n) + (r->d[1] << (64 - n)); + r->d[1] = (r->d[1] >> n) + (r->d[2] << (64 - n)); + r->d[2] = (r->d[2] >> n) + (r->d[3] << (64 - n)); + r->d[3] = (r->d[3] >> n); + return ret; +} + +static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) { uint64_t l[8]; secp256k1_scalar_sqr_512(l, a); secp256k1_scalar_reduce_512(r, l); } -static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a) { +#ifdef USE_ENDOMORPHISM +static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { r1->d[0] = a->d[0]; r1->d[1] = a->d[1]; r1->d[2] = 0; @@ -893,12 +923,13 @@ static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_ r2->d[2] = 0; r2->d[3] = 0; } +#endif -SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { +SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) { return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3])) == 0; } -SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b, unsigned int shift) { +SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift) { uint64_t l[8]; unsigned int shiftlimbs; unsigned int shiftlow; @@ -912,9 +943,7 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t * r->d[1] = shift < 448 ? (l[1 + shiftlimbs] >> shiftlow | (shift < 384 && shiftlow ? (l[2 + shiftlimbs] << shifthigh) : 0)) : 0; r->d[2] = shift < 384 ? (l[2 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[3 + shiftlimbs] << shifthigh) : 0)) : 0; r->d[3] = shift < 320 ? (l[3 + shiftlimbs] >> shiftlow) : 0; - if ((l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1) { - secp256k1_scalar_add_bit(r, 0); - } + secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 6] >> ((shift - 1) & 0x3f)) & 1); } -#endif +#endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/scalar_8x32.h b/src/cryptoconditions/src/include/secp256k1/src/scalar_8x32.h index f17017e24..2c9a348e2 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/scalar_8x32.h +++ b/src/cryptoconditions/src/include/secp256k1/src/scalar_8x32.h @@ -4,16 +4,16 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_SCALAR_REPR_ -#define _SECP256K1_SCALAR_REPR_ +#ifndef SECP256K1_SCALAR_REPR_H +#define SECP256K1_SCALAR_REPR_H #include /** A scalar modulo the group order of the secp256k1 curve. */ typedef struct { uint32_t d[8]; -} secp256k1_scalar_t; +} secp256k1_scalar; #define SECP256K1_SCALAR_CONST(d7, d6, d5, d4, d3, d2, d1, d0) {{(d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7)}} -#endif +#endif /* SECP256K1_SCALAR_REPR_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/scalar_8x32_impl.h b/src/cryptoconditions/src/include/secp256k1/src/scalar_8x32_impl.h index 22b31d411..4f9ed61fe 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/scalar_8x32_impl.h +++ b/src/cryptoconditions/src/include/secp256k1/src/scalar_8x32_impl.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_SCALAR_REPR_IMPL_H_ -#define _SECP256K1_SCALAR_REPR_IMPL_H_ +#ifndef SECP256K1_SCALAR_REPR_IMPL_H +#define SECP256K1_SCALAR_REPR_IMPL_H /* Limbs of the secp256k1 order. */ #define SECP256K1_N_0 ((uint32_t)0xD0364141UL) @@ -34,7 +34,7 @@ #define SECP256K1_N_H_6 ((uint32_t)0xFFFFFFFFUL) #define SECP256K1_N_H_7 ((uint32_t)0x7FFFFFFFUL) -SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar_t *r) { +SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { r->d[0] = 0; r->d[1] = 0; r->d[2] = 0; @@ -45,7 +45,7 @@ SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar_t *r) { r->d[7] = 0; } -SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar_t *r, unsigned int v) { +SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { r->d[0] = v; r->d[1] = 0; r->d[2] = 0; @@ -56,12 +56,12 @@ SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar_t *r, uns r->d[7] = 0; } -SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count) { +SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { VERIFY_CHECK((offset + count - 1) >> 5 == offset >> 5); return (a->d[offset >> 5] >> (offset & 0x1F)) & ((1 << count) - 1); } -SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar_t *a, unsigned int offset, unsigned int count) { +SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { VERIFY_CHECK(count < 32); VERIFY_CHECK(offset + count <= 256); if ((offset + count - 1) >> 5 == offset >> 5) { @@ -72,7 +72,7 @@ SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256 } } -SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar_t *a) { +SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { int yes = 0; int no = 0; no |= (a->d[7] < SECP256K1_N_7); /* No need for a > check. */ @@ -90,7 +90,7 @@ SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scal return yes; } -SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar_t *r, uint32_t overflow) { +SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar *r, uint32_t overflow) { uint64_t t; VERIFY_CHECK(overflow <= 1); t = (uint64_t)r->d[0] + overflow * SECP256K1_N_C_0; @@ -112,7 +112,7 @@ SECP256K1_INLINE static int secp256k1_scalar_reduce(secp256k1_scalar_t *r, uint3 return overflow; } -static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { +static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { int overflow; uint64_t t = (uint64_t)a->d[0] + b->d[0]; r->d[0] = t & 0xFFFFFFFFULL; t >>= 32; @@ -136,9 +136,10 @@ static int secp256k1_scalar_add(secp256k1_scalar_t *r, const secp256k1_scalar_t return overflow; } -static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit) { +static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { uint64_t t; VERIFY_CHECK(bit < 256); + bit += ((uint32_t) flag - 1) & 0x100; /* forcing (bit >> 5) > 7 makes this a noop */ t = (uint64_t)r->d[0] + (((uint32_t)((bit >> 5) == 0)) << (bit & 0x1F)); r->d[0] = t & 0xFFFFFFFFULL; t >>= 32; t += (uint64_t)r->d[1] + (((uint32_t)((bit >> 5) == 1)) << (bit & 0x1F)); @@ -161,7 +162,7 @@ static void secp256k1_scalar_add_bit(secp256k1_scalar_t *r, unsigned int bit) { #endif } -static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char *b32, int *overflow) { +static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) { int over; r->d[0] = (uint32_t)b32[31] | (uint32_t)b32[30] << 8 | (uint32_t)b32[29] << 16 | (uint32_t)b32[28] << 24; r->d[1] = (uint32_t)b32[27] | (uint32_t)b32[26] << 8 | (uint32_t)b32[25] << 16 | (uint32_t)b32[24] << 24; @@ -177,7 +178,7 @@ static void secp256k1_scalar_set_b32(secp256k1_scalar_t *r, const unsigned char } } -static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar_t* a) { +static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) { bin[0] = a->d[7] >> 24; bin[1] = a->d[7] >> 16; bin[2] = a->d[7] >> 8; bin[3] = a->d[7]; bin[4] = a->d[6] >> 24; bin[5] = a->d[6] >> 16; bin[6] = a->d[6] >> 8; bin[7] = a->d[6]; bin[8] = a->d[5] >> 24; bin[9] = a->d[5] >> 16; bin[10] = a->d[5] >> 8; bin[11] = a->d[5]; @@ -188,11 +189,11 @@ static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar_ bin[28] = a->d[0] >> 24; bin[29] = a->d[0] >> 16; bin[30] = a->d[0] >> 8; bin[31] = a->d[0]; } -SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar_t *a) { +SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) { return (a->d[0] | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0; } -static void secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) { +static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) { uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(a) == 0); uint64_t t = (uint64_t)(~a->d[0]) + SECP256K1_N_0 + 1; r->d[0] = t & nonzero; t >>= 32; @@ -212,11 +213,11 @@ static void secp256k1_scalar_negate(secp256k1_scalar_t *r, const secp256k1_scala r->d[7] = t & nonzero; } -SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar_t *a) { +SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) { return ((a->d[0] ^ 1) | a->d[1] | a->d[2] | a->d[3] | a->d[4] | a->d[5] | a->d[6] | a->d[7]) == 0; } -static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) { +static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { int yes = 0; int no = 0; no |= (a->d[7] < SECP256K1_N_H_7); @@ -234,6 +235,31 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) { return yes; } +static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { + /* If we are flag = 0, mask = 00...00 and this is a no-op; + * if we are flag = 1, mask = 11...11 and this is identical to secp256k1_scalar_negate */ + uint32_t mask = !flag - 1; + uint32_t nonzero = 0xFFFFFFFFUL * (secp256k1_scalar_is_zero(r) == 0); + uint64_t t = (uint64_t)(r->d[0] ^ mask) + ((SECP256K1_N_0 + 1) & mask); + r->d[0] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[1] ^ mask) + (SECP256K1_N_1 & mask); + r->d[1] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[2] ^ mask) + (SECP256K1_N_2 & mask); + r->d[2] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[3] ^ mask) + (SECP256K1_N_3 & mask); + r->d[3] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[4] ^ mask) + (SECP256K1_N_4 & mask); + r->d[4] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[5] ^ mask) + (SECP256K1_N_5 & mask); + r->d[5] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[6] ^ mask) + (SECP256K1_N_6 & mask); + r->d[6] = t & nonzero; t >>= 32; + t += (uint64_t)(r->d[7] ^ mask) + (SECP256K1_N_7 & mask); + r->d[7] = t & nonzero; + return 2 * (mask == 0) - 1; +} + + /* Inspired by the macros in OpenSSL's crypto/bn/asm/x86_64-gcc.c. */ /** Add a*b to the number defined by (c0,c1,c2). c2 must never overflow. */ @@ -320,7 +346,7 @@ static int secp256k1_scalar_is_high(const secp256k1_scalar_t *a) { VERIFY_CHECK(c2 == 0); \ } -static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint32_t *l) { +static void secp256k1_scalar_reduce_512(secp256k1_scalar *r, const uint32_t *l) { uint64_t c; uint32_t n0 = l[8], n1 = l[9], n2 = l[10], n3 = l[11], n4 = l[12], n5 = l[13], n6 = l[14], n7 = l[15]; uint32_t m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12; @@ -462,7 +488,7 @@ static void secp256k1_scalar_reduce_512(secp256k1_scalar_t *r, const uint32_t *l secp256k1_scalar_reduce(r, c + secp256k1_scalar_check_overflow(r)); } -static void secp256k1_scalar_mul_512(uint32_t *l, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { +static void secp256k1_scalar_mul_512(uint32_t *l, const secp256k1_scalar *a, const secp256k1_scalar *b) { /* 96 bit accumulator. */ uint32_t c0 = 0, c1 = 0, c2 = 0; @@ -550,7 +576,7 @@ static void secp256k1_scalar_mul_512(uint32_t *l, const secp256k1_scalar_t *a, c l[15] = c0; } -static void secp256k1_scalar_sqr_512(uint32_t *l, const secp256k1_scalar_t *a) { +static void secp256k1_scalar_sqr_512(uint32_t *l, const secp256k1_scalar *a) { /* 96 bit accumulator. */ uint32_t c0 = 0, c1 = 0, c2 = 0; @@ -618,20 +644,36 @@ static void secp256k1_scalar_sqr_512(uint32_t *l, const secp256k1_scalar_t *a) { #undef extract #undef extract_fast -static void secp256k1_scalar_mul(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { +static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { uint32_t l[16]; secp256k1_scalar_mul_512(l, a, b); secp256k1_scalar_reduce_512(r, l); } -static void secp256k1_scalar_sqr(secp256k1_scalar_t *r, const secp256k1_scalar_t *a) { +static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) { + int ret; + VERIFY_CHECK(n > 0); + VERIFY_CHECK(n < 16); + ret = r->d[0] & ((1 << n) - 1); + r->d[0] = (r->d[0] >> n) + (r->d[1] << (32 - n)); + r->d[1] = (r->d[1] >> n) + (r->d[2] << (32 - n)); + r->d[2] = (r->d[2] >> n) + (r->d[3] << (32 - n)); + r->d[3] = (r->d[3] >> n) + (r->d[4] << (32 - n)); + r->d[4] = (r->d[4] >> n) + (r->d[5] << (32 - n)); + r->d[5] = (r->d[5] >> n) + (r->d[6] << (32 - n)); + r->d[6] = (r->d[6] >> n) + (r->d[7] << (32 - n)); + r->d[7] = (r->d[7] >> n); + return ret; +} + +static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) { uint32_t l[16]; secp256k1_scalar_sqr_512(l, a); secp256k1_scalar_reduce_512(r, l); } #ifdef USE_ENDOMORPHISM -static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a) { +static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { r1->d[0] = a->d[0]; r1->d[1] = a->d[1]; r1->d[2] = a->d[2]; @@ -651,11 +693,11 @@ static void secp256k1_scalar_split_128(secp256k1_scalar_t *r1, secp256k1_scalar_ } #endif -SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar_t *a, const secp256k1_scalar_t *b) { +SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) { return ((a->d[0] ^ b->d[0]) | (a->d[1] ^ b->d[1]) | (a->d[2] ^ b->d[2]) | (a->d[3] ^ b->d[3]) | (a->d[4] ^ b->d[4]) | (a->d[5] ^ b->d[5]) | (a->d[6] ^ b->d[6]) | (a->d[7] ^ b->d[7])) == 0; } -SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *a, const secp256k1_scalar_t *b, unsigned int shift) { +SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b, unsigned int shift) { uint32_t l[16]; unsigned int shiftlimbs; unsigned int shiftlow; @@ -673,9 +715,7 @@ SECP256K1_INLINE static void secp256k1_scalar_mul_shift_var(secp256k1_scalar_t * r->d[5] = shift < 352 ? (l[5 + shiftlimbs] >> shiftlow | (shift < 320 && shiftlow ? (l[6 + shiftlimbs] << shifthigh) : 0)) : 0; r->d[6] = shift < 320 ? (l[6 + shiftlimbs] >> shiftlow | (shift < 288 && shiftlow ? (l[7 + shiftlimbs] << shifthigh) : 0)) : 0; r->d[7] = shift < 288 ? (l[7 + shiftlimbs] >> shiftlow) : 0; - if ((l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1) { - secp256k1_scalar_add_bit(r, 0); - } + secp256k1_scalar_cadd_bit(r, 0, (l[(shift - 1) >> 5] >> ((shift - 1) & 0x1f)) & 1); } -#endif +#endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/scalar_impl.h b/src/cryptoconditions/src/include/secp256k1/src/scalar_impl.h index 33824983e..fa790570f 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/scalar_impl.h +++ b/src/cryptoconditions/src/include/secp256k1/src/scalar_impl.h @@ -4,10 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_SCALAR_IMPL_H_ -#define _SECP256K1_SCALAR_IMPL_H_ - -#include +#ifndef SECP256K1_SCALAR_IMPL_H +#define SECP256K1_SCALAR_IMPL_H #include "group.h" #include "scalar.h" @@ -16,7 +14,9 @@ #include "libsecp256k1-config.h" #endif -#if defined(USE_SCALAR_4X64) +#if defined(EXHAUSTIVE_TEST_ORDER) +#include "scalar_low_impl.h" +#elif defined(USE_SCALAR_4X64) #include "scalar_4x64_impl.h" #elif defined(USE_SCALAR_8X32) #include "scalar_8x32_impl.h" @@ -25,109 +25,120 @@ #endif #ifndef USE_NUM_NONE -static void secp256k1_scalar_get_num(secp256k1_num_t *r, const secp256k1_scalar_t *a) { +static void secp256k1_scalar_get_num(secp256k1_num *r, const secp256k1_scalar *a) { unsigned char c[32]; secp256k1_scalar_get_b32(c, a); secp256k1_num_set_bin(r, c, 32); } /** secp256k1 curve order, see secp256k1_ecdsa_const_order_as_fe in ecdsa_impl.h */ -static void secp256k1_scalar_order_get_num(secp256k1_num_t *r) { +static void secp256k1_scalar_order_get_num(secp256k1_num *r) { +#if defined(EXHAUSTIVE_TEST_ORDER) + static const unsigned char order[32] = { + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,EXHAUSTIVE_TEST_ORDER + }; +#else static const unsigned char order[32] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE, 0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B, 0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x41 }; +#endif secp256k1_num_set_bin(r, order, 32); } #endif -static void secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scalar_t *x) { - secp256k1_scalar_t *t; +static void secp256k1_scalar_inverse(secp256k1_scalar *r, const secp256k1_scalar *x) { +#if defined(EXHAUSTIVE_TEST_ORDER) int i; - /* First compute x ^ (2^N - 1) for some values of N. */ - secp256k1_scalar_t x2, x3, x4, x6, x7, x8, x15, x30, x60, x120, x127; + *r = 0; + for (i = 0; i < EXHAUSTIVE_TEST_ORDER; i++) + if ((i * *x) % EXHAUSTIVE_TEST_ORDER == 1) + *r = i; + /* If this VERIFY_CHECK triggers we were given a noninvertible scalar (and thus + * have a composite group order; fix it in exhaustive_tests.c). */ + VERIFY_CHECK(*r != 0); +} +#else + secp256k1_scalar *t; + int i; + /* First compute xN as x ^ (2^N - 1) for some values of N, + * and uM as x ^ M for some values of M. */ + secp256k1_scalar x2, x3, x6, x8, x14, x28, x56, x112, x126; + secp256k1_scalar u2, u5, u9, u11, u13; - secp256k1_scalar_sqr(&x2, x); - secp256k1_scalar_mul(&x2, &x2, x); + secp256k1_scalar_sqr(&u2, x); + secp256k1_scalar_mul(&x2, &u2, x); + secp256k1_scalar_mul(&u5, &u2, &x2); + secp256k1_scalar_mul(&x3, &u5, &u2); + secp256k1_scalar_mul(&u9, &x3, &u2); + secp256k1_scalar_mul(&u11, &u9, &u2); + secp256k1_scalar_mul(&u13, &u11, &u2); - secp256k1_scalar_sqr(&x3, &x2); - secp256k1_scalar_mul(&x3, &x3, x); - - secp256k1_scalar_sqr(&x4, &x3); - secp256k1_scalar_mul(&x4, &x4, x); - - secp256k1_scalar_sqr(&x6, &x4); + secp256k1_scalar_sqr(&x6, &u13); secp256k1_scalar_sqr(&x6, &x6); - secp256k1_scalar_mul(&x6, &x6, &x2); + secp256k1_scalar_mul(&x6, &x6, &u11); - secp256k1_scalar_sqr(&x7, &x6); - secp256k1_scalar_mul(&x7, &x7, x); + secp256k1_scalar_sqr(&x8, &x6); + secp256k1_scalar_sqr(&x8, &x8); + secp256k1_scalar_mul(&x8, &x8, &x2); - secp256k1_scalar_sqr(&x8, &x7); - secp256k1_scalar_mul(&x8, &x8, x); - - secp256k1_scalar_sqr(&x15, &x8); - for (i = 0; i < 6; i++) { - secp256k1_scalar_sqr(&x15, &x15); + secp256k1_scalar_sqr(&x14, &x8); + for (i = 0; i < 5; i++) { + secp256k1_scalar_sqr(&x14, &x14); } - secp256k1_scalar_mul(&x15, &x15, &x7); + secp256k1_scalar_mul(&x14, &x14, &x6); - secp256k1_scalar_sqr(&x30, &x15); - for (i = 0; i < 14; i++) { - secp256k1_scalar_sqr(&x30, &x30); + secp256k1_scalar_sqr(&x28, &x14); + for (i = 0; i < 13; i++) { + secp256k1_scalar_sqr(&x28, &x28); } - secp256k1_scalar_mul(&x30, &x30, &x15); + secp256k1_scalar_mul(&x28, &x28, &x14); - secp256k1_scalar_sqr(&x60, &x30); - for (i = 0; i < 29; i++) { - secp256k1_scalar_sqr(&x60, &x60); + secp256k1_scalar_sqr(&x56, &x28); + for (i = 0; i < 27; i++) { + secp256k1_scalar_sqr(&x56, &x56); } - secp256k1_scalar_mul(&x60, &x60, &x30); + secp256k1_scalar_mul(&x56, &x56, &x28); - secp256k1_scalar_sqr(&x120, &x60); - for (i = 0; i < 59; i++) { - secp256k1_scalar_sqr(&x120, &x120); + secp256k1_scalar_sqr(&x112, &x56); + for (i = 0; i < 55; i++) { + secp256k1_scalar_sqr(&x112, &x112); } - secp256k1_scalar_mul(&x120, &x120, &x60); + secp256k1_scalar_mul(&x112, &x112, &x56); - secp256k1_scalar_sqr(&x127, &x120); - for (i = 0; i < 6; i++) { - secp256k1_scalar_sqr(&x127, &x127); + secp256k1_scalar_sqr(&x126, &x112); + for (i = 0; i < 13; i++) { + secp256k1_scalar_sqr(&x126, &x126); } - secp256k1_scalar_mul(&x127, &x127, &x7); + secp256k1_scalar_mul(&x126, &x126, &x14); - /* Then accumulate the final result (t starts at x127). */ - t = &x127; - for (i = 0; i < 2; i++) { /* 0 */ + /* Then accumulate the final result (t starts at x126). */ + t = &x126; + for (i = 0; i < 3; i++) { secp256k1_scalar_sqr(t, t); } - secp256k1_scalar_mul(t, t, x); /* 1 */ + secp256k1_scalar_mul(t, t, &u5); /* 101 */ for (i = 0; i < 4; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); } secp256k1_scalar_mul(t, t, &x3); /* 111 */ - for (i = 0; i < 2; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 2; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 2; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, x); /* 1 */ for (i = 0; i < 4; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); } - secp256k1_scalar_mul(t, t, &x3); /* 111 */ - for (i = 0; i < 3; i++) { /* 0 */ + secp256k1_scalar_mul(t, t, &u5); /* 101 */ + for (i = 0; i < 5; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); } - secp256k1_scalar_mul(t, t, &x2); /* 11 */ + secp256k1_scalar_mul(t, t, &u11); /* 1011 */ + for (i = 0; i < 4; i++) { + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &u11); /* 1011 */ for (i = 0; i < 4; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); } @@ -136,38 +147,26 @@ static void secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scal secp256k1_scalar_sqr(t, t); } secp256k1_scalar_mul(t, t, &x3); /* 111 */ - for (i = 0; i < 4; i++) { /* 00 */ + for (i = 0; i < 6; i++) { /* 00 */ secp256k1_scalar_sqr(t, t); } - secp256k1_scalar_mul(t, t, &x2); /* 11 */ - for (i = 0; i < 2; i++) { /* 0 */ + secp256k1_scalar_mul(t, t, &u13); /* 1101 */ + for (i = 0; i < 4; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); } - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 2; i++) { /* 0 */ + secp256k1_scalar_mul(t, t, &u5); /* 101 */ + for (i = 0; i < 3; i++) { secp256k1_scalar_sqr(t, t); } - secp256k1_scalar_mul(t, t, x); /* 1 */ + secp256k1_scalar_mul(t, t, &x3); /* 111 */ for (i = 0; i < 5; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); } - secp256k1_scalar_mul(t, t, &x4); /* 1111 */ - for (i = 0; i < 2; i++) { /* 0 */ + secp256k1_scalar_mul(t, t, &u9); /* 1001 */ + for (i = 0; i < 6; i++) { /* 000 */ secp256k1_scalar_sqr(t, t); } - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 3; i++) { /* 00 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 4; i++) { /* 000 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 2; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, x); /* 1 */ + secp256k1_scalar_mul(t, t, &u5); /* 101 */ for (i = 0; i < 10; i++) { /* 0000000 */ secp256k1_scalar_sqr(t, t); } @@ -180,50 +179,34 @@ static void secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scal secp256k1_scalar_sqr(t, t); } secp256k1_scalar_mul(t, t, &x8); /* 11111111 */ - for (i = 0; i < 2; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 3; i++) { /* 00 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 3; i++) { /* 00 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, x); /* 1 */ for (i = 0; i < 5; i++) { /* 0 */ secp256k1_scalar_sqr(t, t); } - secp256k1_scalar_mul(t, t, &x4); /* 1111 */ - for (i = 0; i < 2; i++) { /* 0 */ + secp256k1_scalar_mul(t, t, &u9); /* 1001 */ + for (i = 0; i < 6; i++) { /* 00 */ secp256k1_scalar_sqr(t, t); } - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 5; i++) { /* 000 */ + secp256k1_scalar_mul(t, t, &u11); /* 1011 */ + for (i = 0; i < 4; i++) { + secp256k1_scalar_sqr(t, t); + } + secp256k1_scalar_mul(t, t, &u13); /* 1101 */ + for (i = 0; i < 5; i++) { secp256k1_scalar_sqr(t, t); } secp256k1_scalar_mul(t, t, &x2); /* 11 */ - for (i = 0; i < 4; i++) { /* 00 */ + for (i = 0; i < 6; i++) { /* 00 */ secp256k1_scalar_sqr(t, t); } - secp256k1_scalar_mul(t, t, &x2); /* 11 */ - for (i = 0; i < 2; i++) { /* 0 */ + secp256k1_scalar_mul(t, t, &u13); /* 1101 */ + for (i = 0; i < 10; i++) { /* 000000 */ secp256k1_scalar_sqr(t, t); } - secp256k1_scalar_mul(t, t, x); /* 1 */ - for (i = 0; i < 8; i++) { /* 000000 */ + secp256k1_scalar_mul(t, t, &u13); /* 1101 */ + for (i = 0; i < 4; i++) { secp256k1_scalar_sqr(t, t); } - secp256k1_scalar_mul(t, t, &x2); /* 11 */ - for (i = 0; i < 3; i++) { /* 0 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, &x2); /* 11 */ - for (i = 0; i < 3; i++) { /* 00 */ - secp256k1_scalar_sqr(t, t); - } - secp256k1_scalar_mul(t, t, x); /* 1 */ + secp256k1_scalar_mul(t, t, &u9); /* 1001 */ for (i = 0; i < 6; i++) { /* 00000 */ secp256k1_scalar_sqr(t, t); } @@ -234,24 +217,45 @@ static void secp256k1_scalar_inverse(secp256k1_scalar_t *r, const secp256k1_scal secp256k1_scalar_mul(r, t, &x6); /* 111111 */ } -static void secp256k1_scalar_inverse_var(secp256k1_scalar_t *r, const secp256k1_scalar_t *x) { +SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) { + return !(a->d[0] & 1); +} +#endif + +static void secp256k1_scalar_inverse_var(secp256k1_scalar *r, const secp256k1_scalar *x) { #if defined(USE_SCALAR_INV_BUILTIN) secp256k1_scalar_inverse(r, x); #elif defined(USE_SCALAR_INV_NUM) unsigned char b[32]; - secp256k1_num_t n, m; - secp256k1_scalar_get_b32(b, x); + secp256k1_num n, m; + secp256k1_scalar t = *x; + secp256k1_scalar_get_b32(b, &t); secp256k1_num_set_bin(&n, b, 32); secp256k1_scalar_order_get_num(&m); secp256k1_num_mod_inverse(&n, &n, &m); secp256k1_num_get_bin(b, 32, &n); secp256k1_scalar_set_b32(r, b, NULL); + /* Verify that the inverse was computed correctly, without GMP code. */ + secp256k1_scalar_mul(&t, &t, r); + CHECK(secp256k1_scalar_is_one(&t)); #else #error "Please select scalar inverse implementation" #endif } #ifdef USE_ENDOMORPHISM +#if defined(EXHAUSTIVE_TEST_ORDER) +/** + * Find k1 and k2 given k, such that k1 + k2 * lambda == k mod n; unlike in the + * full case we don't bother making k1 and k2 be small, we just want them to be + * nontrivial to get full test coverage for the exhaustive tests. We therefore + * (arbitrarily) set k2 = k + 5 and k1 = k - k2 * lambda. + */ +static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { + *r2 = (*a + 5) % EXHAUSTIVE_TEST_ORDER; + *r1 = (*a + (EXHAUSTIVE_TEST_ORDER - *r2) * EXHAUSTIVE_TEST_LAMBDA) % EXHAUSTIVE_TEST_ORDER; +} +#else /** * The Secp256k1 curve has an endomorphism, where lambda * (x, y) = (beta * x, y), where * lambda is {0x53,0x63,0xad,0x4c,0xc0,0x5c,0x30,0xe0,0xa5,0x26,0x1c,0x02,0x88,0x12,0x64,0x5a, @@ -290,30 +294,31 @@ static void secp256k1_scalar_inverse_var(secp256k1_scalar_t *r, const secp256k1_ * The function below splits a in r1 and r2, such that r1 + lambda * r2 == a (mod order). */ -static void secp256k1_scalar_split_lambda_var(secp256k1_scalar_t *r1, secp256k1_scalar_t *r2, const secp256k1_scalar_t *a) { - secp256k1_scalar_t c1, c2; - static const secp256k1_scalar_t minus_lambda = SECP256K1_SCALAR_CONST( +static void secp256k1_scalar_split_lambda(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { + secp256k1_scalar c1, c2; + static const secp256k1_scalar minus_lambda = SECP256K1_SCALAR_CONST( 0xAC9C52B3UL, 0x3FA3CF1FUL, 0x5AD9E3FDUL, 0x77ED9BA4UL, 0xA880B9FCUL, 0x8EC739C2UL, 0xE0CFC810UL, 0xB51283CFUL ); - static const secp256k1_scalar_t minus_b1 = SECP256K1_SCALAR_CONST( + static const secp256k1_scalar minus_b1 = SECP256K1_SCALAR_CONST( 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00000000UL, 0xE4437ED6UL, 0x010E8828UL, 0x6F547FA9UL, 0x0ABFE4C3UL ); - static const secp256k1_scalar_t minus_b2 = SECP256K1_SCALAR_CONST( + static const secp256k1_scalar minus_b2 = SECP256K1_SCALAR_CONST( 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFEUL, 0x8A280AC5UL, 0x0774346DUL, 0xD765CDA8UL, 0x3DB1562CUL ); - static const secp256k1_scalar_t g1 = SECP256K1_SCALAR_CONST( + static const secp256k1_scalar g1 = SECP256K1_SCALAR_CONST( 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x00003086UL, 0xD221A7D4UL, 0x6BCDE86CUL, 0x90E49284UL, 0xEB153DABUL ); - static const secp256k1_scalar_t g2 = SECP256K1_SCALAR_CONST( + static const secp256k1_scalar g2 = SECP256K1_SCALAR_CONST( 0x00000000UL, 0x00000000UL, 0x00000000UL, 0x0000E443UL, 0x7ED6010EUL, 0x88286F54UL, 0x7FA90ABFUL, 0xE4C42212UL ); VERIFY_CHECK(r1 != a); VERIFY_CHECK(r2 != a); + /* these _var calls are constant time since the shift amount is constant */ secp256k1_scalar_mul_shift_var(&c1, a, &g1, 272); secp256k1_scalar_mul_shift_var(&c2, a, &g2, 272); secp256k1_scalar_mul(&c1, &c1, &minus_b1); @@ -323,5 +328,6 @@ static void secp256k1_scalar_split_lambda_var(secp256k1_scalar_t *r1, secp256k1_ secp256k1_scalar_add(r1, r1, a); } #endif - #endif + +#endif /* SECP256K1_SCALAR_IMPL_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/scalar_low.h b/src/cryptoconditions/src/include/secp256k1/src/scalar_low.h new file mode 100644 index 000000000..5836febc5 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/scalar_low.h @@ -0,0 +1,15 @@ +/********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_SCALAR_REPR_H +#define SECP256K1_SCALAR_REPR_H + +#include + +/** A scalar modulo the group order of the secp256k1 curve. */ +typedef uint32_t secp256k1_scalar; + +#endif /* SECP256K1_SCALAR_REPR_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/scalar_low_impl.h b/src/cryptoconditions/src/include/secp256k1/src/scalar_low_impl.h new file mode 100644 index 000000000..c80e70c5a --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/scalar_low_impl.h @@ -0,0 +1,114 @@ +/********************************************************************** + * Copyright (c) 2015 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#ifndef SECP256K1_SCALAR_REPR_IMPL_H +#define SECP256K1_SCALAR_REPR_IMPL_H + +#include "scalar.h" + +#include + +SECP256K1_INLINE static int secp256k1_scalar_is_even(const secp256k1_scalar *a) { + return !(*a & 1); +} + +SECP256K1_INLINE static void secp256k1_scalar_clear(secp256k1_scalar *r) { *r = 0; } +SECP256K1_INLINE static void secp256k1_scalar_set_int(secp256k1_scalar *r, unsigned int v) { *r = v; } + +SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { + if (offset < 32) + return ((*a >> offset) & ((((uint32_t)1) << count) - 1)); + else + return 0; +} + +SECP256K1_INLINE static unsigned int secp256k1_scalar_get_bits_var(const secp256k1_scalar *a, unsigned int offset, unsigned int count) { + return secp256k1_scalar_get_bits(a, offset, count); +} + +SECP256K1_INLINE static int secp256k1_scalar_check_overflow(const secp256k1_scalar *a) { return *a >= EXHAUSTIVE_TEST_ORDER; } + +static int secp256k1_scalar_add(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { + *r = (*a + *b) % EXHAUSTIVE_TEST_ORDER; + return *r < *b; +} + +static void secp256k1_scalar_cadd_bit(secp256k1_scalar *r, unsigned int bit, int flag) { + if (flag && bit < 32) + *r += (1 << bit); +#ifdef VERIFY + VERIFY_CHECK(secp256k1_scalar_check_overflow(r) == 0); +#endif +} + +static void secp256k1_scalar_set_b32(secp256k1_scalar *r, const unsigned char *b32, int *overflow) { + const int base = 0x100 % EXHAUSTIVE_TEST_ORDER; + int i; + *r = 0; + for (i = 0; i < 32; i++) { + *r = ((*r * base) + b32[i]) % EXHAUSTIVE_TEST_ORDER; + } + /* just deny overflow, it basically always happens */ + if (overflow) *overflow = 0; +} + +static void secp256k1_scalar_get_b32(unsigned char *bin, const secp256k1_scalar* a) { + memset(bin, 0, 32); + bin[28] = *a >> 24; bin[29] = *a >> 16; bin[30] = *a >> 8; bin[31] = *a; +} + +SECP256K1_INLINE static int secp256k1_scalar_is_zero(const secp256k1_scalar *a) { + return *a == 0; +} + +static void secp256k1_scalar_negate(secp256k1_scalar *r, const secp256k1_scalar *a) { + if (*a == 0) { + *r = 0; + } else { + *r = EXHAUSTIVE_TEST_ORDER - *a; + } +} + +SECP256K1_INLINE static int secp256k1_scalar_is_one(const secp256k1_scalar *a) { + return *a == 1; +} + +static int secp256k1_scalar_is_high(const secp256k1_scalar *a) { + return *a > EXHAUSTIVE_TEST_ORDER / 2; +} + +static int secp256k1_scalar_cond_negate(secp256k1_scalar *r, int flag) { + if (flag) secp256k1_scalar_negate(r, r); + return flag ? -1 : 1; +} + +static void secp256k1_scalar_mul(secp256k1_scalar *r, const secp256k1_scalar *a, const secp256k1_scalar *b) { + *r = (*a * *b) % EXHAUSTIVE_TEST_ORDER; +} + +static int secp256k1_scalar_shr_int(secp256k1_scalar *r, int n) { + int ret; + VERIFY_CHECK(n > 0); + VERIFY_CHECK(n < 16); + ret = *r & ((1 << n) - 1); + *r >>= n; + return ret; +} + +static void secp256k1_scalar_sqr(secp256k1_scalar *r, const secp256k1_scalar *a) { + *r = (*a * *a) % EXHAUSTIVE_TEST_ORDER; +} + +static void secp256k1_scalar_split_128(secp256k1_scalar *r1, secp256k1_scalar *r2, const secp256k1_scalar *a) { + *r1 = *a; + *r2 = 0; +} + +SECP256K1_INLINE static int secp256k1_scalar_eq(const secp256k1_scalar *a, const secp256k1_scalar *b) { + return *a == *b; +} + +#endif /* SECP256K1_SCALAR_REPR_IMPL_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/secp256k1.c b/src/cryptoconditions/src/include/secp256k1/src/secp256k1.c index 48569ad9e..cecb1550b 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/secp256k1.c +++ b/src/cryptoconditions/src/include/secp256k1/src/secp256k1.c @@ -4,8 +4,6 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#define SECP256K1_BUILD (1) - #include "include/secp256k1.h" #include "util.h" @@ -14,89 +12,326 @@ #include "scalar_impl.h" #include "group_impl.h" #include "ecmult_impl.h" +#include "ecmult_const_impl.h" #include "ecmult_gen_impl.h" #include "ecdsa_impl.h" #include "eckey_impl.h" #include "hash_impl.h" -struct secp256k1_context_struct { - secp256k1_ecmult_context_t ecmult_ctx; - secp256k1_ecmult_gen_context_t ecmult_gen_ctx; +#define ARG_CHECK(cond) do { \ + if (EXPECT(!(cond), 0)) { \ + secp256k1_callback_call(&ctx->illegal_callback, #cond); \ + return 0; \ + } \ +} while(0) + +static void default_illegal_callback_fn(const char* str, void* data) { + (void)data; + fprintf(stderr, "[libsecp256k1] illegal argument: %s\n", str); + abort(); +} + +static const secp256k1_callback default_illegal_callback = { + default_illegal_callback_fn, + NULL }; -secp256k1_context_t* secp256k1_context_create(int flags) { - secp256k1_context_t* ret = (secp256k1_context_t*)checked_malloc(sizeof(secp256k1_context_t)); +static void default_error_callback_fn(const char* str, void* data) { + (void)data; + fprintf(stderr, "[libsecp256k1] internal consistency check failed: %s\n", str); + abort(); +} + +static const secp256k1_callback default_error_callback = { + default_error_callback_fn, + NULL +}; + + +struct secp256k1_context_struct { + secp256k1_ecmult_context ecmult_ctx; + secp256k1_ecmult_gen_context ecmult_gen_ctx; + secp256k1_callback illegal_callback; + secp256k1_callback error_callback; +}; + +secp256k1_context* secp256k1_context_create(unsigned int flags) { + secp256k1_context* ret = (secp256k1_context*)checked_malloc(&default_error_callback, sizeof(secp256k1_context)); + ret->illegal_callback = default_illegal_callback; + ret->error_callback = default_error_callback; + + if (EXPECT((flags & SECP256K1_FLAGS_TYPE_MASK) != SECP256K1_FLAGS_TYPE_CONTEXT, 0)) { + secp256k1_callback_call(&ret->illegal_callback, + "Invalid flags"); + free(ret); + return NULL; + } secp256k1_ecmult_context_init(&ret->ecmult_ctx); secp256k1_ecmult_gen_context_init(&ret->ecmult_gen_ctx); - if (flags & SECP256K1_CONTEXT_SIGN) { - secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx); + if (flags & SECP256K1_FLAGS_BIT_CONTEXT_SIGN) { + secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx, &ret->error_callback); } - if (flags & SECP256K1_CONTEXT_VERIFY) { - secp256k1_ecmult_context_build(&ret->ecmult_ctx); + if (flags & SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) { + secp256k1_ecmult_context_build(&ret->ecmult_ctx, &ret->error_callback); } return ret; } -secp256k1_context_t* secp256k1_context_clone(const secp256k1_context_t* ctx) { - secp256k1_context_t* ret = (secp256k1_context_t*)checked_malloc(sizeof(secp256k1_context_t)); - secp256k1_ecmult_context_clone(&ret->ecmult_ctx, &ctx->ecmult_ctx); - secp256k1_ecmult_gen_context_clone(&ret->ecmult_gen_ctx, &ctx->ecmult_gen_ctx); +secp256k1_context* secp256k1_context_clone(const secp256k1_context* ctx) { + secp256k1_context* ret = (secp256k1_context*)checked_malloc(&ctx->error_callback, sizeof(secp256k1_context)); + ret->illegal_callback = ctx->illegal_callback; + ret->error_callback = ctx->error_callback; + secp256k1_ecmult_context_clone(&ret->ecmult_ctx, &ctx->ecmult_ctx, &ctx->error_callback); + secp256k1_ecmult_gen_context_clone(&ret->ecmult_gen_ctx, &ctx->ecmult_gen_ctx, &ctx->error_callback); return ret; } -void secp256k1_context_destroy(secp256k1_context_t* ctx) { - secp256k1_ecmult_context_clear(&ctx->ecmult_ctx); - secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx); +void secp256k1_context_destroy(secp256k1_context* ctx) { + if (ctx != NULL) { + secp256k1_ecmult_context_clear(&ctx->ecmult_ctx); + secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx); - free(ctx); + free(ctx); + } } -int secp256k1_ecdsa_verify(const secp256k1_context_t* ctx, const unsigned char *msg32, const unsigned char *sig, int siglen, const unsigned char *pubkey, int pubkeylen) { - secp256k1_ge_t q; - secp256k1_ecdsa_sig_t s; - secp256k1_scalar_t m; - int ret = -3; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - DEBUG_CHECK(msg32 != NULL); - DEBUG_CHECK(sig != NULL); - DEBUG_CHECK(pubkey != NULL); +void secp256k1_context_set_illegal_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) { + if (fun == NULL) { + fun = default_illegal_callback_fn; + } + ctx->illegal_callback.fn = fun; + ctx->illegal_callback.data = data; +} + +void secp256k1_context_set_error_callback(secp256k1_context* ctx, void (*fun)(const char* message, void* data), const void* data) { + if (fun == NULL) { + fun = default_error_callback_fn; + } + ctx->error_callback.fn = fun; + ctx->error_callback.data = data; +} + +static int secp256k1_pubkey_load(const secp256k1_context* ctx, secp256k1_ge* ge, const secp256k1_pubkey* pubkey) { + if (sizeof(secp256k1_ge_storage) == 64) { + /* When the secp256k1_ge_storage type is exactly 64 byte, use its + * representation inside secp256k1_pubkey, as conversion is very fast. + * Note that secp256k1_pubkey_save must use the same representation. */ + secp256k1_ge_storage s; + memcpy(&s, &pubkey->data[0], 64); + secp256k1_ge_from_storage(ge, &s); + } else { + /* Otherwise, fall back to 32-byte big endian for X and Y. */ + secp256k1_fe x, y; + secp256k1_fe_set_b32(&x, pubkey->data); + secp256k1_fe_set_b32(&y, pubkey->data + 32); + secp256k1_ge_set_xy(ge, &x, &y); + } + ARG_CHECK(!secp256k1_fe_is_zero(&ge->x)); + return 1; +} + +static void secp256k1_pubkey_save(secp256k1_pubkey* pubkey, secp256k1_ge* ge) { + if (sizeof(secp256k1_ge_storage) == 64) { + secp256k1_ge_storage s; + secp256k1_ge_to_storage(&s, ge); + memcpy(&pubkey->data[0], &s, 64); + } else { + VERIFY_CHECK(!secp256k1_ge_is_infinity(ge)); + secp256k1_fe_normalize_var(&ge->x); + secp256k1_fe_normalize_var(&ge->y); + secp256k1_fe_get_b32(pubkey->data, &ge->x); + secp256k1_fe_get_b32(pubkey->data + 32, &ge->y); + } +} + +int secp256k1_ec_pubkey_parse(const secp256k1_context* ctx, secp256k1_pubkey* pubkey, const unsigned char *input, size_t inputlen) { + secp256k1_ge Q; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + memset(pubkey, 0, sizeof(*pubkey)); + ARG_CHECK(input != NULL); + if (!secp256k1_eckey_pubkey_parse(&Q, input, inputlen)) { + return 0; + } + secp256k1_pubkey_save(pubkey, &Q); + secp256k1_ge_clear(&Q); + return 1; +} + +int secp256k1_ec_pubkey_serialize(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_pubkey* pubkey, unsigned int flags) { + secp256k1_ge Q; + size_t len; + int ret = 0; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(outputlen != NULL); + ARG_CHECK(*outputlen >= ((flags & SECP256K1_FLAGS_BIT_COMPRESSION) ? 33 : 65)); + len = *outputlen; + *outputlen = 0; + ARG_CHECK(output != NULL); + memset(output, 0, len); + ARG_CHECK(pubkey != NULL); + ARG_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_COMPRESSION); + if (secp256k1_pubkey_load(ctx, &Q, pubkey)) { + ret = secp256k1_eckey_pubkey_serialize(&Q, output, &len, flags & SECP256K1_FLAGS_BIT_COMPRESSION); + if (ret) { + *outputlen = len; + } + } + return ret; +} + +static void secp256k1_ecdsa_signature_load(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_ecdsa_signature* sig) { + (void)ctx; + if (sizeof(secp256k1_scalar) == 32) { + /* When the secp256k1_scalar type is exactly 32 byte, use its + * representation inside secp256k1_ecdsa_signature, as conversion is very fast. + * Note that secp256k1_ecdsa_signature_save must use the same representation. */ + memcpy(r, &sig->data[0], 32); + memcpy(s, &sig->data[32], 32); + } else { + secp256k1_scalar_set_b32(r, &sig->data[0], NULL); + secp256k1_scalar_set_b32(s, &sig->data[32], NULL); + } +} + +static void secp256k1_ecdsa_signature_save(secp256k1_ecdsa_signature* sig, const secp256k1_scalar* r, const secp256k1_scalar* s) { + if (sizeof(secp256k1_scalar) == 32) { + memcpy(&sig->data[0], r, 32); + memcpy(&sig->data[32], s, 32); + } else { + secp256k1_scalar_get_b32(&sig->data[0], r); + secp256k1_scalar_get_b32(&sig->data[32], s); + } +} + +int secp256k1_ecdsa_signature_parse_der(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input, size_t inputlen) { + secp256k1_scalar r, s; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(input != NULL); + + if (secp256k1_ecdsa_sig_parse(&r, &s, input, inputlen)) { + secp256k1_ecdsa_signature_save(sig, &r, &s); + return 1; + } else { + memset(sig, 0, sizeof(*sig)); + return 0; + } +} + +int secp256k1_ecdsa_signature_parse_compact(const secp256k1_context* ctx, secp256k1_ecdsa_signature* sig, const unsigned char *input64) { + secp256k1_scalar r, s; + int ret = 1; + int overflow = 0; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(input64 != NULL); + + secp256k1_scalar_set_b32(&r, &input64[0], &overflow); + ret &= !overflow; + secp256k1_scalar_set_b32(&s, &input64[32], &overflow); + ret &= !overflow; + if (ret) { + secp256k1_ecdsa_signature_save(sig, &r, &s); + } else { + memset(sig, 0, sizeof(*sig)); + } + return ret; +} + +int secp256k1_ecdsa_signature_serialize_der(const secp256k1_context* ctx, unsigned char *output, size_t *outputlen, const secp256k1_ecdsa_signature* sig) { + secp256k1_scalar r, s; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output != NULL); + ARG_CHECK(outputlen != NULL); + ARG_CHECK(sig != NULL); + + secp256k1_ecdsa_signature_load(ctx, &r, &s, sig); + return secp256k1_ecdsa_sig_serialize(output, outputlen, &r, &s); +} + +int secp256k1_ecdsa_signature_serialize_compact(const secp256k1_context* ctx, unsigned char *output64, const secp256k1_ecdsa_signature* sig) { + secp256k1_scalar r, s; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(output64 != NULL); + ARG_CHECK(sig != NULL); + + secp256k1_ecdsa_signature_load(ctx, &r, &s, sig); + secp256k1_scalar_get_b32(&output64[0], &r); + secp256k1_scalar_get_b32(&output64[32], &s); + return 1; +} + +int secp256k1_ecdsa_signature_normalize(const secp256k1_context* ctx, secp256k1_ecdsa_signature *sigout, const secp256k1_ecdsa_signature *sigin) { + secp256k1_scalar r, s; + int ret = 0; + + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(sigin != NULL); + + secp256k1_ecdsa_signature_load(ctx, &r, &s, sigin); + ret = secp256k1_scalar_is_high(&s); + if (sigout != NULL) { + if (ret) { + secp256k1_scalar_negate(&s, &s); + } + secp256k1_ecdsa_signature_save(sigout, &r, &s); + } + + return ret; +} + +int secp256k1_ecdsa_verify(const secp256k1_context* ctx, const secp256k1_ecdsa_signature *sig, const unsigned char *msg32, const secp256k1_pubkey *pubkey) { + secp256k1_ge q; + secp256k1_scalar r, s; + secp256k1_scalar m; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(sig != NULL); + ARG_CHECK(pubkey != NULL); secp256k1_scalar_set_b32(&m, msg32, NULL); - - if (secp256k1_eckey_pubkey_parse(&q, pubkey, pubkeylen)) { - if (secp256k1_ecdsa_sig_parse(&s, sig, siglen)) { - if (secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &s, &q, &m)) { - /* success is 1, all other values are fail */ - ret = 1; - } else { - ret = 0; - } - } else { - ret = -2; - } - } else { - ret = -1; - } - - return ret; + secp256k1_ecdsa_signature_load(ctx, &r, &s, sig); + return (!secp256k1_scalar_is_high(&s) && + secp256k1_pubkey_load(ctx, &q, pubkey) && + secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &r, &s, &q, &m)); } - -int secp256k1_ecdsa_check_canonical_sig(const unsigned char *sig, int siglen) { - secp256k1_ecdsa_sig_t s; - if (!secp256k1_ecdsa_sig_parse(&s, sig, siglen)) return -1; - return !secp256k1_scalar_is_high(&s.s); -} - - -static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) { - secp256k1_rfc6979_hmac_sha256_t rng; +static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { + unsigned char keydata[112]; + int keylen = 64; + secp256k1_rfc6979_hmac_sha256 rng; unsigned int i; - secp256k1_rfc6979_hmac_sha256_initialize(&rng, key32, 32, msg32, 32, (const unsigned char*)data, data != NULL ? 32 : 0); + /* We feed a byte array to the PRNG as input, consisting of: + * - the private key (32 bytes) and message (32 bytes), see RFC 6979 3.2d. + * - optionally 32 extra bytes of data, see RFC 6979 3.6 Additional Data. + * - optionally 16 extra bytes with the algorithm name. + * Because the arguments have distinct fixed lengths it is not possible for + * different argument mixtures to emulate each other and result in the same + * nonces. + */ + memcpy(keydata, key32, 32); + memcpy(keydata + 32, msg32, 32); + if (data != NULL) { + memcpy(keydata + 64, data, 32); + keylen = 96; + } + if (algo16 != NULL) { + memcpy(keydata + keylen, algo16, 16); + keylen += 16; + } + secp256k1_rfc6979_hmac_sha256_initialize(&rng, keydata, keylen); + memset(keydata, 0, sizeof(keydata)); for (i = 0; i <= counter; i++) { secp256k1_rfc6979_hmac_sha256_generate(&rng, nonce32, 32); } @@ -104,21 +339,19 @@ static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *m return 1; } -const secp256k1_nonce_function_t secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979; -const secp256k1_nonce_function_t secp256k1_nonce_function_default = nonce_function_rfc6979; +const secp256k1_nonce_function secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979; +const secp256k1_nonce_function secp256k1_nonce_function_default = nonce_function_rfc6979; -int secp256k1_ecdsa_sign(const secp256k1_context_t* ctx, const unsigned char *msg32, unsigned char *signature, int *signaturelen, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata) { - secp256k1_ecdsa_sig_t sig; - secp256k1_scalar_t sec, non, msg; +int secp256k1_ecdsa_sign(const secp256k1_context* ctx, secp256k1_ecdsa_signature *signature, const unsigned char *msg32, const unsigned char *seckey, secp256k1_nonce_function noncefp, const void* noncedata) { + secp256k1_scalar r, s; + secp256k1_scalar sec, non, msg; int ret = 0; int overflow = 0; - unsigned int count = 0; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - DEBUG_CHECK(msg32 != NULL); - DEBUG_CHECK(signature != NULL); - DEBUG_CHECK(signaturelen != NULL); - DEBUG_CHECK(seckey != NULL); + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(msg32 != NULL); + ARG_CHECK(signature != NULL); + ARG_CHECK(seckey != NULL); if (noncefp == NULL) { noncefp = secp256k1_nonce_function_default; } @@ -126,186 +359,112 @@ int secp256k1_ecdsa_sign(const secp256k1_context_t* ctx, const unsigned char *ms secp256k1_scalar_set_b32(&sec, seckey, &overflow); /* Fail if the secret key is invalid. */ if (!overflow && !secp256k1_scalar_is_zero(&sec)) { + unsigned char nonce32[32]; + unsigned int count = 0; secp256k1_scalar_set_b32(&msg, msg32, NULL); while (1) { - unsigned char nonce32[32]; - ret = noncefp(nonce32, msg32, seckey, count, noncedata); + ret = noncefp(nonce32, msg32, seckey, NULL, (void*)noncedata, count); if (!ret) { break; } secp256k1_scalar_set_b32(&non, nonce32, &overflow); - memset(nonce32, 0, 32); - if (!secp256k1_scalar_is_zero(&non) && !overflow) { - if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &sig, &sec, &msg, &non, NULL)) { + if (!overflow && !secp256k1_scalar_is_zero(&non)) { + if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, NULL)) { break; } } count++; } - if (ret) { - ret = secp256k1_ecdsa_sig_serialize(signature, signaturelen, &sig); - } + memset(nonce32, 0, 32); secp256k1_scalar_clear(&msg); secp256k1_scalar_clear(&non); secp256k1_scalar_clear(&sec); } - if (!ret) { - *signaturelen = 0; + if (ret) { + secp256k1_ecdsa_signature_save(signature, &r, &s); + } else { + memset(signature, 0, sizeof(*signature)); } return ret; } -int secp256k1_ecdsa_sign_compact(const secp256k1_context_t* ctx, const unsigned char *msg32, unsigned char *sig64, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata, int *recid) { - secp256k1_ecdsa_sig_t sig; - secp256k1_scalar_t sec, non, msg; - int ret = 0; - int overflow = 0; - unsigned int count = 0; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - DEBUG_CHECK(msg32 != NULL); - DEBUG_CHECK(sig64 != NULL); - DEBUG_CHECK(seckey != NULL); - if (noncefp == NULL) { - noncefp = secp256k1_nonce_function_default; - } - - secp256k1_scalar_set_b32(&sec, seckey, &overflow); - /* Fail if the secret key is invalid. */ - if (!overflow && !secp256k1_scalar_is_zero(&sec)) { - secp256k1_scalar_set_b32(&msg, msg32, NULL); - while (1) { - unsigned char nonce32[32]; - ret = noncefp(nonce32, msg32, seckey, count, noncedata); - if (!ret) { - break; - } - secp256k1_scalar_set_b32(&non, nonce32, &overflow); - memset(nonce32, 0, 32); - if (!secp256k1_scalar_is_zero(&non) && !overflow) { - if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &sig, &sec, &msg, &non, recid)) { - break; - } - } - count++; - } - if (ret) { - secp256k1_scalar_get_b32(sig64, &sig.r); - secp256k1_scalar_get_b32(sig64 + 32, &sig.s); - } - secp256k1_scalar_clear(&msg); - secp256k1_scalar_clear(&non); - secp256k1_scalar_clear(&sec); - } - if (!ret) { - memset(sig64, 0, 64); - } - return ret; -} - -int secp256k1_ecdsa_recover_compact(const secp256k1_context_t* ctx, const unsigned char *msg32, const unsigned char *sig64, unsigned char *pubkey, int *pubkeylen, int compressed, int recid) { - secp256k1_ge_t q; - secp256k1_ecdsa_sig_t sig; - secp256k1_scalar_t m; - int ret = 0; - int overflow = 0; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - DEBUG_CHECK(msg32 != NULL); - DEBUG_CHECK(sig64 != NULL); - DEBUG_CHECK(pubkey != NULL); - DEBUG_CHECK(pubkeylen != NULL); - DEBUG_CHECK(recid >= 0 && recid <= 3); - - secp256k1_scalar_set_b32(&sig.r, sig64, &overflow); - if (!overflow) { - secp256k1_scalar_set_b32(&sig.s, sig64 + 32, &overflow); - if (!overflow) { - secp256k1_scalar_set_b32(&m, msg32, NULL); - - if (secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &sig, &q, &m, recid)) { - ret = secp256k1_eckey_pubkey_serialize(&q, pubkey, pubkeylen, compressed); - } - } - } - return ret; -} - -int secp256k1_ec_seckey_verify(const secp256k1_context_t* ctx, const unsigned char *seckey) { - secp256k1_scalar_t sec; +int secp256k1_ec_seckey_verify(const secp256k1_context* ctx, const unsigned char *seckey) { + secp256k1_scalar sec; int ret; int overflow; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(seckey != NULL); - (void)ctx; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); secp256k1_scalar_set_b32(&sec, seckey, &overflow); - ret = !secp256k1_scalar_is_zero(&sec) && !overflow; + ret = !overflow && !secp256k1_scalar_is_zero(&sec); secp256k1_scalar_clear(&sec); return ret; } -int secp256k1_ec_pubkey_verify(const secp256k1_context_t* ctx, const unsigned char *pubkey, int pubkeylen) { - secp256k1_ge_t q; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(pubkey != NULL); - (void)ctx; - - return secp256k1_eckey_pubkey_parse(&q, pubkey, pubkeylen); -} - -int secp256k1_ec_pubkey_create(const secp256k1_context_t* ctx, unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed) { - secp256k1_gej_t pj; - secp256k1_ge_t p; - secp256k1_scalar_t sec; +int secp256k1_ec_pubkey_create(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *seckey) { + secp256k1_gej pj; + secp256k1_ge p; + secp256k1_scalar sec; int overflow; int ret = 0; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - DEBUG_CHECK(pubkey != NULL); - DEBUG_CHECK(pubkeylen != NULL); - DEBUG_CHECK(seckey != NULL); + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); + memset(pubkey, 0, sizeof(*pubkey)); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); + ARG_CHECK(seckey != NULL); secp256k1_scalar_set_b32(&sec, seckey, &overflow); - if (!overflow) { + ret = (!overflow) & (!secp256k1_scalar_is_zero(&sec)); + if (ret) { secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec); - secp256k1_scalar_clear(&sec); secp256k1_ge_set_gej(&p, &pj); - ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, pubkeylen, compressed); - } - if (!ret) { - *pubkeylen = 0; + secp256k1_pubkey_save(pubkey, &p); } + secp256k1_scalar_clear(&sec); return ret; } -int secp256k1_ec_pubkey_decompress(const secp256k1_context_t* ctx, unsigned char *pubkey, int *pubkeylen) { - secp256k1_ge_t p; +int secp256k1_ec_privkey_negate(const secp256k1_context* ctx, unsigned char *seckey) { + secp256k1_scalar sec; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + + secp256k1_scalar_set_b32(&sec, seckey, NULL); + secp256k1_scalar_negate(&sec, &sec); + secp256k1_scalar_get_b32(seckey, &sec); + + return 1; +} + +int secp256k1_ec_pubkey_negate(const secp256k1_context* ctx, secp256k1_pubkey *pubkey) { int ret = 0; - DEBUG_CHECK(pubkey != NULL); - DEBUG_CHECK(pubkeylen != NULL); - (void)ctx; + secp256k1_ge p; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(pubkey != NULL); - if (secp256k1_eckey_pubkey_parse(&p, pubkey, *pubkeylen)) { - ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, pubkeylen, 0); + ret = secp256k1_pubkey_load(ctx, &p, pubkey); + memset(pubkey, 0, sizeof(*pubkey)); + if (ret) { + secp256k1_ge_neg(&p, &p); + secp256k1_pubkey_save(pubkey, &p); } return ret; } -int secp256k1_ec_privkey_tweak_add(const secp256k1_context_t* ctx, unsigned char *seckey, const unsigned char *tweak) { - secp256k1_scalar_t term; - secp256k1_scalar_t sec; +int secp256k1_ec_privkey_tweak_add(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) { + secp256k1_scalar term; + secp256k1_scalar sec; int ret = 0; int overflow = 0; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(seckey != NULL); - DEBUG_CHECK(tweak != NULL); - (void)ctx; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + ARG_CHECK(tweak != NULL); secp256k1_scalar_set_b32(&term, tweak, &overflow); secp256k1_scalar_set_b32(&sec, seckey, NULL); - ret = secp256k1_eckey_privkey_tweak_add(&sec, &term) && !overflow; + ret = !overflow && secp256k1_eckey_privkey_tweak_add(&sec, &term); + memset(seckey, 0, 32); if (ret) { secp256k1_scalar_get_b32(seckey, &sec); } @@ -315,45 +474,43 @@ int secp256k1_ec_privkey_tweak_add(const secp256k1_context_t* ctx, unsigned char return ret; } -int secp256k1_ec_pubkey_tweak_add(const secp256k1_context_t* ctx, unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) { - secp256k1_ge_t p; - secp256k1_scalar_t term; +int secp256k1_ec_pubkey_tweak_add(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak) { + secp256k1_ge p; + secp256k1_scalar term; int ret = 0; int overflow = 0; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - DEBUG_CHECK(pubkey != NULL); - DEBUG_CHECK(tweak != NULL); + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(tweak != NULL); secp256k1_scalar_set_b32(&term, tweak, &overflow); - if (!overflow) { - ret = secp256k1_eckey_pubkey_parse(&p, pubkey, pubkeylen); - if (ret) { - ret = secp256k1_eckey_pubkey_tweak_add(&ctx->ecmult_ctx, &p, &term); - } - if (ret) { - int oldlen = pubkeylen; - ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33); - VERIFY_CHECK(pubkeylen == oldlen); + ret = !overflow && secp256k1_pubkey_load(ctx, &p, pubkey); + memset(pubkey, 0, sizeof(*pubkey)); + if (ret) { + if (secp256k1_eckey_pubkey_tweak_add(&ctx->ecmult_ctx, &p, &term)) { + secp256k1_pubkey_save(pubkey, &p); + } else { + ret = 0; } } return ret; } -int secp256k1_ec_privkey_tweak_mul(const secp256k1_context_t* ctx, unsigned char *seckey, const unsigned char *tweak) { - secp256k1_scalar_t factor; - secp256k1_scalar_t sec; +int secp256k1_ec_privkey_tweak_mul(const secp256k1_context* ctx, unsigned char *seckey, const unsigned char *tweak) { + secp256k1_scalar factor; + secp256k1_scalar sec; int ret = 0; int overflow = 0; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(seckey != NULL); - DEBUG_CHECK(tweak != NULL); - (void)ctx; + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(seckey != NULL); + ARG_CHECK(tweak != NULL); secp256k1_scalar_set_b32(&factor, tweak, &overflow); secp256k1_scalar_set_b32(&sec, seckey, NULL); - ret = secp256k1_eckey_privkey_tweak_mul(&sec, &factor) && !overflow; + ret = !overflow && secp256k1_eckey_privkey_tweak_mul(&sec, &factor); + memset(seckey, 0, 32); if (ret) { secp256k1_scalar_get_b32(seckey, &sec); } @@ -363,65 +520,65 @@ int secp256k1_ec_privkey_tweak_mul(const secp256k1_context_t* ctx, unsigned char return ret; } -int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context_t* ctx, unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) { - secp256k1_ge_t p; - secp256k1_scalar_t factor; +int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context* ctx, secp256k1_pubkey *pubkey, const unsigned char *tweak) { + secp256k1_ge p; + secp256k1_scalar factor; int ret = 0; int overflow = 0; - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); - DEBUG_CHECK(pubkey != NULL); - DEBUG_CHECK(tweak != NULL); + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(pubkey != NULL); + ARG_CHECK(tweak != NULL); secp256k1_scalar_set_b32(&factor, tweak, &overflow); - if (!overflow) { - ret = secp256k1_eckey_pubkey_parse(&p, pubkey, pubkeylen); - if (ret) { - ret = secp256k1_eckey_pubkey_tweak_mul(&ctx->ecmult_ctx, &p, &factor); - } - if (ret) { - int oldlen = pubkeylen; - ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33); - VERIFY_CHECK(pubkeylen == oldlen); - } - } - - return ret; -} - -int secp256k1_ec_privkey_export(const secp256k1_context_t* ctx, const unsigned char *seckey, unsigned char *privkey, int *privkeylen, int compressed) { - secp256k1_scalar_t key; - int ret = 0; - DEBUG_CHECK(seckey != NULL); - DEBUG_CHECK(privkey != NULL); - DEBUG_CHECK(privkeylen != NULL); - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); - - secp256k1_scalar_set_b32(&key, seckey, NULL); - ret = secp256k1_eckey_privkey_serialize(&ctx->ecmult_gen_ctx, privkey, privkeylen, &key, compressed); - secp256k1_scalar_clear(&key); - return ret; -} - -int secp256k1_ec_privkey_import(const secp256k1_context_t* ctx, unsigned char *seckey, const unsigned char *privkey, int privkeylen) { - secp256k1_scalar_t key; - int ret = 0; - DEBUG_CHECK(seckey != NULL); - DEBUG_CHECK(privkey != NULL); - (void)ctx; - - ret = secp256k1_eckey_privkey_parse(&key, privkey, privkeylen); + ret = !overflow && secp256k1_pubkey_load(ctx, &p, pubkey); + memset(pubkey, 0, sizeof(*pubkey)); if (ret) { - secp256k1_scalar_get_b32(seckey, &key); + if (secp256k1_eckey_pubkey_tweak_mul(&ctx->ecmult_ctx, &p, &factor)) { + secp256k1_pubkey_save(pubkey, &p); + } else { + ret = 0; + } } - secp256k1_scalar_clear(&key); + return ret; } -int secp256k1_context_randomize(secp256k1_context_t* ctx, const unsigned char *seed32) { - DEBUG_CHECK(ctx != NULL); - DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); +int secp256k1_context_randomize(secp256k1_context* ctx, const unsigned char *seed32) { + VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, seed32); return 1; } + +int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey *pubnonce, const secp256k1_pubkey * const *pubnonces, size_t n) { + size_t i; + secp256k1_gej Qj; + secp256k1_ge Q; + + ARG_CHECK(pubnonce != NULL); + memset(pubnonce, 0, sizeof(*pubnonce)); + ARG_CHECK(n >= 1); + ARG_CHECK(pubnonces != NULL); + + secp256k1_gej_set_infinity(&Qj); + + for (i = 0; i < n; i++) { + secp256k1_pubkey_load(ctx, &Q, pubnonces[i]); + secp256k1_gej_add_ge(&Qj, &Qj, &Q); + } + if (secp256k1_gej_is_infinity(&Qj)) { + return 0; + } + secp256k1_ge_set_gej(&Q, &Qj); + secp256k1_pubkey_save(pubnonce, &Q); + return 1; +} + +#ifdef ENABLE_MODULE_ECDH +# include "modules/ecdh/main_impl.h" +#endif + +#ifdef ENABLE_MODULE_RECOVERY +# include "modules/recovery/main_impl.h" +#endif diff --git a/src/cryptoconditions/src/include/secp256k1/src/testrand.h b/src/cryptoconditions/src/include/secp256k1/src/testrand.h index 041bb92c4..f1f9be077 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/testrand.h +++ b/src/cryptoconditions/src/include/secp256k1/src/testrand.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_TESTRAND_H_ -#define _SECP256K1_TESTRAND_H_ +#ifndef SECP256K1_TESTRAND_H +#define SECP256K1_TESTRAND_H #if defined HAVE_CONFIG_H #include "libsecp256k1-config.h" @@ -16,13 +16,23 @@ /** Seed the pseudorandom number generator for testing. */ SECP256K1_INLINE static void secp256k1_rand_seed(const unsigned char *seed16); -/** Generate a pseudorandom 32-bit number. */ +/** Generate a pseudorandom number in the range [0..2**32-1]. */ static uint32_t secp256k1_rand32(void); +/** Generate a pseudorandom number in the range [0..2**bits-1]. Bits must be 1 or + * more. */ +static uint32_t secp256k1_rand_bits(int bits); + +/** Generate a pseudorandom number in the range [0..range-1]. */ +static uint32_t secp256k1_rand_int(uint32_t range); + /** Generate a pseudorandom 32-byte array. */ static void secp256k1_rand256(unsigned char *b32); /** Generate a pseudorandom 32-byte array with long sequences of zero and one bits. */ static void secp256k1_rand256_test(unsigned char *b32); -#endif +/** Generate pseudorandom bytes with long sequences of zero and one bits. */ +static void secp256k1_rand_bytes_test(unsigned char *bytes, size_t len); + +#endif /* SECP256K1_TESTRAND_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/testrand_impl.h b/src/cryptoconditions/src/include/secp256k1/src/testrand_impl.h index 21c69f1c5..30a91e529 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/testrand_impl.h +++ b/src/cryptoconditions/src/include/secp256k1/src/testrand_impl.h @@ -1,11 +1,11 @@ /********************************************************************** - * Copyright (c) 2013, 2014 Pieter Wuille * + * Copyright (c) 2013-2015 Pieter Wuille * * Distributed under the MIT software license, see the accompanying * * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_TESTRAND_IMPL_H_ -#define _SECP256K1_TESTRAND_IMPL_H_ +#ifndef SECP256K1_TESTRAND_IMPL_H +#define SECP256K1_TESTRAND_IMPL_H #include #include @@ -13,12 +13,14 @@ #include "testrand.h" #include "hash.h" -static secp256k1_rfc6979_hmac_sha256_t secp256k1_test_rng; +static secp256k1_rfc6979_hmac_sha256 secp256k1_test_rng; static uint32_t secp256k1_test_rng_precomputed[8]; static int secp256k1_test_rng_precomputed_used = 8; +static uint64_t secp256k1_test_rng_integer; +static int secp256k1_test_rng_integer_bits_left = 0; SECP256K1_INLINE static void secp256k1_rand_seed(const unsigned char *seed16) { - secp256k1_rfc6979_hmac_sha256_initialize(&secp256k1_test_rng, (const unsigned char*)"TestRNG", 7, seed16, 16, NULL, 0); + secp256k1_rfc6979_hmac_sha256_initialize(&secp256k1_test_rng, seed16, 16); } SECP256K1_INLINE static uint32_t secp256k1_rand32(void) { @@ -29,32 +31,80 @@ SECP256K1_INLINE static uint32_t secp256k1_rand32(void) { return secp256k1_test_rng_precomputed[secp256k1_test_rng_precomputed_used++]; } +static uint32_t secp256k1_rand_bits(int bits) { + uint32_t ret; + if (secp256k1_test_rng_integer_bits_left < bits) { + secp256k1_test_rng_integer |= (((uint64_t)secp256k1_rand32()) << secp256k1_test_rng_integer_bits_left); + secp256k1_test_rng_integer_bits_left += 32; + } + ret = secp256k1_test_rng_integer; + secp256k1_test_rng_integer >>= bits; + secp256k1_test_rng_integer_bits_left -= bits; + ret &= ((~((uint32_t)0)) >> (32 - bits)); + return ret; +} + +static uint32_t secp256k1_rand_int(uint32_t range) { + /* We want a uniform integer between 0 and range-1, inclusive. + * B is the smallest number such that range <= 2**B. + * two mechanisms implemented here: + * - generate B bits numbers until one below range is found, and return it + * - find the largest multiple M of range that is <= 2**(B+A), generate B+A + * bits numbers until one below M is found, and return it modulo range + * The second mechanism consumes A more bits of entropy in every iteration, + * but may need fewer iterations due to M being closer to 2**(B+A) then + * range is to 2**B. The array below (indexed by B) contains a 0 when the + * first mechanism is to be used, and the number A otherwise. + */ + static const int addbits[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 1, 0}; + uint32_t trange, mult; + int bits = 0; + if (range <= 1) { + return 0; + } + trange = range - 1; + while (trange > 0) { + trange >>= 1; + bits++; + } + if (addbits[bits]) { + bits = bits + addbits[bits]; + mult = ((~((uint32_t)0)) >> (32 - bits)) / range; + trange = range * mult; + } else { + trange = range; + mult = 1; + } + while(1) { + uint32_t x = secp256k1_rand_bits(bits); + if (x < trange) { + return (mult == 1) ? x : (x % range); + } + } +} + static void secp256k1_rand256(unsigned char *b32) { secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, b32, 32); } -static void secp256k1_rand256_test(unsigned char *b32) { - int bits=0; - uint64_t ent = 0; - int entleft = 0; - memset(b32, 0, 32); - while (bits < 256) { +static void secp256k1_rand_bytes_test(unsigned char *bytes, size_t len) { + size_t bits = 0; + memset(bytes, 0, len); + while (bits < len * 8) { int now; uint32_t val; - if (entleft < 12) { - ent |= ((uint64_t)secp256k1_rand32()) << entleft; - entleft += 32; - } - now = 1 + ((ent % 64)*((ent >> 6) % 32)+16)/31; - val = 1 & (ent >> 11); - ent >>= 12; - entleft -= 12; - while (now > 0 && bits < 256) { - b32[bits / 8] |= val << (bits % 8); + now = 1 + (secp256k1_rand_bits(6) * secp256k1_rand_bits(5) + 16) / 31; + val = secp256k1_rand_bits(1); + while (now > 0 && bits < len * 8) { + bytes[bits / 8] |= val << (bits % 8); now--; bits++; } } } -#endif +static void secp256k1_rand256_test(unsigned char *b32) { + secp256k1_rand_bytes_test(b32, 32); +} + +#endif /* SECP256K1_TESTRAND_IMPL_H */ diff --git a/src/cryptoconditions/src/include/secp256k1/src/tests.c b/src/cryptoconditions/src/include/secp256k1/src/tests.c index d0e05057f..f307b99d5 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/tests.c +++ b/src/cryptoconditions/src/include/secp256k1/src/tests.c @@ -10,10 +10,12 @@ #include #include +#include #include #include "secp256k1.c" +#include "include/secp256k1.h" #include "testrand_impl.h" #ifdef ENABLE_OPENSSL_TESTS @@ -23,10 +25,40 @@ #include "openssl/obj_mac.h" #endif -static int count = 64; -static secp256k1_context_t *ctx = NULL; +#include "contrib/lax_der_parsing.c" +#include "contrib/lax_der_privatekey_parsing.c" -void random_field_element_test(secp256k1_fe_t *fe) { +#if !defined(VG_CHECK) +# if defined(VALGRIND) +# include +# define VG_UNDEF(x,y) VALGRIND_MAKE_MEM_UNDEFINED((x),(y)) +# define VG_CHECK(x,y) VALGRIND_CHECK_MEM_IS_DEFINED((x),(y)) +# else +# define VG_UNDEF(x,y) +# define VG_CHECK(x,y) +# endif +#endif + +static int count = 64; +static secp256k1_context *ctx = NULL; + +static void counting_illegal_callback_fn(const char* str, void* data) { + /* Dummy callback function that just counts. */ + int32_t *p; + (void)str; + p = data; + (*p)++; +} + +static void uncounting_illegal_callback_fn(const char* str, void* data) { + /* Dummy callback function that just counts (backwards). */ + int32_t *p; + (void)str; + p = data; + (*p)--; +} + +void random_field_element_test(secp256k1_fe *fe) { do { unsigned char b32[32]; secp256k1_rand256_test(b32); @@ -36,9 +68,9 @@ void random_field_element_test(secp256k1_fe_t *fe) { } while(1); } -void random_field_element_magnitude(secp256k1_fe_t *fe) { - secp256k1_fe_t zero; - int n = secp256k1_rand32() % 9; +void random_field_element_magnitude(secp256k1_fe *fe) { + secp256k1_fe zero; + int n = secp256k1_rand_int(9); secp256k1_fe_normalize(fe); if (n == 0) { return; @@ -47,23 +79,22 @@ void random_field_element_magnitude(secp256k1_fe_t *fe) { secp256k1_fe_negate(&zero, &zero, 0); secp256k1_fe_mul_int(&zero, n - 1); secp256k1_fe_add(fe, &zero); -#ifdef VERIFY - CHECK(fe->magnitude == n); -#endif + VERIFY_CHECK(fe->magnitude == n); } -void random_group_element_test(secp256k1_ge_t *ge) { - secp256k1_fe_t fe; +void random_group_element_test(secp256k1_ge *ge) { + secp256k1_fe fe; do { random_field_element_test(&fe); - if (secp256k1_ge_set_xo_var(ge, &fe, secp256k1_rand32() & 1)) { + if (secp256k1_ge_set_xo_var(ge, &fe, secp256k1_rand_bits(1))) { + secp256k1_fe_normalize(&ge->y); break; } } while(1); } -void random_group_element_jacobian_test(secp256k1_gej_t *gej, const secp256k1_ge_t *ge) { - secp256k1_fe_t z2, z3; +void random_group_element_jacobian_test(secp256k1_gej *gej, const secp256k1_ge *ge) { + secp256k1_fe z2, z3; do { random_field_element_test(&gej->z); if (!secp256k1_fe_is_zero(&gej->z)) { @@ -77,7 +108,7 @@ void random_group_element_jacobian_test(secp256k1_gej_t *gej, const secp256k1_ge gej->infinity = ge->infinity; } -void random_scalar_order_test(secp256k1_scalar_t *num) { +void random_scalar_order_test(secp256k1_scalar *num) { do { unsigned char b32[32]; int overflow = 0; @@ -90,7 +121,7 @@ void random_scalar_order_test(secp256k1_scalar_t *num) { } while(1); } -void random_scalar_order(secp256k1_scalar_t *num) { +void random_scalar_order(secp256k1_scalar *num) { do { unsigned char b32[32]; int overflow = 0; @@ -104,19 +135,34 @@ void random_scalar_order(secp256k1_scalar_t *num) { } void run_context_tests(void) { - secp256k1_context_t *none = secp256k1_context_create(0); - secp256k1_context_t *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); - secp256k1_context_t *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); - secp256k1_context_t *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + secp256k1_pubkey pubkey; + secp256k1_pubkey zero_pubkey; + secp256k1_ecdsa_signature sig; + unsigned char ctmp[32]; + int32_t ecount; + int32_t ecount2; + secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - secp256k1_gej_t pubj; - secp256k1_ge_t pub; - secp256k1_scalar_t msg, key, nonce; - secp256k1_ecdsa_sig_t sig; + secp256k1_gej pubj; + secp256k1_ge pub; + secp256k1_scalar msg, key, nonce; + secp256k1_scalar sigr, sigs; + + memset(&zero_pubkey, 0, sizeof(zero_pubkey)); + + ecount = 0; + ecount2 = 10; + secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount2); + secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, NULL); + CHECK(vrfy->error_callback.fn != sign->error_callback.fn); /*** clone and destroy all of them to make sure cloning was complete ***/ { - secp256k1_context_t *ctx_tmp; + secp256k1_context *ctx_tmp; ctx_tmp = none; none = secp256k1_context_clone(none); secp256k1_context_destroy(ctx_tmp); ctx_tmp = sign; sign = secp256k1_context_clone(sign); secp256k1_context_destroy(ctx_tmp); @@ -124,30 +170,82 @@ void run_context_tests(void) { ctx_tmp = both; both = secp256k1_context_clone(both); secp256k1_context_destroy(ctx_tmp); } + /* Verify that the error callback makes it across the clone. */ + CHECK(vrfy->error_callback.fn != sign->error_callback.fn); + /* And that it resets back to default. */ + secp256k1_context_set_error_callback(sign, NULL, NULL); + CHECK(vrfy->error_callback.fn == sign->error_callback.fn); + /*** attempt to use them ***/ random_scalar_order_test(&msg); random_scalar_order_test(&key); secp256k1_ecmult_gen(&both->ecmult_gen_ctx, &pubj, &key); secp256k1_ge_set_gej(&pub, &pubj); + /* Verify context-type checking illegal-argument errors. */ + memset(ctmp, 1, 32); + CHECK(secp256k1_ec_pubkey_create(vrfy, &pubkey, ctmp) == 0); + CHECK(ecount == 1); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(sign, &pubkey, ctmp) == 1); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ecdsa_sign(vrfy, &sig, ctmp, ctmp, NULL, NULL) == 0); + CHECK(ecount == 2); + VG_UNDEF(&sig, sizeof(sig)); + CHECK(secp256k1_ecdsa_sign(sign, &sig, ctmp, ctmp, NULL, NULL) == 1); + VG_CHECK(&sig, sizeof(sig)); + CHECK(ecount2 == 10); + CHECK(secp256k1_ecdsa_verify(sign, &sig, ctmp, &pubkey) == 0); + CHECK(ecount2 == 11); + CHECK(secp256k1_ecdsa_verify(vrfy, &sig, ctmp, &pubkey) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_ec_pubkey_tweak_add(sign, &pubkey, ctmp) == 0); + CHECK(ecount2 == 12); + CHECK(secp256k1_ec_pubkey_tweak_add(vrfy, &pubkey, ctmp) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_ec_pubkey_tweak_mul(sign, &pubkey, ctmp) == 0); + CHECK(ecount2 == 13); + CHECK(secp256k1_ec_pubkey_negate(vrfy, &pubkey) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_ec_pubkey_negate(sign, &pubkey) == 1); + CHECK(ecount == 2); + CHECK(secp256k1_ec_pubkey_negate(sign, NULL) == 0); + CHECK(ecount2 == 14); + CHECK(secp256k1_ec_pubkey_negate(vrfy, &zero_pubkey) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_ec_pubkey_tweak_mul(vrfy, &pubkey, ctmp) == 1); + CHECK(ecount == 3); + CHECK(secp256k1_context_randomize(vrfy, ctmp) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_context_randomize(sign, NULL) == 1); + CHECK(ecount2 == 14); + secp256k1_context_set_illegal_callback(vrfy, NULL, NULL); + secp256k1_context_set_illegal_callback(sign, NULL, NULL); + + /* This shouldn't leak memory, due to already-set tests. */ + secp256k1_ecmult_gen_context_build(&sign->ecmult_gen_ctx, NULL); + secp256k1_ecmult_context_build(&vrfy->ecmult_ctx, NULL); + /* obtain a working nonce */ do { random_scalar_order_test(&nonce); - } while(!secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sig, &key, &msg, &nonce, NULL)); + } while(!secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); /* try signing */ - CHECK(secp256k1_ecdsa_sig_sign(&sign->ecmult_gen_ctx, &sig, &key, &msg, &nonce, NULL)); - CHECK(secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sig, &key, &msg, &nonce, NULL)); + CHECK(secp256k1_ecdsa_sig_sign(&sign->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); + CHECK(secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL)); /* try verifying */ - CHECK(secp256k1_ecdsa_sig_verify(&vrfy->ecmult_ctx, &sig, &pub, &msg)); - CHECK(secp256k1_ecdsa_sig_verify(&both->ecmult_ctx, &sig, &pub, &msg)); + CHECK(secp256k1_ecdsa_sig_verify(&vrfy->ecmult_ctx, &sigr, &sigs, &pub, &msg)); + CHECK(secp256k1_ecdsa_sig_verify(&both->ecmult_ctx, &sigr, &sigs, &pub, &msg)); /* cleanup */ secp256k1_context_destroy(none); secp256k1_context_destroy(sign); secp256k1_context_destroy(vrfy); secp256k1_context_destroy(both); + /* Defined as no-op. */ + secp256k1_context_destroy(NULL); } /***** HASH TESTS *****/ @@ -172,13 +270,13 @@ void run_sha256_tests(void) { int i; for (i = 0; i < 8; i++) { unsigned char out[32]; - secp256k1_sha256_t hasher; + secp256k1_sha256 hasher; secp256k1_sha256_initialize(&hasher); secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); secp256k1_sha256_finalize(&hasher, out); CHECK(memcmp(out, outputs[i], 32) == 0); if (strlen(inputs[i]) > 0) { - int split = secp256k1_rand32() % strlen(inputs[i]); + int split = secp256k1_rand_int(strlen(inputs[i])); secp256k1_sha256_initialize(&hasher); secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); secp256k1_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); @@ -215,14 +313,14 @@ void run_hmac_sha256_tests(void) { }; int i; for (i = 0; i < 6; i++) { - secp256k1_hmac_sha256_t hasher; + secp256k1_hmac_sha256 hasher; unsigned char out[32]; secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), strlen(inputs[i])); secp256k1_hmac_sha256_finalize(&hasher, out); CHECK(memcmp(out, outputs[i], 32) == 0); if (strlen(inputs[i]) > 0) { - int split = secp256k1_rand32() % strlen(inputs[i]); + int split = secp256k1_rand_int(strlen(inputs[i])); secp256k1_hmac_sha256_initialize(&hasher, (const unsigned char*)(keys[i]), strlen(keys[i])); secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i]), split); secp256k1_hmac_sha256_write(&hasher, (const unsigned char*)(inputs[i] + split), strlen(inputs[i]) - split); @@ -233,42 +331,39 @@ void run_hmac_sha256_tests(void) { } void run_rfc6979_hmac_sha256_tests(void) { - static const unsigned char key1[32] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00}; - static const unsigned char msg1[32] = {0x4b, 0xf5, 0x12, 0x2f, 0x34, 0x45, 0x54, 0xc5, 0x3b, 0xde, 0x2e, 0xbb, 0x8c, 0xd2, 0xb7, 0xe3, 0xd1, 0x60, 0x0a, 0xd6, 0x31, 0xc3, 0x85, 0xa5, 0xd7, 0xcc, 0xe2, 0x3c, 0x77, 0x85, 0x45, 0x9a}; + static const unsigned char key1[65] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x00, 0x4b, 0xf5, 0x12, 0x2f, 0x34, 0x45, 0x54, 0xc5, 0x3b, 0xde, 0x2e, 0xbb, 0x8c, 0xd2, 0xb7, 0xe3, 0xd1, 0x60, 0x0a, 0xd6, 0x31, 0xc3, 0x85, 0xa5, 0xd7, 0xcc, 0xe2, 0x3c, 0x77, 0x85, 0x45, 0x9a, 0}; static const unsigned char out1[3][32] = { {0x4f, 0xe2, 0x95, 0x25, 0xb2, 0x08, 0x68, 0x09, 0x15, 0x9a, 0xcd, 0xf0, 0x50, 0x6e, 0xfb, 0x86, 0xb0, 0xec, 0x93, 0x2c, 0x7b, 0xa4, 0x42, 0x56, 0xab, 0x32, 0x1e, 0x42, 0x1e, 0x67, 0xe9, 0xfb}, {0x2b, 0xf0, 0xff, 0xf1, 0xd3, 0xc3, 0x78, 0xa2, 0x2d, 0xc5, 0xde, 0x1d, 0x85, 0x65, 0x22, 0x32, 0x5c, 0x65, 0xb5, 0x04, 0x49, 0x1a, 0x0c, 0xbd, 0x01, 0xcb, 0x8f, 0x3a, 0xa6, 0x7f, 0xfd, 0x4a}, {0xf5, 0x28, 0xb4, 0x10, 0xcb, 0x54, 0x1f, 0x77, 0x00, 0x0d, 0x7a, 0xfb, 0x6c, 0x5b, 0x53, 0xc5, 0xc4, 0x71, 0xea, 0xb4, 0x3e, 0x46, 0x6d, 0x9a, 0xc5, 0x19, 0x0c, 0x39, 0xc8, 0x2f, 0xd8, 0x2e} }; - static const unsigned char key2[32] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - static const unsigned char msg2[32] = {0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}; + static const unsigned char key2[64] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55}; static const unsigned char out2[3][32] = { {0x9c, 0x23, 0x6c, 0x16, 0x5b, 0x82, 0xae, 0x0c, 0xd5, 0x90, 0x65, 0x9e, 0x10, 0x0b, 0x6b, 0xab, 0x30, 0x36, 0xe7, 0xba, 0x8b, 0x06, 0x74, 0x9b, 0xaf, 0x69, 0x81, 0xe1, 0x6f, 0x1a, 0x2b, 0x95}, {0xdf, 0x47, 0x10, 0x61, 0x62, 0x5b, 0xc0, 0xea, 0x14, 0xb6, 0x82, 0xfe, 0xee, 0x2c, 0x9c, 0x02, 0xf2, 0x35, 0xda, 0x04, 0x20, 0x4c, 0x1d, 0x62, 0xa1, 0x53, 0x6c, 0x6e, 0x17, 0xae, 0xd7, 0xa9}, {0x75, 0x97, 0x88, 0x7c, 0xbd, 0x76, 0x32, 0x1f, 0x32, 0xe3, 0x04, 0x40, 0x67, 0x9a, 0x22, 0xcf, 0x7f, 0x8d, 0x9d, 0x2e, 0xac, 0x39, 0x0e, 0x58, 0x1f, 0xea, 0x09, 0x1c, 0xe2, 0x02, 0xba, 0x94} }; - secp256k1_rfc6979_hmac_sha256_t rng; + secp256k1_rfc6979_hmac_sha256 rng; unsigned char out[32]; - unsigned char zero[1] = {0}; int i; - secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 32, msg1, 32, NULL, 1); + secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 64); for (i = 0; i < 3; i++) { secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); CHECK(memcmp(out, out1[i], 32) == 0); } secp256k1_rfc6979_hmac_sha256_finalize(&rng); - secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 32, msg1, 32, zero, 1); + secp256k1_rfc6979_hmac_sha256_initialize(&rng, key1, 65); for (i = 0; i < 3; i++) { secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); CHECK(memcmp(out, out1[i], 32) != 0); } secp256k1_rfc6979_hmac_sha256_finalize(&rng); - secp256k1_rfc6979_hmac_sha256_initialize(&rng, key2, 32, msg2, 32, zero, 0); + secp256k1_rfc6979_hmac_sha256_initialize(&rng, key2, 64); for (i = 0; i < 3; i++) { secp256k1_rfc6979_hmac_sha256_generate(&rng, out, 32); CHECK(memcmp(out, out2[i], 32) == 0); @@ -276,30 +371,102 @@ void run_rfc6979_hmac_sha256_tests(void) { secp256k1_rfc6979_hmac_sha256_finalize(&rng); } +/***** RANDOM TESTS *****/ + +void test_rand_bits(int rand32, int bits) { + /* (1-1/2^B)^rounds[B] < 1/10^9, so rounds is the number of iterations to + * get a false negative chance below once in a billion */ + static const unsigned int rounds[7] = {1, 30, 73, 156, 322, 653, 1316}; + /* We try multiplying the results with various odd numbers, which shouldn't + * influence the uniform distribution modulo a power of 2. */ + static const uint32_t mults[6] = {1, 3, 21, 289, 0x9999, 0x80402011}; + /* We only select up to 6 bits from the output to analyse */ + unsigned int usebits = bits > 6 ? 6 : bits; + unsigned int maxshift = bits - usebits; + /* For each of the maxshift+1 usebits-bit sequences inside a bits-bit + number, track all observed outcomes, one per bit in a uint64_t. */ + uint64_t x[6][27] = {{0}}; + unsigned int i, shift, m; + /* Multiply the output of all rand calls with the odd number m, which + should not change the uniformity of its distribution. */ + for (i = 0; i < rounds[usebits]; i++) { + uint32_t r = (rand32 ? secp256k1_rand32() : secp256k1_rand_bits(bits)); + CHECK((((uint64_t)r) >> bits) == 0); + for (m = 0; m < sizeof(mults) / sizeof(mults[0]); m++) { + uint32_t rm = r * mults[m]; + for (shift = 0; shift <= maxshift; shift++) { + x[m][shift] |= (((uint64_t)1) << ((rm >> shift) & ((1 << usebits) - 1))); + } + } + } + for (m = 0; m < sizeof(mults) / sizeof(mults[0]); m++) { + for (shift = 0; shift <= maxshift; shift++) { + /* Test that the lower usebits bits of x[shift] are 1 */ + CHECK(((~x[m][shift]) << (64 - (1 << usebits))) == 0); + } + } +} + +/* Subrange must be a whole divisor of range, and at most 64 */ +void test_rand_int(uint32_t range, uint32_t subrange) { + /* (1-1/subrange)^rounds < 1/10^9 */ + int rounds = (subrange * 2073) / 100; + int i; + uint64_t x = 0; + CHECK((range % subrange) == 0); + for (i = 0; i < rounds; i++) { + uint32_t r = secp256k1_rand_int(range); + CHECK(r < range); + r = r % subrange; + x |= (((uint64_t)1) << r); + } + /* Test that the lower subrange bits of x are 1. */ + CHECK(((~x) << (64 - subrange)) == 0); +} + +void run_rand_bits(void) { + size_t b; + test_rand_bits(1, 32); + for (b = 1; b <= 32; b++) { + test_rand_bits(0, b); + } +} + +void run_rand_int(void) { + static const uint32_t ms[] = {1, 3, 17, 1000, 13771, 999999, 33554432}; + static const uint32_t ss[] = {1, 3, 6, 9, 13, 31, 64}; + unsigned int m, s; + for (m = 0; m < sizeof(ms) / sizeof(ms[0]); m++) { + for (s = 0; s < sizeof(ss) / sizeof(ss[0]); s++) { + test_rand_int(ms[m] * ss[s], ss[s]); + } + } +} + /***** NUM TESTS *****/ #ifndef USE_NUM_NONE -void random_num_negate(secp256k1_num_t *num) { - if (secp256k1_rand32() & 1) { +void random_num_negate(secp256k1_num *num) { + if (secp256k1_rand_bits(1)) { secp256k1_num_negate(num); } } -void random_num_order_test(secp256k1_num_t *num) { - secp256k1_scalar_t sc; +void random_num_order_test(secp256k1_num *num) { + secp256k1_scalar sc; random_scalar_order_test(&sc); secp256k1_scalar_get_num(num, &sc); } -void random_num_order(secp256k1_num_t *num) { - secp256k1_scalar_t sc; +void random_num_order(secp256k1_num *num) { + secp256k1_scalar sc; random_scalar_order(&sc); secp256k1_scalar_get_num(num, &sc); } void test_num_negate(void) { - secp256k1_num_t n1; - secp256k1_num_t n2; + secp256k1_num n1; + secp256k1_num n2; random_num_order_test(&n1); /* n1 = R */ random_num_negate(&n1); secp256k1_num_copy(&n2, &n1); /* n2 = R */ @@ -318,16 +485,17 @@ void test_num_negate(void) { } void test_num_add_sub(void) { - secp256k1_num_t n1; - secp256k1_num_t n2; - secp256k1_num_t n1p2, n2p1, n1m2, n2m1; - int r = secp256k1_rand32(); + int i; + secp256k1_scalar s; + secp256k1_num n1; + secp256k1_num n2; + secp256k1_num n1p2, n2p1, n1m2, n2m1; random_num_order_test(&n1); /* n1 = R1 */ - if (r & 1) { + if (secp256k1_rand_bits(1)) { random_num_negate(&n1); } random_num_order_test(&n2); /* n2 = R2 */ - if (r & 2) { + if (secp256k1_rand_bits(1)) { random_num_negate(&n2); } secp256k1_num_add(&n1p2, &n1, &n2); /* n1p2 = R1 + R2 */ @@ -344,6 +512,110 @@ void test_num_add_sub(void) { CHECK(!secp256k1_num_eq(&n2p1, &n1)); secp256k1_num_sub(&n2p1, &n2p1, &n2); /* n2p1 = R2 + R1 - R2 = R1 */ CHECK(secp256k1_num_eq(&n2p1, &n1)); + + /* check is_one */ + secp256k1_scalar_set_int(&s, 1); + secp256k1_scalar_get_num(&n1, &s); + CHECK(secp256k1_num_is_one(&n1)); + /* check that 2^n + 1 is never 1 */ + secp256k1_scalar_get_num(&n2, &s); + for (i = 0; i < 250; ++i) { + secp256k1_num_add(&n1, &n1, &n1); /* n1 *= 2 */ + secp256k1_num_add(&n1p2, &n1, &n2); /* n1p2 = n1 + 1 */ + CHECK(!secp256k1_num_is_one(&n1p2)); + } +} + +void test_num_mod(void) { + int i; + secp256k1_scalar s; + secp256k1_num order, n; + + /* check that 0 mod anything is 0 */ + random_scalar_order_test(&s); + secp256k1_scalar_get_num(&order, &s); + secp256k1_scalar_set_int(&s, 0); + secp256k1_scalar_get_num(&n, &s); + secp256k1_num_mod(&n, &order); + CHECK(secp256k1_num_is_zero(&n)); + + /* check that anything mod 1 is 0 */ + secp256k1_scalar_set_int(&s, 1); + secp256k1_scalar_get_num(&order, &s); + secp256k1_scalar_get_num(&n, &s); + secp256k1_num_mod(&n, &order); + CHECK(secp256k1_num_is_zero(&n)); + + /* check that increasing the number past 2^256 does not break this */ + random_scalar_order_test(&s); + secp256k1_scalar_get_num(&n, &s); + /* multiply by 2^8, which'll test this case with high probability */ + for (i = 0; i < 8; ++i) { + secp256k1_num_add(&n, &n, &n); + } + secp256k1_num_mod(&n, &order); + CHECK(secp256k1_num_is_zero(&n)); +} + +void test_num_jacobi(void) { + secp256k1_scalar sqr; + secp256k1_scalar small; + secp256k1_scalar five; /* five is not a quadratic residue */ + secp256k1_num order, n; + int i; + /* squares mod 5 are 1, 4 */ + const int jacobi5[10] = { 0, 1, -1, -1, 1, 0, 1, -1, -1, 1 }; + + /* check some small values with 5 as the order */ + secp256k1_scalar_set_int(&five, 5); + secp256k1_scalar_get_num(&order, &five); + for (i = 0; i < 10; ++i) { + secp256k1_scalar_set_int(&small, i); + secp256k1_scalar_get_num(&n, &small); + CHECK(secp256k1_num_jacobi(&n, &order) == jacobi5[i]); + } + + /** test large values with 5 as group order */ + secp256k1_scalar_get_num(&order, &five); + /* we first need a scalar which is not a multiple of 5 */ + do { + secp256k1_num fiven; + random_scalar_order_test(&sqr); + secp256k1_scalar_get_num(&fiven, &five); + secp256k1_scalar_get_num(&n, &sqr); + secp256k1_num_mod(&n, &fiven); + } while (secp256k1_num_is_zero(&n)); + /* next force it to be a residue. 2 is a nonresidue mod 5 so we can + * just multiply by two, i.e. add the number to itself */ + if (secp256k1_num_jacobi(&n, &order) == -1) { + secp256k1_num_add(&n, &n, &n); + } + + /* test residue */ + CHECK(secp256k1_num_jacobi(&n, &order) == 1); + /* test nonresidue */ + secp256k1_num_add(&n, &n, &n); + CHECK(secp256k1_num_jacobi(&n, &order) == -1); + + /** test with secp group order as order */ + secp256k1_scalar_order_get_num(&order); + random_scalar_order_test(&sqr); + secp256k1_scalar_sqr(&sqr, &sqr); + /* test residue */ + secp256k1_scalar_get_num(&n, &sqr); + CHECK(secp256k1_num_jacobi(&n, &order) == 1); + /* test nonresidue */ + secp256k1_scalar_mul(&sqr, &sqr, &five); + secp256k1_scalar_get_num(&n, &sqr); + CHECK(secp256k1_num_jacobi(&n, &order) == -1); + /* test multiple of the order*/ + CHECK(secp256k1_num_jacobi(&order, &order) == 0); + + /* check one less than the order */ + secp256k1_scalar_set_int(&small, 1); + secp256k1_scalar_get_num(&n, &small); + secp256k1_num_sub(&n, &order, &n); + CHECK(secp256k1_num_jacobi(&n, &order) == 1); /* sage confirms this is 1 */ } void run_num_smalltests(void) { @@ -351,6 +623,8 @@ void run_num_smalltests(void) { for (i = 0; i < 100*count; i++) { test_num_negate(); test_num_add_sub(); + test_num_mod(); + test_num_jacobi(); } } #endif @@ -358,12 +632,12 @@ void run_num_smalltests(void) { /***** SCALAR TESTS *****/ void scalar_test(void) { - secp256k1_scalar_t s; - secp256k1_scalar_t s1; - secp256k1_scalar_t s2; + secp256k1_scalar s; + secp256k1_scalar s1; + secp256k1_scalar s2; #ifndef USE_NUM_NONE - secp256k1_num_t snum, s1num, s2num; - secp256k1_num_t order, half_order; + secp256k1_num snum, s1num, s2num; + secp256k1_num order, half_order; #endif unsigned char c[32]; @@ -390,10 +664,10 @@ void scalar_test(void) { { int i; /* Test that fetching groups of 4 bits from a scalar and recursing n(i)=16*n(i-1)+p(i) reconstructs it. */ - secp256k1_scalar_t n; + secp256k1_scalar n; secp256k1_scalar_set_int(&n, 0); for (i = 0; i < 256; i += 4) { - secp256k1_scalar_t t; + secp256k1_scalar t; int j; secp256k1_scalar_set_int(&t, secp256k1_scalar_get_bits(&s, 256 - 4 - i, 4)); for (j = 0; j < 4; j++) { @@ -406,13 +680,13 @@ void scalar_test(void) { { /* Test that fetching groups of randomly-sized bits from a scalar and recursing n(i)=b*n(i-1)+p(i) reconstructs it. */ - secp256k1_scalar_t n; + secp256k1_scalar n; int i = 0; secp256k1_scalar_set_int(&n, 0); while (i < 256) { - secp256k1_scalar_t t; + secp256k1_scalar t; int j; - int now = (secp256k1_rand32() % 15) + 1; + int now = secp256k1_rand_int(15) + 1; if (now + i > 256) { now = 256 - i; } @@ -429,9 +703,9 @@ void scalar_test(void) { #ifndef USE_NUM_NONE { /* Test that adding the scalars together is equal to adding their numbers together modulo the order. */ - secp256k1_num_t rnum; - secp256k1_num_t r2num; - secp256k1_scalar_t r; + secp256k1_num rnum; + secp256k1_num r2num; + secp256k1_scalar r; secp256k1_num_add(&rnum, &snum, &s2num); secp256k1_num_mod(&rnum, &order); secp256k1_scalar_add(&r, &s, &s2); @@ -440,10 +714,10 @@ void scalar_test(void) { } { - /* Test that multipying the scalars is equal to multiplying their numbers modulo the order. */ - secp256k1_scalar_t r; - secp256k1_num_t r2num; - secp256k1_num_t rnum; + /* Test that multiplying the scalars is equal to multiplying their numbers modulo the order. */ + secp256k1_scalar r; + secp256k1_num r2num; + secp256k1_num rnum; secp256k1_num_mul(&rnum, &snum, &s2num); secp256k1_num_mod(&rnum, &order); secp256k1_scalar_mul(&r, &s, &s2); @@ -457,9 +731,9 @@ void scalar_test(void) { } { - secp256k1_scalar_t neg; - secp256k1_num_t negnum; - secp256k1_num_t negnum2; + secp256k1_scalar neg; + secp256k1_num negnum; + secp256k1_num negnum2; /* Check that comparison with zero matches comparison with zero on the number. */ CHECK(secp256k1_num_is_zero(&snum) == secp256k1_scalar_is_zero(&s)); /* Check that comparison with the half order is equal to testing for high scalar. */ @@ -484,12 +758,12 @@ void scalar_test(void) { { /* Test secp256k1_scalar_mul_shift_var. */ - secp256k1_scalar_t r; - secp256k1_num_t one; - secp256k1_num_t rnum; - secp256k1_num_t rnum2; + secp256k1_scalar r; + secp256k1_num one; + secp256k1_num rnum; + secp256k1_num rnum2; unsigned char cone[1] = {0x01}; - unsigned int shift = 256 + (secp256k1_rand32() % 257); + unsigned int shift = 256 + secp256k1_rand_int(257); secp256k1_scalar_mul_shift_var(&r, &s1, &s2, shift); secp256k1_num_mul(&rnum, &s1num, &s2num); secp256k1_num_shift(&rnum, shift - 1); @@ -499,15 +773,29 @@ void scalar_test(void) { secp256k1_scalar_get_num(&rnum2, &r); CHECK(secp256k1_num_eq(&rnum, &rnum2)); } + + { + /* test secp256k1_scalar_shr_int */ + secp256k1_scalar r; + int i; + random_scalar_order_test(&r); + for (i = 0; i < 100; ++i) { + int low; + int shift = 1 + secp256k1_rand_int(15); + int expected = r.d[0] % (1 << shift); + low = secp256k1_scalar_shr_int(&r, shift); + CHECK(expected == low); + } + } #endif { /* Test that scalar inverses are equal to the inverse of their number modulo the order. */ if (!secp256k1_scalar_is_zero(&s)) { - secp256k1_scalar_t inv; + secp256k1_scalar inv; #ifndef USE_NUM_NONE - secp256k1_num_t invnum; - secp256k1_num_t invnum2; + secp256k1_num invnum; + secp256k1_num invnum2; #endif secp256k1_scalar_inverse(&inv, &s); #ifndef USE_NUM_NONE @@ -521,23 +809,27 @@ void scalar_test(void) { secp256k1_scalar_inverse(&inv, &inv); /* Inverting one must result in one. */ CHECK(secp256k1_scalar_is_one(&inv)); +#ifndef USE_NUM_NONE + secp256k1_scalar_get_num(&invnum, &inv); + CHECK(secp256k1_num_is_one(&invnum)); +#endif } } { /* Test commutativity of add. */ - secp256k1_scalar_t r1, r2; + secp256k1_scalar r1, r2; secp256k1_scalar_add(&r1, &s1, &s2); secp256k1_scalar_add(&r2, &s2, &s1); CHECK(secp256k1_scalar_eq(&r1, &r2)); } { - secp256k1_scalar_t r1, r2; - secp256k1_scalar_t b; + secp256k1_scalar r1, r2; + secp256k1_scalar b; int i; /* Test add_bit. */ - int bit = secp256k1_rand32() % 256; + int bit = secp256k1_rand_bits(8); secp256k1_scalar_set_int(&b, 1); CHECK(secp256k1_scalar_is_one(&b)); for (i = 0; i < bit; i++) { @@ -547,14 +839,17 @@ void scalar_test(void) { r2 = s1; if (!secp256k1_scalar_add(&r1, &r1, &b)) { /* No overflow happened. */ - secp256k1_scalar_add_bit(&r2, bit); + secp256k1_scalar_cadd_bit(&r2, bit, 1); + CHECK(secp256k1_scalar_eq(&r1, &r2)); + /* cadd is a noop when flag is zero */ + secp256k1_scalar_cadd_bit(&r2, bit, 0); CHECK(secp256k1_scalar_eq(&r1, &r2)); } } { /* Test commutativity of mul. */ - secp256k1_scalar_t r1, r2; + secp256k1_scalar r1, r2; secp256k1_scalar_mul(&r1, &s1, &s2); secp256k1_scalar_mul(&r2, &s2, &s1); CHECK(secp256k1_scalar_eq(&r1, &r2)); @@ -562,7 +857,7 @@ void scalar_test(void) { { /* Test associativity of add. */ - secp256k1_scalar_t r1, r2; + secp256k1_scalar r1, r2; secp256k1_scalar_add(&r1, &s1, &s2); secp256k1_scalar_add(&r1, &r1, &s); secp256k1_scalar_add(&r2, &s2, &s); @@ -572,7 +867,7 @@ void scalar_test(void) { { /* Test associativity of mul. */ - secp256k1_scalar_t r1, r2; + secp256k1_scalar r1, r2; secp256k1_scalar_mul(&r1, &s1, &s2); secp256k1_scalar_mul(&r1, &r1, &s); secp256k1_scalar_mul(&r2, &s2, &s); @@ -582,7 +877,7 @@ void scalar_test(void) { { /* Test distributitivity of mul over add. */ - secp256k1_scalar_t r1, r2, t; + secp256k1_scalar r1, r2, t; secp256k1_scalar_add(&r1, &s1, &s2); secp256k1_scalar_mul(&r1, &r1, &s); secp256k1_scalar_mul(&r2, &s1, &s); @@ -593,7 +888,7 @@ void scalar_test(void) { { /* Test square. */ - secp256k1_scalar_t r1, r2; + secp256k1_scalar r1, r2; secp256k1_scalar_sqr(&r1, &s1); secp256k1_scalar_mul(&r2, &s1, &s1); CHECK(secp256k1_scalar_eq(&r1, &r2)); @@ -601,7 +896,7 @@ void scalar_test(void) { { /* Test multiplicative identity. */ - secp256k1_scalar_t r1, v1; + secp256k1_scalar r1, v1; secp256k1_scalar_set_int(&v1,1); secp256k1_scalar_mul(&r1, &s1, &v1); CHECK(secp256k1_scalar_eq(&r1, &s1)); @@ -609,7 +904,7 @@ void scalar_test(void) { { /* Test additive identity. */ - secp256k1_scalar_t r1, v0; + secp256k1_scalar r1, v0; secp256k1_scalar_set_int(&v0,0); secp256k1_scalar_add(&r1, &s1, &v0); CHECK(secp256k1_scalar_eq(&r1, &s1)); @@ -617,7 +912,7 @@ void scalar_test(void) { { /* Test zero product property. */ - secp256k1_scalar_t r1, v0; + secp256k1_scalar r1, v0; secp256k1_scalar_set_int(&v0,0); secp256k1_scalar_mul(&r1, &s1, &v0); CHECK(secp256k1_scalar_eq(&r1, &v0)); @@ -633,7 +928,7 @@ void run_scalar_tests(void) { { /* (-1)+1 should be zero. */ - secp256k1_scalar_t s, o; + secp256k1_scalar s, o; secp256k1_scalar_set_int(&s, 1); CHECK(secp256k1_scalar_is_one(&s)); secp256k1_scalar_negate(&o, &s); @@ -646,8 +941,8 @@ void run_scalar_tests(void) { #ifndef USE_NUM_NONE { /* A scalar with value of the curve order should be 0. */ - secp256k1_num_t order; - secp256k1_scalar_t zero; + secp256k1_num order; + secp256k1_scalar zero; unsigned char bin[32]; int overflow = 0; secp256k1_scalar_order_get_num(&order); @@ -657,11 +952,605 @@ void run_scalar_tests(void) { CHECK(secp256k1_scalar_is_zero(&zero)); } #endif + + { + /* Does check_overflow check catch all ones? */ + static const secp256k1_scalar overflowed = SECP256K1_SCALAR_CONST( + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, + 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL, 0xFFFFFFFFUL + ); + CHECK(secp256k1_scalar_check_overflow(&overflowed)); + } + + { + /* Static test vectors. + * These were reduced from ~10^12 random vectors based on comparison-decision + * and edge-case coverage on 32-bit and 64-bit implementations. + * The responses were generated with Sage 5.9. + */ + secp256k1_scalar x; + secp256k1_scalar y; + secp256k1_scalar z; + secp256k1_scalar zz; + secp256k1_scalar one; + secp256k1_scalar r1; + secp256k1_scalar r2; +#if defined(USE_SCALAR_INV_NUM) + secp256k1_scalar zzv; +#endif + int overflow; + unsigned char chal[33][2][32] = { + {{0xff, 0xff, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, + 0xff, 0xff, 0x03, 0x00, 0xc0, 0xff, 0xff, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff}}, + {{0xef, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + {0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x80, 0xff}}, + {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0x3f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x00}, + {0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0xe0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x1e, 0xf8, 0xff, 0xff, 0xff, 0xfd, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, + 0x00, 0x00, 0x00, 0xf8, 0xff, 0x03, 0x00, 0xe0, + 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, + 0xf3, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x1c, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, + 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x1f, 0x00, 0x00, 0x80, 0xff, 0xff, 0x3f, + 0x00, 0xfe, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xfc, 0x9f, + 0xff, 0xff, 0xff, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0x0f, 0xfc, 0xff, 0x7f, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, + {0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0xf8, 0xff, 0x0f, 0xc0, 0xff, 0xff, + 0xff, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x07, 0x80, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, + 0xf7, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0x00, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xf0}, + {0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0x00, 0xf8, 0xff, 0x03, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x03, 0xc0, 0xff, 0x0f, 0xfc, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, + 0xff, 0x01, 0x00, 0x00, 0x00, 0x3f, 0x00, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0x8f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x7f, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x0f, 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, 0xc0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x03, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0xff, 0x7f}, + {0xff, 0xcf, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x00, 0xc0, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, + 0xbf, 0xff, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, + 0xff, 0xff, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0x01, 0xfc, 0xff, 0x01, 0x00, 0xfe, 0xff}, + {0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00}}, + {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x7f, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf8, 0xff, 0x01, 0x00, 0xf0, 0xff, 0xff, + 0xe0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0xfc, 0xff, 0xff, 0x3f, 0xf0, 0xff, 0xff, 0x3f, + 0x00, 0x00, 0xf8, 0x07, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x0f, 0x7e, 0x00, 0x00}}, + {{0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x1f, 0x00, 0x00, 0xfe, 0x07, 0x00}, + {0x00, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfb, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60}}, + {{0xff, 0x01, 0x00, 0xff, 0xff, 0xff, 0x0f, 0x00, + 0x80, 0x7f, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0xff, 0xff, 0x1f, 0x00, 0xf0, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00}}, + {{0x80, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf1, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, + 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0xff, 0xff, 0xcf, 0xff, 0x1f, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x7e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00}, + {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0x7f, 0x00, 0x80, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, + {0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x80, + 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0x7f, 0xf8, 0xff, 0xff, 0x1f, 0x00, 0xfe}}, + {{0xff, 0xff, 0xff, 0x3f, 0xf8, 0xff, 0xff, 0xff, + 0xff, 0x03, 0xfe, 0x01, 0x00, 0x00, 0x00, 0x00, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0x01, 0x80, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 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, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40}}, + {{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, 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, 0x00}}, + {{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xc0, + 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff}}, + {{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {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, 0x02}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40}, + {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, 0x01}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x7e, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x07, 0x00, + 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0xff, 0x01, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}, + {{0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x00, + 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, + 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, + 0xff, 0xff, 0x3f, 0x00, 0xf8, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x3f, 0x00, 0x00, 0xc0, 0xf1, 0x7f, 0x00}}, + {{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x00}, + {0x00, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, + 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1f, + 0x00, 0x00, 0xfc, 0xff, 0xff, 0x01, 0xff, 0xff}}, + {{0x00, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0x00, 0x00, 0x80, 0xff, 0x03, 0xe0, 0x01, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xfc, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}, + {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0xff, 0xff, 0xf0, 0x07, 0x00, 0x3c, 0x80, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x07, 0xe0, 0xff, 0x00, 0x00, 0x00}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x80, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0x7f, 0xfe, 0xff, 0x1f, + 0x00, 0xfe, 0xff, 0x03, 0x00, 0x00, 0xfe, 0xff}}, + {{0xff, 0xff, 0x81, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x83, + 0xff, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, + 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xf0}, + {0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x00, 0x00, + 0xf8, 0x07, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xc7, 0xff, 0xff, 0xe0, 0xff, 0xff, 0xff}}, + {{0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, + 0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0x03, 0xfb, + 0xfa, 0x8a, 0x7d, 0xdf, 0x13, 0x86, 0xe2, 0x03}, + {0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, + 0x82, 0xc9, 0xfa, 0xb0, 0x68, 0x04, 0xa0, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x6f, 0x03, 0xfb, + 0xfa, 0x8a, 0x7d, 0xdf, 0x13, 0x86, 0xe2, 0x03}} + }; + unsigned char res[33][2][32] = { + {{0x0c, 0x3b, 0x0a, 0xca, 0x8d, 0x1a, 0x2f, 0xb9, + 0x8a, 0x7b, 0x53, 0x5a, 0x1f, 0xc5, 0x22, 0xa1, + 0x07, 0x2a, 0x48, 0xea, 0x02, 0xeb, 0xb3, 0xd6, + 0x20, 0x1e, 0x86, 0xd0, 0x95, 0xf6, 0x92, 0x35}, + {0xdc, 0x90, 0x7a, 0x07, 0x2e, 0x1e, 0x44, 0x6d, + 0xf8, 0x15, 0x24, 0x5b, 0x5a, 0x96, 0x37, 0x9c, + 0x37, 0x7b, 0x0d, 0xac, 0x1b, 0x65, 0x58, 0x49, + 0x43, 0xb7, 0x31, 0xbb, 0xa7, 0xf4, 0x97, 0x15}}, + {{0xf1, 0xf7, 0x3a, 0x50, 0xe6, 0x10, 0xba, 0x22, + 0x43, 0x4d, 0x1f, 0x1f, 0x7c, 0x27, 0xca, 0x9c, + 0xb8, 0xb6, 0xa0, 0xfc, 0xd8, 0xc0, 0x05, 0x2f, + 0xf7, 0x08, 0xe1, 0x76, 0xdd, 0xd0, 0x80, 0xc8}, + {0xe3, 0x80, 0x80, 0xb8, 0xdb, 0xe3, 0xa9, 0x77, + 0x00, 0xb0, 0xf5, 0x2e, 0x27, 0xe2, 0x68, 0xc4, + 0x88, 0xe8, 0x04, 0xc1, 0x12, 0xbf, 0x78, 0x59, + 0xe6, 0xa9, 0x7c, 0xe1, 0x81, 0xdd, 0xb9, 0xd5}}, + {{0x96, 0xe2, 0xee, 0x01, 0xa6, 0x80, 0x31, 0xef, + 0x5c, 0xd0, 0x19, 0xb4, 0x7d, 0x5f, 0x79, 0xab, + 0xa1, 0x97, 0xd3, 0x7e, 0x33, 0xbb, 0x86, 0x55, + 0x60, 0x20, 0x10, 0x0d, 0x94, 0x2d, 0x11, 0x7c}, + {0xcc, 0xab, 0xe0, 0xe8, 0x98, 0x65, 0x12, 0x96, + 0x38, 0x5a, 0x1a, 0xf2, 0x85, 0x23, 0x59, 0x5f, + 0xf9, 0xf3, 0xc2, 0x81, 0x70, 0x92, 0x65, 0x12, + 0x9c, 0x65, 0x1e, 0x96, 0x00, 0xef, 0xe7, 0x63}}, + {{0xac, 0x1e, 0x62, 0xc2, 0x59, 0xfc, 0x4e, 0x5c, + 0x83, 0xb0, 0xd0, 0x6f, 0xce, 0x19, 0xf6, 0xbf, + 0xa4, 0xb0, 0xe0, 0x53, 0x66, 0x1f, 0xbf, 0xc9, + 0x33, 0x47, 0x37, 0xa9, 0x3d, 0x5d, 0xb0, 0x48}, + {0x86, 0xb9, 0x2a, 0x7f, 0x8e, 0xa8, 0x60, 0x42, + 0x26, 0x6d, 0x6e, 0x1c, 0xa2, 0xec, 0xe0, 0xe5, + 0x3e, 0x0a, 0x33, 0xbb, 0x61, 0x4c, 0x9f, 0x3c, + 0xd1, 0xdf, 0x49, 0x33, 0xcd, 0x72, 0x78, 0x18}}, + {{0xf7, 0xd3, 0xcd, 0x49, 0x5c, 0x13, 0x22, 0xfb, + 0x2e, 0xb2, 0x2f, 0x27, 0xf5, 0x8a, 0x5d, 0x74, + 0xc1, 0x58, 0xc5, 0xc2, 0x2d, 0x9f, 0x52, 0xc6, + 0x63, 0x9f, 0xba, 0x05, 0x76, 0x45, 0x7a, 0x63}, + {0x8a, 0xfa, 0x55, 0x4d, 0xdd, 0xa3, 0xb2, 0xc3, + 0x44, 0xfd, 0xec, 0x72, 0xde, 0xef, 0xc0, 0x99, + 0xf5, 0x9f, 0xe2, 0x52, 0xb4, 0x05, 0x32, 0x58, + 0x57, 0xc1, 0x8f, 0xea, 0xc3, 0x24, 0x5b, 0x94}}, + {{0x05, 0x83, 0xee, 0xdd, 0x64, 0xf0, 0x14, 0x3b, + 0xa0, 0x14, 0x4a, 0x3a, 0x41, 0x82, 0x7c, 0xa7, + 0x2c, 0xaa, 0xb1, 0x76, 0xbb, 0x59, 0x64, 0x5f, + 0x52, 0xad, 0x25, 0x29, 0x9d, 0x8f, 0x0b, 0xb0}, + {0x7e, 0xe3, 0x7c, 0xca, 0xcd, 0x4f, 0xb0, 0x6d, + 0x7a, 0xb2, 0x3e, 0xa0, 0x08, 0xb9, 0xa8, 0x2d, + 0xc2, 0xf4, 0x99, 0x66, 0xcc, 0xac, 0xd8, 0xb9, + 0x72, 0x2a, 0x4a, 0x3e, 0x0f, 0x7b, 0xbf, 0xf4}}, + {{0x8c, 0x9c, 0x78, 0x2b, 0x39, 0x61, 0x7e, 0xf7, + 0x65, 0x37, 0x66, 0x09, 0x38, 0xb9, 0x6f, 0x70, + 0x78, 0x87, 0xff, 0xcf, 0x93, 0xca, 0x85, 0x06, + 0x44, 0x84, 0xa7, 0xfe, 0xd3, 0xa4, 0xe3, 0x7e}, + {0xa2, 0x56, 0x49, 0x23, 0x54, 0xa5, 0x50, 0xe9, + 0x5f, 0xf0, 0x4d, 0xe7, 0xdc, 0x38, 0x32, 0x79, + 0x4f, 0x1c, 0xb7, 0xe4, 0xbb, 0xf8, 0xbb, 0x2e, + 0x40, 0x41, 0x4b, 0xcc, 0xe3, 0x1e, 0x16, 0x36}}, + {{0x0c, 0x1e, 0xd7, 0x09, 0x25, 0x40, 0x97, 0xcb, + 0x5c, 0x46, 0xa8, 0xda, 0xef, 0x25, 0xd5, 0xe5, + 0x92, 0x4d, 0xcf, 0xa3, 0xc4, 0x5d, 0x35, 0x4a, + 0xe4, 0x61, 0x92, 0xf3, 0xbf, 0x0e, 0xcd, 0xbe}, + {0xe4, 0xaf, 0x0a, 0xb3, 0x30, 0x8b, 0x9b, 0x48, + 0x49, 0x43, 0xc7, 0x64, 0x60, 0x4a, 0x2b, 0x9e, + 0x95, 0x5f, 0x56, 0xe8, 0x35, 0xdc, 0xeb, 0xdc, + 0xc7, 0xc4, 0xfe, 0x30, 0x40, 0xc7, 0xbf, 0xa4}}, + {{0xd4, 0xa0, 0xf5, 0x81, 0x49, 0x6b, 0xb6, 0x8b, + 0x0a, 0x69, 0xf9, 0xfe, 0xa8, 0x32, 0xe5, 0xe0, + 0xa5, 0xcd, 0x02, 0x53, 0xf9, 0x2c, 0xe3, 0x53, + 0x83, 0x36, 0xc6, 0x02, 0xb5, 0xeb, 0x64, 0xb8}, + {0x1d, 0x42, 0xb9, 0xf9, 0xe9, 0xe3, 0x93, 0x2c, + 0x4c, 0xee, 0x6c, 0x5a, 0x47, 0x9e, 0x62, 0x01, + 0x6b, 0x04, 0xfe, 0xa4, 0x30, 0x2b, 0x0d, 0x4f, + 0x71, 0x10, 0xd3, 0x55, 0xca, 0xf3, 0x5e, 0x80}}, + {{0x77, 0x05, 0xf6, 0x0c, 0x15, 0x9b, 0x45, 0xe7, + 0xb9, 0x11, 0xb8, 0xf5, 0xd6, 0xda, 0x73, 0x0c, + 0xda, 0x92, 0xea, 0xd0, 0x9d, 0xd0, 0x18, 0x92, + 0xce, 0x9a, 0xaa, 0xee, 0x0f, 0xef, 0xde, 0x30}, + {0xf1, 0xf1, 0xd6, 0x9b, 0x51, 0xd7, 0x77, 0x62, + 0x52, 0x10, 0xb8, 0x7a, 0x84, 0x9d, 0x15, 0x4e, + 0x07, 0xdc, 0x1e, 0x75, 0x0d, 0x0c, 0x3b, 0xdb, + 0x74, 0x58, 0x62, 0x02, 0x90, 0x54, 0x8b, 0x43}}, + {{0xa6, 0xfe, 0x0b, 0x87, 0x80, 0x43, 0x67, 0x25, + 0x57, 0x5d, 0xec, 0x40, 0x50, 0x08, 0xd5, 0x5d, + 0x43, 0xd7, 0xe0, 0xaa, 0xe0, 0x13, 0xb6, 0xb0, + 0xc0, 0xd4, 0xe5, 0x0d, 0x45, 0x83, 0xd6, 0x13}, + {0x40, 0x45, 0x0a, 0x92, 0x31, 0xea, 0x8c, 0x60, + 0x8c, 0x1f, 0xd8, 0x76, 0x45, 0xb9, 0x29, 0x00, + 0x26, 0x32, 0xd8, 0xa6, 0x96, 0x88, 0xe2, 0xc4, + 0x8b, 0xdb, 0x7f, 0x17, 0x87, 0xcc, 0xc8, 0xf2}}, + {{0xc2, 0x56, 0xe2, 0xb6, 0x1a, 0x81, 0xe7, 0x31, + 0x63, 0x2e, 0xbb, 0x0d, 0x2f, 0x81, 0x67, 0xd4, + 0x22, 0xe2, 0x38, 0x02, 0x25, 0x97, 0xc7, 0x88, + 0x6e, 0xdf, 0xbe, 0x2a, 0xa5, 0x73, 0x63, 0xaa}, + {0x50, 0x45, 0xe2, 0xc3, 0xbd, 0x89, 0xfc, 0x57, + 0xbd, 0x3c, 0xa3, 0x98, 0x7e, 0x7f, 0x36, 0x38, + 0x92, 0x39, 0x1f, 0x0f, 0x81, 0x1a, 0x06, 0x51, + 0x1f, 0x8d, 0x6a, 0xff, 0x47, 0x16, 0x06, 0x9c}}, + {{0x33, 0x95, 0xa2, 0x6f, 0x27, 0x5f, 0x9c, 0x9c, + 0x64, 0x45, 0xcb, 0xd1, 0x3c, 0xee, 0x5e, 0x5f, + 0x48, 0xa6, 0xaf, 0xe3, 0x79, 0xcf, 0xb1, 0xe2, + 0xbf, 0x55, 0x0e, 0xa2, 0x3b, 0x62, 0xf0, 0xe4}, + {0x14, 0xe8, 0x06, 0xe3, 0xbe, 0x7e, 0x67, 0x01, + 0xc5, 0x21, 0x67, 0xd8, 0x54, 0xb5, 0x7f, 0xa4, + 0xf9, 0x75, 0x70, 0x1c, 0xfd, 0x79, 0xdb, 0x86, + 0xad, 0x37, 0x85, 0x83, 0x56, 0x4e, 0xf0, 0xbf}}, + {{0xbc, 0xa6, 0xe0, 0x56, 0x4e, 0xef, 0xfa, 0xf5, + 0x1d, 0x5d, 0x3f, 0x2a, 0x5b, 0x19, 0xab, 0x51, + 0xc5, 0x8b, 0xdd, 0x98, 0x28, 0x35, 0x2f, 0xc3, + 0x81, 0x4f, 0x5c, 0xe5, 0x70, 0xb9, 0xeb, 0x62}, + {0xc4, 0x6d, 0x26, 0xb0, 0x17, 0x6b, 0xfe, 0x6c, + 0x12, 0xf8, 0xe7, 0xc1, 0xf5, 0x2f, 0xfa, 0x91, + 0x13, 0x27, 0xbd, 0x73, 0xcc, 0x33, 0x31, 0x1c, + 0x39, 0xe3, 0x27, 0x6a, 0x95, 0xcf, 0xc5, 0xfb}}, + {{0x30, 0xb2, 0x99, 0x84, 0xf0, 0x18, 0x2a, 0x6e, + 0x1e, 0x27, 0xed, 0xa2, 0x29, 0x99, 0x41, 0x56, + 0xe8, 0xd4, 0x0d, 0xef, 0x99, 0x9c, 0xf3, 0x58, + 0x29, 0x55, 0x1a, 0xc0, 0x68, 0xd6, 0x74, 0xa4}, + {0x07, 0x9c, 0xe7, 0xec, 0xf5, 0x36, 0x73, 0x41, + 0xa3, 0x1c, 0xe5, 0x93, 0x97, 0x6a, 0xfd, 0xf7, + 0x53, 0x18, 0xab, 0xaf, 0xeb, 0x85, 0xbd, 0x92, + 0x90, 0xab, 0x3c, 0xbf, 0x30, 0x82, 0xad, 0xf6}}, + {{0xc6, 0x87, 0x8a, 0x2a, 0xea, 0xc0, 0xa9, 0xec, + 0x6d, 0xd3, 0xdc, 0x32, 0x23, 0xce, 0x62, 0x19, + 0xa4, 0x7e, 0xa8, 0xdd, 0x1c, 0x33, 0xae, 0xd3, + 0x4f, 0x62, 0x9f, 0x52, 0xe7, 0x65, 0x46, 0xf4}, + {0x97, 0x51, 0x27, 0x67, 0x2d, 0xa2, 0x82, 0x87, + 0x98, 0xd3, 0xb6, 0x14, 0x7f, 0x51, 0xd3, 0x9a, + 0x0b, 0xd0, 0x76, 0x81, 0xb2, 0x4f, 0x58, 0x92, + 0xa4, 0x86, 0xa1, 0xa7, 0x09, 0x1d, 0xef, 0x9b}}, + {{0xb3, 0x0f, 0x2b, 0x69, 0x0d, 0x06, 0x90, 0x64, + 0xbd, 0x43, 0x4c, 0x10, 0xe8, 0x98, 0x1c, 0xa3, + 0xe1, 0x68, 0xe9, 0x79, 0x6c, 0x29, 0x51, 0x3f, + 0x41, 0xdc, 0xdf, 0x1f, 0xf3, 0x60, 0xbe, 0x33}, + {0xa1, 0x5f, 0xf7, 0x1d, 0xb4, 0x3e, 0x9b, 0x3c, + 0xe7, 0xbd, 0xb6, 0x06, 0xd5, 0x60, 0x06, 0x6d, + 0x50, 0xd2, 0xf4, 0x1a, 0x31, 0x08, 0xf2, 0xea, + 0x8e, 0xef, 0x5f, 0x7d, 0xb6, 0xd0, 0xc0, 0x27}}, + {{0x62, 0x9a, 0xd9, 0xbb, 0x38, 0x36, 0xce, 0xf7, + 0x5d, 0x2f, 0x13, 0xec, 0xc8, 0x2d, 0x02, 0x8a, + 0x2e, 0x72, 0xf0, 0xe5, 0x15, 0x9d, 0x72, 0xae, + 0xfc, 0xb3, 0x4f, 0x02, 0xea, 0xe1, 0x09, 0xfe}, + {0x00, 0x00, 0x00, 0x00, 0xfa, 0x0a, 0x3d, 0xbc, + 0xad, 0x16, 0x0c, 0xb6, 0xe7, 0x7c, 0x8b, 0x39, + 0x9a, 0x43, 0xbb, 0xe3, 0xc2, 0x55, 0x15, 0x14, + 0x75, 0xac, 0x90, 0x9b, 0x7f, 0x9a, 0x92, 0x00}}, + {{0x8b, 0xac, 0x70, 0x86, 0x29, 0x8f, 0x00, 0x23, + 0x7b, 0x45, 0x30, 0xaa, 0xb8, 0x4c, 0xc7, 0x8d, + 0x4e, 0x47, 0x85, 0xc6, 0x19, 0xe3, 0x96, 0xc2, + 0x9a, 0xa0, 0x12, 0xed, 0x6f, 0xd7, 0x76, 0x16}, + {0x45, 0xaf, 0x7e, 0x33, 0xc7, 0x7f, 0x10, 0x6c, + 0x7c, 0x9f, 0x29, 0xc1, 0xa8, 0x7e, 0x15, 0x84, + 0xe7, 0x7d, 0xc0, 0x6d, 0xab, 0x71, 0x5d, 0xd0, + 0x6b, 0x9f, 0x97, 0xab, 0xcb, 0x51, 0x0c, 0x9f}}, + {{0x9e, 0xc3, 0x92, 0xb4, 0x04, 0x9f, 0xc8, 0xbb, + 0xdd, 0x9e, 0xc6, 0x05, 0xfd, 0x65, 0xec, 0x94, + 0x7f, 0x2c, 0x16, 0xc4, 0x40, 0xac, 0x63, 0x7b, + 0x7d, 0xb8, 0x0c, 0xe4, 0x5b, 0xe3, 0xa7, 0x0e}, + {0x43, 0xf4, 0x44, 0xe8, 0xcc, 0xc8, 0xd4, 0x54, + 0x33, 0x37, 0x50, 0xf2, 0x87, 0x42, 0x2e, 0x00, + 0x49, 0x60, 0x62, 0x02, 0xfd, 0x1a, 0x7c, 0xdb, + 0x29, 0x6c, 0x6d, 0x54, 0x53, 0x08, 0xd1, 0xc8}}, + {{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}, + {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}}, + {{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}, + {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, 0x01}}, + {{0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1, + 0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0, + 0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59, + 0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}, + {0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1, + 0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0, + 0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59, + 0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}}, + {{0x28, 0x56, 0xac, 0x0e, 0x4f, 0x98, 0x09, 0xf0, + 0x49, 0xfa, 0x7f, 0x84, 0xac, 0x7e, 0x50, 0x5b, + 0x17, 0x43, 0x14, 0x89, 0x9c, 0x53, 0xa8, 0x94, + 0x30, 0xf2, 0x11, 0x4d, 0x92, 0x14, 0x27, 0xe8}, + {0x39, 0x7a, 0x84, 0x56, 0x79, 0x9d, 0xec, 0x26, + 0x2c, 0x53, 0xc1, 0x94, 0xc9, 0x8d, 0x9e, 0x9d, + 0x32, 0x1f, 0xdd, 0x84, 0x04, 0xe8, 0xe2, 0x0a, + 0x6b, 0xbe, 0xbb, 0x42, 0x40, 0x67, 0x30, 0x6c}}, + {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4, + 0x40, 0x2d, 0xa1, 0x73, 0x2f, 0xc9, 0xbe, 0xbd}, + {0x27, 0x59, 0xc7, 0x35, 0x60, 0x71, 0xa6, 0xf1, + 0x79, 0xa5, 0xfd, 0x79, 0x16, 0xf3, 0x41, 0xf0, + 0x57, 0xb4, 0x02, 0x97, 0x32, 0xe7, 0xde, 0x59, + 0xe2, 0x2d, 0x9b, 0x11, 0xea, 0x2c, 0x35, 0x92}}, + {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40}, + {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, 0x01}}, + {{0x1c, 0xc4, 0xf7, 0xda, 0x0f, 0x65, 0xca, 0x39, + 0x70, 0x52, 0x92, 0x8e, 0xc3, 0xc8, 0x15, 0xea, + 0x7f, 0x10, 0x9e, 0x77, 0x4b, 0x6e, 0x2d, 0xdf, + 0xe8, 0x30, 0x9d, 0xda, 0xe8, 0x9a, 0x65, 0xae}, + {0x02, 0xb0, 0x16, 0xb1, 0x1d, 0xc8, 0x57, 0x7b, + 0xa2, 0x3a, 0xa2, 0xa3, 0x38, 0x5c, 0x8f, 0xeb, + 0x66, 0x37, 0x91, 0xa8, 0x5f, 0xef, 0x04, 0xf6, + 0x59, 0x75, 0xe1, 0xee, 0x92, 0xf6, 0x0e, 0x30}}, + {{0x8d, 0x76, 0x14, 0xa4, 0x14, 0x06, 0x9f, 0x9a, + 0xdf, 0x4a, 0x85, 0xa7, 0x6b, 0xbf, 0x29, 0x6f, + 0xbc, 0x34, 0x87, 0x5d, 0xeb, 0xbb, 0x2e, 0xa9, + 0xc9, 0x1f, 0x58, 0xd6, 0x9a, 0x82, 0xa0, 0x56}, + {0xd4, 0xb9, 0xdb, 0x88, 0x1d, 0x04, 0xe9, 0x93, + 0x8d, 0x3f, 0x20, 0xd5, 0x86, 0xa8, 0x83, 0x07, + 0xdb, 0x09, 0xd8, 0x22, 0x1f, 0x7f, 0xf1, 0x71, + 0xc8, 0xe7, 0x5d, 0x47, 0xaf, 0x8b, 0x72, 0xe9}}, + {{0x83, 0xb9, 0x39, 0xb2, 0xa4, 0xdf, 0x46, 0x87, + 0xc2, 0xb8, 0xf1, 0xe6, 0x4c, 0xd1, 0xe2, 0xa9, + 0xe4, 0x70, 0x30, 0x34, 0xbc, 0x52, 0x7c, 0x55, + 0xa6, 0xec, 0x80, 0xa4, 0xe5, 0xd2, 0xdc, 0x73}, + {0x08, 0xf1, 0x03, 0xcf, 0x16, 0x73, 0xe8, 0x7d, + 0xb6, 0x7e, 0x9b, 0xc0, 0xb4, 0xc2, 0xa5, 0x86, + 0x02, 0x77, 0xd5, 0x27, 0x86, 0xa5, 0x15, 0xfb, + 0xae, 0x9b, 0x8c, 0xa9, 0xf9, 0xf8, 0xa8, 0x4a}}, + {{0x8b, 0x00, 0x49, 0xdb, 0xfa, 0xf0, 0x1b, 0xa2, + 0xed, 0x8a, 0x9a, 0x7a, 0x36, 0x78, 0x4a, 0xc7, + 0xf7, 0xad, 0x39, 0xd0, 0x6c, 0x65, 0x7a, 0x41, + 0xce, 0xd6, 0xd6, 0x4c, 0x20, 0x21, 0x6b, 0xc7}, + {0xc6, 0xca, 0x78, 0x1d, 0x32, 0x6c, 0x6c, 0x06, + 0x91, 0xf2, 0x1a, 0xe8, 0x43, 0x16, 0xea, 0x04, + 0x3c, 0x1f, 0x07, 0x85, 0xf7, 0x09, 0x22, 0x08, + 0xba, 0x13, 0xfd, 0x78, 0x1e, 0x3f, 0x6f, 0x62}}, + {{0x25, 0x9b, 0x7c, 0xb0, 0xac, 0x72, 0x6f, 0xb2, + 0xe3, 0x53, 0x84, 0x7a, 0x1a, 0x9a, 0x98, 0x9b, + 0x44, 0xd3, 0x59, 0xd0, 0x8e, 0x57, 0x41, 0x40, + 0x78, 0xa7, 0x30, 0x2f, 0x4c, 0x9c, 0xb9, 0x68}, + {0xb7, 0x75, 0x03, 0x63, 0x61, 0xc2, 0x48, 0x6e, + 0x12, 0x3d, 0xbf, 0x4b, 0x27, 0xdf, 0xb1, 0x7a, + 0xff, 0x4e, 0x31, 0x07, 0x83, 0xf4, 0x62, 0x5b, + 0x19, 0xa5, 0xac, 0xa0, 0x32, 0x58, 0x0d, 0xa7}}, + {{0x43, 0x4f, 0x10, 0xa4, 0xca, 0xdb, 0x38, 0x67, + 0xfa, 0xae, 0x96, 0xb5, 0x6d, 0x97, 0xff, 0x1f, + 0xb6, 0x83, 0x43, 0xd3, 0xa0, 0x2d, 0x70, 0x7a, + 0x64, 0x05, 0x4c, 0xa7, 0xc1, 0xa5, 0x21, 0x51}, + {0xe4, 0xf1, 0x23, 0x84, 0xe1, 0xb5, 0x9d, 0xf2, + 0xb8, 0x73, 0x8b, 0x45, 0x2b, 0x35, 0x46, 0x38, + 0x10, 0x2b, 0x50, 0xf8, 0x8b, 0x35, 0xcd, 0x34, + 0xc8, 0x0e, 0xf6, 0xdb, 0x09, 0x35, 0xf0, 0xda}}, + {{0xdb, 0x21, 0x5c, 0x8d, 0x83, 0x1d, 0xb3, 0x34, + 0xc7, 0x0e, 0x43, 0xa1, 0x58, 0x79, 0x67, 0x13, + 0x1e, 0x86, 0x5d, 0x89, 0x63, 0xe6, 0x0a, 0x46, + 0x5c, 0x02, 0x97, 0x1b, 0x62, 0x43, 0x86, 0xf5}, + {0xdb, 0x21, 0x5c, 0x8d, 0x83, 0x1d, 0xb3, 0x34, + 0xc7, 0x0e, 0x43, 0xa1, 0x58, 0x79, 0x67, 0x13, + 0x1e, 0x86, 0x5d, 0x89, 0x63, 0xe6, 0x0a, 0x46, + 0x5c, 0x02, 0x97, 0x1b, 0x62, 0x43, 0x86, 0xf5}} + }; + secp256k1_scalar_set_int(&one, 1); + for (i = 0; i < 33; i++) { + secp256k1_scalar_set_b32(&x, chal[i][0], &overflow); + CHECK(!overflow); + secp256k1_scalar_set_b32(&y, chal[i][1], &overflow); + CHECK(!overflow); + secp256k1_scalar_set_b32(&r1, res[i][0], &overflow); + CHECK(!overflow); + secp256k1_scalar_set_b32(&r2, res[i][1], &overflow); + CHECK(!overflow); + secp256k1_scalar_mul(&z, &x, &y); + CHECK(!secp256k1_scalar_check_overflow(&z)); + CHECK(secp256k1_scalar_eq(&r1, &z)); + if (!secp256k1_scalar_is_zero(&y)) { + secp256k1_scalar_inverse(&zz, &y); + CHECK(!secp256k1_scalar_check_overflow(&zz)); +#if defined(USE_SCALAR_INV_NUM) + secp256k1_scalar_inverse_var(&zzv, &y); + CHECK(secp256k1_scalar_eq(&zzv, &zz)); +#endif + secp256k1_scalar_mul(&z, &z, &zz); + CHECK(!secp256k1_scalar_check_overflow(&z)); + CHECK(secp256k1_scalar_eq(&x, &z)); + secp256k1_scalar_mul(&zz, &zz, &y); + CHECK(!secp256k1_scalar_check_overflow(&zz)); + CHECK(secp256k1_scalar_eq(&one, &zz)); + } + secp256k1_scalar_mul(&z, &x, &x); + CHECK(!secp256k1_scalar_check_overflow(&z)); + secp256k1_scalar_sqr(&zz, &x); + CHECK(!secp256k1_scalar_check_overflow(&zz)); + CHECK(secp256k1_scalar_eq(&zz, &z)); + CHECK(secp256k1_scalar_eq(&r2, &zz)); + } + } } /***** FIELD TESTS *****/ -void random_fe(secp256k1_fe_t *x) { +void random_fe(secp256k1_fe *x) { unsigned char bin[32]; do { secp256k1_rand256(bin); @@ -671,7 +1560,17 @@ void random_fe(secp256k1_fe_t *x) { } while(1); } -void random_fe_non_zero(secp256k1_fe_t *nz) { +void random_fe_test(secp256k1_fe *x) { + unsigned char bin[32]; + do { + secp256k1_rand256_test(bin); + if (secp256k1_fe_set_b32(x, bin)) { + return; + } + } while(1); +} + +void random_fe_non_zero(secp256k1_fe *nz) { int tries = 10; while (--tries >= 0) { random_fe(nz); @@ -684,25 +1583,25 @@ void random_fe_non_zero(secp256k1_fe_t *nz) { CHECK(tries >= 0); } -void random_fe_non_square(secp256k1_fe_t *ns) { - secp256k1_fe_t r; +void random_fe_non_square(secp256k1_fe *ns) { + secp256k1_fe r; random_fe_non_zero(ns); - if (secp256k1_fe_sqrt_var(&r, ns)) { + if (secp256k1_fe_sqrt(&r, ns)) { secp256k1_fe_negate(ns, ns, 1); } } -int check_fe_equal(const secp256k1_fe_t *a, const secp256k1_fe_t *b) { - secp256k1_fe_t an = *a; - secp256k1_fe_t bn = *b; +int check_fe_equal(const secp256k1_fe *a, const secp256k1_fe *b) { + secp256k1_fe an = *a; + secp256k1_fe bn = *b; secp256k1_fe_normalize_weak(&an); secp256k1_fe_normalize_var(&bn); return secp256k1_fe_equal_var(&an, &bn); } -int check_fe_inverse(const secp256k1_fe_t *a, const secp256k1_fe_t *ai) { - secp256k1_fe_t x; - secp256k1_fe_t one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); +int check_fe_inverse(const secp256k1_fe *a, const secp256k1_fe *ai) { + secp256k1_fe x; + secp256k1_fe one = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 1); secp256k1_fe_mul(&x, a, ai); return check_fe_equal(&x, &one); } @@ -714,17 +1613,17 @@ void run_field_convert(void) { 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x40 }; - static const secp256k1_fe_storage_t fes = SECP256K1_FE_STORAGE_CONST( + static const secp256k1_fe_storage fes = SECP256K1_FE_STORAGE_CONST( 0x00010203UL, 0x04050607UL, 0x11121314UL, 0x15161718UL, 0x22232425UL, 0x26272829UL, 0x33343536UL, 0x37383940UL ); - static const secp256k1_fe_t fe = SECP256K1_FE_CONST( + static const secp256k1_fe fe = SECP256K1_FE_CONST( 0x00010203UL, 0x04050607UL, 0x11121314UL, 0x15161718UL, 0x22232425UL, 0x26272829UL, 0x33343536UL, 0x37383940UL ); - secp256k1_fe_t fe2; + secp256k1_fe fe2; unsigned char b322[32]; - secp256k1_fe_storage_t fes2; + secp256k1_fe_storage fes2; /* Check conversions to fe. */ CHECK(secp256k1_fe_set_b32(&fe2, b32)); CHECK(secp256k1_fe_equal_var(&fe, &fe2)); @@ -737,15 +1636,24 @@ void run_field_convert(void) { CHECK(memcmp(&fes2, &fes, sizeof(fes)) == 0); } +int fe_memcmp(const secp256k1_fe *a, const secp256k1_fe *b) { + secp256k1_fe t = *b; +#ifdef VERIFY + t.magnitude = a->magnitude; + t.normalized = a->normalized; +#endif + return memcmp(a, &t, sizeof(secp256k1_fe)); +} + void run_field_misc(void) { - secp256k1_fe_t x; - secp256k1_fe_t y; - secp256k1_fe_t z; - secp256k1_fe_t q; - secp256k1_fe_t fe5 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 5); - int i; + secp256k1_fe x; + secp256k1_fe y; + secp256k1_fe z; + secp256k1_fe q; + secp256k1_fe fe5 = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 5); + int i, j; for (i = 0; i < 5*count; i++) { - secp256k1_fe_storage_t xs, ys, zs; + secp256k1_fe_storage xs, ys, zs; random_fe(&x); random_fe_non_zero(&y); /* Test the fe equality and comparison operations. */ @@ -756,14 +1664,27 @@ void run_field_misc(void) { /* Test fe conditional move; z is not normalized here. */ q = x; secp256k1_fe_cmov(&x, &z, 0); + VERIFY_CHECK(!x.normalized && x.magnitude == z.magnitude); secp256k1_fe_cmov(&x, &x, 1); - CHECK(memcmp(&x, &z, sizeof(x)) != 0); - CHECK(memcmp(&x, &q, sizeof(x)) == 0); + CHECK(fe_memcmp(&x, &z) != 0); + CHECK(fe_memcmp(&x, &q) == 0); secp256k1_fe_cmov(&q, &z, 1); - CHECK(memcmp(&q, &z, sizeof(q)) == 0); - /* Test storage conversion and conditional moves. */ - secp256k1_fe_normalize(&z); + VERIFY_CHECK(!q.normalized && q.magnitude == z.magnitude); + CHECK(fe_memcmp(&q, &z) == 0); + secp256k1_fe_normalize_var(&x); + secp256k1_fe_normalize_var(&z); CHECK(!secp256k1_fe_equal_var(&x, &z)); + secp256k1_fe_normalize_var(&q); + secp256k1_fe_cmov(&q, &z, (i&1)); + VERIFY_CHECK(q.normalized && q.magnitude == 1); + for (j = 0; j < 6; j++) { + secp256k1_fe_negate(&z, &z, j+1); + secp256k1_fe_normalize_var(&q); + secp256k1_fe_cmov(&q, &z, (j&1)); + VERIFY_CHECK(!q.normalized && q.magnitude == (j+2)); + } + secp256k1_fe_normalize_var(&z); + /* Test storage conversion and conditional moves. */ secp256k1_fe_to_storage(&xs, &x); secp256k1_fe_to_storage(&ys, &y); secp256k1_fe_to_storage(&zs, &z); @@ -797,7 +1718,7 @@ void run_field_misc(void) { } void run_field_inv(void) { - secp256k1_fe_t x, xi, xii; + secp256k1_fe x, xi, xii; int i; for (i = 0; i < 10*count; i++) { random_fe_non_zero(&x); @@ -809,7 +1730,7 @@ void run_field_inv(void) { } void run_field_inv_var(void) { - secp256k1_fe_t x, xi, xii; + secp256k1_fe x, xi, xii; int i; for (i = 0; i < 10*count; i++) { random_fe_non_zero(&x); @@ -821,21 +1742,21 @@ void run_field_inv_var(void) { } void run_field_inv_all_var(void) { - secp256k1_fe_t x[16], xi[16], xii[16]; + secp256k1_fe x[16], xi[16], xii[16]; int i; /* Check it's safe to call for 0 elements */ - secp256k1_fe_inv_all_var(0, xi, x); + secp256k1_fe_inv_all_var(xi, x, 0); for (i = 0; i < count; i++) { size_t j; - size_t len = (secp256k1_rand32() & 15) + 1; + size_t len = secp256k1_rand_int(15) + 1; for (j = 0; j < len; j++) { random_fe_non_zero(&x[j]); } - secp256k1_fe_inv_all_var(len, xi, x); + secp256k1_fe_inv_all_var(xi, x, len); for (j = 0; j < len; j++) { CHECK(check_fe_inverse(&x[j], &xi[j])); } - secp256k1_fe_inv_all_var(len, xii, xi); + secp256k1_fe_inv_all_var(xii, xi, len); for (j = 0; j < len; j++) { CHECK(check_fe_equal(&x[j], &xii[j])); } @@ -843,7 +1764,7 @@ void run_field_inv_all_var(void) { } void run_sqr(void) { - secp256k1_fe_t x, s; + secp256k1_fe x, s; { int i; @@ -858,9 +1779,9 @@ void run_sqr(void) { } } -void test_sqrt(const secp256k1_fe_t *a, const secp256k1_fe_t *k) { - secp256k1_fe_t r1, r2; - int v = secp256k1_fe_sqrt_var(&r1, a); +void test_sqrt(const secp256k1_fe *a, const secp256k1_fe *k) { + secp256k1_fe r1, r2; + int v = secp256k1_fe_sqrt(&r1, a); CHECK((v == 0) == (k == NULL)); if (k != NULL) { @@ -873,7 +1794,7 @@ void test_sqrt(const secp256k1_fe_t *a, const secp256k1_fe_t *k) { } void run_sqrt(void) { - secp256k1_fe_t ns, x, s, t; + secp256k1_fe ns, x, s, t; int i; /* Check sqrt(0) is 0 */ @@ -908,19 +1829,19 @@ void run_sqrt(void) { /***** GROUP TESTS *****/ -void ge_equals_ge(const secp256k1_ge_t *a, const secp256k1_ge_t *b) { +void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) { CHECK(a->infinity == b->infinity); if (a->infinity) { return; } CHECK(secp256k1_fe_equal_var(&a->x, &b->x)); - CHECK(secp256k1_fe_equal_var(&b->y, &b->y)); + CHECK(secp256k1_fe_equal_var(&a->y, &b->y)); } /* This compares jacobian points including their Z, not just their geometric meaning. */ -int gej_xyz_equals_gej(const secp256k1_gej_t *a, const secp256k1_gej_t *b) { - secp256k1_gej_t a2; - secp256k1_gej_t b2; +int gej_xyz_equals_gej(const secp256k1_gej *a, const secp256k1_gej *b) { + secp256k1_gej a2; + secp256k1_gej b2; int ret = 1; ret &= a->infinity == b->infinity; if (ret && !a->infinity) { @@ -939,9 +1860,9 @@ int gej_xyz_equals_gej(const secp256k1_gej_t *a, const secp256k1_gej_t *b) { return ret; } -void ge_equals_gej(const secp256k1_ge_t *a, const secp256k1_gej_t *b) { - secp256k1_fe_t z2s; - secp256k1_fe_t u1, u2, s1, s2; +void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) { + secp256k1_fe z2s; + secp256k1_fe u1, u2, s1, s2; CHECK(a->infinity == b->infinity); if (a->infinity) { return; @@ -958,21 +1879,39 @@ void ge_equals_gej(const secp256k1_ge_t *a, const secp256k1_gej_t *b) { void test_ge(void) { int i, i1; +#ifdef USE_ENDOMORPHISM + int runs = 6; +#else int runs = 4; +#endif /* Points: (infinity, p1, p1, -p1, -p1, p2, p2, -p2, -p2, p3, p3, -p3, -p3, p4, p4, -p4, -p4). * The second in each pair of identical points uses a random Z coordinate in the Jacobian form. * All magnitudes are randomized. - * All 17*17 combinations of points are added to eachother, using all applicable methods. + * All 17*17 combinations of points are added to each other, using all applicable methods. + * + * When the endomorphism code is compiled in, p5 = lambda*p1 and p6 = lambda^2*p1 are added as well. */ - secp256k1_ge_t *ge = (secp256k1_ge_t *)malloc(sizeof(secp256k1_ge_t) * (1 + 4 * runs)); - secp256k1_gej_t *gej = (secp256k1_gej_t *)malloc(sizeof(secp256k1_gej_t) * (1 + 4 * runs)); + secp256k1_ge *ge = (secp256k1_ge *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_ge) * (1 + 4 * runs)); + secp256k1_gej *gej = (secp256k1_gej *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_gej) * (1 + 4 * runs)); + secp256k1_fe *zinv = (secp256k1_fe *)checked_malloc(&ctx->error_callback, sizeof(secp256k1_fe) * (1 + 4 * runs)); + secp256k1_fe zf; + secp256k1_fe zfi2, zfi3; + secp256k1_gej_set_infinity(&gej[0]); secp256k1_ge_clear(&ge[0]); secp256k1_ge_set_gej_var(&ge[0], &gej[0]); for (i = 0; i < runs; i++) { int j; - secp256k1_ge_t g; + secp256k1_ge g; random_group_element_test(&g); +#ifdef USE_ENDOMORPHISM + if (i >= runs - 2) { + secp256k1_ge_mul_lambda(&g, &ge[1]); + } + if (i >= runs - 1) { + secp256k1_ge_mul_lambda(&g, &g); + } +#endif ge[1 + 4 * i] = g; ge[2 + 4 * i] = g; secp256k1_ge_neg(&ge[3 + 4 * i], &g); @@ -990,18 +1929,65 @@ void test_ge(void) { } } + /* Compute z inverses. */ + { + secp256k1_fe *zs = checked_malloc(&ctx->error_callback, sizeof(secp256k1_fe) * (1 + 4 * runs)); + for (i = 0; i < 4 * runs + 1; i++) { + if (i == 0) { + /* The point at infinity does not have a meaningful z inverse. Any should do. */ + do { + random_field_element_test(&zs[i]); + } while(secp256k1_fe_is_zero(&zs[i])); + } else { + zs[i] = gej[i].z; + } + } + secp256k1_fe_inv_all_var(zinv, zs, 4 * runs + 1); + free(zs); + } + + /* Generate random zf, and zfi2 = 1/zf^2, zfi3 = 1/zf^3 */ + do { + random_field_element_test(&zf); + } while(secp256k1_fe_is_zero(&zf)); + random_field_element_magnitude(&zf); + secp256k1_fe_inv_var(&zfi3, &zf); + secp256k1_fe_sqr(&zfi2, &zfi3); + secp256k1_fe_mul(&zfi3, &zfi3, &zfi2); + for (i1 = 0; i1 < 1 + 4 * runs; i1++) { int i2; for (i2 = 0; i2 < 1 + 4 * runs; i2++) { /* Compute reference result using gej + gej (var). */ - secp256k1_gej_t refj, resj; - secp256k1_ge_t ref; - secp256k1_gej_add_var(&refj, &gej[i1], &gej[i2]); + secp256k1_gej refj, resj; + secp256k1_ge ref; + secp256k1_fe zr; + secp256k1_gej_add_var(&refj, &gej[i1], &gej[i2], secp256k1_gej_is_infinity(&gej[i1]) ? NULL : &zr); + /* Check Z ratio. */ + if (!secp256k1_gej_is_infinity(&gej[i1]) && !secp256k1_gej_is_infinity(&refj)) { + secp256k1_fe zrz; secp256k1_fe_mul(&zrz, &zr, &gej[i1].z); + CHECK(secp256k1_fe_equal_var(&zrz, &refj.z)); + } secp256k1_ge_set_gej_var(&ref, &refj); - /* Test gej + ge (var). */ - secp256k1_gej_add_ge_var(&resj, &gej[i1], &ge[i2]); + /* Test gej + ge with Z ratio result (var). */ + secp256k1_gej_add_ge_var(&resj, &gej[i1], &ge[i2], secp256k1_gej_is_infinity(&gej[i1]) ? NULL : &zr); ge_equals_gej(&ref, &resj); + if (!secp256k1_gej_is_infinity(&gej[i1]) && !secp256k1_gej_is_infinity(&resj)) { + secp256k1_fe zrz; secp256k1_fe_mul(&zrz, &zr, &gej[i1].z); + CHECK(secp256k1_fe_equal_var(&zrz, &resj.z)); + } + + /* Test gej + ge (var, with additional Z factor). */ + { + secp256k1_ge ge2_zfi = ge[i2]; /* the second term with x and y rescaled for z = 1/zf */ + secp256k1_fe_mul(&ge2_zfi.x, &ge2_zfi.x, &zfi2); + secp256k1_fe_mul(&ge2_zfi.y, &ge2_zfi.y, &zfi3); + random_field_element_magnitude(&ge2_zfi.x); + random_field_element_magnitude(&ge2_zfi.y); + secp256k1_gej_add_zinv_var(&resj, &gej[i1], &ge2_zfi, &zf); + ge_equals_gej(&ref, &resj); + } /* Test gej + ge (const). */ if (i2 != 0) { @@ -1012,10 +1998,15 @@ void test_ge(void) { /* Test doubling (var). */ if ((i1 == 0 && i2 == 0) || ((i1 + 3)/4 == (i2 + 3)/4 && ((i1 + 3)%4)/2 == ((i2 + 3)%4)/2)) { - /* Normal doubling. */ - secp256k1_gej_double_var(&resj, &gej[i1]); + secp256k1_fe zr2; + /* Normal doubling with Z ratio result. */ + secp256k1_gej_double_var(&resj, &gej[i1], &zr2); ge_equals_gej(&ref, &resj); - secp256k1_gej_double_var(&resj, &gej[i2]); + /* Check Z ratio. */ + secp256k1_fe_mul(&zr2, &zr2, &gej[i1].z); + CHECK(secp256k1_fe_equal_var(&zr2, &resj.z)); + /* Normal doubling. */ + secp256k1_gej_double_var(&resj, &gej[i2], NULL); ge_equals_gej(&ref, &resj); } @@ -1040,41 +2031,121 @@ void test_ge(void) { /* Test adding all points together in random order equals infinity. */ { - secp256k1_gej_t sum = SECP256K1_GEJ_CONST_INFINITY; - secp256k1_gej_t *gej_shuffled = (secp256k1_gej_t *)malloc((4 * runs + 1) * sizeof(secp256k1_gej_t)); + secp256k1_gej sum = SECP256K1_GEJ_CONST_INFINITY; + secp256k1_gej *gej_shuffled = (secp256k1_gej *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_gej)); for (i = 0; i < 4 * runs + 1; i++) { gej_shuffled[i] = gej[i]; } for (i = 0; i < 4 * runs + 1; i++) { - int swap = i + secp256k1_rand32() % (4 * runs + 1 - i); + int swap = i + secp256k1_rand_int(4 * runs + 1 - i); if (swap != i) { - secp256k1_gej_t t = gej_shuffled[i]; + secp256k1_gej t = gej_shuffled[i]; gej_shuffled[i] = gej_shuffled[swap]; gej_shuffled[swap] = t; } } for (i = 0; i < 4 * runs + 1; i++) { - secp256k1_gej_add_var(&sum, &sum, &gej_shuffled[i]); + secp256k1_gej_add_var(&sum, &sum, &gej_shuffled[i], NULL); } CHECK(secp256k1_gej_is_infinity(&sum)); free(gej_shuffled); } - /* Test batch gej -> ge conversion. */ + /* Test batch gej -> ge conversion with and without known z ratios. */ { - secp256k1_ge_t *ge_set_all = (secp256k1_ge_t *)malloc((4 * runs + 1) * sizeof(secp256k1_ge_t)); - secp256k1_ge_set_all_gej_var(4 * runs + 1, ge_set_all, gej); + secp256k1_fe *zr = (secp256k1_fe *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_fe)); + secp256k1_ge *ge_set_table = (secp256k1_ge *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_ge)); + secp256k1_ge *ge_set_all = (secp256k1_ge *)checked_malloc(&ctx->error_callback, (4 * runs + 1) * sizeof(secp256k1_ge)); for (i = 0; i < 4 * runs + 1; i++) { - secp256k1_fe_t s; + /* Compute gej[i + 1].z / gez[i].z (with gej[n].z taken to be 1). */ + if (i < 4 * runs) { + secp256k1_fe_mul(&zr[i + 1], &zinv[i], &gej[i + 1].z); + } + } + secp256k1_ge_set_table_gej_var(ge_set_table, gej, zr, 4 * runs + 1); + secp256k1_ge_set_all_gej_var(ge_set_all, gej, 4 * runs + 1, &ctx->error_callback); + for (i = 0; i < 4 * runs + 1; i++) { + secp256k1_fe s; random_fe_non_zero(&s); secp256k1_gej_rescale(&gej[i], &s); + ge_equals_gej(&ge_set_table[i], &gej[i]); ge_equals_gej(&ge_set_all[i], &gej[i]); } + free(ge_set_table); free(ge_set_all); + free(zr); } free(ge); free(gej); + free(zinv); +} + +void test_add_neg_y_diff_x(void) { + /* The point of this test is to check that we can add two points + * whose y-coordinates are negatives of each other but whose x + * coordinates differ. If the x-coordinates were the same, these + * points would be negatives of each other and their sum is + * infinity. This is cool because it "covers up" any degeneracy + * in the addition algorithm that would cause the xy coordinates + * of the sum to be wrong (since infinity has no xy coordinates). + * HOWEVER, if the x-coordinates are different, infinity is the + * wrong answer, and such degeneracies are exposed. This is the + * root of https://github.com/bitcoin-core/secp256k1/issues/257 + * which this test is a regression test for. + * + * These points were generated in sage as + * # secp256k1 params + * F = FiniteField (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F) + * C = EllipticCurve ([F (0), F (7)]) + * G = C.lift_x(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798) + * N = FiniteField(G.order()) + * + * # endomorphism values (lambda is 1^{1/3} in N, beta is 1^{1/3} in F) + * x = polygen(N) + * lam = (1 - x^3).roots()[1][0] + * + * # random "bad pair" + * P = C.random_element() + * Q = -int(lam) * P + * print " P: %x %x" % P.xy() + * print " Q: %x %x" % Q.xy() + * print "P + Q: %x %x" % (P + Q).xy() + */ + secp256k1_gej aj = SECP256K1_GEJ_CONST( + 0x8d24cd95, 0x0a355af1, 0x3c543505, 0x44238d30, + 0x0643d79f, 0x05a59614, 0x2f8ec030, 0xd58977cb, + 0x001e337a, 0x38093dcd, 0x6c0f386d, 0x0b1293a8, + 0x4d72c879, 0xd7681924, 0x44e6d2f3, 0x9190117d + ); + secp256k1_gej bj = SECP256K1_GEJ_CONST( + 0xc7b74206, 0x1f788cd9, 0xabd0937d, 0x164a0d86, + 0x95f6ff75, 0xf19a4ce9, 0xd013bd7b, 0xbf92d2a7, + 0xffe1cc85, 0xc7f6c232, 0x93f0c792, 0xf4ed6c57, + 0xb28d3786, 0x2897e6db, 0xbb192d0b, 0x6e6feab2 + ); + secp256k1_gej sumj = SECP256K1_GEJ_CONST( + 0x671a63c0, 0x3efdad4c, 0x389a7798, 0x24356027, + 0xb3d69010, 0x278625c3, 0x5c86d390, 0x184a8f7a, + 0x5f6409c2, 0x2ce01f2b, 0x511fd375, 0x25071d08, + 0xda651801, 0x70e95caf, 0x8f0d893c, 0xbed8fbbe + ); + secp256k1_ge b; + secp256k1_gej resj; + secp256k1_ge res; + secp256k1_ge_set_gej(&b, &bj); + + secp256k1_gej_add_var(&resj, &aj, &bj, NULL); + secp256k1_ge_set_gej(&res, &resj); + ge_equals_gej(&res, &sumj); + + secp256k1_gej_add_ge(&resj, &aj, &b); + secp256k1_ge_set_gej(&res, &resj); + ge_equals_gej(&res, &sumj); + + secp256k1_gej_add_ge_var(&resj, &aj, &b, NULL); + secp256k1_ge_set_gej(&res, &resj); + ge_equals_gej(&res, &sumj); } void run_ge(void) { @@ -1082,36 +2153,142 @@ void run_ge(void) { for (i = 0; i < count * 32; i++) { test_ge(); } + test_add_neg_y_diff_x(); +} + +void test_ec_combine(void) { + secp256k1_scalar sum = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + secp256k1_pubkey data[6]; + const secp256k1_pubkey* d[6]; + secp256k1_pubkey sd; + secp256k1_pubkey sd2; + secp256k1_gej Qj; + secp256k1_ge Q; + int i; + for (i = 1; i <= 6; i++) { + secp256k1_scalar s; + random_scalar_order_test(&s); + secp256k1_scalar_add(&sum, &sum, &s); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &s); + secp256k1_ge_set_gej(&Q, &Qj); + secp256k1_pubkey_save(&data[i - 1], &Q); + d[i - 1] = &data[i - 1]; + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &Qj, &sum); + secp256k1_ge_set_gej(&Q, &Qj); + secp256k1_pubkey_save(&sd, &Q); + CHECK(secp256k1_ec_pubkey_combine(ctx, &sd2, d, i) == 1); + CHECK(memcmp(&sd, &sd2, sizeof(sd)) == 0); + } +} + +void run_ec_combine(void) { + int i; + for (i = 0; i < count * 8; i++) { + test_ec_combine(); + } +} + +void test_group_decompress(const secp256k1_fe* x) { + /* The input itself, normalized. */ + secp256k1_fe fex = *x; + secp256k1_fe fez; + /* Results of set_xquad_var, set_xo_var(..., 0), set_xo_var(..., 1). */ + secp256k1_ge ge_quad, ge_even, ge_odd; + secp256k1_gej gej_quad; + /* Return values of the above calls. */ + int res_quad, res_even, res_odd; + + secp256k1_fe_normalize_var(&fex); + + res_quad = secp256k1_ge_set_xquad(&ge_quad, &fex); + res_even = secp256k1_ge_set_xo_var(&ge_even, &fex, 0); + res_odd = secp256k1_ge_set_xo_var(&ge_odd, &fex, 1); + + CHECK(res_quad == res_even); + CHECK(res_quad == res_odd); + + if (res_quad) { + secp256k1_fe_normalize_var(&ge_quad.x); + secp256k1_fe_normalize_var(&ge_odd.x); + secp256k1_fe_normalize_var(&ge_even.x); + secp256k1_fe_normalize_var(&ge_quad.y); + secp256k1_fe_normalize_var(&ge_odd.y); + secp256k1_fe_normalize_var(&ge_even.y); + + /* No infinity allowed. */ + CHECK(!ge_quad.infinity); + CHECK(!ge_even.infinity); + CHECK(!ge_odd.infinity); + + /* Check that the x coordinates check out. */ + CHECK(secp256k1_fe_equal_var(&ge_quad.x, x)); + CHECK(secp256k1_fe_equal_var(&ge_even.x, x)); + CHECK(secp256k1_fe_equal_var(&ge_odd.x, x)); + + /* Check that the Y coordinate result in ge_quad is a square. */ + CHECK(secp256k1_fe_is_quad_var(&ge_quad.y)); + + /* Check odd/even Y in ge_odd, ge_even. */ + CHECK(secp256k1_fe_is_odd(&ge_odd.y)); + CHECK(!secp256k1_fe_is_odd(&ge_even.y)); + + /* Check secp256k1_gej_has_quad_y_var. */ + secp256k1_gej_set_ge(&gej_quad, &ge_quad); + CHECK(secp256k1_gej_has_quad_y_var(&gej_quad)); + do { + random_fe_test(&fez); + } while (secp256k1_fe_is_zero(&fez)); + secp256k1_gej_rescale(&gej_quad, &fez); + CHECK(secp256k1_gej_has_quad_y_var(&gej_quad)); + secp256k1_gej_neg(&gej_quad, &gej_quad); + CHECK(!secp256k1_gej_has_quad_y_var(&gej_quad)); + do { + random_fe_test(&fez); + } while (secp256k1_fe_is_zero(&fez)); + secp256k1_gej_rescale(&gej_quad, &fez); + CHECK(!secp256k1_gej_has_quad_y_var(&gej_quad)); + secp256k1_gej_neg(&gej_quad, &gej_quad); + CHECK(secp256k1_gej_has_quad_y_var(&gej_quad)); + } +} + +void run_group_decompress(void) { + int i; + for (i = 0; i < count * 4; i++) { + secp256k1_fe fe; + random_fe_test(&fe); + test_group_decompress(&fe); + } } /***** ECMULT TESTS *****/ void run_ecmult_chain(void) { /* random starting point A (on the curve) */ - secp256k1_gej_t a = SECP256K1_GEJ_CONST( + secp256k1_gej a = SECP256K1_GEJ_CONST( 0x8b30bbe9, 0xae2a9906, 0x96b22f67, 0x0709dff3, 0x727fd8bc, 0x04d3362c, 0x6c7bf458, 0xe2846004, 0xa357ae91, 0x5c4a6528, 0x1309edf2, 0x0504740f, 0x0eb33439, 0x90216b4f, 0x81063cb6, 0x5f2f7e0f ); /* two random initial factors xn and gn */ - secp256k1_scalar_t xn = SECP256K1_SCALAR_CONST( + secp256k1_scalar xn = SECP256K1_SCALAR_CONST( 0x84cc5452, 0xf7fde1ed, 0xb4d38a8c, 0xe9b1b84c, 0xcef31f14, 0x6e569be9, 0x705d357a, 0x42985407 ); - secp256k1_scalar_t gn = SECP256K1_SCALAR_CONST( + secp256k1_scalar gn = SECP256K1_SCALAR_CONST( 0xa1e58d22, 0x553dcd42, 0xb2398062, 0x5d4c57a9, 0x6e9323d4, 0x2b3152e5, 0xca2c3990, 0xedc7c9de ); /* two small multipliers to be applied to xn and gn in every iteration: */ - static const secp256k1_scalar_t xf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x1337); - static const secp256k1_scalar_t gf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x7113); + static const secp256k1_scalar xf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x1337); + static const secp256k1_scalar gf = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0x7113); /* accumulators with the resulting coefficients to A and G */ - secp256k1_scalar_t ae = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); - secp256k1_scalar_t ge = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + secp256k1_scalar ae = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); + secp256k1_scalar ge = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); /* actual points */ - secp256k1_gej_t x = a; - secp256k1_gej_t x2; + secp256k1_gej x; + secp256k1_gej x2; int i; /* the point being computed */ @@ -1131,7 +2308,7 @@ void run_ecmult_chain(void) { /* verify */ if (i == 19999) { /* expected result after 19999 iterations */ - secp256k1_gej_t rp = SECP256K1_GEJ_CONST( + secp256k1_gej rp = SECP256K1_GEJ_CONST( 0xD6E96687, 0xF9B10D09, 0x2A6F3543, 0x9D86CEBE, 0xA4535D0D, 0x409F5358, 0x6440BD74, 0xB933E830, 0xB95CBCA2, 0xC77DA786, 0x539BE8FD, 0x53354D2D, @@ -1139,30 +2316,32 @@ void run_ecmult_chain(void) { ); secp256k1_gej_neg(&rp, &rp); - secp256k1_gej_add_var(&rp, &rp, &x); + secp256k1_gej_add_var(&rp, &rp, &x, NULL); CHECK(secp256k1_gej_is_infinity(&rp)); } } /* redo the computation, but directly with the resulting ae and ge coefficients: */ secp256k1_ecmult(&ctx->ecmult_ctx, &x2, &a, &ae, &ge); secp256k1_gej_neg(&x2, &x2); - secp256k1_gej_add_var(&x2, &x2, &x); + secp256k1_gej_add_var(&x2, &x2, &x, NULL); CHECK(secp256k1_gej_is_infinity(&x2)); } -void test_point_times_order(const secp256k1_gej_t *point) { +void test_point_times_order(const secp256k1_gej *point) { /* X * (point + G) + (order-X) * (pointer + G) = 0 */ - secp256k1_scalar_t x; - secp256k1_scalar_t nx; - secp256k1_gej_t res1, res2; - secp256k1_ge_t res3; + secp256k1_scalar x; + secp256k1_scalar nx; + secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + secp256k1_scalar one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); + secp256k1_gej res1, res2; + secp256k1_ge res3; unsigned char pub[65]; - int psize = 65; + size_t psize = 65; random_scalar_order_test(&x); secp256k1_scalar_negate(&nx, &x); secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &x, &x); /* calc res1 = x * point + x * G; */ secp256k1_ecmult(&ctx->ecmult_ctx, &res2, point, &nx, &nx); /* calc res2 = (order - x) * point + (order - x) * G; */ - secp256k1_gej_add_var(&res1, &res1, &res2); + secp256k1_gej_add_var(&res1, &res1, &res2, NULL); CHECK(secp256k1_gej_is_infinity(&res1)); CHECK(secp256k1_gej_is_valid_var(&res1) == 0); secp256k1_ge_set_gej(&res3, &res1); @@ -1171,19 +2350,29 @@ void test_point_times_order(const secp256k1_gej_t *point) { CHECK(secp256k1_eckey_pubkey_serialize(&res3, pub, &psize, 0) == 0); psize = 65; CHECK(secp256k1_eckey_pubkey_serialize(&res3, pub, &psize, 1) == 0); + /* check zero/one edge cases */ + secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &zero, &zero); + secp256k1_ge_set_gej(&res3, &res1); + CHECK(secp256k1_ge_is_infinity(&res3)); + secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &one, &zero); + secp256k1_ge_set_gej(&res3, &res1); + ge_equals_gej(&res3, point); + secp256k1_ecmult(&ctx->ecmult_ctx, &res1, point, &zero, &one); + secp256k1_ge_set_gej(&res3, &res1); + ge_equals_ge(&res3, &secp256k1_ge_const_g); } void run_point_times_order(void) { int i; - secp256k1_fe_t x = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 2); - static const secp256k1_fe_t xr = SECP256K1_FE_CONST( + secp256k1_fe x = SECP256K1_FE_CONST(0, 0, 0, 0, 0, 0, 0, 2); + static const secp256k1_fe xr = SECP256K1_FE_CONST( 0x7603CB59, 0xB0EF6C63, 0xFE608479, 0x2A0C378C, 0xDB3233A8, 0x0F8A9A09, 0xA877DEAD, 0x31B38C45 ); for (i = 0; i < 500; i++) { - secp256k1_ge_t p; + secp256k1_ge p; if (secp256k1_ge_set_xo_var(&p, &x, 1)) { - secp256k1_gej_t j; + secp256k1_gej j; CHECK(secp256k1_ge_is_valid_var(&p)); secp256k1_gej_set_ge(&j, &p); CHECK(secp256k1_gej_is_valid_var(&j)); @@ -1195,15 +2384,118 @@ void run_point_times_order(void) { CHECK(secp256k1_fe_equal_var(&x, &xr)); } -void test_wnaf(const secp256k1_scalar_t *number, int w) { - secp256k1_scalar_t x, two, t; +void ecmult_const_random_mult(void) { + /* random starting point A (on the curve) */ + secp256k1_ge a = SECP256K1_GE_CONST( + 0x6d986544, 0x57ff52b8, 0xcf1b8126, 0x5b802a5b, + 0xa97f9263, 0xb1e88044, 0x93351325, 0x91bc450a, + 0x535c59f7, 0x325e5d2b, 0xc391fbe8, 0x3c12787c, + 0x337e4a98, 0xe82a9011, 0x0123ba37, 0xdd769c7d + ); + /* random initial factor xn */ + secp256k1_scalar xn = SECP256K1_SCALAR_CONST( + 0x649d4f77, 0xc4242df7, 0x7f2079c9, 0x14530327, + 0xa31b876a, 0xd2d8ce2a, 0x2236d5c6, 0xd7b2029b + ); + /* expected xn * A (from sage) */ + secp256k1_ge expected_b = SECP256K1_GE_CONST( + 0x23773684, 0x4d209dc7, 0x098a786f, 0x20d06fcd, + 0x070a38bf, 0xc11ac651, 0x03004319, 0x1e2a8786, + 0xed8c3b8e, 0xc06dd57b, 0xd06ea66e, 0x45492b0f, + 0xb84e4e1b, 0xfb77e21f, 0x96baae2a, 0x63dec956 + ); + secp256k1_gej b; + secp256k1_ecmult_const(&b, &a, &xn); + + CHECK(secp256k1_ge_is_valid_var(&a)); + ge_equals_gej(&expected_b, &b); +} + +void ecmult_const_commutativity(void) { + secp256k1_scalar a; + secp256k1_scalar b; + secp256k1_gej res1; + secp256k1_gej res2; + secp256k1_ge mid1; + secp256k1_ge mid2; + random_scalar_order_test(&a); + random_scalar_order_test(&b); + + secp256k1_ecmult_const(&res1, &secp256k1_ge_const_g, &a); + secp256k1_ecmult_const(&res2, &secp256k1_ge_const_g, &b); + secp256k1_ge_set_gej(&mid1, &res1); + secp256k1_ge_set_gej(&mid2, &res2); + secp256k1_ecmult_const(&res1, &mid1, &b); + secp256k1_ecmult_const(&res2, &mid2, &a); + secp256k1_ge_set_gej(&mid1, &res1); + secp256k1_ge_set_gej(&mid2, &res2); + ge_equals_ge(&mid1, &mid2); +} + +void ecmult_const_mult_zero_one(void) { + secp256k1_scalar zero = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 0); + secp256k1_scalar one = SECP256K1_SCALAR_CONST(0, 0, 0, 0, 0, 0, 0, 1); + secp256k1_scalar negone; + secp256k1_gej res1; + secp256k1_ge res2; + secp256k1_ge point; + secp256k1_scalar_negate(&negone, &one); + + random_group_element_test(&point); + secp256k1_ecmult_const(&res1, &point, &zero); + secp256k1_ge_set_gej(&res2, &res1); + CHECK(secp256k1_ge_is_infinity(&res2)); + secp256k1_ecmult_const(&res1, &point, &one); + secp256k1_ge_set_gej(&res2, &res1); + ge_equals_ge(&res2, &point); + secp256k1_ecmult_const(&res1, &point, &negone); + secp256k1_gej_neg(&res1, &res1); + secp256k1_ge_set_gej(&res2, &res1); + ge_equals_ge(&res2, &point); +} + +void ecmult_const_chain_multiply(void) { + /* Check known result (randomly generated test problem from sage) */ + const secp256k1_scalar scalar = SECP256K1_SCALAR_CONST( + 0x4968d524, 0x2abf9b7a, 0x466abbcf, 0x34b11b6d, + 0xcd83d307, 0x827bed62, 0x05fad0ce, 0x18fae63b + ); + const secp256k1_gej expected_point = SECP256K1_GEJ_CONST( + 0x5494c15d, 0x32099706, 0xc2395f94, 0x348745fd, + 0x757ce30e, 0x4e8c90fb, 0xa2bad184, 0xf883c69f, + 0x5d195d20, 0xe191bf7f, 0x1be3e55f, 0x56a80196, + 0x6071ad01, 0xf1462f66, 0xc997fa94, 0xdb858435 + ); + secp256k1_gej point; + secp256k1_ge res; + int i; + + secp256k1_gej_set_ge(&point, &secp256k1_ge_const_g); + for (i = 0; i < 100; ++i) { + secp256k1_ge tmp; + secp256k1_ge_set_gej(&tmp, &point); + secp256k1_ecmult_const(&point, &tmp, &scalar); + } + secp256k1_ge_set_gej(&res, &point); + ge_equals_gej(&res, &expected_point); +} + +void run_ecmult_const_tests(void) { + ecmult_const_mult_zero_one(); + ecmult_const_random_mult(); + ecmult_const_commutativity(); + ecmult_const_chain_multiply(); +} + +void test_wnaf(const secp256k1_scalar *number, int w) { + secp256k1_scalar x, two, t; int wnaf[256]; int zeroes = -1; int i; int bits; secp256k1_scalar_set_int(&x, 0); secp256k1_scalar_set_int(&two, 2); - bits = secp256k1_ecmult_wnaf(wnaf, number, w); + bits = secp256k1_ecmult_wnaf(wnaf, 256, number, w); CHECK(bits <= 256); for (i = bits-1; i >= 0; i--) { int v = wnaf[i]; @@ -1229,20 +2521,89 @@ void test_wnaf(const secp256k1_scalar_t *number, int w) { CHECK(secp256k1_scalar_eq(&x, number)); /* check that wnaf represents number */ } +void test_constant_wnaf_negate(const secp256k1_scalar *number) { + secp256k1_scalar neg1 = *number; + secp256k1_scalar neg2 = *number; + int sign1 = 1; + int sign2 = 1; + + if (!secp256k1_scalar_get_bits(&neg1, 0, 1)) { + secp256k1_scalar_negate(&neg1, &neg1); + sign1 = -1; + } + sign2 = secp256k1_scalar_cond_negate(&neg2, secp256k1_scalar_is_even(&neg2)); + CHECK(sign1 == sign2); + CHECK(secp256k1_scalar_eq(&neg1, &neg2)); +} + +void test_constant_wnaf(const secp256k1_scalar *number, int w) { + secp256k1_scalar x, shift; + int wnaf[256] = {0}; + int i; + int skew; + secp256k1_scalar num = *number; + + secp256k1_scalar_set_int(&x, 0); + secp256k1_scalar_set_int(&shift, 1 << w); + /* With USE_ENDOMORPHISM on we only consider 128-bit numbers */ +#ifdef USE_ENDOMORPHISM + for (i = 0; i < 16; ++i) { + secp256k1_scalar_shr_int(&num, 8); + } +#endif + skew = secp256k1_wnaf_const(wnaf, num, w); + + for (i = WNAF_SIZE(w); i >= 0; --i) { + secp256k1_scalar t; + int v = wnaf[i]; + CHECK(v != 0); /* check nonzero */ + CHECK(v & 1); /* check parity */ + CHECK(v > -(1 << w)); /* check range above */ + CHECK(v < (1 << w)); /* check range below */ + + secp256k1_scalar_mul(&x, &x, &shift); + if (v >= 0) { + secp256k1_scalar_set_int(&t, v); + } else { + secp256k1_scalar_set_int(&t, -v); + secp256k1_scalar_negate(&t, &t); + } + secp256k1_scalar_add(&x, &x, &t); + } + /* Skew num because when encoding numbers as odd we use an offset */ + secp256k1_scalar_cadd_bit(&num, skew == 2, 1); + CHECK(secp256k1_scalar_eq(&x, &num)); +} + void run_wnaf(void) { int i; - secp256k1_scalar_t n; + secp256k1_scalar n = {{0}}; + + /* Sanity check: 1 and 2 are the smallest odd and even numbers and should + * have easier-to-diagnose failure modes */ + n.d[0] = 1; + test_constant_wnaf(&n, 4); + n.d[0] = 2; + test_constant_wnaf(&n, 4); + /* Random tests */ for (i = 0; i < count; i++) { random_scalar_order(&n); test_wnaf(&n, 4+(i%10)); + test_constant_wnaf_negate(&n); + test_constant_wnaf(&n, 4 + (i % 10)); } + secp256k1_scalar_set_int(&n, 0); + CHECK(secp256k1_scalar_cond_negate(&n, 1) == -1); + CHECK(secp256k1_scalar_is_zero(&n)); + CHECK(secp256k1_scalar_cond_negate(&n, 0) == 1); + CHECK(secp256k1_scalar_is_zero(&n)); } void test_ecmult_constants(void) { /* Test ecmult_gen() for [0..36) and [order-36..0). */ - secp256k1_scalar_t x; - secp256k1_gej_t r; - secp256k1_ge_t ng; + secp256k1_scalar x; + secp256k1_gej r; + secp256k1_ge ng; int i; int j; secp256k1_ge_neg(&ng, &secp256k1_ge_const_g); @@ -1276,14 +2637,14 @@ void run_ecmult_constants(void) { } void test_ecmult_gen_blind(void) { - /* Test ecmult_gen() blinding and confirm that the blinding changes, the affline points match, and the z's don't match. */ - secp256k1_scalar_t key; - secp256k1_scalar_t b; + /* Test ecmult_gen() blinding and confirm that the blinding changes, the affine points match, and the z's don't match. */ + secp256k1_scalar key; + secp256k1_scalar b; unsigned char seed32[32]; - secp256k1_gej_t pgej; - secp256k1_gej_t pgej2; - secp256k1_gej_t i; - secp256k1_ge_t pge; + secp256k1_gej pgej; + secp256k1_gej pgej2; + secp256k1_gej i; + secp256k1_ge pge; random_scalar_order_test(&key); secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pgej, &key); secp256k1_rand256(seed32); @@ -1300,8 +2661,8 @@ void test_ecmult_gen_blind(void) { void test_ecmult_gen_blind_reset(void) { /* Test ecmult_gen() blinding reset and confirm that the blinding is consistent. */ - secp256k1_scalar_t b; - secp256k1_gej_t initial; + secp256k1_scalar b; + secp256k1_gej initial; secp256k1_ecmult_gen_blind(&ctx->ecmult_gen_ctx, 0); b = ctx->ecmult_gen_ctx.blind; initial = ctx->ecmult_gen_ctx.initial; @@ -1318,35 +2679,702 @@ void run_ecmult_gen_blind(void) { } } +#ifdef USE_ENDOMORPHISM +/***** ENDOMORPHISH TESTS *****/ +void test_scalar_split(void) { + secp256k1_scalar full; + secp256k1_scalar s1, slam; + const unsigned char zero[32] = {0}; + unsigned char tmp[32]; -void random_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *key, const secp256k1_scalar_t *msg, int *recid) { - secp256k1_scalar_t nonce; + random_scalar_order_test(&full); + secp256k1_scalar_split_lambda(&s1, &slam, &full); + + /* check that both are <= 128 bits in size */ + if (secp256k1_scalar_is_high(&s1)) { + secp256k1_scalar_negate(&s1, &s1); + } + if (secp256k1_scalar_is_high(&slam)) { + secp256k1_scalar_negate(&slam, &slam); + } + + secp256k1_scalar_get_b32(tmp, &s1); + CHECK(memcmp(zero, tmp, 16) == 0); + secp256k1_scalar_get_b32(tmp, &slam); + CHECK(memcmp(zero, tmp, 16) == 0); +} + +void run_endomorphism_tests(void) { + test_scalar_split(); +} +#endif + +void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvalid) { + unsigned char pubkeyc[65]; + secp256k1_pubkey pubkey; + secp256k1_ge ge; + size_t pubkeyclen; + int32_t ecount; + ecount = 0; + secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); + for (pubkeyclen = 3; pubkeyclen <= 65; pubkeyclen++) { + /* Smaller sizes are tested exhaustively elsewhere. */ + int32_t i; + memcpy(&pubkeyc[1], input, 64); + VG_UNDEF(&pubkeyc[pubkeyclen], 65 - pubkeyclen); + for (i = 0; i < 256; i++) { + /* Try all type bytes. */ + int xpass; + int ypass; + int ysign; + pubkeyc[0] = i; + /* What sign does this point have? */ + ysign = (input[63] & 1) + 2; + /* For the current type (i) do we expect parsing to work? Handled all of compressed/uncompressed/hybrid. */ + xpass = xvalid && (pubkeyclen == 33) && ((i & 254) == 2); + /* Do we expect a parse and re-serialize as uncompressed to give a matching y? */ + ypass = xvalid && yvalid && ((i & 4) == ((pubkeyclen == 65) << 2)) && + ((i == 4) || ((i & 251) == ysign)) && ((pubkeyclen == 33) || (pubkeyclen == 65)); + if (xpass || ypass) { + /* These cases must parse. */ + unsigned char pubkeyo[65]; + size_t outl; + memset(&pubkey, 0, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + ecount = 0; + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1); + VG_CHECK(&pubkey, sizeof(pubkey)); + outl = 65; + VG_UNDEF(pubkeyo, 65); + CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyo, &outl, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + VG_CHECK(pubkeyo, outl); + CHECK(outl == 33); + CHECK(memcmp(&pubkeyo[1], &pubkeyc[1], 32) == 0); + CHECK((pubkeyclen != 33) || (pubkeyo[0] == pubkeyc[0])); + if (ypass) { + /* This test isn't always done because we decode with alternative signs, so the y won't match. */ + CHECK(pubkeyo[0] == ysign); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 1); + memset(&pubkey, 0, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + secp256k1_pubkey_save(&pubkey, &ge); + VG_CHECK(&pubkey, sizeof(pubkey)); + outl = 65; + VG_UNDEF(pubkeyo, 65); + CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyo, &outl, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1); + VG_CHECK(pubkeyo, outl); + CHECK(outl == 65); + CHECK(pubkeyo[0] == 4); + CHECK(memcmp(&pubkeyo[1], input, 64) == 0); + } + CHECK(ecount == 0); + } else { + /* These cases must fail to parse. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + } + } + } + secp256k1_context_set_illegal_callback(ctx, NULL, NULL); +} + +void run_ec_pubkey_parse_test(void) { +#define SECP256K1_EC_PARSE_TEST_NVALID (12) + const unsigned char valid[SECP256K1_EC_PARSE_TEST_NVALID][64] = { + { + /* Point with leading and trailing zeros in x and y serialization. */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x52, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x64, 0xef, 0xa1, 0x7b, 0x77, 0x61, 0xe1, 0xe4, 0x27, 0x06, 0x98, 0x9f, 0xb4, 0x83, + 0xb8, 0xd2, 0xd4, 0x9b, 0xf7, 0x8f, 0xae, 0x98, 0x03, 0xf0, 0x99, 0xb8, 0x34, 0xed, 0xeb, 0x00 + }, + { + /* Point with x equal to a 3rd root of unity.*/ + 0x7a, 0xe9, 0x6a, 0x2b, 0x65, 0x7c, 0x07, 0x10, 0x6e, 0x64, 0x47, 0x9e, 0xac, 0x34, 0x34, 0xe9, + 0x9c, 0xf0, 0x49, 0x75, 0x12, 0xf5, 0x89, 0x95, 0xc1, 0x39, 0x6c, 0x28, 0x71, 0x95, 0x01, 0xee, + 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, + 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee, + }, + { + /* Point with largest x. (1/2) */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2c, + 0x0e, 0x99, 0x4b, 0x14, 0xea, 0x72, 0xf8, 0xc3, 0xeb, 0x95, 0xc7, 0x1e, 0xf6, 0x92, 0x57, 0x5e, + 0x77, 0x50, 0x58, 0x33, 0x2d, 0x7e, 0x52, 0xd0, 0x99, 0x5c, 0xf8, 0x03, 0x88, 0x71, 0xb6, 0x7d, + }, + { + /* Point with largest x. (2/2) */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2c, + 0xf1, 0x66, 0xb4, 0xeb, 0x15, 0x8d, 0x07, 0x3c, 0x14, 0x6a, 0x38, 0xe1, 0x09, 0x6d, 0xa8, 0xa1, + 0x88, 0xaf, 0xa7, 0xcc, 0xd2, 0x81, 0xad, 0x2f, 0x66, 0xa3, 0x07, 0xfb, 0x77, 0x8e, 0x45, 0xb2, + }, + { + /* Point with smallest x. (1/2) */ + 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, 0x01, + 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, + 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee, + }, + { + /* Point with smallest x. (2/2) */ + 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, 0x01, + 0xbd, 0xe7, 0x0d, 0xf5, 0x19, 0x39, 0xb9, 0x4c, 0x9c, 0x24, 0x97, 0x9f, 0xa7, 0xdd, 0x04, 0xeb, + 0xd9, 0xb3, 0x57, 0x2d, 0xa7, 0x80, 0x22, 0x90, 0x43, 0x8a, 0xf2, 0xa6, 0x81, 0x89, 0x54, 0x41, + }, + { + /* Point with largest y. (1/3) */ + 0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, + 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + }, + { + /* Point with largest y. (2/3) */ + 0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, + 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + }, + { + /* Point with largest y. (3/3) */ + 0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc, + 0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + }, + { + /* Point with smallest y. (1/3) */ + 0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, + 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, + 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, 0x01, + }, + { + /* Point with smallest y. (2/3) */ + 0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, + 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, + 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, 0x01, + }, + { + /* Point with smallest y. (3/3) */ + 0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc, + 0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5, + 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, 0x01 + } + }; +#define SECP256K1_EC_PARSE_TEST_NXVALID (4) + const unsigned char onlyxvalid[SECP256K1_EC_PARSE_TEST_NXVALID][64] = { + { + /* Valid if y overflow ignored (y = 1 mod p). (1/3) */ + 0x1f, 0xe1, 0xe5, 0xef, 0x3f, 0xce, 0xb5, 0xc1, 0x35, 0xab, 0x77, 0x41, 0x33, 0x3c, 0xe5, 0xa6, + 0xe8, 0x0d, 0x68, 0x16, 0x76, 0x53, 0xf6, 0xb2, 0xb2, 0x4b, 0xcb, 0xcf, 0xaa, 0xaf, 0xf5, 0x07, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, + }, + { + /* Valid if y overflow ignored (y = 1 mod p). (2/3) */ + 0xcb, 0xb0, 0xde, 0xab, 0x12, 0x57, 0x54, 0xf1, 0xfd, 0xb2, 0x03, 0x8b, 0x04, 0x34, 0xed, 0x9c, + 0xb3, 0xfb, 0x53, 0xab, 0x73, 0x53, 0x91, 0x12, 0x99, 0x94, 0xa5, 0x35, 0xd9, 0x25, 0xf6, 0x73, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, + }, + { + /* Valid if y overflow ignored (y = 1 mod p). (3/3)*/ + 0x14, 0x6d, 0x3b, 0x65, 0xad, 0xd9, 0xf5, 0x4c, 0xcc, 0xa2, 0x85, 0x33, 0xc8, 0x8e, 0x2c, 0xbc, + 0x63, 0xf7, 0x44, 0x3e, 0x16, 0x58, 0x78, 0x3a, 0xb4, 0x1f, 0x8e, 0xf9, 0x7c, 0x2a, 0x10, 0xb5, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, + }, + { + /* x on curve, y is from y^2 = x^3 + 8. */ + 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, 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, 0x03 + } + }; +#define SECP256K1_EC_PARSE_TEST_NINVALID (7) + const unsigned char invalid[SECP256K1_EC_PARSE_TEST_NINVALID][64] = { + { + /* x is third root of -8, y is -1 * (x^3+7); also on the curve for y^2 = x^3 + 9. */ + 0x0a, 0x2d, 0x2b, 0xa9, 0x35, 0x07, 0xf1, 0xdf, 0x23, 0x37, 0x70, 0xc2, 0xa7, 0x97, 0x96, 0x2c, + 0xc6, 0x1f, 0x6d, 0x15, 0xda, 0x14, 0xec, 0xd4, 0x7d, 0x8d, 0x27, 0xae, 0x1c, 0xd5, 0xf8, 0x53, + 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, 0x01, + }, + { + /* Valid if x overflow ignored (x = 1 mod p). */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, + 0x42, 0x18, 0xf2, 0x0a, 0xe6, 0xc6, 0x46, 0xb3, 0x63, 0xdb, 0x68, 0x60, 0x58, 0x22, 0xfb, 0x14, + 0x26, 0x4c, 0xa8, 0xd2, 0x58, 0x7f, 0xdd, 0x6f, 0xbc, 0x75, 0x0d, 0x58, 0x7e, 0x76, 0xa7, 0xee, + }, + { + /* Valid if x overflow ignored (x = 1 mod p). */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x30, + 0xbd, 0xe7, 0x0d, 0xf5, 0x19, 0x39, 0xb9, 0x4c, 0x9c, 0x24, 0x97, 0x9f, 0xa7, 0xdd, 0x04, 0xeb, + 0xd9, 0xb3, 0x57, 0x2d, 0xa7, 0x80, 0x22, 0x90, 0x43, 0x8a, 0xf2, 0xa6, 0x81, 0x89, 0x54, 0x41, + }, + { + /* x is -1, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 5. */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + 0xf4, 0x84, 0x14, 0x5c, 0xb0, 0x14, 0x9b, 0x82, 0x5d, 0xff, 0x41, 0x2f, 0xa0, 0x52, 0xa8, 0x3f, + 0xcb, 0x72, 0xdb, 0x61, 0xd5, 0x6f, 0x37, 0x70, 0xce, 0x06, 0x6b, 0x73, 0x49, 0xa2, 0xaa, 0x28, + }, + { + /* x is -1, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 5. */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xfc, 0x2e, + 0x0b, 0x7b, 0xeb, 0xa3, 0x4f, 0xeb, 0x64, 0x7d, 0xa2, 0x00, 0xbe, 0xd0, 0x5f, 0xad, 0x57, 0xc0, + 0x34, 0x8d, 0x24, 0x9e, 0x2a, 0x90, 0xc8, 0x8f, 0x31, 0xf9, 0x94, 0x8b, 0xb6, 0x5d, 0x52, 0x07, + }, + { + /* x is zero, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 7. */ + 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, + 0x8f, 0x53, 0x7e, 0xef, 0xdf, 0xc1, 0x60, 0x6a, 0x07, 0x27, 0xcd, 0x69, 0xb4, 0xa7, 0x33, 0x3d, + 0x38, 0xed, 0x44, 0xe3, 0x93, 0x2a, 0x71, 0x79, 0xee, 0xcb, 0x4b, 0x6f, 0xba, 0x93, 0x60, 0xdc, + }, + { + /* x is zero, y is the result of the sqrt ladder; also on the curve for y^2 = x^3 - 7. */ + 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, + 0x70, 0xac, 0x81, 0x10, 0x20, 0x3e, 0x9f, 0x95, 0xf8, 0xd8, 0x32, 0x96, 0x4b, 0x58, 0xcc, 0xc2, + 0xc7, 0x12, 0xbb, 0x1c, 0x6c, 0xd5, 0x8e, 0x86, 0x11, 0x34, 0xb4, 0x8f, 0x45, 0x6c, 0x9b, 0x53 + } + }; + const unsigned char pubkeyc[66] = { + /* Serialization of G. */ + 0x04, 0x79, 0xBE, 0x66, 0x7E, 0xF9, 0xDC, 0xBB, 0xAC, 0x55, 0xA0, 0x62, 0x95, 0xCE, 0x87, 0x0B, + 0x07, 0x02, 0x9B, 0xFC, 0xDB, 0x2D, 0xCE, 0x28, 0xD9, 0x59, 0xF2, 0x81, 0x5B, 0x16, 0xF8, 0x17, + 0x98, 0x48, 0x3A, 0xDA, 0x77, 0x26, 0xA3, 0xC4, 0x65, 0x5D, 0xA4, 0xFB, 0xFC, 0x0E, 0x11, 0x08, + 0xA8, 0xFD, 0x17, 0xB4, 0x48, 0xA6, 0x85, 0x54, 0x19, 0x9C, 0x47, 0xD0, 0x8F, 0xFB, 0x10, 0xD4, + 0xB8, 0x00 + }; + unsigned char sout[65]; + unsigned char shortkey[2]; + secp256k1_ge ge; + secp256k1_pubkey pubkey; + size_t len; + int32_t i; + int32_t ecount; + int32_t ecount2; + ecount = 0; + /* Nothing should be reading this far into pubkeyc. */ + VG_UNDEF(&pubkeyc[65], 1); + secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); + /* Zero length claimed, fail, zeroize, no illegal arg error. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(shortkey, 2); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, shortkey, 0) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + /* Length one claimed, fail, zeroize, no illegal arg error. */ + for (i = 0; i < 256 ; i++) { + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + shortkey[0] = i; + VG_UNDEF(&shortkey[1], 1); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, shortkey, 1) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + } + /* Length two claimed, fail, zeroize, no illegal arg error. */ + for (i = 0; i < 65536 ; i++) { + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + shortkey[0] = i & 255; + shortkey[1] = i >> 8; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, shortkey, 2) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + } + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + /* 33 bytes claimed on otherwise valid input starting with 0x04, fail, zeroize output, no illegal arg error. */ + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 33) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + /* NULL pubkey, illegal arg error. Pubkey isn't rewritten before this step, since it's NULL into the parser. */ + CHECK(secp256k1_ec_pubkey_parse(ctx, NULL, pubkeyc, 65) == 0); + CHECK(ecount == 2); + /* NULL input string. Illegal arg and zeroize output. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, NULL, 65) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 1); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 2); + /* 64 bytes claimed on input starting with 0x04, fail, zeroize output, no illegal arg error. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 64) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + /* 66 bytes claimed, fail, zeroize output, no illegal arg error. */ + memset(&pubkey, 0xfe, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 66) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 0); + CHECK(ecount == 1); + /* Valid parse. */ + memset(&pubkey, 0, sizeof(pubkey)); + ecount = 0; + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, 65) == 1); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(ecount == 0); + VG_UNDEF(&ge, sizeof(ge)); + CHECK(secp256k1_pubkey_load(ctx, &ge, &pubkey) == 1); + VG_CHECK(&ge.x, sizeof(ge.x)); + VG_CHECK(&ge.y, sizeof(ge.y)); + VG_CHECK(&ge.infinity, sizeof(ge.infinity)); + ge_equals_ge(&secp256k1_ge_const_g, &ge); + CHECK(ecount == 0); + /* secp256k1_ec_pubkey_serialize illegal args. */ + ecount = 0; + len = 65; + CHECK(secp256k1_ec_pubkey_serialize(ctx, NULL, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0); + CHECK(ecount == 1); + CHECK(len == 0); + CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, NULL, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 0); + CHECK(ecount == 2); + len = 65; + VG_UNDEF(sout, 65); + CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, &len, NULL, SECP256K1_EC_UNCOMPRESSED) == 0); + VG_CHECK(sout, 65); + CHECK(ecount == 3); + CHECK(len == 0); + len = 65; + CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, &len, &pubkey, ~0) == 0); + CHECK(ecount == 4); + CHECK(len == 0); + len = 65; + VG_UNDEF(sout, 65); + CHECK(secp256k1_ec_pubkey_serialize(ctx, sout, &len, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1); + VG_CHECK(sout, 65); + CHECK(ecount == 4); + CHECK(len == 65); + /* Multiple illegal args. Should still set arg error only once. */ + ecount = 0; + ecount2 = 11; + CHECK(secp256k1_ec_pubkey_parse(ctx, NULL, NULL, 65) == 0); + CHECK(ecount == 1); + /* Does the illegal arg callback actually change the behavior? */ + secp256k1_context_set_illegal_callback(ctx, uncounting_illegal_callback_fn, &ecount2); + CHECK(secp256k1_ec_pubkey_parse(ctx, NULL, NULL, 65) == 0); + CHECK(ecount == 1); + CHECK(ecount2 == 10); + secp256k1_context_set_illegal_callback(ctx, NULL, NULL); + /* Try a bunch of prefabbed points with all possible encodings. */ + for (i = 0; i < SECP256K1_EC_PARSE_TEST_NVALID; i++) { + ec_pubkey_parse_pointtest(valid[i], 1, 1); + } + for (i = 0; i < SECP256K1_EC_PARSE_TEST_NXVALID; i++) { + ec_pubkey_parse_pointtest(onlyxvalid[i], 1, 0); + } + for (i = 0; i < SECP256K1_EC_PARSE_TEST_NINVALID; i++) { + ec_pubkey_parse_pointtest(invalid[i], 0, 0); + } +} + +void run_eckey_edge_case_test(void) { + const unsigned char orderc[32] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41 + }; + const unsigned char zeros[sizeof(secp256k1_pubkey)] = {0x00}; + unsigned char ctmp[33]; + unsigned char ctmp2[33]; + secp256k1_pubkey pubkey; + secp256k1_pubkey pubkey2; + secp256k1_pubkey pubkey_one; + secp256k1_pubkey pubkey_negone; + const secp256k1_pubkey *pubkeys[3]; + size_t len; + int32_t ecount; + /* Group order is too large, reject. */ + CHECK(secp256k1_ec_seckey_verify(ctx, orderc) == 0); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, orderc) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* Maximum value is too large, reject. */ + memset(ctmp, 255, 32); + CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0); + memset(&pubkey, 1, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* Zero is too small, reject. */ + memset(ctmp, 0, 32); + CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0); + memset(&pubkey, 1, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* One must be accepted. */ + ctmp[31] = 0x01; + CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1); + memset(&pubkey, 0, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 1); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + pubkey_one = pubkey; + /* Group order + 1 is too large, reject. */ + memcpy(ctmp, orderc, 32); + ctmp[31] = 0x42; + CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 0); + memset(&pubkey, 1, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 0); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* -1 must be accepted. */ + ctmp[31] = 0x40; + CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1); + memset(&pubkey, 0, sizeof(pubkey)); + VG_UNDEF(&pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, ctmp) == 1); + VG_CHECK(&pubkey, sizeof(pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + pubkey_negone = pubkey; + /* Tweak of zero leaves the value changed. */ + memset(ctmp2, 0, 32); + CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, ctmp2) == 1); + CHECK(memcmp(orderc, ctmp, 31) == 0 && ctmp[31] == 0x40); + memcpy(&pubkey2, &pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + /* Multiply tweak of zero zeroizes the output. */ + CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, ctmp2) == 0); + CHECK(memcmp(zeros, ctmp, 32) == 0); + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, ctmp2) == 0); + CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + /* Overflowing key tweak zeroizes. */ + memcpy(ctmp, orderc, 32); + ctmp[31] = 0x40; + CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, orderc) == 0); + CHECK(memcmp(zeros, ctmp, 32) == 0); + memcpy(ctmp, orderc, 32); + ctmp[31] = 0x40; + CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, orderc) == 0); + CHECK(memcmp(zeros, ctmp, 32) == 0); + memcpy(ctmp, orderc, 32); + ctmp[31] = 0x40; + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, orderc) == 0); + CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, orderc) == 0); + CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + /* Private key tweaks results in a key of zero. */ + ctmp2[31] = 1; + CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp2, ctmp) == 0); + CHECK(memcmp(zeros, ctmp2, 32) == 0); + ctmp2[31] = 1; + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 0); + CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + /* Tweak computation wraps and results in a key of 1. */ + ctmp2[31] = 2; + CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp2, ctmp) == 1); + CHECK(memcmp(ctmp2, zeros, 31) == 0 && ctmp2[31] == 1); + ctmp2[31] = 2; + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1); + ctmp2[31] = 1; + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, ctmp2) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + /* Tweak mul * 2 = 1+1. */ + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 1); + ctmp2[31] = 2; + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey2, ctmp2) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); + /* Test argument errors. */ + ecount = 0; + secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); + CHECK(ecount == 0); + /* Zeroize pubkey on parse error. */ + memset(&pubkey, 0, 32); + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, ctmp2) == 0); + CHECK(ecount == 1); + CHECK(memcmp(&pubkey, zeros, sizeof(pubkey)) == 0); + memcpy(&pubkey, &pubkey2, sizeof(pubkey)); + memset(&pubkey2, 0, 32); + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey2, ctmp2) == 0); + CHECK(ecount == 2); + CHECK(memcmp(&pubkey2, zeros, sizeof(pubkey2)) == 0); + /* Plain argument errors. */ + ecount = 0; + CHECK(secp256k1_ec_seckey_verify(ctx, ctmp) == 1); + CHECK(ecount == 0); + CHECK(secp256k1_ec_seckey_verify(ctx, NULL) == 0); + CHECK(ecount == 1); + ecount = 0; + memset(ctmp2, 0, 32); + ctmp2[31] = 4; + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, NULL, ctmp2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, NULL) == 0); + CHECK(ecount == 2); + ecount = 0; + memset(ctmp2, 0, 32); + ctmp2[31] = 4; + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, NULL, ctmp2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, NULL) == 0); + CHECK(ecount == 2); + ecount = 0; + memset(ctmp2, 0, 32); + CHECK(secp256k1_ec_privkey_tweak_add(ctx, NULL, ctmp2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ec_privkey_tweak_add(ctx, ctmp, NULL) == 0); + CHECK(ecount == 2); + ecount = 0; + memset(ctmp2, 0, 32); + ctmp2[31] = 1; + CHECK(secp256k1_ec_privkey_tweak_mul(ctx, NULL, ctmp2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ec_privkey_tweak_mul(ctx, ctmp, NULL) == 0); + CHECK(ecount == 2); + ecount = 0; + CHECK(secp256k1_ec_pubkey_create(ctx, NULL, ctmp) == 0); + CHECK(ecount == 1); + memset(&pubkey, 1, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, NULL) == 0); + CHECK(ecount == 2); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + /* secp256k1_ec_pubkey_combine tests. */ + ecount = 0; + pubkeys[0] = &pubkey_one; + VG_UNDEF(&pubkeys[0], sizeof(secp256k1_pubkey *)); + VG_UNDEF(&pubkeys[1], sizeof(secp256k1_pubkey *)); + VG_UNDEF(&pubkeys[2], sizeof(secp256k1_pubkey *)); + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 0) == 0); + VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ec_pubkey_combine(ctx, NULL, pubkeys, 1) == 0); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK(ecount == 2); + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, NULL, 1) == 0); + VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK(ecount == 3); + pubkeys[0] = &pubkey_negone; + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 1) == 1); + VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + CHECK(ecount == 3); + len = 33; + CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp2, &len, &pubkey_negone, SECP256K1_EC_COMPRESSED) == 1); + CHECK(memcmp(ctmp, ctmp2, 33) == 0); + /* Result is infinity. */ + pubkeys[0] = &pubkey_one; + pubkeys[1] = &pubkey_negone; + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 2) == 0); + VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) == 0); + CHECK(ecount == 3); + /* Passes through infinity but comes out one. */ + pubkeys[2] = &pubkey_one; + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 3) == 1); + VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + CHECK(ecount == 3); + len = 33; + CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp, &len, &pubkey, SECP256K1_EC_COMPRESSED) == 1); + CHECK(secp256k1_ec_pubkey_serialize(ctx, ctmp2, &len, &pubkey_one, SECP256K1_EC_COMPRESSED) == 1); + CHECK(memcmp(ctmp, ctmp2, 33) == 0); + /* Adds to two. */ + pubkeys[1] = &pubkey_one; + memset(&pubkey, 255, sizeof(secp256k1_pubkey)); + VG_UNDEF(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(secp256k1_ec_pubkey_combine(ctx, &pubkey, pubkeys, 2) == 1); + VG_CHECK(&pubkey, sizeof(secp256k1_pubkey)); + CHECK(memcmp(&pubkey, zeros, sizeof(secp256k1_pubkey)) > 0); + CHECK(ecount == 3); + secp256k1_context_set_illegal_callback(ctx, NULL, NULL); +} + +void random_sign(secp256k1_scalar *sigr, secp256k1_scalar *sigs, const secp256k1_scalar *key, const secp256k1_scalar *msg, int *recid) { + secp256k1_scalar nonce; do { random_scalar_order_test(&nonce); - } while(!secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, sig, key, msg, &nonce, recid)); + } while(!secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, sigr, sigs, key, msg, &nonce, recid)); } void test_ecdsa_sign_verify(void) { - secp256k1_gej_t pubj; - secp256k1_ge_t pub; - secp256k1_scalar_t one; - secp256k1_scalar_t msg, key; - secp256k1_ecdsa_sig_t sig; + secp256k1_gej pubj; + secp256k1_ge pub; + secp256k1_scalar one; + secp256k1_scalar msg, key; + secp256k1_scalar sigr, sigs; int recid; int getrec; random_scalar_order_test(&msg); random_scalar_order_test(&key); secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubj, &key); secp256k1_ge_set_gej(&pub, &pubj); - getrec = secp256k1_rand32()&1; - random_sign(&sig, &key, &msg, getrec?&recid:NULL); + getrec = secp256k1_rand_bits(1); + random_sign(&sigr, &sigs, &key, &msg, getrec?&recid:NULL); if (getrec) { CHECK(recid >= 0 && recid < 4); } - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &pub, &msg)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &pub, &msg)); secp256k1_scalar_set_int(&one, 1); secp256k1_scalar_add(&msg, &msg, &one); - CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &pub, &msg)); + CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &pub, &msg)); } void run_ecdsa_sign_verify(void) { @@ -1357,22 +3385,23 @@ void run_ecdsa_sign_verify(void) { } /** Dummy nonce generation function that just uses a precomputed nonce, and fails if it is not accepted. Use only for testing. */ -static int precomputed_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) { +static int precomputed_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { (void)msg32; (void)key32; + (void)algo16; memcpy(nonce32, data, 32); return (counter == 0); } -static int nonce_function_test_fail(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) { +static int nonce_function_test_fail(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { /* Dummy nonce generator that has a fatal error on the first counter value. */ if (counter == 0) { return 0; } - return nonce_function_rfc6979(nonce32, msg32, key32, counter - 1, data); + return nonce_function_rfc6979(nonce32, msg32, key32, algo16, data, counter - 1); } -static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) { +static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *algo16, void *data, unsigned int counter) { /* Dummy nonce generator that produces unacceptable nonces for the first several counter values. */ if (counter < 3) { memset(nonce32, counter==0 ? 0 : 255, 32); @@ -1394,17 +3423,17 @@ static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char } return 1; } - /* Retry rate of 6979 is negligible esp. as we only call this in determinstic tests. */ + /* Retry rate of 6979 is negligible esp. as we only call this in deterministic tests. */ /* If someone does fine a case where it retries for secp256k1, we'd like to know. */ if (counter > 5) { return 0; } - return nonce_function_rfc6979(nonce32, msg32, key32, counter - 5, data); + return nonce_function_rfc6979(nonce32, msg32, key32, algo16, data, counter - 5); } -int is_empty_compact_signature(const unsigned char *sig64) { - static const unsigned char res[64] = {0}; - return memcmp(sig64, res, 64) == 0; +int is_empty_signature(const secp256k1_ecdsa_signature *sig) { + static const unsigned char res[sizeof(secp256k1_ecdsa_signature)] = {0}; + return memcmp(sig, res, sizeof(secp256k1_ecdsa_signature)) == 0; } void test_ecdsa_end_to_end(void) { @@ -1412,26 +3441,20 @@ void test_ecdsa_end_to_end(void) { unsigned char privkey[32]; unsigned char message[32]; unsigned char privkey2[32]; - unsigned char csignature[64]; - unsigned char signature[72]; - unsigned char signature2[72]; - unsigned char signature3[72]; - unsigned char signature4[72]; - unsigned char pubkey[65]; - unsigned char recpubkey[65]; + secp256k1_ecdsa_signature signature[6]; + secp256k1_scalar r, s; + unsigned char sig[74]; + size_t siglen = 74; + unsigned char pubkeyc[65]; + size_t pubkeyclen = 65; + secp256k1_pubkey pubkey; + secp256k1_pubkey pubkey_tmp; unsigned char seckey[300]; - int signaturelen = 72; - int signaturelen2 = 72; - int signaturelen3 = 72; - int signaturelen4 = 72; - int recid = 0; - int recpubkeylen = 0; - int pubkeylen = 65; - int seckeylen = 300; + size_t seckeylen = 300; /* Generate a random key and message. */ { - secp256k1_scalar_t msg, key; + secp256k1_scalar msg, key; random_scalar_order_test(&msg); random_scalar_order_test(&key); secp256k1_scalar_get_b32(privkey, &key); @@ -1440,117 +3463,127 @@ void test_ecdsa_end_to_end(void) { /* Construct and verify corresponding public key. */ CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); - CHECK(secp256k1_ec_pubkey_create(ctx, pubkey, &pubkeylen, privkey, (secp256k1_rand32() & 3) != 0) == 1); - if (secp256k1_rand32() & 1) { - CHECK(secp256k1_ec_pubkey_decompress(ctx, pubkey, &pubkeylen)); - } - CHECK(secp256k1_ec_pubkey_verify(ctx, pubkey, pubkeylen)); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); + + /* Verify exporting and importing public key. */ + CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyc, &pubkeyclen, &pubkey, secp256k1_rand_bits(1) == 1 ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED)); + memset(&pubkey, 0, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1); + + /* Verify negation changes the key and changes it back */ + memcpy(&pubkey_tmp, &pubkey, sizeof(pubkey)); + CHECK(secp256k1_ec_pubkey_negate(ctx, &pubkey_tmp) == 1); + CHECK(memcmp(&pubkey_tmp, &pubkey, sizeof(pubkey)) != 0); + CHECK(secp256k1_ec_pubkey_negate(ctx, &pubkey_tmp) == 1); + CHECK(memcmp(&pubkey_tmp, &pubkey, sizeof(pubkey)) == 0); /* Verify private key import and export. */ - CHECK(secp256k1_ec_privkey_export(ctx, privkey, seckey, &seckeylen, secp256k1_rand32() % 2) == 1); - CHECK(secp256k1_ec_privkey_import(ctx, privkey2, seckey, seckeylen) == 1); + CHECK(ec_privkey_export_der(ctx, seckey, &seckeylen, privkey, secp256k1_rand_bits(1) == 1)); + CHECK(ec_privkey_import_der(ctx, privkey2, seckey, seckeylen) == 1); CHECK(memcmp(privkey, privkey2, 32) == 0); /* Optionally tweak the keys using addition. */ - if (secp256k1_rand32() % 3 == 0) { + if (secp256k1_rand_int(3) == 0) { int ret1; int ret2; unsigned char rnd[32]; - unsigned char pubkey2[65]; - int pubkeylen2 = 65; + secp256k1_pubkey pubkey2; secp256k1_rand256_test(rnd); ret1 = secp256k1_ec_privkey_tweak_add(ctx, privkey, rnd); - ret2 = secp256k1_ec_pubkey_tweak_add(ctx, pubkey, pubkeylen, rnd); + ret2 = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, rnd); CHECK(ret1 == ret2); if (ret1 == 0) { return; } - CHECK(secp256k1_ec_pubkey_create(ctx, pubkey2, &pubkeylen2, privkey, pubkeylen == 33) == 1); - CHECK(memcmp(pubkey, pubkey2, pubkeylen) == 0); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); } /* Optionally tweak the keys using multiplication. */ - if (secp256k1_rand32() % 3 == 0) { + if (secp256k1_rand_int(3) == 0) { int ret1; int ret2; unsigned char rnd[32]; - unsigned char pubkey2[65]; - int pubkeylen2 = 65; + secp256k1_pubkey pubkey2; secp256k1_rand256_test(rnd); ret1 = secp256k1_ec_privkey_tweak_mul(ctx, privkey, rnd); - ret2 = secp256k1_ec_pubkey_tweak_mul(ctx, pubkey, pubkeylen, rnd); + ret2 = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, rnd); CHECK(ret1 == ret2); if (ret1 == 0) { return; } - CHECK(secp256k1_ec_pubkey_create(ctx, pubkey2, &pubkeylen2, privkey, pubkeylen == 33) == 1); - CHECK(memcmp(pubkey, pubkey2, pubkeylen) == 0); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1); + CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0); } /* Sign. */ - CHECK(secp256k1_ecdsa_sign(ctx, message, signature, &signaturelen, privkey, NULL, NULL) == 1); - CHECK(signaturelen > 0); - CHECK(secp256k1_ecdsa_sign(ctx, message, signature2, &signaturelen2, privkey, NULL, extra) == 1); - CHECK(signaturelen2 > 0); + CHECK(secp256k1_ecdsa_sign(ctx, &signature[0], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, &signature[4], message, privkey, NULL, NULL) == 1); + CHECK(secp256k1_ecdsa_sign(ctx, &signature[1], message, privkey, NULL, extra) == 1); extra[31] = 1; - CHECK(secp256k1_ecdsa_sign(ctx, message, signature3, &signaturelen3, privkey, NULL, extra) == 1); - CHECK(signaturelen3 > 0); + CHECK(secp256k1_ecdsa_sign(ctx, &signature[2], message, privkey, NULL, extra) == 1); extra[31] = 0; extra[0] = 1; - CHECK(secp256k1_ecdsa_sign(ctx, message, signature4, &signaturelen4, privkey, NULL, extra) == 1); - CHECK(signaturelen3 > 0); - CHECK((signaturelen != signaturelen2) || (memcmp(signature, signature2, signaturelen) != 0)); - CHECK((signaturelen != signaturelen3) || (memcmp(signature, signature3, signaturelen) != 0)); - CHECK((signaturelen3 != signaturelen2) || (memcmp(signature3, signature2, signaturelen3) != 0)); - CHECK((signaturelen4 != signaturelen3) || (memcmp(signature4, signature3, signaturelen4) != 0)); - CHECK((signaturelen4 != signaturelen2) || (memcmp(signature4, signature2, signaturelen4) != 0)); - CHECK((signaturelen4 != signaturelen) || (memcmp(signature4, signature, signaturelen4) != 0)); + CHECK(secp256k1_ecdsa_sign(ctx, &signature[3], message, privkey, NULL, extra) == 1); + CHECK(memcmp(&signature[0], &signature[4], sizeof(signature[0])) == 0); + CHECK(memcmp(&signature[0], &signature[1], sizeof(signature[0])) != 0); + CHECK(memcmp(&signature[0], &signature[2], sizeof(signature[0])) != 0); + CHECK(memcmp(&signature[0], &signature[3], sizeof(signature[0])) != 0); + CHECK(memcmp(&signature[1], &signature[2], sizeof(signature[0])) != 0); + CHECK(memcmp(&signature[1], &signature[3], sizeof(signature[0])) != 0); + CHECK(memcmp(&signature[2], &signature[3], sizeof(signature[0])) != 0); /* Verify. */ - CHECK(secp256k1_ecdsa_verify(ctx, message, signature, signaturelen, pubkey, pubkeylen) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, message, signature2, signaturelen2, pubkey, pubkeylen) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, message, signature3, signaturelen3, pubkey, pubkeylen) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, message, signature4, signaturelen4, pubkey, pubkeylen) == 1); - /* Destroy signature and verify again. */ - signature[signaturelen - 1 - secp256k1_rand32() % 20] += 1 + (secp256k1_rand32() % 255); - CHECK(secp256k1_ecdsa_verify(ctx, message, signature, signaturelen, pubkey, pubkeylen) != 1); - - /* Compact sign. */ - CHECK(secp256k1_ecdsa_sign_compact(ctx, message, csignature, privkey, NULL, NULL, &recid) == 1); - CHECK(!is_empty_compact_signature(csignature)); - /* Recover. */ - CHECK(secp256k1_ecdsa_recover_compact(ctx, message, csignature, recpubkey, &recpubkeylen, pubkeylen == 33, recid) == 1); - CHECK(recpubkeylen == pubkeylen); - CHECK(memcmp(pubkey, recpubkey, pubkeylen) == 0); - /* Destroy signature and verify again. */ - csignature[secp256k1_rand32() % 64] += 1 + (secp256k1_rand32() % 255); - CHECK(secp256k1_ecdsa_recover_compact(ctx, message, csignature, recpubkey, &recpubkeylen, pubkeylen == 33, recid) != 1 || - memcmp(pubkey, recpubkey, pubkeylen) != 0); - CHECK(recpubkeylen == pubkeylen); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[1], message, &pubkey) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[2], message, &pubkey) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[3], message, &pubkey) == 1); + /* Test lower-S form, malleate, verify and fail, test again, malleate again */ + CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[0])); + secp256k1_ecdsa_signature_load(ctx, &r, &s, &signature[0]); + secp256k1_scalar_negate(&s, &s); + secp256k1_ecdsa_signature_save(&signature[5], &r, &s); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 0); + CHECK(secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5])); + CHECK(secp256k1_ecdsa_signature_normalize(ctx, &signature[5], &signature[5])); + CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5])); + CHECK(!secp256k1_ecdsa_signature_normalize(ctx, &signature[5], &signature[5])); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 1); + secp256k1_scalar_negate(&s, &s); + secp256k1_ecdsa_signature_save(&signature[5], &r, &s); + CHECK(!secp256k1_ecdsa_signature_normalize(ctx, NULL, &signature[5])); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[5], message, &pubkey) == 1); + CHECK(memcmp(&signature[5], &signature[0], 64) == 0); + /* Serialize/parse DER and verify again */ + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1); + memset(&signature[0], 0, sizeof(signature[0])); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 1); + /* Serialize/destroy/parse DER and verify again. */ + siglen = 74; + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1); + sig[secp256k1_rand_int(siglen)] += 1 + secp256k1_rand_int(255); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 0 || + secp256k1_ecdsa_verify(ctx, &signature[0], message, &pubkey) == 0); } void test_random_pubkeys(void) { - secp256k1_ge_t elem; - secp256k1_ge_t elem2; + secp256k1_ge elem; + secp256k1_ge elem2; unsigned char in[65]; /* Generate some randomly sized pubkeys. */ - uint32_t r = secp256k1_rand32(); - int len = (r & 3) == 0 ? 65 : 33; - r>>=2; - if ((r & 3) == 0) { - len = (r & 252) >> 3; + size_t len = secp256k1_rand_bits(2) == 0 ? 65 : 33; + if (secp256k1_rand_bits(2) == 0) { + len = secp256k1_rand_bits(6); } - r>>=8; if (len == 65) { - in[0] = (r & 2) ? 4 : (r & 1? 6 : 7); + in[0] = secp256k1_rand_bits(1) ? 4 : (secp256k1_rand_bits(1) ? 6 : 7); } else { - in[0] = (r & 1) ? 2 : 3; + in[0] = secp256k1_rand_bits(1) ? 2 : 3; } - r>>=2; - if ((r & 7) == 0) { - in[0] = (r & 2040) >> 3; + if (secp256k1_rand_bits(3) == 0) { + in[0] = secp256k1_rand_bits(8); } - r>>=11; if (len > 1) { secp256k1_rand256(&in[1]); } @@ -1561,7 +3594,7 @@ void test_random_pubkeys(void) { unsigned char out[65]; unsigned char firstb; int res; - int size = len; + size_t size = len; firstb = in[0]; /* If the pubkey can be parsed, it should round-trip... */ CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, len == 33)); @@ -1577,7 +3610,7 @@ void test_random_pubkeys(void) { CHECK(secp256k1_eckey_pubkey_parse(&elem2, in, size)); ge_equals_ge(&elem,&elem2); /* Check that the X9.62 hybrid type is checked. */ - in[0] = (r & 1) ? 6 : 7; + in[0] = secp256k1_rand_bits(1) ? 6 : 7; res = secp256k1_eckey_pubkey_parse(&elem2, in, size); if (firstb == 2 || firstb == 3) { if (in[0] == firstb + 4) { @@ -1608,185 +3641,508 @@ void run_ecdsa_end_to_end(void) { } } -/* Tests several edge cases. */ -void test_ecdsa_edge_cases(void) { - const unsigned char msg32[32] = { - 'T', 'h', 'i', 's', ' ', 'i', 's', ' ', - 'a', ' ', 'v', 'e', 'r', 'y', ' ', 's', - 'e', 'c', 'r', 'e', 't', ' ', 'm', 'e', - 's', 's', 'a', 'g', 'e', '.', '.', '.' +int test_ecdsa_der_parse(const unsigned char *sig, size_t siglen, int certainly_der, int certainly_not_der) { + static const unsigned char zeroes[32] = {0}; +#ifdef ENABLE_OPENSSL_TESTS + static const unsigned char max_scalar[32] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, + 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x40 }; - const unsigned char sig64[64] = { - /* Generated by signing the above message with nonce 'This is the nonce we will use...' - * and secret key 0 (which is not valid), resulting in recid 0. */ - 0x67, 0xCB, 0x28, 0x5F, 0x9C, 0xD1, 0x94, 0xE8, - 0x40, 0xD6, 0x29, 0x39, 0x7A, 0xF5, 0x56, 0x96, - 0x62, 0xFD, 0xE4, 0x46, 0x49, 0x99, 0x59, 0x63, - 0x17, 0x9A, 0x7D, 0xD1, 0x7B, 0xD2, 0x35, 0x32, - 0x4B, 0x1B, 0x7D, 0xF3, 0x4C, 0xE1, 0xF6, 0x8E, - 0x69, 0x4F, 0xF6, 0xF1, 0x1A, 0xC7, 0x51, 0xDD, - 0x7D, 0xD7, 0x3E, 0x38, 0x7E, 0xE4, 0xFC, 0x86, - 0x6E, 0x1B, 0xE8, 0xEC, 0xC7, 0xDD, 0x95, 0x57 - }; - unsigned char pubkey[65]; - int t; - int pubkeylen = 65; - /* signature (r,s) = (4,4), which can be recovered with all 4 recids. */ - const unsigned char sigb64[64] = { - 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, 0x04, - 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, 0x04, - }; - unsigned char pubkeyb[33]; - int pubkeyblen = 33; - int recid; +#endif - CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 0)); - CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 1)); - CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 2)); - CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 3)); + int ret = 0; - for (recid = 0; recid < 4; recid++) { - int i; - int recid2; - /* (4,4) encoded in DER. */ - unsigned char sigbder[8] = {0x30, 0x06, 0x02, 0x01, 0x04, 0x02, 0x01, 0x04}; - unsigned char sigcder_zr[7] = {0x30, 0x05, 0x02, 0x00, 0x02, 0x01, 0x01}; - unsigned char sigcder_zs[7] = {0x30, 0x05, 0x02, 0x01, 0x01, 0x02, 0x00}; - unsigned char sigbderalt1[39] = { - 0x30, 0x25, 0x02, 0x20, 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, 0x04, 0x02, 0x01, 0x04, - }; - unsigned char sigbderalt2[39] = { - 0x30, 0x25, 0x02, 0x01, 0x04, 0x02, 0x20, 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, 0x04, - }; - unsigned char sigbderalt3[40] = { - 0x30, 0x26, 0x02, 0x21, 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, 0x04, 0x02, 0x01, 0x04, - }; - unsigned char sigbderalt4[40] = { - 0x30, 0x26, 0x02, 0x01, 0x04, 0x02, 0x21, 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, 0x04, - }; - /* (order + r,4) encoded in DER. */ - unsigned char sigbderlong[40] = { - 0x30, 0x26, 0x02, 0x21, 0x00, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBA, 0xAE, 0xDC, - 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, - 0x8C, 0xD0, 0x36, 0x41, 0x45, 0x02, 0x01, 0x04 - }; - CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigb64, pubkeyb, &pubkeyblen, 1, recid)); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == 1); - for (recid2 = 0; recid2 < 4; recid2++) { - unsigned char pubkey2b[33]; - int pubkey2blen = 33; - CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigb64, pubkey2b, &pubkey2blen, 1, recid2)); - /* Verifying with (order + r,4) should always fail. */ - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderlong, sizeof(sigbderlong), pubkey2b, pubkey2blen) != 1); + secp256k1_ecdsa_signature sig_der; + unsigned char roundtrip_der[2048]; + unsigned char compact_der[64]; + size_t len_der = 2048; + int parsed_der = 0, valid_der = 0, roundtrips_der = 0; + + secp256k1_ecdsa_signature sig_der_lax; + unsigned char roundtrip_der_lax[2048]; + unsigned char compact_der_lax[64]; + size_t len_der_lax = 2048; + int parsed_der_lax = 0, valid_der_lax = 0, roundtrips_der_lax = 0; + +#ifdef ENABLE_OPENSSL_TESTS + ECDSA_SIG *sig_openssl; + const unsigned char *sigptr; + unsigned char roundtrip_openssl[2048]; + int len_openssl = 2048; + int parsed_openssl, valid_openssl = 0, roundtrips_openssl = 0; +#endif + + parsed_der = secp256k1_ecdsa_signature_parse_der(ctx, &sig_der, sig, siglen); + if (parsed_der) { + ret |= (!secp256k1_ecdsa_signature_serialize_compact(ctx, compact_der, &sig_der)) << 0; + valid_der = (memcmp(compact_der, zeroes, 32) != 0) && (memcmp(compact_der + 32, zeroes, 32) != 0); + } + if (valid_der) { + ret |= (!secp256k1_ecdsa_signature_serialize_der(ctx, roundtrip_der, &len_der, &sig_der)) << 1; + roundtrips_der = (len_der == siglen) && memcmp(roundtrip_der, sig, siglen) == 0; + } + + parsed_der_lax = ecdsa_signature_parse_der_lax(ctx, &sig_der_lax, sig, siglen); + if (parsed_der_lax) { + ret |= (!secp256k1_ecdsa_signature_serialize_compact(ctx, compact_der_lax, &sig_der_lax)) << 10; + valid_der_lax = (memcmp(compact_der_lax, zeroes, 32) != 0) && (memcmp(compact_der_lax + 32, zeroes, 32) != 0); + } + if (valid_der_lax) { + ret |= (!secp256k1_ecdsa_signature_serialize_der(ctx, roundtrip_der_lax, &len_der_lax, &sig_der_lax)) << 11; + roundtrips_der_lax = (len_der_lax == siglen) && memcmp(roundtrip_der_lax, sig, siglen) == 0; + } + + if (certainly_der) { + ret |= (!parsed_der) << 2; + } + if (certainly_not_der) { + ret |= (parsed_der) << 17; + } + if (valid_der) { + ret |= (!roundtrips_der) << 3; + } + + if (valid_der) { + ret |= (!roundtrips_der_lax) << 12; + ret |= (len_der != len_der_lax) << 13; + ret |= (memcmp(roundtrip_der_lax, roundtrip_der, len_der) != 0) << 14; + } + ret |= (roundtrips_der != roundtrips_der_lax) << 15; + if (parsed_der) { + ret |= (!parsed_der_lax) << 16; + } + +#ifdef ENABLE_OPENSSL_TESTS + sig_openssl = ECDSA_SIG_new(); + sigptr = sig; + parsed_openssl = (d2i_ECDSA_SIG(&sig_openssl, &sigptr, siglen) != NULL); + if (parsed_openssl) { + valid_openssl = !BN_is_negative(sig_openssl->r) && !BN_is_negative(sig_openssl->s) && BN_num_bits(sig_openssl->r) > 0 && BN_num_bits(sig_openssl->r) <= 256 && BN_num_bits(sig_openssl->s) > 0 && BN_num_bits(sig_openssl->s) <= 256; + if (valid_openssl) { + unsigned char tmp[32] = {0}; + BN_bn2bin(sig_openssl->r, tmp + 32 - BN_num_bytes(sig_openssl->r)); + valid_openssl = memcmp(tmp, max_scalar, 32) < 0; } - /* DER parsing tests. */ - /* Zero length r/s. */ - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder_zr, sizeof(sigcder_zr), pubkeyb, pubkeyblen) == -2); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder_zs, sizeof(sigcder_zs), pubkeyb, pubkeyblen) == -2); - /* Leading zeros. */ - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt1, sizeof(sigbderalt1), pubkeyb, pubkeyblen) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt2, sizeof(sigbderalt2), pubkeyb, pubkeyblen) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt3, sizeof(sigbderalt3), pubkeyb, pubkeyblen) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt4, sizeof(sigbderalt4), pubkeyb, pubkeyblen) == 1); - sigbderalt3[4] = 1; - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt3, sizeof(sigbderalt3), pubkeyb, pubkeyblen) == -2); - sigbderalt4[7] = 1; - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt4, sizeof(sigbderalt4), pubkeyb, pubkeyblen) == -2); - /* Damage signature. */ - sigbder[7]++; - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == 0); - sigbder[7]--; - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, 6, pubkeyb, pubkeyblen) == -2); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder)-1, pubkeyb, pubkeyblen) == -2); - for(i = 0; i < 8; i++) { - int c; - unsigned char orig = sigbder[i]; - /*Try every single-byte change.*/ - for (c = 0; c < 256; c++) { - if (c == orig ) { - continue; - } - sigbder[i] = c; - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == - (i==4 || i==7) ? 0 : -2 ); - } - sigbder[i] = orig; + if (valid_openssl) { + unsigned char tmp[32] = {0}; + BN_bn2bin(sig_openssl->s, tmp + 32 - BN_num_bytes(sig_openssl->s)); + valid_openssl = memcmp(tmp, max_scalar, 32) < 0; } } + len_openssl = i2d_ECDSA_SIG(sig_openssl, NULL); + if (len_openssl <= 2048) { + unsigned char *ptr = roundtrip_openssl; + CHECK(i2d_ECDSA_SIG(sig_openssl, &ptr) == len_openssl); + roundtrips_openssl = valid_openssl && ((size_t)len_openssl == siglen) && (memcmp(roundtrip_openssl, sig, siglen) == 0); + } else { + len_openssl = 0; + } + ECDSA_SIG_free(sig_openssl); + + ret |= (parsed_der && !parsed_openssl) << 4; + ret |= (valid_der && !valid_openssl) << 5; + ret |= (roundtrips_openssl && !parsed_der) << 6; + ret |= (roundtrips_der != roundtrips_openssl) << 7; + if (roundtrips_openssl) { + ret |= (len_der != (size_t)len_openssl) << 8; + ret |= (memcmp(roundtrip_der, roundtrip_openssl, len_der) != 0) << 9; + } +#endif + return ret; +} + +static void assign_big_endian(unsigned char *ptr, size_t ptrlen, uint32_t val) { + size_t i; + for (i = 0; i < ptrlen; i++) { + int shift = ptrlen - 1 - i; + if (shift >= 4) { + ptr[i] = 0; + } else { + ptr[i] = (val >> shift) & 0xFF; + } + } +} + +static void damage_array(unsigned char *sig, size_t *len) { + int pos; + int action = secp256k1_rand_bits(3); + if (action < 1 && *len > 3) { + /* Delete a byte. */ + pos = secp256k1_rand_int(*len); + memmove(sig + pos, sig + pos + 1, *len - pos - 1); + (*len)--; + return; + } else if (action < 2 && *len < 2048) { + /* Insert a byte. */ + pos = secp256k1_rand_int(1 + *len); + memmove(sig + pos + 1, sig + pos, *len - pos); + sig[pos] = secp256k1_rand_bits(8); + (*len)++; + return; + } else if (action < 4) { + /* Modify a byte. */ + sig[secp256k1_rand_int(*len)] += 1 + secp256k1_rand_int(255); + return; + } else { /* action < 8 */ + /* Modify a bit. */ + sig[secp256k1_rand_int(*len)] ^= 1 << secp256k1_rand_bits(3); + return; + } +} + +static void random_ber_signature(unsigned char *sig, size_t *len, int* certainly_der, int* certainly_not_der) { + int der; + int nlow[2], nlen[2], nlenlen[2], nhbit[2], nhbyte[2], nzlen[2]; + size_t tlen, elen, glen; + int indet; + int n; + + *len = 0; + der = secp256k1_rand_bits(2) == 0; + *certainly_der = der; + *certainly_not_der = 0; + indet = der ? 0 : secp256k1_rand_int(10) == 0; + + for (n = 0; n < 2; n++) { + /* We generate two classes of numbers: nlow==1 "low" ones (up to 32 bytes), nlow==0 "high" ones (32 bytes with 129 top bits set, or larger than 32 bytes) */ + nlow[n] = der ? 1 : (secp256k1_rand_bits(3) != 0); + /* The length of the number in bytes (the first byte of which will always be nonzero) */ + nlen[n] = nlow[n] ? secp256k1_rand_int(33) : 32 + secp256k1_rand_int(200) * secp256k1_rand_int(8) / 8; + CHECK(nlen[n] <= 232); + /* The top bit of the number. */ + nhbit[n] = (nlow[n] == 0 && nlen[n] == 32) ? 1 : (nlen[n] == 0 ? 0 : secp256k1_rand_bits(1)); + /* The top byte of the number (after the potential hardcoded 16 0xFF characters for "high" 32 bytes numbers) */ + nhbyte[n] = nlen[n] == 0 ? 0 : (nhbit[n] ? 128 + secp256k1_rand_bits(7) : 1 + secp256k1_rand_int(127)); + /* The number of zero bytes in front of the number (which is 0 or 1 in case of DER, otherwise we extend up to 300 bytes) */ + nzlen[n] = der ? ((nlen[n] == 0 || nhbit[n]) ? 1 : 0) : (nlow[n] ? secp256k1_rand_int(3) : secp256k1_rand_int(300 - nlen[n]) * secp256k1_rand_int(8) / 8); + if (nzlen[n] > ((nlen[n] == 0 || nhbit[n]) ? 1 : 0)) { + *certainly_not_der = 1; + } + CHECK(nlen[n] + nzlen[n] <= 300); + /* The length of the length descriptor for the number. 0 means short encoding, anything else is long encoding. */ + nlenlen[n] = nlen[n] + nzlen[n] < 128 ? 0 : (nlen[n] + nzlen[n] < 256 ? 1 : 2); + if (!der) { + /* nlenlen[n] max 127 bytes */ + int add = secp256k1_rand_int(127 - nlenlen[n]) * secp256k1_rand_int(16) * secp256k1_rand_int(16) / 256; + nlenlen[n] += add; + if (add != 0) { + *certainly_not_der = 1; + } + } + CHECK(nlen[n] + nzlen[n] + nlenlen[n] <= 427); + } + + /* The total length of the data to go, so far */ + tlen = 2 + nlenlen[0] + nlen[0] + nzlen[0] + 2 + nlenlen[1] + nlen[1] + nzlen[1]; + CHECK(tlen <= 856); + + /* The length of the garbage inside the tuple. */ + elen = (der || indet) ? 0 : secp256k1_rand_int(980 - tlen) * secp256k1_rand_int(8) / 8; + if (elen != 0) { + *certainly_not_der = 1; + } + tlen += elen; + CHECK(tlen <= 980); + + /* The length of the garbage after the end of the tuple. */ + glen = der ? 0 : secp256k1_rand_int(990 - tlen) * secp256k1_rand_int(8) / 8; + if (glen != 0) { + *certainly_not_der = 1; + } + CHECK(tlen + glen <= 990); + + /* Write the tuple header. */ + sig[(*len)++] = 0x30; + if (indet) { + /* Indeterminate length */ + sig[(*len)++] = 0x80; + *certainly_not_der = 1; + } else { + int tlenlen = tlen < 128 ? 0 : (tlen < 256 ? 1 : 2); + if (!der) { + int add = secp256k1_rand_int(127 - tlenlen) * secp256k1_rand_int(16) * secp256k1_rand_int(16) / 256; + tlenlen += add; + if (add != 0) { + *certainly_not_der = 1; + } + } + if (tlenlen == 0) { + /* Short length notation */ + sig[(*len)++] = tlen; + } else { + /* Long length notation */ + sig[(*len)++] = 128 + tlenlen; + assign_big_endian(sig + *len, tlenlen, tlen); + *len += tlenlen; + } + tlen += tlenlen; + } + tlen += 2; + CHECK(tlen + glen <= 1119); + + for (n = 0; n < 2; n++) { + /* Write the integer header. */ + sig[(*len)++] = 0x02; + if (nlenlen[n] == 0) { + /* Short length notation */ + sig[(*len)++] = nlen[n] + nzlen[n]; + } else { + /* Long length notation. */ + sig[(*len)++] = 128 + nlenlen[n]; + assign_big_endian(sig + *len, nlenlen[n], nlen[n] + nzlen[n]); + *len += nlenlen[n]; + } + /* Write zero padding */ + while (nzlen[n] > 0) { + sig[(*len)++] = 0x00; + nzlen[n]--; + } + if (nlen[n] == 32 && !nlow[n]) { + /* Special extra 16 0xFF bytes in "high" 32-byte numbers */ + int i; + for (i = 0; i < 16; i++) { + sig[(*len)++] = 0xFF; + } + nlen[n] -= 16; + } + /* Write first byte of number */ + if (nlen[n] > 0) { + sig[(*len)++] = nhbyte[n]; + nlen[n]--; + } + /* Generate remaining random bytes of number */ + secp256k1_rand_bytes_test(sig + *len, nlen[n]); + *len += nlen[n]; + nlen[n] = 0; + } + + /* Generate random garbage inside tuple. */ + secp256k1_rand_bytes_test(sig + *len, elen); + *len += elen; + + /* Generate end-of-contents bytes. */ + if (indet) { + sig[(*len)++] = 0; + sig[(*len)++] = 0; + tlen += 2; + } + CHECK(tlen + glen <= 1121); + + /* Generate random garbage outside tuple. */ + secp256k1_rand_bytes_test(sig + *len, glen); + *len += glen; + tlen += glen; + CHECK(tlen <= 1121); + CHECK(tlen == *len); +} + +void run_ecdsa_der_parse(void) { + int i,j; + for (i = 0; i < 200 * count; i++) { + unsigned char buffer[2048]; + size_t buflen = 0; + int certainly_der = 0; + int certainly_not_der = 0; + random_ber_signature(buffer, &buflen, &certainly_der, &certainly_not_der); + CHECK(buflen <= 2048); + for (j = 0; j < 16; j++) { + int ret = 0; + if (j > 0) { + damage_array(buffer, &buflen); + /* We don't know anything anymore about the DERness of the result */ + certainly_der = 0; + certainly_not_der = 0; + } + ret = test_ecdsa_der_parse(buffer, buflen, certainly_der, certainly_not_der); + if (ret != 0) { + size_t k; + fprintf(stderr, "Failure %x on ", ret); + for (k = 0; k < buflen; k++) { + fprintf(stderr, "%02x ", buffer[k]); + } + fprintf(stderr, "\n"); + } + CHECK(ret == 0); + } + } +} + +/* Tests several edge cases. */ +void test_ecdsa_edge_cases(void) { + int t; + secp256k1_ecdsa_signature sig; /* Test the case where ECDSA recomputes a point that is infinity. */ { - secp256k1_gej_t keyj; - secp256k1_ge_t key; - secp256k1_scalar_t msg; - secp256k1_ecdsa_sig_t sig; - secp256k1_scalar_set_int(&sig.s, 1); - secp256k1_scalar_negate(&sig.s, &sig.s); - secp256k1_scalar_inverse(&sig.s, &sig.s); - secp256k1_scalar_set_int(&sig.r, 1); - secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &keyj, &sig.r); + secp256k1_gej keyj; + secp256k1_ge key; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 1); + secp256k1_scalar_negate(&ss, &ss); + secp256k1_scalar_inverse(&ss, &ss); + secp256k1_scalar_set_int(&sr, 1); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &keyj, &sr); secp256k1_ge_set_gej(&key, &keyj); - msg = sig.s; - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &key, &msg) == 0); + msg = ss; + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); } - /* Test r/s equal to zero */ + /* Verify signature with r of zero fails. */ { - /* (1,1) encoded in DER. */ - unsigned char sigcder[8] = {0x30, 0x06, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01}; - unsigned char sigc64[64] = { - 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, 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, 0x01, + const unsigned char pubkey_mods_zero[33] = { + 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, + 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, + 0x41 }; - unsigned char pubkeyc[65]; - int pubkeyclen = 65; - CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, pubkeyc, &pubkeyclen, 0, 0) == 1); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 1); - sigcder[4] = 0; - sigc64[31] = 0; - CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, pubkeyb, &pubkeyblen, 1, 0) == 0); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 0); - sigcder[4] = 1; - sigcder[7] = 0; - sigc64[31] = 1; - sigc64[63] = 0; - CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, pubkeyb, &pubkeyblen, 1, 0) == 0); - CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 0); + secp256k1_ge key; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 1); + secp256k1_scalar_set_int(&msg, 0); + secp256k1_scalar_set_int(&sr, 0); + CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey_mods_zero, 33)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); } - /*Signature where s would be zero.*/ + /* Verify signature with s of zero fails. */ { - const unsigned char nonce[32] = { + const unsigned char pubkey[33] = { + 0x02, 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, + 0x01 + }; + secp256k1_ge key; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 0); + secp256k1_scalar_set_int(&msg, 0); + secp256k1_scalar_set_int(&sr, 1); + CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + } + + /* Verify signature with message 0 passes. */ + { + const unsigned char pubkey[33] = { + 0x02, 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, + 0x02 + }; + const unsigned char pubkey2[33] = { + 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfe, 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, + 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, + 0x43 + }; + secp256k1_ge key; + secp256k1_ge key2; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 2); + secp256k1_scalar_set_int(&msg, 0); + secp256k1_scalar_set_int(&sr, 2); + CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(secp256k1_eckey_pubkey_parse(&key2, pubkey2, 33)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); + secp256k1_scalar_negate(&ss, &ss); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); + secp256k1_scalar_set_int(&ss, 1); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 0); + } + + /* Verify signature with message 1 passes. */ + { + const unsigned char pubkey[33] = { + 0x02, 0x14, 0x4e, 0x5a, 0x58, 0xef, 0x5b, 0x22, + 0x6f, 0xd2, 0xe2, 0x07, 0x6a, 0x77, 0xcf, 0x05, + 0xb4, 0x1d, 0xe7, 0x4a, 0x30, 0x98, 0x27, 0x8c, + 0x93, 0xe6, 0xe6, 0x3c, 0x0b, 0xc4, 0x73, 0x76, + 0x25 + }; + const unsigned char pubkey2[33] = { + 0x02, 0x8a, 0xd5, 0x37, 0xed, 0x73, 0xd9, 0x40, + 0x1d, 0xa0, 0x33, 0xd2, 0xdc, 0xf0, 0xaf, 0xae, + 0x34, 0xcf, 0x5f, 0x96, 0x4c, 0x73, 0x28, 0x0f, + 0x92, 0xc0, 0xf6, 0x9d, 0xd9, 0xb2, 0x09, 0x10, + 0x62 + }; + const unsigned char csr[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4, + 0x40, 0x2d, 0xa1, 0x72, 0x2f, 0xc9, 0xba, 0xeb + }; + secp256k1_ge key; + secp256k1_ge key2; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 1); + secp256k1_scalar_set_int(&msg, 1); + secp256k1_scalar_set_b32(&sr, csr, NULL); + CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(secp256k1_eckey_pubkey_parse(&key2, pubkey2, 33)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); + secp256k1_scalar_negate(&ss, &ss); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 1); + secp256k1_scalar_set_int(&ss, 2); + secp256k1_scalar_inverse_var(&ss, &ss); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key2, &msg) == 0); + } + + /* Verify signature with message -1 passes. */ + { + const unsigned char pubkey[33] = { + 0x03, 0xaf, 0x97, 0xff, 0x7d, 0x3a, 0xf6, 0xa0, + 0x02, 0x94, 0xbd, 0x9f, 0x4b, 0x2e, 0xd7, 0x52, + 0x28, 0xdb, 0x49, 0x2a, 0x65, 0xcb, 0x1e, 0x27, + 0x57, 0x9c, 0xba, 0x74, 0x20, 0xd5, 0x1d, 0x20, + 0xf1 + }; + const unsigned char csr[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x45, 0x51, 0x23, 0x19, 0x50, 0xb7, 0x5f, 0xc4, + 0x40, 0x2d, 0xa1, 0x72, 0x2f, 0xc9, 0xba, 0xee + }; + secp256k1_ge key; + secp256k1_scalar msg; + secp256k1_scalar sr, ss; + secp256k1_scalar_set_int(&ss, 1); + secp256k1_scalar_set_int(&msg, 1); + secp256k1_scalar_negate(&msg, &msg); + secp256k1_scalar_set_b32(&sr, csr, NULL); + CHECK(secp256k1_eckey_pubkey_parse(&key, pubkey, 33)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + secp256k1_scalar_negate(&ss, &ss); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 1); + secp256k1_scalar_set_int(&ss, 3); + secp256k1_scalar_inverse_var(&ss, &ss); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0); + } + + /* Signature where s would be zero. */ + { + secp256k1_pubkey pubkey; + size_t siglen; + int32_t ecount; + unsigned char signature[72]; + static const unsigned char nonce[32] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1810,21 +4166,72 @@ void test_ecdsa_edge_cases(void) { 0xb8, 0x12, 0xe0, 0x0b, 0x81, 0x7a, 0x77, 0x62, 0x65, 0xdf, 0xdd, 0x31, 0xb9, 0x3e, 0x29, 0xa9, }; - unsigned char sig[72]; - int siglen = 72; - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce) == 0); - CHECK(siglen == 0); - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce2) == 0); - CHECK(siglen == 0); + ecount = 0; + secp256k1_context_set_illegal_callback(ctx, counting_illegal_callback_fn, &ecount); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce) == 0); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce2) == 0); msg[31] = 0xaa; + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce) == 1); + CHECK(ecount == 0); + CHECK(secp256k1_ecdsa_sign(ctx, NULL, msg, key, precomputed_nonce_function, nonce2) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, NULL, key, precomputed_nonce_function, nonce2) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, NULL, precomputed_nonce_function, nonce2) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, precomputed_nonce_function, nonce2) == 1); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, key) == 1); + CHECK(secp256k1_ecdsa_verify(ctx, NULL, msg, &pubkey) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, NULL, &pubkey) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, NULL) == 0); + CHECK(ecount == 6); + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, &pubkey) == 1); + CHECK(ecount == 6); + CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, NULL) == 0); + CHECK(ecount == 7); + /* That pubkeyload fails via an ARGCHECK is a little odd but makes sense because pubkeys are an opaque data type. */ + CHECK(secp256k1_ecdsa_verify(ctx, &sig, msg, &pubkey) == 0); + CHECK(ecount == 8); siglen = 72; - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce) == 1); - CHECK(siglen > 0); - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce2) == 1); - CHECK(siglen > 0); + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, NULL, &siglen, &sig) == 0); + CHECK(ecount == 9); + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, NULL, &sig) == 0); + CHECK(ecount == 10); + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, NULL) == 0); + CHECK(ecount == 11); + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 1); + CHECK(ecount == 11); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, NULL, signature, siglen) == 0); + CHECK(ecount == 12); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, NULL, siglen) == 0); + CHECK(ecount == 13); + CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, signature, siglen) == 1); + CHECK(ecount == 13); siglen = 10; - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce) != 1); - CHECK(siglen == 0); + /* Too little room for a signature does not fail via ARGCHECK. */ + CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 0); + CHECK(ecount == 13); + ecount = 0; + CHECK(secp256k1_ecdsa_signature_normalize(ctx, NULL, NULL) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, NULL, &sig) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, signature, NULL) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, signature, &sig) == 1); + CHECK(ecount == 3); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, NULL, signature) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, NULL) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, signature) == 1); + CHECK(ecount == 5); + memset(signature, 255, 64); + CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, signature) == 0); + CHECK(ecount == 5); + secp256k1_context_set_illegal_callback(ctx, NULL, NULL); } /* Nonce function corner cases. */ @@ -1833,65 +4240,43 @@ void test_ecdsa_edge_cases(void) { int i; unsigned char key[32]; unsigned char msg[32]; - unsigned char sig[72]; - unsigned char sig2[72]; - secp256k1_ecdsa_sig_t s[512]; - int siglen = 72; - int siglen2 = 72; - int recid2; + secp256k1_ecdsa_signature sig2; + secp256k1_scalar sr[512], ss; const unsigned char *extra; extra = t == 0 ? NULL : zero; memset(msg, 0, 32); msg[31] = 1; /* High key results in signature failure. */ memset(key, 0xFF, 32); - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, NULL, extra) == 0); - CHECK(siglen == 0); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, NULL, extra) == 0); + CHECK(is_empty_signature(&sig)); /* Zero key results in signature failure. */ memset(key, 0, 32); - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, NULL, extra) == 0); - CHECK(siglen == 0); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, NULL, extra) == 0); + CHECK(is_empty_signature(&sig)); /* Nonce function failure results in signature failure. */ key[31] = 1; - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, nonce_function_test_fail, extra) == 0); - CHECK(siglen == 0); - CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig, key, nonce_function_test_fail, extra, &recid) == 0); - CHECK(is_empty_compact_signature(sig)); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, nonce_function_test_fail, extra) == 0); + CHECK(is_empty_signature(&sig)); /* The retry loop successfully makes its way to the first good value. */ - siglen = 72; - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, nonce_function_test_retry, extra) == 1); - CHECK(siglen > 0); - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, nonce_function_rfc6979, extra) == 1); - CHECK(siglen > 0); - CHECK((siglen == siglen2) && (memcmp(sig, sig2, siglen) == 0)); - CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig, key, nonce_function_test_retry, extra, &recid) == 1); - CHECK(!is_empty_compact_signature(sig)); - CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig2, key, nonce_function_rfc6979, extra, &recid2) == 1); - CHECK(!is_empty_compact_signature(sig2)); - CHECK((recid == recid2) && (memcmp(sig, sig2, 64) == 0)); - /* The default nonce function is determinstic. */ - siglen = 72; - siglen2 = 72; - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, NULL, extra) == 1); - CHECK(siglen > 0); - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, NULL, extra) == 1); - CHECK(siglen2 > 0); - CHECK((siglen == siglen2) && (memcmp(sig, sig2, siglen) == 0)); - CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig, key, NULL, extra, &recid) == 1); - CHECK(!is_empty_compact_signature(sig)); - CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig2, key, NULL, extra, &recid2) == 1); - CHECK(!is_empty_compact_signature(sig)); - CHECK((recid == recid2) && (memcmp(sig, sig2, 64) == 0)); + CHECK(secp256k1_ecdsa_sign(ctx, &sig, msg, key, nonce_function_test_retry, extra) == 1); + CHECK(!is_empty_signature(&sig)); + CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, nonce_function_rfc6979, extra) == 1); + CHECK(!is_empty_signature(&sig2)); + CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0); + /* The default nonce function is deterministic. */ + CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1); + CHECK(!is_empty_signature(&sig2)); + CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0); /* The default nonce function changes output with different messages. */ for(i = 0; i < 256; i++) { int j; - siglen2 = 72; msg[0] = i; - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, NULL, extra) == 1); - CHECK(!is_empty_compact_signature(sig)); - CHECK(secp256k1_ecdsa_sig_parse(&s[i], sig2, siglen2)); + CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1); + CHECK(!is_empty_signature(&sig2)); + secp256k1_ecdsa_signature_load(ctx, &sr[i], &ss, &sig2); for (j = 0; j < i; j++) { - CHECK(!secp256k1_scalar_eq(&s[i].r, &s[j].r)); + CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j])); } } msg[0] = 0; @@ -1899,17 +4284,45 @@ void test_ecdsa_edge_cases(void) { /* The default nonce function changes output with different keys. */ for(i = 256; i < 512; i++) { int j; - siglen2 = 72; key[0] = i - 256; - CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, NULL, extra) == 1); - CHECK(secp256k1_ecdsa_sig_parse(&s[i], sig2, siglen2)); + CHECK(secp256k1_ecdsa_sign(ctx, &sig2, msg, key, NULL, extra) == 1); + CHECK(!is_empty_signature(&sig2)); + secp256k1_ecdsa_signature_load(ctx, &sr[i], &ss, &sig2); for (j = 0; j < i; j++) { - CHECK(!secp256k1_scalar_eq(&s[i].r, &s[j].r)); + CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j])); } } key[0] = 0; } + { + /* Check that optional nonce arguments do not have equivalent effect. */ + const unsigned char zeros[32] = {0}; + unsigned char nonce[32]; + unsigned char nonce2[32]; + unsigned char nonce3[32]; + unsigned char nonce4[32]; + VG_UNDEF(nonce,32); + VG_UNDEF(nonce2,32); + VG_UNDEF(nonce3,32); + VG_UNDEF(nonce4,32); + CHECK(nonce_function_rfc6979(nonce, zeros, zeros, NULL, NULL, 0) == 1); + VG_CHECK(nonce,32); + CHECK(nonce_function_rfc6979(nonce2, zeros, zeros, zeros, NULL, 0) == 1); + VG_CHECK(nonce2,32); + CHECK(nonce_function_rfc6979(nonce3, zeros, zeros, NULL, (void *)zeros, 0) == 1); + VG_CHECK(nonce3,32); + CHECK(nonce_function_rfc6979(nonce4, zeros, zeros, zeros, (void *)zeros, 0) == 1); + VG_CHECK(nonce4,32); + CHECK(memcmp(nonce, nonce2, 32) != 0); + CHECK(memcmp(nonce, nonce3, 32) != 0); + CHECK(memcmp(nonce, nonce4, 32) != 0); + CHECK(memcmp(nonce2, nonce3, 32) != 0); + CHECK(memcmp(nonce2, nonce4, 32) != 0); + CHECK(memcmp(nonce3, nonce4, 32) != 0); + } + + /* Privkey export where pubkey is the point at infinity. */ { unsigned char privkey[300]; @@ -1919,9 +4332,10 @@ void test_ecdsa_edge_cases(void) { 0xba, 0xae, 0xdc, 0xe6, 0xaf, 0x48, 0xa0, 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41, }; - int outlen = 300; - CHECK(!secp256k1_ec_privkey_export(ctx, seckey, privkey, &outlen, 0)); - CHECK(!secp256k1_ec_privkey_export(ctx, seckey, privkey, &outlen, 1)); + size_t outlen = 300; + CHECK(!ec_privkey_export_der(ctx, privkey, &outlen, seckey, 0)); + outlen = 300; + CHECK(!ec_privkey_export_der(ctx, privkey, &outlen, seckey, 1)); } } @@ -1930,46 +4344,48 @@ void run_ecdsa_edge_cases(void) { } #ifdef ENABLE_OPENSSL_TESTS -EC_KEY *get_openssl_key(const secp256k1_scalar_t *key) { +EC_KEY *get_openssl_key(const unsigned char *key32) { unsigned char privkey[300]; - int privkeylen; + size_t privkeylen; const unsigned char* pbegin = privkey; - int compr = secp256k1_rand32() & 1; + int compr = secp256k1_rand_bits(1); EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_secp256k1); - CHECK(secp256k1_eckey_privkey_serialize(&ctx->ecmult_gen_ctx, privkey, &privkeylen, key, compr)); + CHECK(ec_privkey_export_der(ctx, privkey, &privkeylen, key32, compr)); CHECK(d2i_ECPrivateKey(&ec_key, &pbegin, privkeylen)); CHECK(EC_KEY_check_key(ec_key)); return ec_key; } void test_ecdsa_openssl(void) { - secp256k1_gej_t qj; - secp256k1_ge_t q; - secp256k1_ecdsa_sig_t sig; - secp256k1_scalar_t one; - secp256k1_scalar_t msg2; - secp256k1_scalar_t key, msg; + secp256k1_gej qj; + secp256k1_ge q; + secp256k1_scalar sigr, sigs; + secp256k1_scalar one; + secp256k1_scalar msg2; + secp256k1_scalar key, msg; EC_KEY *ec_key; unsigned int sigsize = 80; - int secp_sigsize = 80; + size_t secp_sigsize = 80; unsigned char message[32]; unsigned char signature[80]; + unsigned char key32[32]; secp256k1_rand256_test(message); secp256k1_scalar_set_b32(&msg, message, NULL); random_scalar_order_test(&key); + secp256k1_scalar_get_b32(key32, &key); secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &qj, &key); secp256k1_ge_set_gej(&q, &qj); - ec_key = get_openssl_key(&key); - CHECK(ec_key); + ec_key = get_openssl_key(key32); + CHECK(ec_key != NULL); CHECK(ECDSA_sign(0, message, sizeof(message), signature, &sigsize, ec_key)); - CHECK(secp256k1_ecdsa_sig_parse(&sig, signature, sigsize)); - CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &q, &msg)); + CHECK(secp256k1_ecdsa_sig_parse(&sigr, &sigs, signature, sigsize)); + CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &q, &msg)); secp256k1_scalar_set_int(&one, 1); secp256k1_scalar_add(&msg2, &msg, &one); - CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &q, &msg2)); + CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &q, &msg2)); - random_sign(&sig, &key, &msg, NULL); - CHECK(secp256k1_ecdsa_sig_serialize(signature, &secp_sigsize, &sig)); + random_sign(&sigr, &sigs, &key, &msg, NULL); + CHECK(secp256k1_ecdsa_sig_serialize(signature, &secp_sigsize, &sigr, &sigs)); CHECK(ECDSA_verify(0, message, sizeof(message), signature, secp_sigsize, ec_key) == 1); EC_KEY_free(ec_key); @@ -1983,6 +4399,14 @@ void run_ecdsa_openssl(void) { } #endif +#ifdef ENABLE_MODULE_ECDH +# include "modules/ecdh/tests_impl.h" +#endif + +#ifdef ENABLE_MODULE_RECOVERY +# include "modules/recovery/tests_impl.h" +#endif + int main(int argc, char **argv) { unsigned char seed16[16] = {0}; unsigned char run32[32] = {0}; @@ -2007,7 +4431,7 @@ int main(int argc, char **argv) { } } else { FILE *frand = fopen("/dev/urandom", "r"); - if (!frand || !fread(&seed16, sizeof(seed16), 1, frand)) { + if ((frand == NULL) || !fread(&seed16, sizeof(seed16), 1, frand)) { uint64_t t = time(NULL) * (uint64_t)1337; seed16[0] ^= t; seed16[1] ^= t >> 8; @@ -2028,12 +4452,14 @@ int main(int argc, char **argv) { /* initialize */ run_context_tests(); ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); - - if (secp256k1_rand32() & 1) { + if (secp256k1_rand_bits(1)) { secp256k1_rand256(run32); - CHECK(secp256k1_context_randomize(ctx, secp256k1_rand32() & 1 ? run32 : NULL)); + CHECK(secp256k1_context_randomize(ctx, secp256k1_rand_bits(1) ? run32 : NULL)); } + run_rand_bits(); + run_rand_int(); + run_sha256_tests(); run_hmac_sha256_tests(); run_rfc6979_hmac_sha256_tests(); @@ -2057,6 +4483,7 @@ int main(int argc, char **argv) { /* group tests */ run_ge(); + run_group_decompress(); /* ecmult tests */ run_wnaf(); @@ -2064,9 +4491,28 @@ int main(int argc, char **argv) { run_ecmult_chain(); run_ecmult_constants(); run_ecmult_gen_blind(); + run_ecmult_const_tests(); + run_ec_combine(); + + /* endomorphism tests */ +#ifdef USE_ENDOMORPHISM + run_endomorphism_tests(); +#endif + + /* EC point parser test */ + run_ec_pubkey_parse_test(); + + /* EC key edge cases */ + run_eckey_edge_case_test(); + +#ifdef ENABLE_MODULE_ECDH + /* ecdh tests */ + run_ecdh_tests(); +#endif /* ecdsa tests */ run_random_pubkeys(); + run_ecdsa_der_parse(); run_ecdsa_sign_verify(); run_ecdsa_end_to_end(); run_ecdsa_edge_cases(); @@ -2074,10 +4520,17 @@ int main(int argc, char **argv) { run_ecdsa_openssl(); #endif +#ifdef ENABLE_MODULE_RECOVERY + /* ECDSA pubkey recovery tests */ + run_recovery_tests(); +#endif + secp256k1_rand256(run32); printf("random run = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", run32[0], run32[1], run32[2], run32[3], run32[4], run32[5], run32[6], run32[7], run32[8], run32[9], run32[10], run32[11], run32[12], run32[13], run32[14], run32[15]); /* shutdown */ secp256k1_context_destroy(ctx); + + printf("no problems found\n"); return 0; } diff --git a/src/cryptoconditions/src/include/secp256k1/src/tests_exhaustive.c b/src/cryptoconditions/src/include/secp256k1/src/tests_exhaustive.c new file mode 100644 index 000000000..b040bb073 --- /dev/null +++ b/src/cryptoconditions/src/include/secp256k1/src/tests_exhaustive.c @@ -0,0 +1,470 @@ +/*********************************************************************** + * Copyright (c) 2016 Andrew Poelstra * + * Distributed under the MIT software license, see the accompanying * + * file COPYING or http://www.opensource.org/licenses/mit-license.php.* + **********************************************************************/ + +#if defined HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + +#include +#include + +#include + +#undef USE_ECMULT_STATIC_PRECOMPUTATION + +#ifndef EXHAUSTIVE_TEST_ORDER +/* see group_impl.h for allowable values */ +#define EXHAUSTIVE_TEST_ORDER 13 +#define EXHAUSTIVE_TEST_LAMBDA 9 /* cube root of 1 mod 13 */ +#endif + +#include "include/secp256k1.h" +#include "group.h" +#include "secp256k1.c" +#include "testrand_impl.h" + +#ifdef ENABLE_MODULE_RECOVERY +#include "src/modules/recovery/main_impl.h" +#include "include/secp256k1_recovery.h" +#endif + +/** stolen from tests.c */ +void ge_equals_ge(const secp256k1_ge *a, const secp256k1_ge *b) { + CHECK(a->infinity == b->infinity); + if (a->infinity) { + return; + } + CHECK(secp256k1_fe_equal_var(&a->x, &b->x)); + CHECK(secp256k1_fe_equal_var(&a->y, &b->y)); +} + +void ge_equals_gej(const secp256k1_ge *a, const secp256k1_gej *b) { + secp256k1_fe z2s; + secp256k1_fe u1, u2, s1, s2; + CHECK(a->infinity == b->infinity); + if (a->infinity) { + return; + } + /* Check a.x * b.z^2 == b.x && a.y * b.z^3 == b.y, to avoid inverses. */ + secp256k1_fe_sqr(&z2s, &b->z); + secp256k1_fe_mul(&u1, &a->x, &z2s); + u2 = b->x; secp256k1_fe_normalize_weak(&u2); + secp256k1_fe_mul(&s1, &a->y, &z2s); secp256k1_fe_mul(&s1, &s1, &b->z); + s2 = b->y; secp256k1_fe_normalize_weak(&s2); + CHECK(secp256k1_fe_equal_var(&u1, &u2)); + CHECK(secp256k1_fe_equal_var(&s1, &s2)); +} + +void random_fe(secp256k1_fe *x) { + unsigned char bin[32]; + do { + secp256k1_rand256(bin); + if (secp256k1_fe_set_b32(x, bin)) { + return; + } + } while(1); +} +/** END stolen from tests.c */ + +int secp256k1_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg32, + const unsigned char *key32, const unsigned char *algo16, + void *data, unsigned int attempt) { + secp256k1_scalar s; + int *idata = data; + (void)msg32; + (void)key32; + (void)algo16; + /* Some nonces cannot be used because they'd cause s and/or r to be zero. + * The signing function has retry logic here that just re-calls the nonce + * function with an increased `attempt`. So if attempt > 0 this means we + * need to change the nonce to avoid an infinite loop. */ + if (attempt > 0) { + *idata = (*idata + 1) % EXHAUSTIVE_TEST_ORDER; + } + secp256k1_scalar_set_int(&s, *idata); + secp256k1_scalar_get_b32(nonce32, &s); + return 1; +} + +#ifdef USE_ENDOMORPHISM +void test_exhaustive_endomorphism(const secp256k1_ge *group, int order) { + int i; + for (i = 0; i < order; i++) { + secp256k1_ge res; + secp256k1_ge_mul_lambda(&res, &group[i]); + ge_equals_ge(&group[i * EXHAUSTIVE_TEST_LAMBDA % EXHAUSTIVE_TEST_ORDER], &res); + } +} +#endif + +void test_exhaustive_addition(const secp256k1_ge *group, const secp256k1_gej *groupj, int order) { + int i, j; + + /* Sanity-check (and check infinity functions) */ + CHECK(secp256k1_ge_is_infinity(&group[0])); + CHECK(secp256k1_gej_is_infinity(&groupj[0])); + for (i = 1; i < order; i++) { + CHECK(!secp256k1_ge_is_infinity(&group[i])); + CHECK(!secp256k1_gej_is_infinity(&groupj[i])); + } + + /* Check all addition formulae */ + for (j = 0; j < order; j++) { + secp256k1_fe fe_inv; + secp256k1_fe_inv(&fe_inv, &groupj[j].z); + for (i = 0; i < order; i++) { + secp256k1_ge zless_gej; + secp256k1_gej tmp; + /* add_var */ + secp256k1_gej_add_var(&tmp, &groupj[i], &groupj[j], NULL); + ge_equals_gej(&group[(i + j) % order], &tmp); + /* add_ge */ + if (j > 0) { + secp256k1_gej_add_ge(&tmp, &groupj[i], &group[j]); + ge_equals_gej(&group[(i + j) % order], &tmp); + } + /* add_ge_var */ + secp256k1_gej_add_ge_var(&tmp, &groupj[i], &group[j], NULL); + ge_equals_gej(&group[(i + j) % order], &tmp); + /* add_zinv_var */ + zless_gej.infinity = groupj[j].infinity; + zless_gej.x = groupj[j].x; + zless_gej.y = groupj[j].y; + secp256k1_gej_add_zinv_var(&tmp, &groupj[i], &zless_gej, &fe_inv); + ge_equals_gej(&group[(i + j) % order], &tmp); + } + } + + /* Check doubling */ + for (i = 0; i < order; i++) { + secp256k1_gej tmp; + if (i > 0) { + secp256k1_gej_double_nonzero(&tmp, &groupj[i], NULL); + ge_equals_gej(&group[(2 * i) % order], &tmp); + } + secp256k1_gej_double_var(&tmp, &groupj[i], NULL); + ge_equals_gej(&group[(2 * i) % order], &tmp); + } + + /* Check negation */ + for (i = 1; i < order; i++) { + secp256k1_ge tmp; + secp256k1_gej tmpj; + secp256k1_ge_neg(&tmp, &group[i]); + ge_equals_ge(&group[order - i], &tmp); + secp256k1_gej_neg(&tmpj, &groupj[i]); + ge_equals_gej(&group[order - i], &tmpj); + } +} + +void test_exhaustive_ecmult(const secp256k1_context *ctx, const secp256k1_ge *group, const secp256k1_gej *groupj, int order) { + int i, j, r_log; + for (r_log = 1; r_log < order; r_log++) { + for (j = 0; j < order; j++) { + for (i = 0; i < order; i++) { + secp256k1_gej tmp; + secp256k1_scalar na, ng; + secp256k1_scalar_set_int(&na, i); + secp256k1_scalar_set_int(&ng, j); + + secp256k1_ecmult(&ctx->ecmult_ctx, &tmp, &groupj[r_log], &na, &ng); + ge_equals_gej(&group[(i * r_log + j) % order], &tmp); + + if (i > 0) { + secp256k1_ecmult_const(&tmp, &group[i], &ng); + ge_equals_gej(&group[(i * j) % order], &tmp); + } + } + } + } +} + +void r_from_k(secp256k1_scalar *r, const secp256k1_ge *group, int k) { + secp256k1_fe x; + unsigned char x_bin[32]; + k %= EXHAUSTIVE_TEST_ORDER; + x = group[k].x; + secp256k1_fe_normalize(&x); + secp256k1_fe_get_b32(x_bin, &x); + secp256k1_scalar_set_b32(r, x_bin, NULL); +} + +void test_exhaustive_verify(const secp256k1_context *ctx, const secp256k1_ge *group, int order) { + int s, r, msg, key; + for (s = 1; s < order; s++) { + for (r = 1; r < order; r++) { + for (msg = 1; msg < order; msg++) { + for (key = 1; key < order; key++) { + secp256k1_ge nonconst_ge; + secp256k1_ecdsa_signature sig; + secp256k1_pubkey pk; + secp256k1_scalar sk_s, msg_s, r_s, s_s; + secp256k1_scalar s_times_k_s, msg_plus_r_times_sk_s; + int k, should_verify; + unsigned char msg32[32]; + + secp256k1_scalar_set_int(&s_s, s); + secp256k1_scalar_set_int(&r_s, r); + secp256k1_scalar_set_int(&msg_s, msg); + secp256k1_scalar_set_int(&sk_s, key); + + /* Verify by hand */ + /* Run through every k value that gives us this r and check that *one* works. + * Note there could be none, there could be multiple, ECDSA is weird. */ + should_verify = 0; + for (k = 0; k < order; k++) { + secp256k1_scalar check_x_s; + r_from_k(&check_x_s, group, k); + if (r_s == check_x_s) { + secp256k1_scalar_set_int(&s_times_k_s, k); + secp256k1_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s); + secp256k1_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s); + secp256k1_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s); + should_verify |= secp256k1_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s); + } + } + /* nb we have a "high s" rule */ + should_verify &= !secp256k1_scalar_is_high(&s_s); + + /* Verify by calling verify */ + secp256k1_ecdsa_signature_save(&sig, &r_s, &s_s); + memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge)); + secp256k1_pubkey_save(&pk, &nonconst_ge); + secp256k1_scalar_get_b32(msg32, &msg_s); + CHECK(should_verify == + secp256k1_ecdsa_verify(ctx, &sig, msg32, &pk)); + } + } + } + } +} + +void test_exhaustive_sign(const secp256k1_context *ctx, const secp256k1_ge *group, int order) { + int i, j, k; + + /* Loop */ + for (i = 1; i < order; i++) { /* message */ + for (j = 1; j < order; j++) { /* key */ + for (k = 1; k < order; k++) { /* nonce */ + const int starting_k = k; + secp256k1_ecdsa_signature sig; + secp256k1_scalar sk, msg, r, s, expected_r; + unsigned char sk32[32], msg32[32]; + secp256k1_scalar_set_int(&msg, i); + secp256k1_scalar_set_int(&sk, j); + secp256k1_scalar_get_b32(sk32, &sk); + secp256k1_scalar_get_b32(msg32, &msg); + + secp256k1_ecdsa_sign(ctx, &sig, msg32, sk32, secp256k1_nonce_function_smallint, &k); + + secp256k1_ecdsa_signature_load(ctx, &r, &s, &sig); + /* Note that we compute expected_r *after* signing -- this is important + * because our nonce-computing function function might change k during + * signing. */ + r_from_k(&expected_r, group, k); + CHECK(r == expected_r); + CHECK((k * s) % order == (i + r * j) % order || + (k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order); + + /* Overflow means we've tried every possible nonce */ + if (k < starting_k) { + break; + } + } + } + } + + /* We would like to verify zero-knowledge here by counting how often every + * possible (s, r) tuple appears, but because the group order is larger + * than the field order, when coercing the x-values to scalar values, some + * appear more often than others, so we are actually not zero-knowledge. + * (This effect also appears in the real code, but the difference is on the + * order of 1/2^128th the field order, so the deviation is not useful to a + * computationally bounded attacker.) + */ +} + +#ifdef ENABLE_MODULE_RECOVERY +void test_exhaustive_recovery_sign(const secp256k1_context *ctx, const secp256k1_ge *group, int order) { + int i, j, k; + + /* Loop */ + for (i = 1; i < order; i++) { /* message */ + for (j = 1; j < order; j++) { /* key */ + for (k = 1; k < order; k++) { /* nonce */ + const int starting_k = k; + secp256k1_fe r_dot_y_normalized; + secp256k1_ecdsa_recoverable_signature rsig; + secp256k1_ecdsa_signature sig; + secp256k1_scalar sk, msg, r, s, expected_r; + unsigned char sk32[32], msg32[32]; + int expected_recid; + int recid; + secp256k1_scalar_set_int(&msg, i); + secp256k1_scalar_set_int(&sk, j); + secp256k1_scalar_get_b32(sk32, &sk); + secp256k1_scalar_get_b32(msg32, &msg); + + secp256k1_ecdsa_sign_recoverable(ctx, &rsig, msg32, sk32, secp256k1_nonce_function_smallint, &k); + + /* Check directly */ + secp256k1_ecdsa_recoverable_signature_load(ctx, &r, &s, &recid, &rsig); + r_from_k(&expected_r, group, k); + CHECK(r == expected_r); + CHECK((k * s) % order == (i + r * j) % order || + (k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order); + /* In computing the recid, there is an overflow condition that is disabled in + * scalar_low_impl.h `secp256k1_scalar_set_b32` because almost every r.y value + * will exceed the group order, and our signing code always holds out for r + * values that don't overflow, so with a proper overflow check the tests would + * loop indefinitely. */ + r_dot_y_normalized = group[k].y; + secp256k1_fe_normalize(&r_dot_y_normalized); + /* Also the recovery id is flipped depending if we hit the low-s branch */ + if ((k * s) % order == (i + r * j) % order) { + expected_recid = secp256k1_fe_is_odd(&r_dot_y_normalized) ? 1 : 0; + } else { + expected_recid = secp256k1_fe_is_odd(&r_dot_y_normalized) ? 0 : 1; + } + CHECK(recid == expected_recid); + + /* Convert to a standard sig then check */ + secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig); + secp256k1_ecdsa_signature_load(ctx, &r, &s, &sig); + /* Note that we compute expected_r *after* signing -- this is important + * because our nonce-computing function function might change k during + * signing. */ + r_from_k(&expected_r, group, k); + CHECK(r == expected_r); + CHECK((k * s) % order == (i + r * j) % order || + (k * (EXHAUSTIVE_TEST_ORDER - s)) % order == (i + r * j) % order); + + /* Overflow means we've tried every possible nonce */ + if (k < starting_k) { + break; + } + } + } + } +} + +void test_exhaustive_recovery_verify(const secp256k1_context *ctx, const secp256k1_ge *group, int order) { + /* This is essentially a copy of test_exhaustive_verify, with recovery added */ + int s, r, msg, key; + for (s = 1; s < order; s++) { + for (r = 1; r < order; r++) { + for (msg = 1; msg < order; msg++) { + for (key = 1; key < order; key++) { + secp256k1_ge nonconst_ge; + secp256k1_ecdsa_recoverable_signature rsig; + secp256k1_ecdsa_signature sig; + secp256k1_pubkey pk; + secp256k1_scalar sk_s, msg_s, r_s, s_s; + secp256k1_scalar s_times_k_s, msg_plus_r_times_sk_s; + int recid = 0; + int k, should_verify; + unsigned char msg32[32]; + + secp256k1_scalar_set_int(&s_s, s); + secp256k1_scalar_set_int(&r_s, r); + secp256k1_scalar_set_int(&msg_s, msg); + secp256k1_scalar_set_int(&sk_s, key); + secp256k1_scalar_get_b32(msg32, &msg_s); + + /* Verify by hand */ + /* Run through every k value that gives us this r and check that *one* works. + * Note there could be none, there could be multiple, ECDSA is weird. */ + should_verify = 0; + for (k = 0; k < order; k++) { + secp256k1_scalar check_x_s; + r_from_k(&check_x_s, group, k); + if (r_s == check_x_s) { + secp256k1_scalar_set_int(&s_times_k_s, k); + secp256k1_scalar_mul(&s_times_k_s, &s_times_k_s, &s_s); + secp256k1_scalar_mul(&msg_plus_r_times_sk_s, &r_s, &sk_s); + secp256k1_scalar_add(&msg_plus_r_times_sk_s, &msg_plus_r_times_sk_s, &msg_s); + should_verify |= secp256k1_scalar_eq(&s_times_k_s, &msg_plus_r_times_sk_s); + } + } + /* nb we have a "high s" rule */ + should_verify &= !secp256k1_scalar_is_high(&s_s); + + /* We would like to try recovering the pubkey and checking that it matches, + * but pubkey recovery is impossible in the exhaustive tests (the reason + * being that there are 12 nonzero r values, 12 nonzero points, and no + * overlap between the sets, so there are no valid signatures). */ + + /* Verify by converting to a standard signature and calling verify */ + secp256k1_ecdsa_recoverable_signature_save(&rsig, &r_s, &s_s, recid); + secp256k1_ecdsa_recoverable_signature_convert(ctx, &sig, &rsig); + memcpy(&nonconst_ge, &group[sk_s], sizeof(nonconst_ge)); + secp256k1_pubkey_save(&pk, &nonconst_ge); + CHECK(should_verify == + secp256k1_ecdsa_verify(ctx, &sig, msg32, &pk)); + } + } + } + } +} +#endif + +int main(void) { + int i; + secp256k1_gej groupj[EXHAUSTIVE_TEST_ORDER]; + secp256k1_ge group[EXHAUSTIVE_TEST_ORDER]; + + /* Build context */ + secp256k1_context *ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + + /* TODO set z = 1, then do num_tests runs with random z values */ + + /* Generate the entire group */ + secp256k1_gej_set_infinity(&groupj[0]); + secp256k1_ge_set_gej(&group[0], &groupj[0]); + for (i = 1; i < EXHAUSTIVE_TEST_ORDER; i++) { + /* Set a different random z-value for each Jacobian point */ + secp256k1_fe z; + random_fe(&z); + + secp256k1_gej_add_ge(&groupj[i], &groupj[i - 1], &secp256k1_ge_const_g); + secp256k1_ge_set_gej(&group[i], &groupj[i]); + secp256k1_gej_rescale(&groupj[i], &z); + + /* Verify against ecmult_gen */ + { + secp256k1_scalar scalar_i; + secp256k1_gej generatedj; + secp256k1_ge generated; + + secp256k1_scalar_set_int(&scalar_i, i); + secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &generatedj, &scalar_i); + secp256k1_ge_set_gej(&generated, &generatedj); + + CHECK(group[i].infinity == 0); + CHECK(generated.infinity == 0); + CHECK(secp256k1_fe_equal_var(&generated.x, &group[i].x)); + CHECK(secp256k1_fe_equal_var(&generated.y, &group[i].y)); + } + } + + /* Run the tests */ +#ifdef USE_ENDOMORPHISM + test_exhaustive_endomorphism(group, EXHAUSTIVE_TEST_ORDER); +#endif + test_exhaustive_addition(group, groupj, EXHAUSTIVE_TEST_ORDER); + test_exhaustive_ecmult(ctx, group, groupj, EXHAUSTIVE_TEST_ORDER); + test_exhaustive_sign(ctx, group, EXHAUSTIVE_TEST_ORDER); + test_exhaustive_verify(ctx, group, EXHAUSTIVE_TEST_ORDER); + +#ifdef ENABLE_MODULE_RECOVERY + test_exhaustive_recovery_sign(ctx, group, EXHAUSTIVE_TEST_ORDER); + test_exhaustive_recovery_verify(ctx, group, EXHAUSTIVE_TEST_ORDER); +#endif + + secp256k1_context_destroy(ctx); + return 0; +} + diff --git a/src/cryptoconditions/src/include/secp256k1/src/util.h b/src/cryptoconditions/src/include/secp256k1/src/util.h index ae98639f7..b0441d8e3 100644 --- a/src/cryptoconditions/src/include/secp256k1/src/util.h +++ b/src/cryptoconditions/src/include/secp256k1/src/util.h @@ -4,8 +4,8 @@ * file COPYING or http://www.opensource.org/licenses/mit-license.php.* **********************************************************************/ -#ifndef _SECP256K1_UTIL_H_ -#define _SECP256K1_UTIL_H_ +#ifndef SECP256K1_UTIL_H +#define SECP256K1_UTIL_H #if defined HAVE_CONFIG_H #include "libsecp256k1-config.h" @@ -15,6 +15,15 @@ #include #include +typedef struct { + void (*fn)(const char *text, void* data); + const void* data; +} secp256k1_callback; + +static SECP256K1_INLINE void secp256k1_callback_call(const secp256k1_callback * const cb, const char * const text) { + cb->fn(text, (void*)cb->data); +} + #ifdef DETERMINISTIC #define TEST_FAILURE(msg) do { \ fprintf(stderr, "%s\n", msg); \ @@ -47,23 +56,23 @@ } while(0) #endif -/* Like assert(), but safe to use on expressions with side effects. */ -#ifndef NDEBUG -#define DEBUG_CHECK CHECK -#else -#define DEBUG_CHECK(cond) do { (void)(cond); } while(0) -#endif - -/* Like DEBUG_CHECK(), but when VERIFY is defined instead of NDEBUG not defined. */ -#ifdef VERIFY +/* Like assert(), but when VERIFY is defined, and side-effect safe. */ +#if defined(COVERAGE) +#define VERIFY_CHECK(check) +#define VERIFY_SETUP(stmt) +#elif defined(VERIFY) #define VERIFY_CHECK CHECK +#define VERIFY_SETUP(stmt) do { stmt; } while(0) #else #define VERIFY_CHECK(cond) do { (void)(cond); } while(0) +#define VERIFY_SETUP(stmt) #endif -static SECP256K1_INLINE void *checked_malloc(size_t size) { +static SECP256K1_INLINE void *checked_malloc(const secp256k1_callback* cb, size_t size) { void *ret = malloc(size); - CHECK(ret != NULL); + if (ret == NULL) { + secp256k1_callback_call(cb, "Out of memory"); + } return ret; } @@ -101,4 +110,4 @@ static SECP256K1_INLINE void *checked_malloc(size_t size) { SECP256K1_GNUC_EXT typedef unsigned __int128 uint128_t; #endif -#endif +#endif /* SECP256K1_UTIL_H */ diff --git a/src/cryptoconditions/src/secp256k1.c b/src/cryptoconditions/src/secp256k1.c index 9e09cabe5..895e91b32 100644 --- a/src/cryptoconditions/src/secp256k1.c +++ b/src/cryptoconditions/src/secp256k1.c @@ -23,7 +23,7 @@ static const size_t SECP256K1_SK_SIZE = 32; static const size_t SECP256K1_SIG_SIZE = 64; -secp256k1_context_t *ec_ctx_sign = 0, *ec_ctx_verify = 0; +secp256k1_context *ec_ctx_sign = 0, *ec_ctx_verify = 0; pthread_mutex_t cc_secp256k1ContextLock = PTHREAD_MUTEX_INITIALIZER; @@ -75,16 +75,25 @@ static unsigned char *secp256k1Fingerprint(const CC *cond) { int secp256k1Verify(CC *cond, CCVisitor visitor) { if (cond->type->typeId != cc_secp256k1Type.typeId) return 1; - // TODO: test failure mode: empty sig / null pointer initVerify(); - // Test for non canonical S - int rc = secp256k1_ecdsa_check_canonical_sig(cond->signature, SECP256K1_SIG_SIZE); - if (rc == 1) - // Test for correct sig - rc = secp256k1_ecdsa_verify(ec_ctx_verify, visitor.msg, cond->signature, SECP256K1_SIG_SIZE, - cond->publicKey, SECP256K1_PK_SIZE); - return rc == 1; + int rc; + + // parse pubkey + secp256k1_pubkey pk; + rc = secp256k1_ec_pubkey_parse(ec_ctx_verify, &pk, cond->publicKey, SECP256K1_PK_SIZE); + if (rc != 1) return 0; + + // parse siganature + secp256k1_ecdsa_signature sig; + rc = secp256k1_ecdsa_signature_parse_compact(ec_ctx_verify, &sig, cond->signature); + if (rc != 1) return 0; + + // Only accepts lower S signatures + rc = secp256k1_ecdsa_verify(ec_ctx_verify, &sig, visitor.msg, &pk); + if (rc != 1) return 0; + + return 1; } @@ -119,15 +128,19 @@ static int secp256k1Sign(CC *cond, CCVisitor visitor) { if (cond->type->typeId != cc_secp256k1Type.typeId) return 1; CCSecp256k1SigningData *signing = (CCSecp256k1SigningData*) visitor.context; if (0 != memcmp(cond->publicKey, signing->pk, SECP256K1_PK_SIZE)) return 1; - if (!cond->signature) cond->signature = calloc(1, SECP256K1_SIG_SIZE); + + secp256k1_ecdsa_signature sig; lockSign(); - int rc = secp256k1_ecdsa_sign_compact(ec_ctx_sign, visitor.msg, cond->signature, signing->sk, NULL, NULL, NULL); + int rc = secp256k1_ecdsa_sign(ec_ctx_sign, &sig, visitor.msg, signing->sk, NULL, NULL); unlockSign(); - if (rc) { - signing->nSigned++; - return 1; - } - return 0; + + if (rc != 1) return 0; + + if (!cond->signature) cond->signature = calloc(1, SECP256K1_SIG_SIZE); + secp256k1_ecdsa_signature_serialize_compact(ec_ctx_verify, cond->signature, &sig); + + signing->nSigned++; + return 1; } @@ -140,14 +153,24 @@ int cc_signTreeSecp256k1Msg32(CC *cond, const unsigned char *privateKey, const u // how to combine message and prefix into 32 byte hash return 0; } + + // derive the pubkey + secp256k1_pubkey spk; + lockSign(); + int rc = secp256k1_ec_pubkey_create(ec_ctx_sign, &spk, privateKey); + unlockSign(); + if (rc != 1) return 0; + + // serialize pubkey unsigned char *publicKey = calloc(1, SECP256K1_PK_SIZE); + size_t ol = SECP256K1_PK_SIZE; + secp256k1_ec_pubkey_serialize(ec_ctx_verify, publicKey, &ol, &spk, SECP256K1_EC_COMPRESSED); + + // sign CCSecp256k1SigningData signing = {publicKey, privateKey, 0}; CCVisitor visitor = {&secp256k1Sign, msg32, 32, &signing}; - int ol = 0; - lockSign(); - int rc = secp256k1_ec_pubkey_create(ec_ctx_sign, publicKey, &ol, privateKey, 1); - unlockSign(); - if (rc) cc_visit(cond, visitor); + cc_visit(cond, visitor); + free(publicKey); return signing.nSigned; } @@ -159,15 +182,16 @@ static unsigned long secp256k1Cost(const CC *cond) { static CC *cc_secp256k1Condition(const unsigned char *publicKey, const unsigned char *signature) { - unsigned char *pk = 0, *sig = 0; - - + // Check that pk parses initVerify(); - int rc = secp256k1_ec_pubkey_verify(ec_ctx_verify, publicKey, SECP256K1_PK_SIZE); + secp256k1_pubkey spk; + int rc = secp256k1_ec_pubkey_parse(ec_ctx_verify, &spk, publicKey, SECP256K1_PK_SIZE); if (!rc) { return NULL; } + unsigned char *pk = 0, *sig = 0; + pk = calloc(1, SECP256K1_PK_SIZE); memcpy(pk, publicKey, SECP256K1_PK_SIZE); if (signature) { diff --git a/src/cryptoconditions/test-requirements.txt b/src/cryptoconditions/test-requirements.txt index 2858c9ae3..3e7a933b9 100644 --- a/src/cryptoconditions/test-requirements.txt +++ b/src/cryptoconditions/test-requirements.txt @@ -1,3 +1,3 @@ -nose base58==0.2.5 secp256k1 +pytest diff --git a/src/cryptoconditions/tests/test_ed25519.py b/src/cryptoconditions/tests/test_ed25519.py index 081a7efd5..271b9b023 100644 --- a/src/cryptoconditions/tests/test_ed25519.py +++ b/src/cryptoconditions/tests/test_ed25519.py @@ -1,6 +1,6 @@ import json import base64 -from test_vectors import jsonRPC +from .test_vectors import jsonRPC def test_sign_ed25519_pass_simple(): diff --git a/src/cryptoconditions/tests/test_failure_modes.py b/src/cryptoconditions/tests/test_failure_modes.py index 4e252424f..839eded3b 100644 --- a/src/cryptoconditions/tests/test_failure_modes.py +++ b/src/cryptoconditions/tests/test_failure_modes.py @@ -1,7 +1,7 @@ import json import ctypes import base64 -from test_vectors import jsonRPC, so, decode_base64 as d64 +from .test_vectors import jsonRPC, so, decode_base64 as d64 ''' diff --git a/src/cryptoconditions/tests/test_secp256k1.py b/src/cryptoconditions/tests/test_secp256k1.py index db36da218..bbc9462fa 100644 --- a/src/cryptoconditions/tests/test_secp256k1.py +++ b/src/cryptoconditions/tests/test_secp256k1.py @@ -2,7 +2,7 @@ import json import base64 import hashlib import secp256k1 -from test_vectors import jsonRPC, encode_base64, decode_base64 +from .test_vectors import jsonRPC, encode_base64, decode_base64 key = secp256k1.PrivateKey() @@ -20,7 +20,7 @@ def test_sign_secp256k1_pass_simple(): 'message': msg, }) - sig = encode_base64(key.ecdsa_serialize_compact(key.ecdsa_sign(msg))) + sig = encode_base64(key.ecdsa_serialize_compact(key.ecdsa_sign(msg.encode()))) assert res == { "num_signed": 1, diff --git a/src/cryptoconditions/tests/test_vectors.py b/src/cryptoconditions/tests/test_vectors.py index b94ed9461..34ed9a7d3 100644 --- a/src/cryptoconditions/tests/test_vectors.py +++ b/src/cryptoconditions/tests/test_vectors.py @@ -114,11 +114,15 @@ def decode_base64(data): def encode_base64(data): - return base64.urlsafe_b64encode(data).rstrip(b'=') + if type(data) == str: + data = data.encode() + return base64.urlsafe_b64encode(data).rstrip(b'=').decode() def b16_to_b64(b16): - return encode_base64(base64.b16decode(b16)).decode() + if type(b16) == str: + b16 = b16.encode() + return encode_base64(base64.b16decode(b16)) def _read_vectors(name): diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 444e5ff2b..6ae466e65 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -959,7 +959,7 @@ bool EvalScript( return set_error(serror, SCRIPT_ERR_CRYPTOCONDITION_INVALID_FULFILLMENT); } - bool fSuccess = checker.CheckCryptoCondition(cond, vchCondition, script); + bool fSuccess = checker.CheckCryptoCondition(cond, vchCondition, script, consensusBranchId); cc_free(cond); @@ -1307,10 +1307,15 @@ static int komodoCCEval(CC *cond, void *checker) } -bool TransactionSignatureChecker::CheckCryptoCondition(const CC *cond, const std::vector& condBin, const CScript& scriptCode) const +bool TransactionSignatureChecker::CheckCryptoCondition(const CC *cond, const std::vector& condBin, const CScript& scriptCode, uint32_t consensusBranchId) const { - uint256 message = SignatureHash(scriptCode, *txTo, nIn, SIGHASH_ALL); - return cc_verify(cond, (const unsigned char*)&message, 32, 0, + uint256 sighash; + try { + sighash = SignatureHash(scriptCode, *txTo, nIn, SIGHASH_ALL, amount, consensusBranchId, this->txdata); + } catch (logic_error ex) { + return false; + } + return cc_verify(cond, (const unsigned char*)&sighash, 32, 0, condBin.data(), condBin.size(), komodoCCEval, (void*)this); } diff --git a/src/script/interpreter.h b/src/script/interpreter.h index b13922f07..86d792e0a 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -128,7 +128,7 @@ public: return false; } - virtual bool CheckCryptoCondition(const CC *cond, const std::vector& condBin, const CScript& scriptCode) const + virtual bool CheckCryptoCondition(const CC *cond, const std::vector& condBin, const CScript& scriptCode, uint32_t consensusBranchId) const { return false; } @@ -152,7 +152,7 @@ public: TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {} bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, uint32_t consensusBranchId) const; bool CheckLockTime(const CScriptNum& nLockTime) const; - bool CheckCryptoCondition(const CC *cond, const std::vector& condBin, const CScript& scriptCode) const; + bool CheckCryptoCondition(const CC *cond, const std::vector& condBin, const CScript& scriptCode, uint32_t consensusBranchId) const; bool CheckEvalCondition(const CC *cond) const; }; From 2c8d8268ddd5c8b8f0f1c2433196a458e47fb6e6 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Fri, 30 Mar 2018 15:46:41 -0300 Subject: [PATCH 052/339] ImportPayout cc eval code and alot of general cc polish. tests to write --- src/Makefile.am | 13 +- src/Makefile.zcash.include | 4 +- src/cc/eval.cpp | 23 +++ src/cc/eval.h | 18 ++ src/cc/importpayout.cpp | 191 ++++++++++++++++++ src/cryptoconditions/Makefile.am | 2 + .../include/cryptoconditions.h | 2 +- src/cryptoconditions/src/cryptoconditions.c | 4 +- src/cryptoconditions/src/internal.h | 1 - src/cryptoconditions/src/prefix.c | 2 +- src/cryptoconditions/src/secp256k1.c | 4 +- src/cryptoconditions/src/threshold.c | 2 +- src/komodo_cc.h | 40 ++++ src/komodo_cryptoconditions.cpp | 28 --- src/komodo_cryptoconditions.h | 19 -- src/main.cpp | 2 +- src/main.h | 2 +- src/script/interpreter.cpp | 26 ++- src/script/interpreter.h | 4 +- src/script/script.cpp | 16 ++ src/script/script.h | 1 + .../{sigcache.cpp => serverchecker.cpp} | 35 +++- src/script/serverchecker.h | 30 +++ src/script/sigcache.h | 26 --- src/script/standard.cpp | 10 +- 25 files changed, 389 insertions(+), 116 deletions(-) create mode 100644 src/cc/eval.cpp create mode 100644 src/cc/eval.h create mode 100644 src/cc/importpayout.cpp create mode 100644 src/komodo_cc.h delete mode 100644 src/komodo_cryptoconditions.cpp delete mode 100644 src/komodo_cryptoconditions.h rename src/script/{sigcache.cpp => serverchecker.cpp} (65%) create mode 100644 src/script/serverchecker.h delete mode 100644 src/script/sigcache.h diff --git a/src/Makefile.am b/src/Makefile.am index 89ee8ec74..affa61fc6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -43,7 +43,7 @@ LIBBITCOIN_CLI=libbitcoin_cli.a LIBBITCOIN_UTIL=libbitcoin_util.a LIBBITCOIN_CRYPTO=crypto/libbitcoin_crypto.a LIBSECP256K1=secp256k1/libsecp256k1.la -LIBCRYPTOCONDITIONS=cryptoconditions/cryptoconditions_core.a +LIBCRYPTOCONDITIONS=cryptoconditions/libcryptoconditions_core.la LIBSNARK=snark/libsnark.a LIBUNIVALUE=univalue/libunivalue.la LIBZCASH=libzcash.a -lcurl @@ -135,6 +135,7 @@ BITCOIN_CORE_H = \ asyncrpcqueue.h \ base58.h \ bloom.h \ + cc/eval.h \ chain.h \ chainparams.h \ chainparamsbase.h \ @@ -162,7 +163,7 @@ BITCOIN_CORE_H = \ init.h \ key.h \ keystore.h \ - komodo_cryptoconditions.h \ + komodo_cc.h \ leveldbwrapper.h \ limitedmap.h \ main.h \ @@ -191,7 +192,7 @@ BITCOIN_CORE_H = \ script/interpreter.h \ script/script.h \ script/script_error.h \ - script/sigcache.h \ + script/serverchecker.h \ script/sign.h \ script/standard.h \ serialize.h \ @@ -249,13 +250,14 @@ libbitcoin_server_a_SOURCES = \ asyncrpcoperation.cpp \ asyncrpcqueue.cpp \ bloom.cpp \ + cc/eval.cpp \ + cc/importpayout.cpp \ chain.cpp \ checkpoints.cpp \ deprecation.cpp \ httprpc.cpp \ httpserver.cpp \ init.cpp \ - komodo_cryptoconditions.cpp \ leveldbwrapper.cpp \ main.cpp \ merkleblock.cpp \ @@ -274,7 +276,7 @@ libbitcoin_server_a_SOURCES = \ rpcnet.cpp \ rpcrawtransaction.cpp \ rpcserver.cpp \ - script/sigcache.cpp \ + script/serverchecker.cpp \ timedata.cpp \ torcontrol.cpp \ txdb.cpp \ @@ -378,7 +380,6 @@ libbitcoin_common_a_SOURCES = \ hash.cpp \ key.cpp \ keystore.cpp \ - komodo_cryptoconditions.cpp \ netbase.cpp \ primitives/block.cpp \ primitives/transaction.cpp \ diff --git a/src/Makefile.zcash.include b/src/Makefile.zcash.include index 177931c88..e6730623a 100644 --- a/src/Makefile.zcash.include +++ b/src/Makefile.zcash.include @@ -25,4 +25,6 @@ zcash_CreateJoinSplit_LDADD = \ $(LIBBITCOIN_UTIL) \ $(LIBBITCOIN_CRYPTO) \ $(BOOST_LIBS) \ - $(LIBZCASH_LIBS) + $(LIBZCASH_LIBS) \ + $(LIBCRYPTOCONDITIONS) \ + $(LIBSECP256K1) diff --git a/src/cc/eval.cpp b/src/cc/eval.cpp new file mode 100644 index 000000000..0291d1e3f --- /dev/null +++ b/src/cc/eval.cpp @@ -0,0 +1,23 @@ +#include "primitives/transaction.h" +#include "komodo_cc.h" +#include "cc/eval.h" +#include + + +/* + * Test the validity of an Eval node + */ +bool EvalConditionValidity(const CC *cond, const CTransaction *txTo, int nIn) +{ + if (strcmp(cond->method, "testEval") == 0) { + return cond->paramsBinLength == 8 && + memcmp(cond->paramsBin, "testEval", 8) == 0; + } + + if (strcmp(cond->method, "ImportPayout") == 0) { + return CheckImportPayout(cond, txTo, nIn); + } + + fprintf(stderr, "no defined behaviour for method: %s\n", cond->method); + return 0; +} diff --git a/src/cc/eval.h b/src/cc/eval.h new file mode 100644 index 000000000..8aa797f99 --- /dev/null +++ b/src/cc/eval.h @@ -0,0 +1,18 @@ +#ifndef CC_EVAL_H +#define CC_EVAL_H + +#include "cryptoconditions/include/cryptoconditions.h" +#include "primitives/transaction.h" + +/* + * Test validity of a CC_Eval node + */ +bool EvalConditionValidity(const CC *cond, const CTransaction *tx, int nIn); + +/* + * Test an ImportPayout CC Eval condition + */ +bool CheckImportPayout(const CC *cond, const CTransaction *payoutTx, int nIn); + + +#endif /* CC_EVAL_H */ diff --git a/src/cc/importpayout.cpp b/src/cc/importpayout.cpp new file mode 100644 index 000000000..d0a8c2fb0 --- /dev/null +++ b/src/cc/importpayout.cpp @@ -0,0 +1,191 @@ +#include "primitives/transaction.h" +#include "streams.h" +#include "chain.h" +#include "main.h" +#include "cryptoconditions/include/cryptoconditions.h" + + +bool GetPushData(const CScript &sig, std::vector &data) +{ + opcodetype opcode; + auto pc = sig.begin(); + if (sig.GetOp(pc, opcode, data)) return opcode > OP_0 && opcode <= OP_PUSHDATA4; + return false; +} + + +bool GetOpReturnData(const CScript &sig, std::vector &data) +{ + auto pc = sig.begin(); + opcodetype opcode; + if (sig.GetOp2(pc, opcode, NULL)) + if (opcode == OP_RETURN) + if (sig.GetOp(pc, opcode, data)) + return opcode > OP_0 && opcode <= OP_PUSHDATA4; + return false; +} + + +class MomProof +{ +public: + uint256 notaryHash; + int nPos; // Position of imported tx in MoM + std::vector branch; + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(notaryHash); + READWRITE(VARINT(nPos)); + READWRITE(branch); + } +}; + + +extern int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp); + +bool DerefNotaryPubkey(const COutPoint &prevout, char *pk33) +{ + CTransaction tx; + uint256 hashBlock; + if (!GetTransaction(prevout.hash, tx, hashBlock, false)) return false; + if (tx.vout.size() < prevout.n) return false; + const unsigned char *script = tx.vout[prevout.n].scriptPubKey.data(); + if (script[0] != 33) return false; + memcpy(pk33, script+1, 33); + return true; +} + +bool CheckNotaryInputs(const CTransaction &tx, uint32_t height, uint32_t timestamp) +{ + if (tx.vin.size() < 11) return false; + + uint8_t notaries[64][33]; + uint8_t seenNotaries[64]; + int nNotaries = komodo_notaries(notaries, height, timestamp); + char *pk; + + BOOST_FOREACH(const CTxIn &txIn, tx.vin) + { + if (!DerefNotaryPubkey(txIn.prevout, pk)) return false; + + for (int i=0; inHeight, blockindex->nTime)) { + return false; + } + if (!notarisationTx.vout.size() < 1) return 0; + std::vector opret; + if (!GetOpReturnData(notarisationTx.vout[0].scriptPubKey, opret)) return 0; + if (opret.size() < 36) return 0; // In reality it is more than 36, but at the moment I + // only know where it is relative to the end, and this + // is enough to prevent a memory fault. In the case that + // the assumption about the presence of a MoM at this + // offset fails, we will return random other data that is + // not more likely to generate a false positive. + memcpy(mom.begin(), opret.data()+opret.size()-36, 32); + return 1; +} + + +uint256 ExecMerkle(uint256 hash, const std::vector& vMerkleBranch, int nIndex) +{ + return CBlock::CheckMerkleBranch(hash, vMerkleBranch, nIndex); +} + + +/* + * Crypto-Condition EVAL method that verifies a payout against a transaction + * notarised on another chain. + * + * IN: cond - CC EVAL node + * IN: payoutTx - Payout transaction on value chain (KMD) + * IN: nIn - index of input of stake + * + * payoutTx: Spends stakeTx with payouts from asset chain + * + * in 0: Spends Stake TX and contains ImportPayout CC + * out 0: OP_RETURN MomProof + * out 1: OP_RETURN serialized exportTx from other chain + * out 2-: arbitrary payouts + * + * exportTx: Spends sessionTx.0 (opener on asset chain) + * + * in 0: spends sessionTx.0 + * in 1-: anything + * out 0: OP_RETURN hash of payouts + * out 1-: anything + */ +bool CheckImportPayout(const CC *cond, const CTransaction *payoutTx, int nIn) +{ + // TODO: Error messages! + if (payoutTx->vin.size() != 1) return 0; + if (payoutTx->vout.size() < 2) return 0; + + // Get hash of payouts + std::vector payouts(payoutTx->vout.begin() + 2, payoutTx->vout.end()); + uint256 payoutsHash = SerializeHash(payouts); + std::vector vPayoutsHash(payoutsHash.begin(), payoutsHash.end()); + + // load exportTx from vout[1] + CTransaction exportTx; + { + std::vector exportData; + if (!GetOpReturnData(payoutTx->vout[1].scriptPubKey, exportData)) return 0; + CDataStream(exportData, SER_DISK, PROTOCOL_VERSION) >> exportTx; + // TODO: end of stream? exception? + } + + // Check exportTx.0 is vPayoutsHash + std::vector exportPayoutsHash; + if (!GetOpReturnData(exportTx.vout[0].scriptPubKey, exportPayoutsHash)) return 0; + if (exportPayoutsHash != vPayoutsHash) return 0; + + // Check exportTx spends sessionTx.0 + // condition ImportPayout params is session ID from other chain + { + if (cond->paramsBinLength != 32) return 0; + COutPoint prevout = exportTx.vin[0].prevout; + if (memcmp(prevout.hash.begin(), cond->paramsBin, 32) != 0 || + prevout.n != 0) return 0; + } + + // Check exportTx solves momproof from vout[0] + { + std::vector vchMomProof; + if (!GetOpReturnData(payoutTx->vout[0].scriptPubKey, vchMomProof)) return 0; + + MomProof momProof; + CDataStream(vchMomProof, SER_DISK, PROTOCOL_VERSION) >> momProof; + + uint256 mom; + if (!GetMoM(momProof.notaryHash, mom)) return 0; + + uint256 proofResult = ExecMerkle(exportTx.GetHash(), momProof.branch, momProof.nPos); + if (proofResult != mom) return 0; + } + + return 1; +} diff --git a/src/cryptoconditions/Makefile.am b/src/cryptoconditions/Makefile.am index 9469acdbf..eed285064 100644 --- a/src/cryptoconditions/Makefile.am +++ b/src/cryptoconditions/Makefile.am @@ -2,6 +2,8 @@ lib_LTLIBRARIES=libcryptoconditions.la noinst_LTLIBRARIES=$(CRYPTOCONDITIONS_CORE) SUBDIRS = src/include/secp256k1 +include_HEADERS = include/cryptoconditions.h + # Have a separate build target for cryptoconditions that does not contain secp256k1 libcryptoconditions_la_SOURCES = include/cryptoconditions.h diff --git a/src/cryptoconditions/include/cryptoconditions.h b/src/cryptoconditions/include/cryptoconditions.h index c434a486b..88a3a6560 100644 --- a/src/cryptoconditions/include/cryptoconditions.h +++ b/src/cryptoconditions/include/cryptoconditions.h @@ -84,9 +84,9 @@ unsigned char* cc_conditionUri(const CC *cond); unsigned char* cc_jsonRPC(unsigned char *request); unsigned long cc_getCost(const CC *cond); enum CCTypeId cc_typeId(const CC *cond); +uint32_t cc_typeMask(const CC *cond); void cc_free(struct CC *cond); - #ifdef __cplusplus } #endif diff --git a/src/cryptoconditions/src/cryptoconditions.c b/src/cryptoconditions/src/cryptoconditions.c index 147cbb334..805c66236 100644 --- a/src/cryptoconditions/src/cryptoconditions.c +++ b/src/cryptoconditions/src/cryptoconditions.c @@ -42,8 +42,8 @@ void appendUriSubtypes(uint32_t mask, unsigned char *buf) { } else { strcat(buf, "&subtypes="); strcat(buf, typeRegistry[i]->name); + append = 1; } - append = 1; } } } @@ -70,7 +70,7 @@ unsigned char *cc_conditionUri(const CC *cond) { } -static uint32_t getSubtypes(CC *cond) { +uint32_t cc_typeMask(const CC *cond) { uint32_t mask = 1 << cond->type->typeId; if (cond->type->hasSubtypes) { mask |= cond->type->getSubtypes(cond); diff --git a/src/cryptoconditions/src/internal.h b/src/cryptoconditions/src/internal.h index bd0e6376a..bfcc6bd14 100644 --- a/src/cryptoconditions/src/internal.h +++ b/src/cryptoconditions/src/internal.h @@ -49,7 +49,6 @@ static CC *mkAnon(const Condition_t *asnCond); static void asnCondition(const CC *cond, Condition_t *asn); static Condition_t *asnConditionNew(const CC *cond); static Fulfillment_t *asnFulfillmentNew(const CC *cond); -static uint32_t getSubtypes(CC *cond); static cJSON *jsonEncodeCondition(cJSON *params, unsigned char *err); static struct CC *fulfillmentToCC(Fulfillment_t *ffill); static struct CCType *getTypeByAsnEnum(Condition_PR present); diff --git a/src/cryptoconditions/src/prefix.c b/src/cryptoconditions/src/prefix.c index 8fdd0a483..527115709 100644 --- a/src/cryptoconditions/src/prefix.c +++ b/src/cryptoconditions/src/prefix.c @@ -71,7 +71,7 @@ static Fulfillment_t *prefixToFulfillment(const CC *cond) { static uint32_t prefixSubtypes(const CC *cond) { - return getSubtypes(cond->subcondition) & ~(1 << cc_prefixType.typeId); + return cc_typeMask(cond->subcondition) & ~(1 << cc_prefixType.typeId); } diff --git a/src/cryptoconditions/src/secp256k1.c b/src/cryptoconditions/src/secp256k1.c index 895e91b32..be8fbd761 100644 --- a/src/cryptoconditions/src/secp256k1.c +++ b/src/cryptoconditions/src/secp256k1.c @@ -98,7 +98,7 @@ int secp256k1Verify(CC *cond, CCVisitor visitor) { static int cc_secp256k1VerifyTreeMsg32(const CC *cond, const unsigned char *msg32) { - int subtypes = getSubtypes(cond); + int subtypes = cc_typeMask(cond); if (subtypes & (1 << cc_prefixType.typeId) && subtypes & (1 << cc_secp256k1Type.typeId)) { // No support for prefix currently, due to pending protocol decision on @@ -148,7 +148,7 @@ static int secp256k1Sign(CC *cond, CCVisitor visitor) { * Sign secp256k1 conditions in a tree */ int cc_signTreeSecp256k1Msg32(CC *cond, const unsigned char *privateKey, const unsigned char *msg32) { - if (getSubtypes(cond) & (1 << cc_preimageType.typeId)) { + if (cc_typeMask(cond) & (1 << cc_preimageType.typeId)) { // No support for prefix currently, due to pending protocol decision on // how to combine message and prefix into 32 byte hash return 0; diff --git a/src/cryptoconditions/src/threshold.c b/src/cryptoconditions/src/threshold.c index 68f4c557d..d3f4d3e63 100644 --- a/src/cryptoconditions/src/threshold.c +++ b/src/cryptoconditions/src/threshold.c @@ -14,7 +14,7 @@ struct CCType cc_thresholdType; static uint32_t thresholdSubtypes(const CC *cond) { uint32_t mask = 0; for (int i=0; isize; i++) { - mask |= getSubtypes(cond->subconditions[i]); + mask |= cc_typeMask(cond->subconditions[i]); } mask &= ~(1 << cc_thresholdType.typeId); return mask; diff --git a/src/komodo_cc.h b/src/komodo_cc.h new file mode 100644 index 000000000..fe05d3fc0 --- /dev/null +++ b/src/komodo_cc.h @@ -0,0 +1,40 @@ +#ifndef KOMODO_CC_H +#define KOMODO_CC_H + +#include "cryptoconditions/include/cryptoconditions.h" +#include "primitives/transaction.h" + + +/* + * Check if CryptoConditions is enabled based on chain or cmd flag + */ +extern int32_t ASSETCHAINS_CC; +static bool IsCryptoConditionsEnabled() +{ + return 0 != ASSETCHAINS_CC; +} + + +/* + * Check if the server can accept the condition based on it's structure / types + */ +static bool IsAcceptableCryptoCondition(const CC *cond) +{ + int32_t typeMask = cc_typeMask(cond); + + // Require a signature to prevent transaction malleability + if (0 == typeMask & (1 << CC_Secp256k1) || + 0 == typeMask & (1 << CC_Ed25519)) return false; + + // Limit acceptable condition types + // Prefix not enabled because no current use case, ambiguity on how to combine with secp256k1 + // RSA not enabled because no current use case, not implemented + int enabledTypes = 1 << CC_Secp256k1 | 1 << CC_Threshold | 1 << CC_Eval | \ + 1 << CC_Preimage | 1 << CC_Ed25519; + if (typeMask & ~enabledTypes) return false; + + return true; +} + + +#endif /* KOMODO_CC_H */ diff --git a/src/komodo_cryptoconditions.cpp b/src/komodo_cryptoconditions.cpp deleted file mode 100644 index 4ebbebbeb..000000000 --- a/src/komodo_cryptoconditions.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "komodo_cryptoconditions.h" -#include "cryptoconditions/include/cryptoconditions.h" - - -/* - * Evaluate the validity of an Eval node - */ -bool EvalConditionValidity(const CC *cond, const CTransaction *txTo) -{ - if (strcmp(cond->method, "testEval") == 0) { - return cond->paramsBinLength == 8 && - memcmp(cond->paramsBin, "testEval", 8) == 0; - } - fprintf(stderr, "no defined behaviour for method: %s\n", cond->method); - return 0; -} - - -bool GetOpReturnData(const CScript &sig, std::vector &data) -{ - auto pc = sig.begin(); - opcodetype opcode; - if (sig.GetOp(pc, opcode)) - if (opcode == OP_RETURN) - if (sig.GetOp(pc, opcode, data)) - return opcode > OP_0 && opcode <= OP_PUSHDATA4; - return false; -} diff --git a/src/komodo_cryptoconditions.h b/src/komodo_cryptoconditions.h deleted file mode 100644 index 4edc2bedc..000000000 --- a/src/komodo_cryptoconditions.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef KOMODO_CRYPTOCONDITIONS_H -#define KOMODO_CRYPTOCONDITIONS_H - -#include "cryptoconditions/include/cryptoconditions.h" -#include "primitives/transaction.h" -#include "script/script.h" - - -extern int32_t ASSETCHAINS_CC; - -static bool IsCryptoConditionsEnabled() { - return 0 != ASSETCHAINS_CC; -} - -bool EvalConditionValidity(const CC *cond, const CTransaction *tx); - -bool GetOpReturnData(const CScript &sig, std::vector &data); - -#endif /* KOMODO_CRYPTOCONDITIONS_H */ diff --git a/src/main.cpp b/src/main.cpp index 151c42383..9fb8402d5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1931,7 +1931,7 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, int nHeight) bool CScriptCheck::operator()() { const CScript &scriptSig = ptxTo->vin[nIn].scriptSig; - if (!VerifyScript(scriptSig, scriptPubKey, nFlags, CachingTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore, *txdata), consensusBranchId, &error)) { + if (!VerifyScript(scriptSig, scriptPubKey, nFlags, ServerTransactionSignatureChecker(ptxTo, nIn, amount, cacheStore, *txdata), consensusBranchId, &error)) { return ::error("CScriptCheck(): %s:%d VerifySignature failed: %s", ptxTo->GetHash().ToString(), nIn, ScriptErrorString(error)); } return true; diff --git a/src/main.h b/src/main.h index 14513b730..1c864de20 100644 --- a/src/main.h +++ b/src/main.h @@ -20,7 +20,7 @@ #include "primitives/block.h" #include "primitives/transaction.h" #include "script/script.h" -#include "script/sigcache.h" +#include "script/serverchecker.h" #include "script/standard.h" #include "sync.h" #include "tinyformat.h" diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 6ae466e65..20027ea41 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -13,7 +13,7 @@ #include "pubkey.h" #include "script/script.h" #include "uint256.h" -#include "komodo_cryptoconditions.h" +#include "cryptoconditions/include/cryptoconditions.h" using namespace std; @@ -1295,20 +1295,10 @@ bool TransactionSignatureChecker::CheckSig( } -bool TransactionSignatureChecker::CheckEvalCondition(const CC *cond) const -{ - return EvalConditionValidity(cond, txTo); -} - - -static int komodoCCEval(CC *cond, void *checker) -{ - return ((TransactionSignatureChecker*)checker)->CheckEvalCondition(cond); -} - - bool TransactionSignatureChecker::CheckCryptoCondition(const CC *cond, const std::vector& condBin, const CScript& scriptCode, uint32_t consensusBranchId) const { + if (!IsAcceptableCryptoCondition(cond)) return false; + uint256 sighash; try { sighash = SignatureHash(scriptCode, *txTo, nIn, SIGHASH_ALL, amount, consensusBranchId, this->txdata); @@ -1316,7 +1306,15 @@ bool TransactionSignatureChecker::CheckCryptoCondition(const CC *cond, const std return false; } return cc_verify(cond, (const unsigned char*)&sighash, 32, 0, - condBin.data(), condBin.size(), komodoCCEval, (void*)this); + condBin.data(), condBin.size(), GetCCEval(), (void*)this); +} + + +VerifyEval TransactionSignatureChecker::GetCCEval() const { + return [] (CC *cond, void *checker) { + fprintf(stderr, "Cannot check crypto-condition Eval outside of server\n"); + return 0; + }; } diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 86d792e0a..86ab8dac3 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -8,7 +8,7 @@ #include "script_error.h" #include "primitives/transaction.h" -#include "komodo_cryptoconditions.h" +#include "komodo_cc.h" #include #include @@ -153,7 +153,7 @@ public: bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, uint32_t consensusBranchId) const; bool CheckLockTime(const CScriptNum& nLockTime) const; bool CheckCryptoCondition(const CC *cond, const std::vector& condBin, const CScript& scriptCode, uint32_t consensusBranchId) const; - bool CheckEvalCondition(const CC *cond) const; + VerifyEval GetCCEval() const; }; class MutableTransactionSignatureChecker : public TransactionSignatureChecker diff --git a/src/script/script.cpp b/src/script/script.cpp index a4446a0df..d885146a2 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -7,6 +7,8 @@ #include "tinyformat.h" #include "utilstrencodings.h" +#include "komodo_cc.h" +#include "cryptoconditions/include/cryptoconditions.h" namespace { inline std::string ValueString(const std::vector& vch) @@ -238,6 +240,20 @@ bool CScript::IsPayToCryptoCondition() const return 0; } +bool CScript::MayAcceptCryptoCondition() const +{ + // Get the type mask of the condition + const_iterator pc = this->begin(); + vector data; + opcodetype opcode; + if (!this->GetOp(pc, opcode, data)) return false; + if (!(opcode > OP_0 && opcode < OP_PUSHDATA1)) return false; + CC *cond = cc_readConditionBinary(data.data(), data.size()); + if (!cond) return false; + bool accept = IsAcceptableCryptoCondition(cond); + return accept; +} + bool CScript::IsPushOnly() const { const_iterator pc = begin(); diff --git a/src/script/script.h b/src/script/script.h index 800289a15..b7442a419 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -565,6 +565,7 @@ public: bool IsPayToScriptHash() const; bool IsPayToCryptoCondition() const; + bool MayAcceptCryptoCondition() const; /** Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). */ bool IsPushOnly() const; diff --git a/src/script/sigcache.cpp b/src/script/serverchecker.cpp similarity index 65% rename from src/script/sigcache.cpp rename to src/script/serverchecker.cpp index 35b9f0e03..852895305 100644 --- a/src/script/sigcache.cpp +++ b/src/script/serverchecker.cpp @@ -3,7 +3,9 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include "sigcache.h" +#include "serverchecker.h" +#include "komodo_cc.h" +#include "cc/eval.h" #include "pubkey.h" #include "random.h" @@ -26,13 +28,13 @@ private: //! sigdata_type is (signature hash, signature, public key): typedef boost::tuple, CPubKey> sigdata_type; std::set< sigdata_type> setValid; - boost::shared_mutex cs_sigcache; + boost::shared_mutex cs_serverchecker; public: bool Get(const uint256 &hash, const std::vector& vchSig, const CPubKey& pubKey) { - boost::shared_lock lock(cs_sigcache); + boost::shared_lock lock(cs_serverchecker); sigdata_type k(hash, vchSig, pubKey); std::set::iterator mi = setValid.find(k); @@ -47,10 +49,10 @@ public: // (~200 bytes per cache entry times 50,000 entries) // Since there can be no more than 20,000 signature operations per block // 50,000 is a reasonable default. - int64_t nMaxCacheSize = GetArg("-maxsigcachesize", 50000); + int64_t nMaxCacheSize = GetArg("-maxservercheckersize", 50000); if (nMaxCacheSize <= 0) return; - boost::unique_lock lock(cs_sigcache); + boost::unique_lock lock(cs_serverchecker); while (static_cast(setValid.size()) > nMaxCacheSize) { @@ -74,7 +76,7 @@ public: } -bool CachingTransactionSignatureChecker::VerifySignature(const std::vector& vchSig, const CPubKey& pubkey, const uint256& sighash) const +bool ServerTransactionSignatureChecker::VerifySignature(const std::vector& vchSig, const CPubKey& pubkey, const uint256& sighash) const { static CSignatureCache signatureCache; @@ -88,3 +90,24 @@ bool CachingTransactionSignatureChecker::VerifySignature(const std::vectorCheckEvalCondition(cond); + }; +} + +int ServerTransactionSignatureChecker::CheckEvalCondition(CC *cond) const +{ + return EvalConditionValidity(cond, txTo, nIn); +} diff --git a/src/script/serverchecker.h b/src/script/serverchecker.h new file mode 100644 index 000000000..c680da7ce --- /dev/null +++ b/src/script/serverchecker.h @@ -0,0 +1,30 @@ +// Copyright (c) 2009-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. + +#ifndef BITCOIN_SCRIPT_SERVERCHECKER_H +#define BITCOIN_SCRIPT_SERVERCHECKER_H + +#include "script/interpreter.h" + +#include + +class CPubKey; + +class ServerTransactionSignatureChecker : public TransactionSignatureChecker +{ +private: + bool store; + const CTransaction* txTo; + unsigned int nIn; + +public: + ServerTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amount, bool storeIn, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nInIn, amount, txdataIn), store(storeIn) {} + + bool VerifySignature(const std::vector& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const; + int CheckEvalCondition(CC *cond) const; + VerifyEval GetCCEval() const; +}; + +#endif // BITCOIN_SCRIPT_SERVERCHECKER_H diff --git a/src/script/sigcache.h b/src/script/sigcache.h deleted file mode 100644 index 134b72a2d..000000000 --- a/src/script/sigcache.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2009-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. - -#ifndef BITCOIN_SCRIPT_SIGCACHE_H -#define BITCOIN_SCRIPT_SIGCACHE_H - -#include "script/interpreter.h" - -#include - -class CPubKey; - -class CachingTransactionSignatureChecker : public TransactionSignatureChecker -{ -private: - bool store; - -public: - CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amount, bool storeIn, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nInIn, amount, txdataIn), store(storeIn) {} - - bool VerifySignature(const std::vector& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const; -}; - -#endif // BITCOIN_SCRIPT_SIGCACHE_H diff --git a/src/script/standard.cpp b/src/script/standard.cpp index 60f059ac3..ee96581fe 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -9,7 +9,7 @@ #include "script/script.h" #include "util.h" #include "utilstrencodings.h" -#include "komodo_cryptoconditions.h" +#include "komodo_cc.h" #include @@ -72,9 +72,11 @@ bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector Date: Fri, 30 Mar 2018 17:20:02 -0300 Subject: [PATCH 053/339] mock up DisputePayout --- src/Makefile.am | 1 + src/cc/disputepayout.cpp | 102 +++++++++++++++++++++++++++++++++++++++ src/cc/eval.cpp | 33 +++++++++++++ src/cc/eval.h | 31 ++++++++++++ src/cc/importpayout.cpp | 44 +++++------------ 5 files changed, 179 insertions(+), 32 deletions(-) create mode 100644 src/cc/disputepayout.cpp diff --git a/src/Makefile.am b/src/Makefile.am index affa61fc6..5bbd26d33 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -252,6 +252,7 @@ libbitcoin_server_a_SOURCES = \ bloom.cpp \ cc/eval.cpp \ cc/importpayout.cpp \ + cc/disputepayout.cpp \ chain.cpp \ checkpoints.cpp \ deprecation.cpp \ diff --git a/src/cc/disputepayout.cpp b/src/cc/disputepayout.cpp new file mode 100644 index 000000000..36a5e1723 --- /dev/null +++ b/src/cc/disputepayout.cpp @@ -0,0 +1,102 @@ +#include "primitives/transaction.h" +#include "streams.h" +#include "chain.h" +#include "main.h" +#include "cc/eval.h" +#include "cryptoconditions/include/cryptoconditions.h" + + +bool GetSpends(uint256 hash, std::vector> &spends) +{ + // NOT IMPLEMENTED + return false; +} + + +class DisputeHeader +{ +public: + int waitBlocks; + std::vector vmHeader; + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(VARINT(waitBlocks)); + READWRITE(vmHeader); + } +}; + + +/* + * Crypto-Condition EVAL method that resolves a dispute of a session + * + * IN: vm - AppVM virtual machine to verify states + * IN: cond - CC EVAL node + * IN: disputeTx - transaction attempting to resolve dispute + * IN: nIn - index of input of dispute tx + * + * disputeTx: attempt to resolve a dispute + * + * in 0: Spends Session TX first output, reveals DisputeHeader + * out 0: OP_RETURN hash of payouts + */ +bool DisputePayout(AppVM &vm, const CC *cond, const CTransaction *disputeTx, int nIn) +{ + // TODO: Error messages! + if (disputeTx->vout.size() < 2) return 0; + + // get payouts hash + std::vector vPayoutHash; + uint256 payoutHash; + if (!GetOpReturnData(disputeTx->vout[0].scriptPubKey, vPayoutHash)) return 0; + memcpy(payoutHash.begin(), vPayoutHash.data(), 32); + + // load dispute header + DisputeHeader disputeHeader; + std::vector headerData(cond->paramsBin, + cond->paramsBin+cond->paramsBinLength); + CDataStream(headerData, SER_DISK, PROTOCOL_VERSION) >> disputeHeader; + // TODO: exception? end of stream? + + // ensure that enough time has passed + CTransaction sessionTx; + uint256 sessionBlockHash; + if (!GetTransaction(disputeTx->vin[0].prevout.hash, sessionTx, sessionBlockHash, false)) + return false; // wth? TODO: log TODO: MUST be upsteam of disputeTx, how to ensure? + // below does this by looking up block in blockindex + // what if GetTransaction returns from mempool, maybe theres no block? + CBlockIndex* sessionBlockIndex = mapBlockIndex[sessionBlockHash]; + if (chainActive.Height() < sessionBlockIndex->nHeight + disputeHeader.waitBlocks) + return false; // Not yet + + // get spends + std::vector> spends; + if (!GetSpends(disputeTx->vin[0].prevout.hash, spends)) return 0; + + // verify result from VM + int maxLength = -1; + uint256 bestPayout; + for (int i=1; i vmBody; + if (!GetOpReturnData(spends[i]->vout[0].scriptPubKey, vmBody)) continue; + auto out = vm.evaluate(disputeHeader.vmHeader, vmBody); + uint256 resultHash = SerializeHash(out.second); + if (out.first > maxLength) { + maxLength = out.first; + bestPayout = resultHash; + } + // The below means that if for any reason there is a draw, + else if (out.first == maxLength) { + if (bestPayout != payoutHash) { + fprintf(stderr, "WARNING: VM has multiple solutions of same length\n"); + bestPayout = resultHash; + } + } + } + + return bestPayout == payoutHash; +} diff --git a/src/cc/eval.cpp b/src/cc/eval.cpp index 0291d1e3f..2615d1e4e 100644 --- a/src/cc/eval.cpp +++ b/src/cc/eval.cpp @@ -18,6 +18,39 @@ bool EvalConditionValidity(const CC *cond, const CTransaction *txTo, int nIn) return CheckImportPayout(cond, txTo, nIn); } + /* Example of how you might call DisputePayout + + if (strcmp(ASSETCHAINS_SYMBOL, "PANGEA") == 0) { + if (strcmp(cond->method, "DisputePoker") == 0) { + return DisputePayout(PokerVM(), cond, txTo, nIn); + } + } + + */ + fprintf(stderr, "no defined behaviour for method: %s\n", cond->method); return 0; } + + + +bool GetPushData(const CScript &sig, std::vector &data) +{ + opcodetype opcode; + auto pc = sig.begin(); + if (sig.GetOp(pc, opcode, data)) return opcode > OP_0 && opcode <= OP_PUSHDATA4; + return false; +} + + +bool GetOpReturnData(const CScript &sig, std::vector &data) +{ + auto pc = sig.begin(); + opcodetype opcode; + if (sig.GetOp2(pc, opcode, NULL)) + if (opcode == OP_RETURN) + if (sig.GetOp(pc, opcode, data)) + return opcode > OP_0 && opcode <= OP_PUSHDATA4; + return false; +} + diff --git a/src/cc/eval.h b/src/cc/eval.h index 8aa797f99..aadb2e85f 100644 --- a/src/cc/eval.h +++ b/src/cc/eval.h @@ -14,5 +14,36 @@ bool EvalConditionValidity(const CC *cond, const CTransaction *tx, int nIn); */ bool CheckImportPayout(const CC *cond, const CTransaction *payoutTx, int nIn); +/* + * Virtual machine to use in the case of on-chain app evaluation + */ +class AppVM +{ +public: + /* + * in: header - paramters agreed upon by all players + * in: body - gamestate + * out: length - length of game (longest wins) + * out: payments - vector of CTxOut, always deterministically sorted. + */ + virtual std::pair> + evaluate(std::vector header, std::vector body) = 0; +}; + +/* + * Test a DisputePayout CC Eval condition, using a provided AppVM + */ +bool DisputePayout(AppVM &vm, const CC *cond, const CTransaction *disputeTx, int nIn); + +/* + * Get PUSHDATA from a script + */ +bool GetPushData(const CScript &sig, std::vector &data); + +/* + * Get OP_RETURN data from a script + */ +bool GetOpReturnData(const CScript &sig, std::vector &data); + #endif /* CC_EVAL_H */ diff --git a/src/cc/importpayout.cpp b/src/cc/importpayout.cpp index d0a8c2fb0..ee8913744 100644 --- a/src/cc/importpayout.cpp +++ b/src/cc/importpayout.cpp @@ -2,30 +2,10 @@ #include "streams.h" #include "chain.h" #include "main.h" +#include "cc/eval.h" #include "cryptoconditions/include/cryptoconditions.h" -bool GetPushData(const CScript &sig, std::vector &data) -{ - opcodetype opcode; - auto pc = sig.begin(); - if (sig.GetOp(pc, opcode, data)) return opcode > OP_0 && opcode <= OP_PUSHDATA4; - return false; -} - - -bool GetOpReturnData(const CScript &sig, std::vector &data) -{ - auto pc = sig.begin(); - opcodetype opcode; - if (sig.GetOp2(pc, opcode, NULL)) - if (opcode == OP_RETURN) - if (sig.GetOp(pc, opcode, data)) - return opcode > OP_0 && opcode <= OP_PUSHDATA4; - return false; -} - - class MomProof { public: @@ -128,10 +108,10 @@ uint256 ExecMerkle(uint256 hash, const std::vector& vMerkleBranch, int * * in 0: Spends Stake TX and contains ImportPayout CC * out 0: OP_RETURN MomProof - * out 1: OP_RETURN serialized exportTx from other chain + * out 1: OP_RETURN serialized disputeTx from other chain * out 2-: arbitrary payouts * - * exportTx: Spends sessionTx.0 (opener on asset chain) + * disputeTx: Spends sessionTx.0 (opener on asset chain) * * in 0: spends sessionTx.0 * in 1-: anything @@ -149,30 +129,30 @@ bool CheckImportPayout(const CC *cond, const CTransaction *payoutTx, int nIn) uint256 payoutsHash = SerializeHash(payouts); std::vector vPayoutsHash(payoutsHash.begin(), payoutsHash.end()); - // load exportTx from vout[1] - CTransaction exportTx; + // load disputeTx from vout[1] + CTransaction disputeTx; { std::vector exportData; if (!GetOpReturnData(payoutTx->vout[1].scriptPubKey, exportData)) return 0; - CDataStream(exportData, SER_DISK, PROTOCOL_VERSION) >> exportTx; + CDataStream(exportData, SER_DISK, PROTOCOL_VERSION) >> disputeTx; // TODO: end of stream? exception? } - // Check exportTx.0 is vPayoutsHash + // Check disputeTx.0 is vPayoutsHash std::vector exportPayoutsHash; - if (!GetOpReturnData(exportTx.vout[0].scriptPubKey, exportPayoutsHash)) return 0; + if (!GetOpReturnData(disputeTx.vout[0].scriptPubKey, exportPayoutsHash)) return 0; if (exportPayoutsHash != vPayoutsHash) return 0; - // Check exportTx spends sessionTx.0 + // Check disputeTx spends sessionTx.0 // condition ImportPayout params is session ID from other chain { if (cond->paramsBinLength != 32) return 0; - COutPoint prevout = exportTx.vin[0].prevout; + COutPoint prevout = disputeTx.vin[0].prevout; if (memcmp(prevout.hash.begin(), cond->paramsBin, 32) != 0 || prevout.n != 0) return 0; } - // Check exportTx solves momproof from vout[0] + // Check disputeTx solves momproof from vout[0] { std::vector vchMomProof; if (!GetOpReturnData(payoutTx->vout[0].scriptPubKey, vchMomProof)) return 0; @@ -183,7 +163,7 @@ bool CheckImportPayout(const CC *cond, const CTransaction *payoutTx, int nIn) uint256 mom; if (!GetMoM(momProof.notaryHash, mom)) return 0; - uint256 proofResult = ExecMerkle(exportTx.GetHash(), momProof.branch, momProof.nPos); + uint256 proofResult = ExecMerkle(disputeTx.GetHash(), momProof.branch, momProof.nPos); if (proofResult != mom) return 0; } From 563581aff4f1ec94465fb9fcb2ee2f7f6d09d14d Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Sat, 31 Mar 2018 23:20:03 -0300 Subject: [PATCH 054/339] many changes: * fix CC malleability * extra validations for CCs such as requiring a signature and limiting types * different SIGHASH types for CC --- src/Makefile.am | 1 + src/Makefile.zcash.include | 1 + src/cryptoconditions/Makefile.am | 1 + .../include/cryptoconditions.h | 16 +++- src/cryptoconditions/src/anon.c | 15 ++-- src/cryptoconditions/src/cryptoconditions.c | 74 ++++++++++++------- src/cryptoconditions/src/ed25519.c | 3 +- src/cryptoconditions/src/eval.c | 3 +- src/cryptoconditions/src/internal.h | 5 +- src/cryptoconditions/src/prefix.c | 5 +- src/cryptoconditions/src/preimage.c | 3 +- src/cryptoconditions/src/secp256k1.c | 3 +- src/cryptoconditions/src/threshold.c | 51 +++++++++---- src/cryptoconditions/src/utils.c | 1 + .../tests/test_failure_modes.py | 13 +++- src/komodo_cc.cpp | 44 +++++++++++ src/komodo_cc.h | 29 ++------ src/script/interpreter.cpp | 45 ++++++----- src/script/interpreter.h | 12 ++- src/script/script.cpp | 5 +- src/zcash/CreateJoinSplit.cpp | 1 + 21 files changed, 215 insertions(+), 116 deletions(-) create mode 100644 src/komodo_cc.cpp diff --git a/src/Makefile.am b/src/Makefile.am index 5bbd26d33..7c64dcfd9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -381,6 +381,7 @@ libbitcoin_common_a_SOURCES = \ hash.cpp \ key.cpp \ keystore.cpp \ + komodo_cc.cpp \ netbase.cpp \ primitives/block.cpp \ primitives/transaction.cpp \ diff --git a/src/Makefile.zcash.include b/src/Makefile.zcash.include index e6730623a..da5b4344d 100644 --- a/src/Makefile.zcash.include +++ b/src/Makefile.zcash.include @@ -28,3 +28,4 @@ zcash_CreateJoinSplit_LDADD = \ $(LIBZCASH_LIBS) \ $(LIBCRYPTOCONDITIONS) \ $(LIBSECP256K1) + diff --git a/src/cryptoconditions/Makefile.am b/src/cryptoconditions/Makefile.am index eed285064..3b482b9c7 100644 --- a/src/cryptoconditions/Makefile.am +++ b/src/cryptoconditions/Makefile.am @@ -21,6 +21,7 @@ CRYPTOCONDITIONS_CORE=libcryptoconditions_core.la libcryptoconditions_core_la_SOURCES = \ src/cryptoconditions.c \ + src/utils.c \ src/include/cJSON.c \ src/include/sha256.c \ src/include/ed25519/src/keypair.c \ diff --git a/src/cryptoconditions/include/cryptoconditions.h b/src/cryptoconditions/include/cryptoconditions.h index 88a3a6560..64cd1db70 100644 --- a/src/cryptoconditions/include/cryptoconditions.h +++ b/src/cryptoconditions/include/cryptoconditions.h @@ -16,6 +16,7 @@ struct CCType; enum CCTypeId { + CC_Condition = -1, CC_Preimage = 0, CC_Prefix = 1, CC_Threshold = 2, @@ -31,19 +32,27 @@ enum CCTypeId { typedef int (*VerifyEval)(struct CC *cond, void *context); + /* * Crypto Condition */ typedef struct CC { struct CCType *type; union { + // public key types struct { unsigned char *publicKey, *signature; }; + // preimage struct { unsigned char *preimage; size_t preimageLength; }; + // threshold struct { long threshold; int size; struct CC **subconditions; }; + // prefix struct { unsigned char *prefix; size_t prefixLength; struct CC *subcondition; unsigned long maxMessageLength; }; + // eval struct { char method[64]; unsigned char *paramsBin; size_t paramsBinLength; }; - struct { unsigned char fingerprint[32]; uint32_t subtypes; unsigned long cost; }; + // anon + struct { unsigned char fingerprint[32]; uint32_t subtypes; unsigned long cost; + struct CCType *conditionType; }; }; } CC; @@ -76,14 +85,15 @@ size_t cc_fulfillmentBinary(const CC *cond, unsigned char *buf, size_t static int cc_secp256k1VerifyTreeMsg32(const CC *cond, const unsigned char *msg32); struct CC* cc_conditionFromJSON(cJSON *params, unsigned char *err); struct CC* cc_conditionFromJSONString(const unsigned char *json, unsigned char *err); -struct CC* cc_readConditionBinary(unsigned char *cond_bin, size_t cond_bin_len); -struct CC* cc_readFulfillmentBinary(unsigned char *ffill_bin, size_t ffill_bin_len); +struct CC* cc_readConditionBinary(const unsigned char *cond_bin, size_t cond_bin_len); +struct CC* cc_readFulfillmentBinary(const unsigned char *ffill_bin, size_t ffill_bin_len); struct cJSON* cc_conditionToJSON(const CC *cond); unsigned char* cc_conditionToJSONString(const CC *cond); unsigned char* cc_conditionUri(const CC *cond); unsigned char* cc_jsonRPC(unsigned char *request); unsigned long cc_getCost(const CC *cond); enum CCTypeId cc_typeId(const CC *cond); +char* cc_typeName(const CC *cond); uint32_t cc_typeMask(const CC *cond); void cc_free(struct CC *cond); diff --git a/src/cryptoconditions/src/anon.c b/src/cryptoconditions/src/anon.c index e23fffe3e..0d10e0df0 100644 --- a/src/cryptoconditions/src/anon.c +++ b/src/cryptoconditions/src/anon.c @@ -11,22 +11,19 @@ struct CCType cc_anonType; static CC *mkAnon(const Condition_t *asnCond) { + CCType *realType = getTypeByAsnEnum(asnCond->present); if (!realType) { printf("Unknown ASN type: %i", asnCond->present); return 0; } CC *cond = calloc(1, sizeof(CC)); - cond->type = (CCType*) calloc(1, sizeof(CCType)); - *cond->type = cc_anonType; - strcpy(cond->type->name, realType->name); - cond->type->hasSubtypes = realType->hasSubtypes; - cond->type->typeId = realType->typeId; - cond->type->asnType = realType->asnType; + cond->type = &cc_anonType; + cond->conditionType = realType; const CompoundSha256Condition_t *deets = &asnCond->choice.thresholdSha256; memcpy(cond->fingerprint, deets->fingerprint.buf, 32); cond->cost = deets->cost; - if (realType->hasSubtypes) { + if (realType->getSubtypes) { cond->subtypes = fromAsnSubtypes(deets->subtypes); } return cond; @@ -66,8 +63,6 @@ static Fulfillment_t *anonFulfillment(const CC *cond) { static void anonFree(CC *cond) { - free(cond->type); - free(cond); } @@ -76,4 +71,4 @@ static int anonIsFulfilled(const CC *cond) { } -struct CCType cc_anonType = { -1, "anon (a buffer large enough to accomodate any type name)", Condition_PR_NOTHING, 0, NULL, &anonFingerprint, &anonCost, &anonSubtypes, NULL, &anonToJSON, NULL, &anonFulfillment, &anonIsFulfilled, &anonFree }; +struct CCType cc_anonType = { -1, "(anon)", Condition_PR_NOTHING, NULL, &anonFingerprint, &anonCost, &anonSubtypes, NULL, &anonToJSON, NULL, &anonFulfillment, &anonIsFulfilled, &anonFree }; diff --git a/src/cryptoconditions/src/cryptoconditions.c b/src/cryptoconditions/src/cryptoconditions.c index 805c66236..164d58f9c 100644 --- a/src/cryptoconditions/src/cryptoconditions.c +++ b/src/cryptoconditions/src/cryptoconditions.c @@ -12,7 +12,6 @@ #include "src/anon.c" #include "src/eval.c" #include "src/json_rpc.c" -#include "src/utils.c" #include #include @@ -57,9 +56,9 @@ unsigned char *cc_conditionUri(const CC *cond) { unsigned char *out = calloc(1, 1000); sprintf(out, "ni:///sha-256;%s?fpt=%s&cost=%lu", - encoded, cond->type->name, cc_getCost(cond)); + encoded, cc_typeName(cond), cc_getCost(cond)); - if (cond->type->hasSubtypes) { + if (cond->type->getSubtypes) { appendUriSubtypes(cond->type->getSubtypes(cond), out); } @@ -70,15 +69,6 @@ unsigned char *cc_conditionUri(const CC *cond) { } -uint32_t cc_typeMask(const CC *cond) { - uint32_t mask = 1 << cond->type->typeId; - if (cond->type->hasSubtypes) { - mask |= cond->type->getSubtypes(cond); - } - return mask; -} - - static ConditionTypes_t asnSubtypes(uint32_t mask) { ConditionTypes_t types; uint8_t buf[4] = {0,0,0,0}; @@ -115,7 +105,7 @@ size_t cc_conditionBinary(const CC *cond, unsigned char *buf) { asnCondition(cond, asn); asn_enc_rval_t rc = der_encode_to_buffer(&asn_DEF_Condition, asn, buf, 1000); if (rc.encoded == -1) { - printf("CONDITION NOT ENCODED\n"); + fprintf(stderr, "CONDITION NOT ENCODED\n"); return 0; } ASN_STRUCT_FREE(asn_DEF_Condition, asn); @@ -127,7 +117,7 @@ size_t cc_fulfillmentBinary(const CC *cond, unsigned char *buf, size_t length) { Fulfillment_t *ffill = asnFulfillmentNew(cond); asn_enc_rval_t rc = der_encode_to_buffer(&asn_DEF_Fulfillment, ffill, buf, length); if (rc.encoded == -1) { - printf("FULFILLMENT NOT ENCODED\n"); + fprintf(stderr, "FULFILLMENT NOT ENCODED\n"); return 0; } ASN_STRUCT_FREE(asn_DEF_Fulfillment, ffill); @@ -136,7 +126,7 @@ size_t cc_fulfillmentBinary(const CC *cond, unsigned char *buf, size_t length) { static void asnCondition(const CC *cond, Condition_t *asn) { - asn->present = cond->type->asnType; + asn->present = cc_isAnon(cond) ? cond->conditionType->asnType : cond->type->asnType; // 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 @@ -187,14 +177,28 @@ static CC *fulfillmentToCC(Fulfillment_t *ffill) { } -CC *cc_readFulfillmentBinary(unsigned char *ffill_bin, size_t ffill_bin_len) { - Fulfillment_t *ffill = 0; +CC *cc_readFulfillmentBinary(const unsigned char *ffill_bin, size_t ffill_bin_len) { CC *cond = 0; + unsigned char *buf = malloc(ffill_bin_len); + Fulfillment_t *ffill = 0; asn_dec_rval_t rval = ber_decode(0, &asn_DEF_Fulfillment, (void **)&ffill, ffill_bin, ffill_bin_len); - if (rval.code == RC_OK) { - cond = fulfillmentToCC(ffill); - ASN_STRUCT_FREE(asn_DEF_Fulfillment, ffill); + if (rval.code != RC_OK) { + goto end; } + // Do malleability check + asn_enc_rval_t rc = der_encode_to_buffer(&asn_DEF_Fulfillment, ffill, buf, ffill_bin_len); + if (rc.encoded == -1) { + fprintf(stderr, "FULFILLMENT NOT ENCODED\n"); + goto end; + } + if (rc.encoded != ffill_bin_len || 0 != memcmp(ffill_bin, buf, rc.encoded)) { + goto end; + } + + cond = fulfillmentToCC(ffill); +end: + free(buf); + if (ffill) ASN_STRUCT_FREE(asn_DEF_Fulfillment, ffill); return cond; } @@ -224,6 +228,7 @@ int cc_verify(const struct CC *cond, const unsigned char *msg, size_t msgLength, unsigned char msgHash[32]; if (doHashMsg) sha256(msg, msgLength, msgHash); else memcpy(msgHash, msg, 32); + if (!cc_secp256k1VerifyTreeMsg32(cond, msgHash)) { return 0; } @@ -235,7 +240,7 @@ int cc_verify(const struct CC *cond, const unsigned char *msg, size_t msgLength, } -CC *cc_readConditionBinary(unsigned char *cond_bin, size_t length) { +CC *cc_readConditionBinary(const unsigned char *cond_bin, size_t length) { Condition_t *asnCond = 0; asn_dec_rval_t rval; rval = ber_decode(0, &asn_DEF_Condition, (void **)&asnCond, cond_bin, length); @@ -249,8 +254,21 @@ CC *cc_readConditionBinary(unsigned char *cond_bin, size_t length) { } +int cc_isAnon(const CC *cond) { + return cond->type->typeId == CC_Condition; +} + + enum CCTypeId cc_typeId(const CC *cond) { - return cond->type->typeId; + return cc_isAnon(cond) ? cond->conditionType->typeId : cond->type->typeId; +} + + +uint32_t cc_typeMask(const CC *cond) { + uint32_t mask = 1 << cc_typeId(cond); + if (cond->type->getSubtypes) + mask |= cond->type->getSubtypes(cond); + return mask; } @@ -259,9 +277,15 @@ int cc_isFulfilled(const CC *cond) { } -void cc_free(CC *cond) { - if (cond) - cond->type->free(cond); +char *cc_typeName(const CC *cond) { + return cc_isAnon(cond) ? cond->conditionType->name : cond->type->name; +} + + +void cc_free(CC *cond) { + if (cond) + cond->type->free(cond); + free(cond); } diff --git a/src/cryptoconditions/src/ed25519.c b/src/cryptoconditions/src/ed25519.c index 85655c2dc..b835cefc0 100644 --- a/src/cryptoconditions/src/ed25519.c +++ b/src/cryptoconditions/src/ed25519.c @@ -158,7 +158,6 @@ static void ed25519Free(CC *cond) { if (cond->signature) { free(cond->signature); } - free(cond); } @@ -167,4 +166,4 @@ static uint32_t ed25519Subtypes(const CC *cond) { } -struct CCType cc_ed25519Type = { 4, "ed25519-sha-256", Condition_PR_ed25519Sha256, 0, 0, &ed25519Fingerprint, &ed25519Cost, &ed25519Subtypes, &ed25519FromJSON, &ed25519ToJSON, &ed25519FromFulfillment, &ed25519ToFulfillment, &ed25519IsFulfilled, &ed25519Free }; +struct CCType cc_ed25519Type = { 4, "ed25519-sha-256", Condition_PR_ed25519Sha256, 0, &ed25519Fingerprint, &ed25519Cost, &ed25519Subtypes, &ed25519FromJSON, &ed25519ToJSON, &ed25519FromFulfillment, &ed25519ToFulfillment, &ed25519IsFulfilled, &ed25519Free }; diff --git a/src/cryptoconditions/src/eval.c b/src/cryptoconditions/src/eval.c index 976af32d7..13388b117 100644 --- a/src/cryptoconditions/src/eval.c +++ b/src/cryptoconditions/src/eval.c @@ -98,7 +98,6 @@ int evalIsFulfilled(const CC *cond) { static void evalFree(CC *cond) { free(cond->paramsBin); - free(cond); } @@ -139,4 +138,4 @@ int cc_verifyEval(const CC *cond, VerifyEval verify, void *context) { } -struct CCType cc_evalType = { 15, "eval-sha-256", Condition_PR_evalSha256, 0, 0, &evalFingerprint, &evalCost, &evalSubtypes, &evalFromJSON, &evalToJSON, &evalFromFulfillment, &evalToFulfillment, &evalIsFulfilled, &evalFree }; +struct CCType cc_evalType = { 15, "eval-sha-256", Condition_PR_evalSha256, 0, &evalFingerprint, &evalCost, &evalSubtypes, &evalFromJSON, &evalToJSON, &evalFromFulfillment, &evalToFulfillment, &evalIsFulfilled, &evalFree }; diff --git a/src/cryptoconditions/src/internal.h b/src/cryptoconditions/src/internal.h index bfcc6bd14..28b3661f4 100644 --- a/src/cryptoconditions/src/internal.h +++ b/src/cryptoconditions/src/internal.h @@ -1,3 +1,5 @@ +#include +#include #include "include/cJSON.h" #include "asn/asn_application.h" #include "cryptoconditions.h" @@ -17,10 +19,9 @@ extern "C" { /* * Condition Type */ typedef struct CCType { - uint8_t typeId; + int typeId; unsigned char name[100]; Condition_PR asnType; - int hasSubtypes; int (*visitChildren)(CC *cond, CCVisitor visitor); unsigned char *(*fingerprint)(const CC *cond); unsigned long (*getCost)(const CC *cond); diff --git a/src/cryptoconditions/src/prefix.c b/src/cryptoconditions/src/prefix.c index 527115709..423ee3ecf 100644 --- a/src/cryptoconditions/src/prefix.c +++ b/src/cryptoconditions/src/prefix.c @@ -71,7 +71,7 @@ static Fulfillment_t *prefixToFulfillment(const CC *cond) { static uint32_t prefixSubtypes(const CC *cond) { - return cc_typeMask(cond->subcondition) & ~(1 << cc_prefixType.typeId); + return cc_typeMask(cond->subcondition) & ~(1 << CC_Prefix); } @@ -119,8 +119,7 @@ int prefixIsFulfilled(const CC *cond) { static void prefixFree(CC *cond) { free(cond->prefix); cc_free(cond->subcondition); - free(cond); } -struct CCType cc_prefixType = { 1, "prefix-sha-256", Condition_PR_prefixSha256, 1, &prefixVisitChildren, &prefixFingerprint, &prefixCost, &prefixSubtypes, &prefixFromJSON, &prefixToJSON, &prefixFromFulfillment, &prefixToFulfillment, &prefixIsFulfilled, &prefixFree }; +struct CCType cc_prefixType = { 1, "prefix-sha-256", Condition_PR_prefixSha256, &prefixVisitChildren, &prefixFingerprint, &prefixCost, &prefixSubtypes, &prefixFromJSON, &prefixToJSON, &prefixFromFulfillment, &prefixToFulfillment, &prefixIsFulfilled, &prefixFree }; diff --git a/src/cryptoconditions/src/preimage.c b/src/cryptoconditions/src/preimage.c index 71d3b2e89..95f19c09d 100644 --- a/src/cryptoconditions/src/preimage.c +++ b/src/cryptoconditions/src/preimage.c @@ -71,7 +71,6 @@ int preimageIsFulfilled(const CC *cond) { static void preimageFree(CC *cond) { free(cond->preimage); - free(cond); } @@ -80,4 +79,4 @@ static uint32_t preimageSubtypes(const CC *cond) { } -struct CCType cc_preimageType = { 0, "preimage-sha-256", Condition_PR_preimageSha256, 0, 0, &preimageFingerprint, &preimageCost, &preimageSubtypes, &preimageFromJSON, &preimageToJSON, &preimageFromFulfillment, &preimageToFulfillment, &preimageIsFulfilled, &preimageFree }; +struct CCType cc_preimageType = { 0, "preimage-sha-256", Condition_PR_preimageSha256, 0, &preimageFingerprint, &preimageCost, &preimageSubtypes, &preimageFromJSON, &preimageToJSON, &preimageFromFulfillment, &preimageToFulfillment, &preimageIsFulfilled, &preimageFree }; diff --git a/src/cryptoconditions/src/secp256k1.c b/src/cryptoconditions/src/secp256k1.c index be8fbd761..cfaf7c3de 100644 --- a/src/cryptoconditions/src/secp256k1.c +++ b/src/cryptoconditions/src/secp256k1.c @@ -270,7 +270,6 @@ static void secp256k1Free(CC *cond) { if (cond->signature) { free(cond->signature); } - free(cond); } @@ -279,4 +278,4 @@ static uint32_t secp256k1Subtypes(const CC *cond) { } -struct CCType cc_secp256k1Type = { 5, "secp256k1-sha-256", Condition_PR_secp256k1Sha256, 0, 0, &secp256k1Fingerprint, &secp256k1Cost, &secp256k1Subtypes, &secp256k1FromJSON, &secp256k1ToJSON, &secp256k1FromFulfillment, &secp256k1ToFulfillment, &secp256k1IsFulfilled, &secp256k1Free }; +struct CCType cc_secp256k1Type = { 5, "secp256k1-sha-256", Condition_PR_secp256k1Sha256, 0, &secp256k1Fingerprint, &secp256k1Cost, &secp256k1Subtypes, &secp256k1FromJSON, &secp256k1ToJSON, &secp256k1FromFulfillment, &secp256k1ToFulfillment, &secp256k1IsFulfilled, &secp256k1Free }; diff --git a/src/cryptoconditions/src/threshold.c b/src/cryptoconditions/src/threshold.c index d3f4d3e63..d79c01813 100644 --- a/src/cryptoconditions/src/threshold.c +++ b/src/cryptoconditions/src/threshold.c @@ -16,7 +16,7 @@ static uint32_t thresholdSubtypes(const CC *cond) { for (int i=0; isize; i++) { mask |= cc_typeMask(cond->subconditions[i]); } - mask &= ~(1 << cc_thresholdType.typeId); + mask &= ~(1 << CC_Threshold); return mask; } @@ -53,13 +53,19 @@ static int thresholdVisitChildren(CC *cond, CCVisitor visitor) { } -static int cmpConditions(const void *a, const void *b) { +static int cmpConditionBin(const void *a, const void *b) { /* Compare conditions by their ASN binary representation */ unsigned char bufa[BUF_SIZE], bufb[BUF_SIZE]; asn_enc_rval_t r0 = der_encode_to_buffer(&asn_DEF_Condition, *(Condition_t**)a, bufa, BUF_SIZE); asn_enc_rval_t r1 = der_encode_to_buffer(&asn_DEF_Condition, *(Condition_t**)b, bufb, BUF_SIZE); - int diff = r0.encoded - r1.encoded; - return diff != 0 ? diff : strcmp(bufa, bufb); + + // below copied from ASN lib + size_t commonLen = r0.encoded < r1.encoded ? r0.encoded : r1.encoded; + int ret = memcmp(bufa, bufb, commonLen); + + if (ret == 0) + return r0.encoded < r1.encoded ? -1 : 1; + return 0; } @@ -68,13 +74,32 @@ static unsigned char *thresholdFingerprint(const CC *cond) { ThresholdFingerprintContents_t *fp = calloc(1, sizeof(ThresholdFingerprintContents_t)); fp->threshold = cond->threshold; for (int i=0; isize; i++) { - asn_set_add(&fp->subconditions2, asnConditionNew(cond->subconditions[i])); + Condition_t *asnCond = asnConditionNew(cond->subconditions[i]); + asn_set_add(&fp->subconditions2, asnCond); } - qsort(fp->subconditions2.list.array, cond->size, sizeof(Condition_t*), cmpConditions); + qsort(fp->subconditions2.list.array, cond->size, sizeof(Condition_t*), cmpConditionBin); return hashFingerprintContents(&asn_DEF_ThresholdFingerprintContents, fp); } +static int cmpConditionCost(const void *a, const void *b) { + CC *ca = *((CC**)a); + CC *cb = *((CC**)b); + + int out = cc_getCost(ca) - cc_getCost(cb); + if (out != 0) return out; + + // Do an additional sort to establish consistent order + // between conditions with the same cost. + Condition_t *asna = asnConditionNew(ca); + Condition_t *asnb = asnConditionNew(cb); + out = cmpConditionBin(&asna, &asnb); + ASN_STRUCT_FREE(asn_DEF_Condition, asna); + ASN_STRUCT_FREE(asn_DEF_Condition, asnb); + return out; +} + + static CC *thresholdFromFulfillment(const Fulfillment_t *ffill) { ThresholdFulfillment_t *t = ffill->choice.thresholdSha256; int threshold = t->subfulfillments.list.count; @@ -83,7 +108,7 @@ static CC *thresholdFromFulfillment(const Fulfillment_t *ffill) { CC **subconditions = calloc(size, sizeof(CC*)); for (int i=0; isubfulfillments.list.array[i]) : mkAnon(t->subconditions.list.array[i-threshold]); @@ -103,16 +128,11 @@ static CC *thresholdFromFulfillment(const Fulfillment_t *ffill) { } -static int cmpByCostDesc(const void *c1, const void *c2) { - return cc_getCost(*((CC**)c1)) - cc_getCost(*((CC**)c2)); -} - - static Fulfillment_t *thresholdToFulfillment(const CC *cond) { CC *sub; Fulfillment_t *fulfillment; - qsort(cond->subconditions, cond->size, sizeof(CC*), cmpByCostDesc); + qsort(cond->subconditions, cond->size, sizeof(CC*), cmpConditionCost); ThresholdFulfillment_t *tf = calloc(1, sizeof(ThresholdFulfillment_t)); @@ -124,7 +144,7 @@ static Fulfillment_t *thresholdToFulfillment(const CC *cond) { asn_set_add(&tf->subfulfillments, fulfillment); needed--; } else { - asn_set_add(&tf->subconditions, asnConditionNew(cond->subconditions[i])); + asn_set_add(&tf->subconditions, asnConditionNew(sub)); } } @@ -199,8 +219,7 @@ static void thresholdFree(CC *cond) { cc_free(cond->subconditions[i]); } free(cond->subconditions); - free(cond); } -struct CCType cc_thresholdType = { 2, "threshold-sha-256", Condition_PR_thresholdSha256, 1, &thresholdVisitChildren, &thresholdFingerprint, &thresholdCost, &thresholdSubtypes, &thresholdFromJSON, &thresholdToJSON, &thresholdFromFulfillment, &thresholdToFulfillment, &thresholdIsFulfilled, &thresholdFree }; +struct CCType cc_thresholdType = { 2, "threshold-sha-256", Condition_PR_thresholdSha256, &thresholdVisitChildren, &thresholdFingerprint, &thresholdCost, &thresholdSubtypes, &thresholdFromJSON, &thresholdToJSON, &thresholdFromFulfillment, &thresholdToFulfillment, &thresholdIsFulfilled, &thresholdFree }; diff --git a/src/cryptoconditions/src/utils.c b/src/cryptoconditions/src/utils.c index d1e63629f..69db32042 100644 --- a/src/cryptoconditions/src/utils.c +++ b/src/cryptoconditions/src/utils.c @@ -187,6 +187,7 @@ int jsonGetBase64Optional(const cJSON *params, unsigned char *key, unsigned char return checkDecodeBase64(item, key, err, data, size); } + void jsonAddBase64(cJSON *params, unsigned char *key, unsigned char *bin, size_t size) { unsigned char *b64 = base64_encode(bin, size); cJSON_AddItemToObject(params, key, cJSON_CreateString(b64)); diff --git a/src/cryptoconditions/tests/test_failure_modes.py b/src/cryptoconditions/tests/test_failure_modes.py index 839eded3b..52ab3bdb9 100644 --- a/src/cryptoconditions/tests/test_failure_modes.py +++ b/src/cryptoconditions/tests/test_failure_modes.py @@ -1,7 +1,7 @@ import json import ctypes import base64 -from .test_vectors import jsonRPC, so, decode_base64 as d64 +from .test_vectors import jsonRPC, so, decode_base64 as d64, encode_base64 as e64 ''' @@ -10,7 +10,6 @@ These tests are aimed at edge cases of serverside deployment. As such, the main functions to test are decoding and verifying fulfillment payloads. ''' - cc_rfb = lambda f: so.cc_readFulfillmentBinary(f, len(f)) cc_rcb = lambda f: so.cc_readConditionBinary(f, len(f)) @@ -44,7 +43,7 @@ def test_large_fulfillment(): def test_decode_valid_condition(): # Valid preimage - assert cc_rcb(d64('oCWAIMqXgRLKG73K-sIxs5oj3E2nhu_4FHxOcrmAd4Wv7ki7gQEB')) + assert cc_rcb(d64(b'oCWAIMqXgRLKG73K-sIxs5oj3E2nhu_4FHxOcrmAd4Wv7ki7gQEB')) # Somewhat bogus condition (prefix with no subtypes) but nonetheless valid structure assert cc_rcb(unhex("a10a8001618101ff82020700")) @@ -76,3 +75,11 @@ def test_non_canonical_secp256k1(): 'message': '' }) assert res['valid'] == False + + +def test_malleability_checked(): + assert cc_rfb(b'\xa2\x13\xa0\x0f\xa0\x05\x80\x03abc\xa0\x06\x80\x04abcd\xa1\x00') + assert not cc_rfb(b'\xa2\x13\xa0\x0f\xa0\x06\x80\x04abcd\xa0\x05\x80\x03abc\xa1\x00') + + +so.cc_conditionUri.restype = ctypes.c_char_p diff --git a/src/komodo_cc.cpp b/src/komodo_cc.cpp new file mode 100644 index 000000000..1b05ea070 --- /dev/null +++ b/src/komodo_cc.cpp @@ -0,0 +1,44 @@ +#include "cryptoconditions/include/cryptoconditions.h" +#include "komodo_cc.h" + + +bool IsCryptoConditionsEnabled() +{ + return 0 != ASSETCHAINS_CC; +} + +// Limit acceptable condition types +// Prefix not enabled because no current use case, ambiguity on how to combine with secp256k1 +// RSA not enabled because no current use case, not implemented +int CCEnabledTypes = 1 << CC_Secp256k1 | \ + 1 << CC_Threshold | \ + 1 << CC_Eval | \ + 1 << CC_Preimage | \ + 1 << CC_Ed25519; + + +int CCSigningNodes = 1 << CC_Ed25519 | 1 << CC_Secp256k1; + + +bool IsSupportedCryptoCondition(const CC *cond) +{ + int mask = cc_typeMask(cond); + + if (mask & ~CCEnabledTypes) return false; + + // Also require that the condition have at least one signable node + if (!(mask & CCSigningNodes)) return false; + + return true; +} + + +bool IsSignedCryptoCondition(const CC *cond) +{ + if (!cc_isFulfilled(cond)) return false; + if (1 << cc_typeId(cond) & CCSigningNodes) return true; + if (cc_typeId(cond) == CC_Threshold) + for (int i=0; isize; i++) + if (IsSignedCryptoCondition(cond->subconditions[i])) return true; + return false; +} diff --git a/src/komodo_cc.h b/src/komodo_cc.h index fe05d3fc0..57d24f92e 100644 --- a/src/komodo_cc.h +++ b/src/komodo_cc.h @@ -2,39 +2,22 @@ #define KOMODO_CC_H #include "cryptoconditions/include/cryptoconditions.h" -#include "primitives/transaction.h" -/* - * Check if CryptoConditions is enabled based on chain or cmd flag - */ extern int32_t ASSETCHAINS_CC; -static bool IsCryptoConditionsEnabled() -{ - return 0 != ASSETCHAINS_CC; -} +bool IsCryptoConditionsEnabled(); /* * Check if the server can accept the condition based on it's structure / types */ -static bool IsAcceptableCryptoCondition(const CC *cond) -{ - int32_t typeMask = cc_typeMask(cond); +bool IsSupportedCryptoCondition(const CC *cond); - // Require a signature to prevent transaction malleability - if (0 == typeMask & (1 << CC_Secp256k1) || - 0 == typeMask & (1 << CC_Ed25519)) return false; - // Limit acceptable condition types - // Prefix not enabled because no current use case, ambiguity on how to combine with secp256k1 - // RSA not enabled because no current use case, not implemented - int enabledTypes = 1 << CC_Secp256k1 | 1 << CC_Threshold | 1 << CC_Eval | \ - 1 << CC_Preimage | 1 << CC_Ed25519; - if (typeMask & ~enabledTypes) return false; - - return true; -} +/* + * Check if crypto condition is signed. Can only accept signed conditions. + */ +bool IsSignedCryptoCondition(const CC *cond); #endif /* KOMODO_CC_H */ diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 20027ea41..851904eb3 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -950,27 +950,19 @@ bool EvalScript( if (stack.size() < 2) return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); - valtype& vchFulfillment = stacktop(-2); - valtype& vchCondition = stacktop(-1); - - CC *cond = cc_readFulfillmentBinary((unsigned char*)vchFulfillment.data(), - vchFulfillment.size()); - if (!cond) { + int fResult = checker.CheckCryptoCondition(stacktop(-1), stacktop(-2), script, consensusBranchId); + if (fResult == -1) { return set_error(serror, SCRIPT_ERR_CRYPTOCONDITION_INVALID_FULFILLMENT); } - - bool fSuccess = checker.CheckCryptoCondition(cond, vchCondition, script, consensusBranchId); - - cc_free(cond); - + popstack(stack); popstack(stack); - stack.push_back(fSuccess ? vchTrue : vchFalse); + stack.push_back(fResult == 1 ? vchTrue : vchFalse); if (opcode == OP_CHECKCRYPTOCONDITIONVERIFY) { - if (fSuccess) + if (fResult == 1) popstack(stack); else return set_error(serror, SCRIPT_ERR_CRYPTOCONDITION_VERIFY); @@ -1295,18 +1287,33 @@ bool TransactionSignatureChecker::CheckSig( } -bool TransactionSignatureChecker::CheckCryptoCondition(const CC *cond, const std::vector& condBin, const CScript& scriptCode, uint32_t consensusBranchId) const +int TransactionSignatureChecker::CheckCryptoCondition( + const std::vector& condBin, + const std::vector& ffillBin, + const CScript& scriptCode, + uint32_t consensusBranchId) const { - if (!IsAcceptableCryptoCondition(cond)) return false; + // Hash type is one byte tacked on to the end of the fulfillment + if (ffillBin.empty()) + return false; + + CC *cond = cc_readFulfillmentBinary((unsigned char*)ffillBin.data(), ffillBin.size()-1); + if (!cond) return -1; + + if (!IsSupportedCryptoCondition(cond)) return 0; + if (!IsSignedCryptoCondition(cond)) return 0; uint256 sighash; + int nHashType = ffillBin.back(); try { - sighash = SignatureHash(scriptCode, *txTo, nIn, SIGHASH_ALL, amount, consensusBranchId, this->txdata); + sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType, amount, consensusBranchId, this->txdata); } catch (logic_error ex) { - return false; + return 0; } - return cc_verify(cond, (const unsigned char*)&sighash, 32, 0, - condBin.data(), condBin.size(), GetCCEval(), (void*)this); + int out = cc_verify(cond, (const unsigned char*)&sighash, 32, 0, + condBin.data(), condBin.size(), GetCCEval(), (void*)this); + cc_free(cond); + return out; } diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 86ab8dac3..699d6e78c 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -128,7 +128,11 @@ public: return false; } - virtual bool CheckCryptoCondition(const CC *cond, const std::vector& condBin, const CScript& scriptCode, uint32_t consensusBranchId) const + virtual int CheckCryptoCondition( + const std::vector& condBin, + const std::vector& ffillBin, + const CScript& scriptCode, + uint32_t consensusBranchId) const { return false; } @@ -152,7 +156,11 @@ public: TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amountIn, const PrecomputedTransactionData& txdataIn) : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {} bool CheckSig(const std::vector& scriptSig, const std::vector& vchPubKey, const CScript& scriptCode, uint32_t consensusBranchId) const; bool CheckLockTime(const CScriptNum& nLockTime) const; - bool CheckCryptoCondition(const CC *cond, const std::vector& condBin, const CScript& scriptCode, uint32_t consensusBranchId) const; + int CheckCryptoCondition( + const std::vector& condBin, + const std::vector& ffillBin, + const CScript& scriptCode, + uint32_t consensusBranchId) const; VerifyEval GetCCEval() const; }; diff --git a/src/script/script.cpp b/src/script/script.cpp index d885146a2..cfea13efe 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -250,8 +250,9 @@ bool CScript::MayAcceptCryptoCondition() const if (!(opcode > OP_0 && opcode < OP_PUSHDATA1)) return false; CC *cond = cc_readConditionBinary(data.data(), data.size()); if (!cond) return false; - bool accept = IsAcceptableCryptoCondition(cond); - return accept; + bool out = IsSupportedCryptoCondition(cond); + cc_free(cond); + return out; } bool CScript::IsPushOnly() const diff --git a/src/zcash/CreateJoinSplit.cpp b/src/zcash/CreateJoinSplit.cpp index 8f651f910..166b4fac7 100644 --- a/src/zcash/CreateJoinSplit.cpp +++ b/src/zcash/CreateJoinSplit.cpp @@ -11,6 +11,7 @@ char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; int64_t MAX_MONEY = 200000000 * 100000000LL; uint16_t BITCOIND_PORT = 7771; +uint32_t ASSETCHAINS_CC = 0; using namespace libzcash; From 4c121ffdb0b3ddcaab24f518809e5633ac9fef19 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Sun, 1 Apr 2018 21:18:01 -0300 Subject: [PATCH 055/339] cpp test suite for cryptoconditions integration --- depends/packages/packages.mk | 4 +- qa/cryptoconditions/README.md | 11 - qa/cryptoconditions/test_integration.py | 223 ----------------- qa/cryptoconditions/testsupport.py | 151 ------------ src/Makefile.am | 5 +- src/Makefile.ktest.include | 14 ++ src/cc/eval.cpp | 4 +- .../include/cryptoconditions.h | 15 +- src/cryptoconditions/src/cryptoconditions.c | 18 +- src/cryptoconditions/src/internal.h | 20 +- src/cryptoconditions/src/json_rpc.c | 50 ++-- src/cryptoconditions/src/secp256k1.c | 9 +- src/cryptoconditions/src/threshold.c | 4 +- src/cryptoconditions/src/utils.c | 10 +- src/komodo_cc.cpp | 12 - src/komodo_cc.h | 11 + src/script/interpreter.h | 2 +- src/test-komodo/main.cpp | 12 + src/test-komodo/test_cryptoconditions.cpp | 226 ++++++++++++++++++ 19 files changed, 336 insertions(+), 465 deletions(-) delete mode 100644 qa/cryptoconditions/README.md delete mode 100644 qa/cryptoconditions/test_integration.py delete mode 100644 qa/cryptoconditions/testsupport.py create mode 100644 src/Makefile.ktest.include create mode 100644 src/test-komodo/main.cpp create mode 100644 src/test-komodo/test_cryptoconditions.cpp diff --git a/depends/packages/packages.mk b/depends/packages/packages.mk index 8475ec7d5..f75fcb50e 100644 --- a/depends/packages/packages.mk +++ b/depends/packages/packages.mk @@ -3,9 +3,9 @@ rust_packages := rust librustzcash proton_packages := proton zcash_packages := libgmp libsodium ifeq ($(host_os),linux) - packages := boost openssl libevent zeromq $(zcash_packages) #googletest googlemock + packages := boost openssl libevent zeromq $(zcash_packages) googletest # googlemock else - packages := boost openssl libevent zeromq $(zcash_packages) libcurl # googletest googlemock libcurl + packages := boost openssl libevent zeromq $(zcash_packages) libcurl googletest # googlemock endif native_packages := native_ccache diff --git a/qa/cryptoconditions/README.md b/qa/cryptoconditions/README.md deleted file mode 100644 index 2bf479ecd..000000000 --- a/qa/cryptoconditions/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Integration tests for Crypto-Conditions - -These tests are for the [Crypto-Conditions](https://github.com/rfcs/crypto-conditions) functionality in Komodod, using [Hoek](https://github.com/libscott/hoek) as a tool to create and sign transactions. - -## How to run the tests - -1. Install hoek: https://github.com/libscott/hoek -1. Allow peer-less block creation: set "fMiningRequiresPeers = false" in src/chainparams.cpp, then build komodod. -1. Start komodod: `src/komodod -ac_name=CCTEST -ac_supply=21000000 -gen -pubkey=0205a8ad0c1dbc515f149af377981aab58b836af008d4d7ab21bd76faf80550b47 -ac_cc=1` -1. Set environment variable pointing to Komodo conf: `export KOMODO_CONF_PATH=~/.komodo/CCTEST/CCTEST.conf` -1. Run tests: `python test_integration.py` (you can also use a test runner such as `nose`). diff --git a/qa/cryptoconditions/test_integration.py b/qa/cryptoconditions/test_integration.py deleted file mode 100644 index bd72b961d..000000000 --- a/qa/cryptoconditions/test_integration.py +++ /dev/null @@ -1,223 +0,0 @@ -import sys -import time -import json -import logging -import binascii -import struct -from testsupport import * - - -SCRIPT_FALSE = 'Script evaluated without error but finished with a false/empty top stack element' - - -@fanout_input(0) -def test_basic_spend(inp): - spend = {'inputs': [inp], "outputs": [nospend]} - spend_txid = submit(sign(spend)) - assert rpc.getrawtransaction(spend_txid) - - -@fanout_input(1) -def test_fulfillment_wrong_signature(inp): - # Set other pubkey and sign - inp['script']['fulfillment']['publicKey'] = bob_pk - spend = {'inputs': [inp], 'outputs': [nospend]} - signed = sign(spend) - - # Set the correct pubkey, signature is bob's - signed['inputs'][0]['script']['fulfillment']['publicKey'] = alice_pk - - try: - assert not submit(signed), 'should raise an error' - except RPCError as e: - assert SCRIPT_FALSE in str(e), str(e) - - -@fanout_input(2) -def test_fulfillment_wrong_pubkey(inp): - spend = {'inputs': [inp], 'outputs': [nospend]} - signed = sign(spend) - - # Set the wrong pubkey, signature is correct - signed['inputs'][0]['script']['fulfillment']['publicKey'] = bob_pk - - try: - assert not submit(signed), 'should raise an error' - except RPCError as e: - assert SCRIPT_FALSE in str(e), str(e) - - -@fanout_input(3) -def test_invalid_fulfillment_binary(inp): - # Create a valid script with an invalid fulfillment payload - inp['script'] = binascii.hexlify(b"\007invalid").decode('utf-8') - spend = {'inputs': [inp], 'outputs': [nospend]} - - try: - assert not submit(spend), 'should raise an error' - except RPCError as e: - assert 'Crypto-Condition payload is invalid' in str(e), str(e) - - -@fanout_input(4) -def test_invalid_condition(inp): - # Create a valid output script with an invalid cryptocondition binary - outputscript = to_hex(b"\007invalid\xcc") - spend = {'inputs': [inp], 'outputs': [{'amount': 1000, 'script': outputscript}]} - spend_txid = submit(sign(spend)) - - spend1 = { - 'inputs': [{'txid': spend_txid, 'idx': 0, 'script': {'fulfillment': cond_alice}}], - 'outputs': [nospend], - } - - try: - assert not submit(sign(spend1)), 'should raise an error' - except RPCError as e: - assert SCRIPT_FALSE in str(e), str(e) - - -@fanout_input(5) -def test_oversize_fulfillment(inp): - # Create oversize fulfillment script where the total length is <2000 - binscript = b'\x4d%s%s' % (struct.pack('h', 2000), b'a' * 2000) - inp['script'] = to_hex(binscript) - spend = {'inputs': [inp], 'outputs': [nospend]} - - try: - assert not submit(spend), 'should raise an error' - except RPCError as e: - assert 'scriptsig-size' in str(e), str(e) - - -@fanout_input(6) -def test_aux_basic(inp): - aux_cond = { - 'type': 'aux-sha-256', - 'method': 'equals', - 'conditionAux': 'LTE', - 'fulfillmentAux': 'LTE' - } - - # Setup some aux outputs - spend0 = { - 'inputs': [inp], - 'outputs': [ - {'amount': 500, 'script': {'condition': aux_cond}}, - {'amount': 500, 'script': {'condition': aux_cond}} - ] - } - spend0_txid = submit(sign(spend0)) - assert rpc.getrawtransaction(spend0_txid) - - # Test a good fulfillment - spend1 = { - 'inputs': [{'txid': spend0_txid, 'idx': 0, 'script': {'fulfillment': aux_cond}}], - 'outputs': [{'amount': 500, 'script': {'condition': aux_cond}}] - } - spend1_txid = submit(sign(spend1)) - assert rpc.getrawtransaction(spend1_txid) - - # Test a bad fulfillment - aux_cond['fulfillmentAux'] = 'WYW' - spend2 = { - 'inputs': [{'txid': spend0_txid, 'idx': 1, 'script': {'fulfillment': aux_cond}}], - 'outputs': [{'amount': 500, 'script': {'condition': aux_cond}}] - } - try: - assert not submit(sign(spend2)), 'should raise an error' - except RPCError as e: - assert SCRIPT_FALSE in str(e), str(e) - - -@fanout_input(7) -def test_aux_complex(inp): - aux_cond = { - 'type': 'aux-sha-256', - 'method': 'inputIsReturn', - 'conditionAux': '', - 'fulfillmentAux': 'AQ' # \1 (tx.vout[1]) - } - - # Setup some aux outputs - spend0 = { - 'inputs': [inp], - 'outputs': [ - {'amount': 500, 'script': {'condition': aux_cond}}, - {'amount': 500, 'script': {'condition': aux_cond}} - ] - } - spend0_txid = submit(sign(spend0)) - assert rpc.getrawtransaction(spend0_txid) - - # Test a good fulfillment - spend1 = { - 'inputs': [{'txid': spend0_txid, 'idx': 0, 'script': {'fulfillment': aux_cond}}], - 'outputs': [ - {'amount': 250, 'script': {'condition': aux_cond}}, - {'amount': 250, 'script': "6A0B68656C6C6F207468657265"} # OP_RETURN somedata - ] - } - spend1_txid = submit(sign(spend1)) - assert rpc.getrawtransaction(spend1_txid) - - # Test a bad fulfillment - spend2 = { - 'inputs': [{'txid': spend0_txid, 'idx': 1, 'script': {'fulfillment': aux_cond}}], - 'outputs': [ - {'amount': 500, 'script': "6A0B68656C6C6F207468657265"} # OP_RETURN somedata - ] - } - try: - assert not submit(sign(spend2)), 'should raise an error' - except RPCError as e: - assert SCRIPT_FALSE in str(e), str(e) - - -@fanout_input(8) -def test_secp256k1_condition(inp): - ec_cond = { - 'type': 'secp256k1-sha-256', - 'publicKey': notary_pk - } - - # Create some secp256k1 outputs - spend0 = { - 'inputs': [inp], - 'outputs': [ - {'amount': 500, 'script': {'condition': ec_cond}}, - {'amount': 500, 'script': {'condition': ec_cond}} - ] - } - spend0_txid = submit(sign(spend0)) - assert rpc.getrawtransaction(spend0_txid) - - # Test a good fulfillment - spend1 = { - 'inputs': [{'txid': spend0_txid, 'idx': 0, 'script': {'fulfillment': ec_cond}}], - 'outputs': [{'amount': 500, 'script': {'condition': ec_cond}}] - } - spend1_txid = submit(sign(spend1)) - assert rpc.getrawtransaction(spend1_txid) - - # Test a bad fulfillment - spend2 = { - 'inputs': [{'txid': spend0_txid, 'idx': 1, 'script': {'fulfillment': ec_cond}}], - 'outputs': [{'amount': 500, 'script': {'condition': ec_cond}}] - } - signed = sign(spend2) - signed['inputs'][0]['script']['fulfillment']['publicKey'] = \ - '0275cef12fc5c49be64f5aab3d1fbba08cd7b0d02908b5112fbd8504218d14bc7d' - try: - assert not submit(signed), 'should raise an error' - except RPCError as e: - assert SCRIPT_FALSE in str(e), str(e) - - -if __name__ == '__main__': - logging.basicConfig(level=logging.INFO) - for name, f in globals().items(): - if name.startswith('test_'): - logging.info("Running test: %s" % name) - f() - logging.info("Test OK: %s" % name) diff --git a/qa/cryptoconditions/testsupport.py b/qa/cryptoconditions/testsupport.py deleted file mode 100644 index e22520f3f..000000000 --- a/qa/cryptoconditions/testsupport.py +++ /dev/null @@ -1,151 +0,0 @@ -from __future__ import print_function -import sys -import json -import time -import copy -import base64 -import logging -import functools -import subprocess - - -class RPCError(IOError): - pass - - -class JsonClient(object): - def __getattr__(self, method): - if method[0] == '_': - return getattr(super(JsonClient, self), method) - def inner(*args): - return self._exec(method, args) - return inner - - def load_response(self, data): - data = json.loads(data.decode("utf-8")) - if data.get('error'): - raise RPCError(data['error']) - if 'result' in data: - return data['result'] - return data - - -def run_cmd(cmd): - proc = subprocess.Popen(cmd, stdout=subprocess.PIPE) - assert proc.wait() == 0 - return proc.stdout.read() - - -def to_hex(s): - return base64.b16encode(s).decode('utf-8') - - -class Hoek(JsonClient): - def _exec(self, method, args): - cmd = ['hoek', method, json.dumps(args[0])] - return self.load_response(run_cmd(cmd)) - - -class Komodod(JsonClient): - def _exec(self, method, args): - if not hasattr(self, '_url'): - urltpl = 'http://$rpcuser:$rpcpassword@${rpchost:-127.0.0.1}:$rpcport' - cmd = ['bash', '-c', '. $KOMODO_CONF_PATH && echo -n %s' % urltpl] - self._url = run_cmd(cmd) - - req = {'method': method, 'params': args, 'id': 1} - cmd = ['curl', '-s', '-H', 'Content-Type: application/json', '-d', json.dumps(req), self._url] - return self.load_response(run_cmd(cmd)) - - -rpc = Komodod() -hoek = Hoek() - - -def wait_for_block(height): - logging.info("Waiting for block height %s" % height) - for i in range(100): - try: - return rpc.getblock(str(height)) - except RPCError as e: - time.sleep(3) - raise Exception('Time out waiting for block at height %s' % height) - - -def sign(tx): - signed = hoek.signTxBitcoin({'tx': tx, 'privateKeys': [notary_sk]}) - signed = hoek.signTxEd25519({'tx': signed, 'privateKeys': [alice_sk, bob_sk]}) - return hoek.signTxSecp256k1({'tx': signed, 'privateKeys': [notary_sk]}) - - -def submit(tx): - encoded = hoek.encodeTx(tx) - try: - rpc.getrawtransaction(encoded['txid']) - logging.info("Transaction already in chain: %s" % encoded['txid']) - return encoded['txid'] - except RPCError: - pass - logging.info("submit transaction: %s:%s" % (encoded['txid'], json.dumps(tx))) - return rpc.sendrawtransaction(encoded['hex']) - - -def get_fanout_txid(): - block = wait_for_block(1) - reward_txid = block['tx'][0] - reward_tx_raw = rpc.getrawtransaction(reward_txid) - reward_tx = hoek.decodeTx({'hex': reward_tx_raw}) - balance = reward_tx['outputs'][0]['amount'] - - n_outs = 16 - remainder = balance - n_outs * 1000 - - fanout = { - 'inputs': [ - {'txid': reward_txid, 'idx': 0, 'script': {'pubkey': notary_pk}} - ], - "outputs": (n_outs * [ - {"amount": 1000, "script": {"condition": cond_alice}} - ] + [{"amount": remainder, 'script': {'address': notary_addr}}]) - } - - return submit(sign(fanout)) - - -def fanout_input(n): - def decorate(f): - def wrapper(): - if not hasattr(fanout_input, 'txid'): - fanout_input.txid = get_fanout_txid() - inp = {'txid': fanout_input.txid, 'idx': n, 'script': {'fulfillment': cond_alice}} - f(copy.deepcopy(inp)) - return functools.wraps(f)(wrapper) - return decorate - - -def decode_base64(data): - """Decode base64, padding being optional. - - :param data: Base64 data as an ASCII byte string - :returns: The decoded byte string. - """ - missing_padding = len(data) % 4 - if missing_padding: - data += '=' * (4 - missing_padding) - return base64.urlsafe_b64decode(data) - - -def encode_base64(data): - return base64.urlsafe_b64encode(data).rstrip(b'=') - - -notary_addr = 'RXSwmXKtDURwXP7sdqNfsJ6Ga8RaxTchxE' -notary_pk = '0205a8ad0c1dbc515f149af377981aab58b836af008d4d7ab21bd76faf80550b47' -notary_sk = 'UxFWWxsf1d7w7K5TvAWSkeX4H95XQKwdwGv49DXwWUTzPTTjHBbU' -alice_pk = '8ryTLBMnozUK4xUz7y49fjzZhxDDMK7c4mucLdbVY6jW' -alice_sk = 'E4ER7uYvaSTdpQFzTXNNSTkR6jNRJyqhZPJMGuU899nY' -cond_alice = {"type": "ed25519-sha-256", "publicKey": alice_pk} -bob_pk = 'C8MfEjKiFxDguacHvcM7MV83cRQ55RAHacC73xqg8qeu' -bob_sk = 'GrP1fZdUxUc1NYmu7kiNkJV4p7PKpshp1yBY7hogPUWT' -cond_bob = {"type": "ed25519-sha-256", "publicKey": bob_pk} -nospend = {"amount": 1000, "script": {"address": notary_addr}} diff --git a/src/Makefile.am b/src/Makefile.am index 7c64dcfd9..092015600 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -620,9 +620,10 @@ endif @test -f $(PROTOC) $(AM_V_GEN) $(PROTOC) --cpp_out=$(@D) --proto_path=$(abspath $(method, "testEval") == 0) { + if (strcmp(cond->method, "TestEval") == 0) { return cond->paramsBinLength == 8 && - memcmp(cond->paramsBin, "testEval", 8) == 0; + memcmp(cond->paramsBin, "TestEval", 8) == 0; } if (strcmp(cond->method, "ImportPayout") == 0) { diff --git a/src/cryptoconditions/include/cryptoconditions.h b/src/cryptoconditions/include/cryptoconditions.h index 64cd1db70..a911ffd79 100644 --- a/src/cryptoconditions/include/cryptoconditions.h +++ b/src/cryptoconditions/include/cryptoconditions.h @@ -26,6 +26,7 @@ enum CCTypeId { }; + /* * Evaliliary verification callback */ @@ -83,17 +84,17 @@ int cc_signTreeSecp256k1Msg32(CC *cond, const unsigned char *private size_t cc_conditionBinary(const CC *cond, unsigned char *buf); size_t cc_fulfillmentBinary(const CC *cond, unsigned char *buf, size_t bufLength); static int cc_secp256k1VerifyTreeMsg32(const CC *cond, const unsigned char *msg32); -struct CC* cc_conditionFromJSON(cJSON *params, unsigned char *err); -struct CC* cc_conditionFromJSONString(const unsigned char *json, unsigned char *err); +struct CC* cc_conditionFromJSON(cJSON *params, char *err); +struct CC* cc_conditionFromJSONString(const char *json, char *err); struct CC* cc_readConditionBinary(const unsigned char *cond_bin, size_t cond_bin_len); struct CC* cc_readFulfillmentBinary(const unsigned char *ffill_bin, size_t ffill_bin_len); struct cJSON* cc_conditionToJSON(const CC *cond); -unsigned char* cc_conditionToJSONString(const CC *cond); -unsigned char* cc_conditionUri(const CC *cond); -unsigned char* cc_jsonRPC(unsigned char *request); -unsigned long cc_getCost(const CC *cond); -enum CCTypeId cc_typeId(const CC *cond); +char* cc_conditionToJSONString(const CC *cond); +char* cc_conditionUri(const CC *cond); +char* cc_jsonRPC(char *request); char* cc_typeName(const CC *cond); +enum CCTypeId cc_typeId(const CC *cond); +unsigned long cc_getCost(const CC *cond); uint32_t cc_typeMask(const CC *cond); void cc_free(struct CC *cond); diff --git a/src/cryptoconditions/src/cryptoconditions.c b/src/cryptoconditions/src/cryptoconditions.c index 164d58f9c..037946a5f 100644 --- a/src/cryptoconditions/src/cryptoconditions.c +++ b/src/cryptoconditions/src/cryptoconditions.c @@ -16,7 +16,7 @@ #include -static struct CCType *typeRegistry[] = { +struct CCType *CCTypeRegistry[] = { &cc_preimageType, &cc_prefixType, &cc_thresholdType, @@ -28,7 +28,7 @@ static struct CCType *typeRegistry[] = { }; -static int typeRegistryLength = sizeof(typeRegistry) / sizeof(typeRegistry[0]); +int CCTypeRegistryLength = sizeof(CCTypeRegistry) / sizeof(CCTypeRegistry[0]); void appendUriSubtypes(uint32_t mask, unsigned char *buf) { @@ -37,10 +37,10 @@ void appendUriSubtypes(uint32_t mask, unsigned char *buf) { if (mask & 1 << i) { if (append) { strcat(buf, ","); - strcat(buf, typeRegistry[i]->name); + strcat(buf, CCTypeRegistry[i]->name); } else { strcat(buf, "&subtypes="); - strcat(buf, typeRegistry[i]->name); + strcat(buf, CCTypeRegistry[i]->name); append = 1; } } @@ -48,7 +48,7 @@ void appendUriSubtypes(uint32_t mask, unsigned char *buf) { } -unsigned char *cc_conditionUri(const CC *cond) { +char *cc_conditionUri(const CC *cond) { unsigned char *fp = cond->type->fingerprint(cond); if (!fp) return NULL; @@ -158,9 +158,9 @@ unsigned long cc_getCost(const CC *cond) { CCType *getTypeByAsnEnum(Condition_PR present) { - for (int i=0; iasnType == present) { - return typeRegistry[i]; + for (int i=0; iasnType == present) { + return CCTypeRegistry[i]; } } return NULL; @@ -245,7 +245,7 @@ CC *cc_readConditionBinary(const unsigned char *cond_bin, size_t length) { asn_dec_rval_t rval; rval = ber_decode(0, &asn_DEF_Condition, (void **)&asnCond, cond_bin, length); if (rval.code != RC_OK) { - printf("Failed reading condition binary\n"); + fprintf(stderr, "Failed reading condition binary\n"); return NULL; } CC *cond = mkAnon(asnCond); diff --git a/src/cryptoconditions/src/internal.h b/src/cryptoconditions/src/internal.h index 28b3661f4..e4cdd49ba 100644 --- a/src/cryptoconditions/src/internal.h +++ b/src/cryptoconditions/src/internal.h @@ -20,13 +20,13 @@ extern "C" { * Condition Type */ typedef struct CCType { int typeId; - unsigned char name[100]; + char name[100]; Condition_PR asnType; int (*visitChildren)(CC *cond, CCVisitor visitor); unsigned char *(*fingerprint)(const CC *cond); unsigned long (*getCost)(const CC *cond); uint32_t (*getSubtypes)(const CC *cond); - CC *(*fromJSON)(const cJSON *params, unsigned char *err); + CC *(*fromJSON)(const cJSON *params, char *err); void (*toJSON)(const CC *cond, cJSON *params); CC *(*fromFulfillment)(const Fulfillment_t *ffill); Fulfillment_t *(*toFulfillment)(const CC *cond); @@ -38,8 +38,8 @@ typedef struct CCType { /* * Globals */ -static struct CCType *typeRegistry[]; -static int typeRegistryLength; +struct CCType *CCTypeRegistry[]; +int CCTypeRegistryLength; /* @@ -50,7 +50,7 @@ static CC *mkAnon(const Condition_t *asnCond); static void asnCondition(const CC *cond, Condition_t *asn); static Condition_t *asnConditionNew(const CC *cond); static Fulfillment_t *asnFulfillmentNew(const CC *cond); -static cJSON *jsonEncodeCondition(cJSON *params, unsigned char *err); +static cJSON *jsonEncodeCondition(cJSON *params, char *err); static struct CC *fulfillmentToCC(Fulfillment_t *ffill); static struct CCType *getTypeByAsnEnum(Condition_PR present); @@ -62,11 +62,11 @@ 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 dumpStr(unsigned char *str, size_t len); -int checkString(const cJSON *value, unsigned char *key, unsigned char *err); -int checkDecodeBase64(const cJSON *value, unsigned char *key, unsigned char *err, unsigned char **data, size_t *size); -int jsonGetBase64(const cJSON *params, unsigned char *key, unsigned char *err, unsigned char **data, size_t *size); -int jsonGetBase64Optional(const cJSON *params, unsigned char *key, unsigned char *err, unsigned char **data, size_t *size); -void jsonAddBase64(cJSON *params, unsigned char *key, unsigned char *bin, size_t size); +int checkString(const cJSON *value, char *key, char *err); +int checkDecodeBase64(const cJSON *value, char *key, char *err, unsigned char **data, size_t *size); +int jsonGetBase64(const cJSON *params, char *key, char *err, unsigned char **data, size_t *size); +int jsonGetBase64Optional(const cJSON *params, char *key, char *err, unsigned char **data, size_t *size); +void jsonAddBase64(cJSON *params, char *key, unsigned char *bin, size_t size); #ifdef __cplusplus diff --git a/src/cryptoconditions/src/json_rpc.c b/src/cryptoconditions/src/json_rpc.c index 8fcf47fdb..13972ca35 100644 --- a/src/cryptoconditions/src/json_rpc.c +++ b/src/cryptoconditions/src/json_rpc.c @@ -34,7 +34,7 @@ static cJSON *jsonFulfillment(CC *cond) { } -CC *cc_conditionFromJSON(cJSON *params, unsigned char *err) { +CC *cc_conditionFromJSON(cJSON *params, char *err) { if (!params || !cJSON_IsObject(params)) { strcpy(err, "Condition params must be an object"); return NULL; @@ -44,10 +44,10 @@ CC *cc_conditionFromJSON(cJSON *params, unsigned char *err) { strcpy(err, "\"type\" must be a string"); return NULL; } - for (int i=0; ivaluestring, typeRegistry[i]->name)) { - return typeRegistry[i]->fromJSON(params, err); + for (int i=0; ivaluestring, CCTypeRegistry[i]->name)) { + return CCTypeRegistry[i]->fromJSON(params, err); } } } @@ -56,7 +56,7 @@ CC *cc_conditionFromJSON(cJSON *params, unsigned char *err) { } -CC *cc_conditionFromJSONString(const unsigned char *data, unsigned char *err) { +CC *cc_conditionFromJSONString(const char *data, char *err) { cJSON *params = cJSON_Parse(data); CC *out = cc_conditionFromJSON(params, err); cJSON_Delete(params); @@ -64,7 +64,7 @@ CC *cc_conditionFromJSONString(const unsigned char *data, unsigned char *err) { } -static cJSON *jsonEncodeCondition(cJSON *params, unsigned char *err) { +static cJSON *jsonEncodeCondition(cJSON *params, char *err) { CC *cond = cc_conditionFromJSON(params, err); cJSON *out = NULL; if (cond != NULL) { @@ -75,7 +75,7 @@ static cJSON *jsonEncodeCondition(cJSON *params, unsigned char *err) { } -static cJSON *jsonEncodeFulfillment(cJSON *params, unsigned char *err) { +static cJSON *jsonEncodeFulfillment(cJSON *params, char *err) { CC *cond = cc_conditionFromJSON(params, err); cJSON *out = NULL; if (cond != NULL) { @@ -86,14 +86,14 @@ static cJSON *jsonEncodeFulfillment(cJSON *params, unsigned char *err) { } -static cJSON *jsonErr(unsigned char *err) { +static cJSON *jsonErr(char *err) { cJSON *out = cJSON_CreateObject(); cJSON_AddItemToObject(out, "error", cJSON_CreateString(err)); return out; } -static cJSON *jsonVerifyFulfillment(cJSON *params, unsigned char *err) { +static cJSON *jsonVerifyFulfillment(cJSON *params, char *err) { unsigned char *ffill_bin = 0, *msg = 0, *cond_bin = 0; size_t ffill_bin_len, msg_len, cond_bin_len; cJSON *out = 0; @@ -121,7 +121,7 @@ END: } -static cJSON *jsonDecodeFulfillment(cJSON *params, unsigned char *err) { +static cJSON *jsonDecodeFulfillment(cJSON *params, char *err) { size_t ffill_bin_len; unsigned char *ffill_bin; if (!jsonGetBase64(params, "fulfillment", err, &ffill_bin, &ffill_bin_len)) @@ -139,7 +139,7 @@ static cJSON *jsonDecodeFulfillment(cJSON *params, unsigned char *err) { } -static cJSON *jsonDecodeCondition(cJSON *params, unsigned char *err) { +static cJSON *jsonDecodeCondition(cJSON *params, char *err) { size_t cond_bin_len; unsigned char *cond_bin; if (!jsonGetBase64(params, "bin", err, &cond_bin, &cond_bin_len)) @@ -160,7 +160,7 @@ static cJSON *jsonDecodeCondition(cJSON *params, unsigned char *err) { } -static cJSON *jsonSignTreeEd25519(cJSON *params, unsigned char *err) { +static cJSON *jsonSignTreeEd25519(cJSON *params, char *err) { cJSON *out = 0; unsigned char *msg = 0, *sk = 0; @@ -197,7 +197,7 @@ END: } -static cJSON *jsonSignTreeSecp256k1(cJSON *params, unsigned char *err) { +static cJSON *jsonSignTreeSecp256k1(cJSON *params, char *err) { cJSON *out = 0; unsigned char *msg = 0, *sk = 0; @@ -244,22 +244,22 @@ cJSON *cc_conditionToJSON(const CC *cond) { } -unsigned char *cc_conditionToJSONString(const CC *cond) { +char *cc_conditionToJSONString(const CC *cond) { assert(cond != NULL); cJSON *params = cc_conditionToJSON(cond); - unsigned char *out = cJSON_Print(params); + char *out = cJSON_Print(params); cJSON_Delete(params); return out; } -static cJSON *jsonListMethods(cJSON *params, unsigned char *err); +static cJSON *jsonListMethods(cJSON *params, char *err); typedef struct JsonMethod { - unsigned char *name; - cJSON* (*method)(cJSON *params, unsigned char *err); - unsigned char *description; + char *name; + cJSON* (*method)(cJSON *params, char *err); + char *description; } JsonMethod; @@ -278,7 +278,7 @@ static JsonMethod cc_jsonMethods[] = { static int nJsonMethods = sizeof(cc_jsonMethods) / sizeof(*cc_jsonMethods); -static cJSON *jsonListMethods(cJSON *params, unsigned char *err) { +static cJSON *jsonListMethods(cJSON *params, char *err) { cJSON *list = cJSON_CreateArray(); for (int i=0; itype->typeId != cc_secp256k1Type.typeId) return 1; + if (cond->type->typeId != CC_Secp256k1) return 1; CCSecp256k1SigningData *signing = (CCSecp256k1SigningData*) visitor.context; if (0 != memcmp(cond->publicKey, signing->pk, SECP256K1_PK_SIZE)) return 1; @@ -148,7 +148,7 @@ static int secp256k1Sign(CC *cond, CCVisitor visitor) { * Sign secp256k1 conditions in a tree */ int cc_signTreeSecp256k1Msg32(CC *cond, const unsigned char *privateKey, const unsigned char *msg32) { - if (cc_typeMask(cond) & (1 << cc_preimageType.typeId)) { + if (cc_typeMask(cond) & (1 << CC_Prefix)) { // No support for prefix currently, due to pending protocol decision on // how to combine message and prefix into 32 byte hash return 0; @@ -159,7 +159,10 @@ int cc_signTreeSecp256k1Msg32(CC *cond, const unsigned char *privateKey, const u lockSign(); int rc = secp256k1_ec_pubkey_create(ec_ctx_sign, &spk, privateKey); unlockSign(); - if (rc != 1) return 0; + if (rc != 1) { + fprintf(stderr, "Cryptoconditions couldn't derive secp256k1 pubkey\n"); + return 0; + } // serialize pubkey unsigned char *publicKey = calloc(1, SECP256K1_PK_SIZE); diff --git a/src/cryptoconditions/src/threshold.c b/src/cryptoconditions/src/threshold.c index d79c01813..1efe9f9e8 100644 --- a/src/cryptoconditions/src/threshold.c +++ b/src/cryptoconditions/src/threshold.c @@ -44,7 +44,7 @@ static unsigned long thresholdCost(const CC *cond) { static int thresholdVisitChildren(CC *cond, CCVisitor visitor) { - for (int i=0; ithreshold; i++) { + for (int i=0; isize; i++) { if (!cc_visit(cond->subconditions[i], visitor)) { return 0; } @@ -203,7 +203,7 @@ static void thresholdToJSON(const CC *cond, cJSON *params) { static int thresholdIsFulfilled(const CC *cond) { int nFulfilled = 0; for (int i=0; ithreshold; i++) { - if (!cc_isFulfilled(cond->subconditions[i])) { + if (cc_isFulfilled(cond->subconditions[i])) { nFulfilled++; } if (nFulfilled == cond->threshold) { diff --git a/src/cryptoconditions/src/utils.c b/src/cryptoconditions/src/utils.c index 69db32042..c87e8ddda 100644 --- a/src/cryptoconditions/src/utils.c +++ b/src/cryptoconditions/src/utils.c @@ -141,7 +141,7 @@ void dumpStr(unsigned char *str, size_t len) { -int checkString(const cJSON *value, unsigned char *key, unsigned char *err) { +int checkString(const cJSON *value, char *key, char *err) { if (value == NULL) { sprintf(err, "%s is required", key); return 0; @@ -153,7 +153,7 @@ int checkString(const cJSON *value, unsigned char *key, unsigned char *err) { return 1; } -int checkDecodeBase64(const cJSON *value, unsigned char *key, unsigned char *err, unsigned char **data, size_t *size) { +int checkDecodeBase64(const cJSON *value, char *key, char *err, unsigned char **data, size_t *size) { if (!checkString(value, key, err)) { sprintf(err, "%s must be valid base64 string", key); return 0; @@ -168,7 +168,7 @@ int checkDecodeBase64(const cJSON *value, unsigned char *key, unsigned char *err } -int jsonGetBase64(const cJSON *params, unsigned char *key, unsigned char *err, unsigned char **data, size_t *size) +int jsonGetBase64(const cJSON *params, char *key, char *err, unsigned char **data, size_t *size) { cJSON *item = cJSON_GetObjectItem(params, key); if (!item) { @@ -179,7 +179,7 @@ int jsonGetBase64(const cJSON *params, unsigned char *key, unsigned char *err, u } -int jsonGetBase64Optional(const cJSON *params, unsigned char *key, unsigned char *err, unsigned char **data, size_t *size) { +int jsonGetBase64Optional(const cJSON *params, char *key, char *err, unsigned char **data, size_t *size) { cJSON *item = cJSON_GetObjectItem(params, key); if (!item) { return 1; @@ -188,7 +188,7 @@ int jsonGetBase64Optional(const cJSON *params, unsigned char *key, unsigned char } -void jsonAddBase64(cJSON *params, unsigned char *key, unsigned char *bin, size_t size) { +void jsonAddBase64(cJSON *params, char *key, unsigned char *bin, size_t size) { unsigned char *b64 = base64_encode(bin, size); cJSON_AddItemToObject(params, key, cJSON_CreateString(b64)); free(b64); diff --git a/src/komodo_cc.cpp b/src/komodo_cc.cpp index 1b05ea070..81459fe2b 100644 --- a/src/komodo_cc.cpp +++ b/src/komodo_cc.cpp @@ -7,18 +7,6 @@ bool IsCryptoConditionsEnabled() return 0 != ASSETCHAINS_CC; } -// Limit acceptable condition types -// Prefix not enabled because no current use case, ambiguity on how to combine with secp256k1 -// RSA not enabled because no current use case, not implemented -int CCEnabledTypes = 1 << CC_Secp256k1 | \ - 1 << CC_Threshold | \ - 1 << CC_Eval | \ - 1 << CC_Preimage | \ - 1 << CC_Ed25519; - - -int CCSigningNodes = 1 << CC_Ed25519 | 1 << CC_Secp256k1; - bool IsSupportedCryptoCondition(const CC *cond) { diff --git a/src/komodo_cc.h b/src/komodo_cc.h index 57d24f92e..62e584a94 100644 --- a/src/komodo_cc.h +++ b/src/komodo_cc.h @@ -7,6 +7,17 @@ extern int32_t ASSETCHAINS_CC; bool IsCryptoConditionsEnabled(); +// Limit acceptable condition types +// Prefix not enabled because no current use case, ambiguity on how to combine with secp256k1 +// RSA not enabled because no current use case, not implemented +const int CCEnabledTypes = 1 << CC_Secp256k1 | \ + 1 << CC_Threshold | \ + 1 << CC_Eval | \ + 1 << CC_Preimage | \ + 1 << CC_Ed25519; + +const int CCSigningNodes = 1 << CC_Ed25519 | 1 << CC_Secp256k1; + /* * Check if the server can accept the condition based on it's structure / types diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 699d6e78c..57051f797 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -161,7 +161,7 @@ public: const std::vector& ffillBin, const CScript& scriptCode, uint32_t consensusBranchId) const; - VerifyEval GetCCEval() const; + virtual VerifyEval GetCCEval() const; }; class MutableTransactionSignatureChecker : public TransactionSignatureChecker diff --git a/src/test-komodo/main.cpp b/src/test-komodo/main.cpp new file mode 100644 index 000000000..2a83e47fa --- /dev/null +++ b/src/test-komodo/main.cpp @@ -0,0 +1,12 @@ +#include "key.h" +#include "gtest/gtest.h" +#include "crypto/common.h" + + +int main(int argc, char **argv) { + assert(init_and_check_sodium() != -1); + ECC_Start(); + + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/src/test-komodo/test_cryptoconditions.cpp b/src/test-komodo/test_cryptoconditions.cpp new file mode 100644 index 000000000..9ab4b676c --- /dev/null +++ b/src/test-komodo/test_cryptoconditions.cpp @@ -0,0 +1,226 @@ +#include +#include + +#include "base58.h" +#include "key.h" +#include "komodo_cc.h" +#include "primitives/transaction.h" +#include "script/interpreter.h" +#include "script/serverchecker.h" + + +#define VCH(a,b) std::vector(a, a + b) + +std::string pubkey = "0205a8ad0c1dbc515f149af377981aab58b836af008d4d7ab21bd76faf80550b47"; +std::string secret = "UxFWWxsf1d7w7K5TvAWSkeX4H95XQKwdwGv49DXwWUTzPTTjHBbU"; +CKey notaryKey; + + +char ccjsonerr[1000] = "\0"; +#define CCFromJson(o,s) \ + o = cc_conditionFromJSONString(s, ccjsonerr); \ + if (!o) FAIL() << "bad json: " << ccjsonerr; + + +CScript CCPubKey(const CC *cond) { + unsigned char buf[1000]; + size_t len = cc_conditionBinary(cond, buf); + return CScript() << VCH(buf, len) << OP_CHECKCRYPTOCONDITION; +} + + +CScript CCSig(const CC *cond) { + unsigned char buf[1000]; + size_t len = cc_fulfillmentBinary(cond, buf, 1000); + auto ffill = VCH(buf, len); + ffill.push_back(SIGHASH_ALL); + return CScript() << ffill; +} + + +void CCSign(CMutableTransaction &tx, CC *cond) { + tx.vin.resize(1); + PrecomputedTransactionData txdata(tx); + uint256 sighash = SignatureHash(CCPubKey(cond), tx, 0, SIGHASH_ALL, 0, 0, &txdata); + + int out = cc_signTreeSecp256k1Msg32(cond, notaryKey.begin(), sighash.begin()); + tx.vin[0].scriptSig = CCSig(cond); +} + + +class CCTest : public ::testing::Test { +protected: + static void SetUpTestCase() { + SelectParams(CBaseChainParams::REGTEST); + // Notary key + CBitcoinSecret vchSecret; + // this returns false due to network prefix mismatch but works anyway + vchSecret.SetString(secret); + notaryKey = vchSecret.GetKey(); + } + virtual void SetUp() { + // enable CC + ASSETCHAINS_CC = 1; + } +}; + + +TEST_F(CCTest, testIsPayToCryptoCondition) +{ + CScript s = CScript() << VCH("a", 1); + ASSERT_FALSE(s.IsPayToCryptoCondition()); + + s = CScript() << VCH("a", 1) << OP_CHECKCRYPTOCONDITION; + ASSERT_TRUE(s.IsPayToCryptoCondition()); + + s = CScript() << OP_CHECKCRYPTOCONDITION; + ASSERT_FALSE(s.IsPayToCryptoCondition()); +} + + +TEST_F(CCTest, testMayAcceptCryptoCondition) +{ + CC *cond; + + // ok + CCFromJson(cond, R"!!( + { "type": "threshold-sha-256", + "threshold": 2, + "subfulfillments": [ + { "type": "secp256k1-sha-256", "publicKey": "AgWorQwdvFFfFJrzd5gaq1i4Nq8AjU16shvXb6+AVQtH" } + ] + })!!"); + ASSERT_TRUE(CCPubKey(cond).MayAcceptCryptoCondition()); + + + // prefix not allowed + CCFromJson(cond, R"!!( + { "type": "prefix-sha-256", + "prefix": "abc", + "maxMessageLength": 10, + "subfulfillment": + { "type": "secp256k1-sha-256", "publicKey": "AgWorQwdvFFfFJrzd5gaq1i4Nq8AjU16shvXb6+AVQtH" } + })!!"); + ASSERT_FALSE(CCPubKey(cond).MayAcceptCryptoCondition()); + + + // has no signature nodes + CCFromJson(cond, R"!!( + { "type": "threshold-sha-256", + "threshold": 1, + "subfulfillments": [ + { "type": "eval-sha-256", "method": "test", "params": "" }, + { "type": "eval-sha-256", "method": "test", "params": "" } + ] + })!!"); + ASSERT_FALSE(CCPubKey(cond).MayAcceptCryptoCondition()); +} + + +TEST_F(CCTest, testVerifyCryptoCondition) +{ + CC *cond; + ScriptError error; + CMutableTransaction mtxTo; + + auto Verify = [&] (const CC *cond) { + CAmount amount; + CTransaction txTo(mtxTo); + PrecomputedTransactionData txdata(txTo); + auto checker = ServerTransactionSignatureChecker(&txTo, 0, amount, false, txdata); + return VerifyScript(CCSig(cond), CCPubKey(cond), 0, checker, 0, &error); + }; + + // ok + CCFromJson(cond, R"!!({ + "type": "secp256k1-sha-256", + "publicKey": "AgWorQwdvFFfFJrzd5gaq1i4Nq8AjU16shvXb6+AVQtH" + })!!"); + CCSign(mtxTo, cond); + ASSERT_TRUE(Verify(cond)); + + + // has signature nodes + CCFromJson(cond, R"!!({ + "type": "threshold-sha-256", + "threshold": 1, + "subfulfillments": [ + { "type": "preimage-sha-256", "preimage": "" }, + { "type": "secp256k1-sha-256", "publicKey": "AgWorQwdvFFfFJrzd5gaq1i4Nq8AjU16shvXb6+AVQtH" } + ] + })!!"); + cond->threshold = 2; + CCSign(mtxTo, cond); + ASSERT_TRUE(Verify(cond)); + + // no signatures; the preimage will get encoded as a fulfillment because it's cheaper + // and the secp256k1 node will get encoded as a condition + cond->threshold = 1; + ASSERT_FALSE(Verify(cond)); + + // here the signature is set wrong + cond->threshold = 2; + ASSERT_TRUE(Verify(cond)); + memset(cond->subconditions[1]->signature, 0, 32); + ASSERT_FALSE(Verify(cond)); +} + + +TEST_F(CCTest, testVerifyEvalCondition) +{ + CC *cond; + ScriptError error; + CMutableTransaction mtxTo; + + auto Verify = [&] (const CC *cond) { + CAmount amount; + CTransaction txTo(mtxTo); + PrecomputedTransactionData txdata(txTo); + auto checker = ServerTransactionSignatureChecker(&txTo, 0, amount, false, txdata); + return VerifyScript(CCSig(cond), CCPubKey(cond), 0, checker, 0, &error); + }; + + // ok + CCFromJson(cond, R"!!({ + "type": "threshold-sha-256", + "threshold": 2, + "subfulfillments": [ + { "type": "secp256k1-sha-256", "publicKey": "AgWorQwdvFFfFJrzd5gaq1i4Nq8AjU16shvXb6+AVQtH" }, + { "type": "eval-sha-256", "method": "TestEval", "params": "" } + ]})!!"); + CC *ecCond = cond->subconditions[1]; + ecCond->paramsBin = (unsigned char*) "TestEval"; + ecCond->paramsBinLength = 8; + CCSign(mtxTo, cond); // will reorder subconditions + ASSERT_TRUE(Verify(cond)); + + ecCond->paramsBin = (unsigned char*) "FailEval"; + ASSERT_FALSE(Verify(cond)); +} + + +TEST_F(CCTest, testCryptoConditionsDisabled) +{ + CC *cond; + ScriptError error; + CMutableTransaction mtxTo; + + auto Verify = [&] (const CC *cond) { + CAmount amount; + CTransaction txTo(mtxTo); + PrecomputedTransactionData txdata(txTo); + auto checker = ServerTransactionSignatureChecker(&txTo, 0, amount, false, txdata); + return VerifyScript(CCSig(cond), CCPubKey(cond), 0, checker, 0, &error); + }; + + // ok + CCFromJson(cond, R"!!({ + "type": "secp256k1-sha-256", + "publicKey": "AgWorQwdvFFfFJrzd5gaq1i4Nq8AjU16shvXb6+AVQtH" + })!!"); + CCSign(mtxTo, cond); + ASSERT_TRUE(Verify(cond)); + + ASSETCHAINS_CC = 0; + ASSERT_FALSE(Verify(cond)); +} From 660b32c300981dae415b55afeafb529bafdad298 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Mon, 2 Apr 2018 20:44:10 -0300 Subject: [PATCH 056/339] cryptoconditions functions to create conditions --- .../include/cryptoconditions.h | 2 +- src/cryptoconditions/src/anon.c | 6 +++--- src/cryptoconditions/src/cryptoconditions.c | 20 ++++++++++++------- src/cryptoconditions/src/ed25519.c | 12 +++++------ src/cryptoconditions/src/eval.c | 10 +++++----- src/cryptoconditions/src/internal.h | 3 ++- src/cryptoconditions/src/prefix.c | 8 ++++---- src/cryptoconditions/src/preimage.c | 8 ++++---- src/cryptoconditions/src/secp256k1.c | 12 +++++------ src/cryptoconditions/src/threshold.c | 8 ++++---- 10 files changed, 48 insertions(+), 41 deletions(-) diff --git a/src/cryptoconditions/include/cryptoconditions.h b/src/cryptoconditions/include/cryptoconditions.h index a911ffd79..1af542b03 100644 --- a/src/cryptoconditions/include/cryptoconditions.h +++ b/src/cryptoconditions/include/cryptoconditions.h @@ -26,7 +26,6 @@ enum CCTypeId { }; - /* * Evaliliary verification callback */ @@ -88,6 +87,7 @@ struct CC* cc_conditionFromJSON(cJSON *params, char *err); struct CC* cc_conditionFromJSONString(const char *json, char *err); struct CC* cc_readConditionBinary(const unsigned char *cond_bin, size_t cond_bin_len); struct CC* cc_readFulfillmentBinary(const unsigned char *ffill_bin, size_t ffill_bin_len); +struct CC* cc_new(int typeId); struct cJSON* cc_conditionToJSON(const CC *cond); char* cc_conditionToJSONString(const CC *cond); char* cc_conditionUri(const CC *cond); diff --git a/src/cryptoconditions/src/anon.c b/src/cryptoconditions/src/anon.c index 0d10e0df0..c9baa6245 100644 --- a/src/cryptoconditions/src/anon.c +++ b/src/cryptoconditions/src/anon.c @@ -7,7 +7,7 @@ #include "cryptoconditions.h" -struct CCType cc_anonType; +struct CCType CC_AnonType; static CC *mkAnon(const Condition_t *asnCond) { @@ -18,7 +18,7 @@ static CC *mkAnon(const Condition_t *asnCond) { return 0; } CC *cond = calloc(1, sizeof(CC)); - cond->type = &cc_anonType; + cond->type = &CC_AnonType; cond->conditionType = realType; const CompoundSha256Condition_t *deets = &asnCond->choice.thresholdSha256; memcpy(cond->fingerprint, deets->fingerprint.buf, 32); @@ -71,4 +71,4 @@ static int anonIsFulfilled(const CC *cond) { } -struct CCType cc_anonType = { -1, "(anon)", Condition_PR_NOTHING, NULL, &anonFingerprint, &anonCost, &anonSubtypes, NULL, &anonToJSON, NULL, &anonFulfillment, &anonIsFulfilled, &anonFree }; +struct CCType CC_AnonType = { -1, "(anon)", Condition_PR_NOTHING, NULL, &anonFingerprint, &anonCost, &anonSubtypes, NULL, &anonToJSON, NULL, &anonFulfillment, &anonIsFulfilled, &anonFree }; diff --git a/src/cryptoconditions/src/cryptoconditions.c b/src/cryptoconditions/src/cryptoconditions.c index 037946a5f..f993b277f 100644 --- a/src/cryptoconditions/src/cryptoconditions.c +++ b/src/cryptoconditions/src/cryptoconditions.c @@ -17,14 +17,14 @@ struct CCType *CCTypeRegistry[] = { - &cc_preimageType, - &cc_prefixType, - &cc_thresholdType, - NULL, /* &cc_rsaType */ - &cc_ed25519Type, - &cc_secp256k1Type, + &CC_PreimageType, + &CC_PrefixType, + &CC_ThresholdType, + NULL, /* &CC_rsaType */ + &CC_Ed25519Type, + &CC_Secp256k1Type, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 6-14 unused */ - &cc_evalType + &CC_EvalType }; @@ -281,6 +281,12 @@ char *cc_typeName(const CC *cond) { return cc_isAnon(cond) ? cond->conditionType->name : cond->type->name; } +CC *cc_new(int typeId) { + CC *cond = malloc(sizeof(CC*)); + cond->type = CCTypeRegistry[type]; + return cond; +} + void cc_free(CC *cond) { if (cond) diff --git a/src/cryptoconditions/src/ed25519.c b/src/cryptoconditions/src/ed25519.c index b835cefc0..541c9b896 100644 --- a/src/cryptoconditions/src/ed25519.c +++ b/src/cryptoconditions/src/ed25519.c @@ -7,7 +7,7 @@ #include "cryptoconditions.h" -struct CCType cc_ed25519Type; +struct CCType CC_Ed25519Type; static unsigned char *ed25519Fingerprint(const CC *cond) { @@ -18,7 +18,7 @@ static unsigned char *ed25519Fingerprint(const CC *cond) { int ed25519Verify(CC *cond, CCVisitor visitor) { - if (cond->type->typeId != cc_ed25519Type.typeId) return 1; + if (cond->type->typeId != CC_Ed25519Type.typeId) return 1; // TODO: test failure mode: empty sig / null pointer return ed25519_verify(cond->signature, visitor.msg, visitor.msgLength, cond->publicKey); } @@ -44,7 +44,7 @@ typedef struct CCEd25519SigningData { * Visitor that signs an ed25519 condition if it has a matching public key */ static int ed25519Sign(CC *cond, CCVisitor visitor) { - if (cond->type->typeId != cc_ed25519Type.typeId) return 1; + if (cond->type->typeId != CC_Ed25519Type.typeId) return 1; CCEd25519SigningData *signing = (CCEd25519SigningData*) visitor.context; if (0 != memcmp(cond->publicKey, signing->pk, 32)) return 1; if (!cond->signature) cond->signature = malloc(64); @@ -105,7 +105,7 @@ static CC *ed25519FromJSON(const cJSON *params, unsigned char *err) { } CC *cond = calloc(1, sizeof(CC)); - cond->type = &cc_ed25519Type; + cond->type = &CC_Ed25519Type; cond->publicKey = pk; cond->signature = sig; return cond; @@ -126,7 +126,7 @@ static void ed25519ToJSON(const CC *cond, cJSON *params) { static CC *ed25519FromFulfillment(const Fulfillment_t *ffill) { CC *cond = calloc(1, sizeof(CC)); - cond->type = &cc_ed25519Type; + cond->type = &CC_Ed25519Type; cond->publicKey = malloc(32); memcpy(cond->publicKey, ffill->choice.ed25519Sha256.publicKey.buf, 32); cond->signature = malloc(64); @@ -166,4 +166,4 @@ static uint32_t ed25519Subtypes(const CC *cond) { } -struct CCType cc_ed25519Type = { 4, "ed25519-sha-256", Condition_PR_ed25519Sha256, 0, &ed25519Fingerprint, &ed25519Cost, &ed25519Subtypes, &ed25519FromJSON, &ed25519ToJSON, &ed25519FromFulfillment, &ed25519ToFulfillment, &ed25519IsFulfilled, &ed25519Free }; +struct CCType CC_Ed25519Type = { 4, "ed25519-sha-256", Condition_PR_ed25519Sha256, 0, &ed25519Fingerprint, &ed25519Cost, &ed25519Subtypes, &ed25519FromJSON, &ed25519ToJSON, &ed25519FromFulfillment, &ed25519ToFulfillment, &ed25519IsFulfilled, &ed25519Free }; diff --git a/src/cryptoconditions/src/eval.c b/src/cryptoconditions/src/eval.c index 13388b117..14db14c70 100644 --- a/src/cryptoconditions/src/eval.c +++ b/src/cryptoconditions/src/eval.c @@ -8,7 +8,7 @@ #include "include/cJSON.h" -struct CCType cc_evalType; +struct CCType CC_EvalType; static unsigned char *evalFingerprint(const CC *cond) { @@ -46,7 +46,7 @@ static CC *evalFromJSON(const cJSON *params, unsigned char *err) { strcpy(cond->method, method_item->valuestring); cond->paramsBin = paramsBin; cond->paramsBinLength = paramsBinLength; - cond->type = &cc_evalType; + cond->type = &CC_EvalType; return cond; } @@ -65,7 +65,7 @@ static void evalToJSON(const CC *cond, cJSON *params) { static CC *evalFromFulfillment(const Fulfillment_t *ffill) { CC *cond = calloc(1, sizeof(CC)); - cond->type = &cc_evalType; + cond->type = &CC_EvalType; EvalFulfillment_t *eval = &ffill->choice.evalSha256; @@ -125,7 +125,7 @@ typedef struct CCEvalVerifyData { int evalVisit(CC *cond, CCVisitor visitor) { - if (cond->type->typeId != cc_evalType.typeId) return 1; + if (cond->type->typeId != CC_Eval) return 1; CCEvalVerifyData *evalData = visitor.context; return evalData->verify(cond, evalData->context); } @@ -138,4 +138,4 @@ int cc_verifyEval(const CC *cond, VerifyEval verify, void *context) { } -struct CCType cc_evalType = { 15, "eval-sha-256", Condition_PR_evalSha256, 0, &evalFingerprint, &evalCost, &evalSubtypes, &evalFromJSON, &evalToJSON, &evalFromFulfillment, &evalToFulfillment, &evalIsFulfilled, &evalFree }; +struct CCType CC_EvalType = { 15, "eval-sha-256", Condition_PR_evalSha256, 0, &evalFingerprint, &evalCost, &evalSubtypes, &evalFromJSON, &evalToJSON, &evalFromFulfillment, &evalToFulfillment, &evalIsFulfilled, &evalFree }; diff --git a/src/cryptoconditions/src/internal.h b/src/cryptoconditions/src/internal.h index e4cdd49ba..d8e09310a 100644 --- a/src/cryptoconditions/src/internal.h +++ b/src/cryptoconditions/src/internal.h @@ -17,7 +17,8 @@ extern "C" { /* - * Condition Type */ + * Condition Type + */ typedef struct CCType { int typeId; char name[100]; diff --git a/src/cryptoconditions/src/prefix.c b/src/cryptoconditions/src/prefix.c index 423ee3ecf..d8d8b7aad 100644 --- a/src/cryptoconditions/src/prefix.c +++ b/src/cryptoconditions/src/prefix.c @@ -7,7 +7,7 @@ #include "cryptoconditions.h" -struct CCType cc_prefixType; +struct CCType CC_PrefixType; static int prefixVisitChildren(CC *cond, CCVisitor visitor) { @@ -43,7 +43,7 @@ static CC *prefixFromFulfillment(const Fulfillment_t *ffill) { CC *sub = fulfillmentToCC(p->subfulfillment); if (!sub) return 0; CC *cond = calloc(1, sizeof(CC)); - cond->type = &cc_prefixType; + cond->type = &CC_PrefixType; cond->maxMessageLength = p->maxMessageLength; cond->prefix = calloc(1, p->prefix.size); memcpy(cond->prefix, p->prefix.buf, p->prefix.size); @@ -89,7 +89,7 @@ static CC *prefixFromJSON(const cJSON *params, unsigned char *err) { } CC *cond = calloc(1, sizeof(CC)); - cond->type = &cc_prefixType; + cond->type = &CC_PrefixType; cond->maxMessageLength = (unsigned long) mml_item->valuedouble; cond->subcondition = sub; @@ -122,4 +122,4 @@ static void prefixFree(CC *cond) { } -struct CCType cc_prefixType = { 1, "prefix-sha-256", Condition_PR_prefixSha256, &prefixVisitChildren, &prefixFingerprint, &prefixCost, &prefixSubtypes, &prefixFromJSON, &prefixToJSON, &prefixFromFulfillment, &prefixToFulfillment, &prefixIsFulfilled, &prefixFree }; +struct CCType CC_PrefixType = { 1, "prefix-sha-256", Condition_PR_prefixSha256, &prefixVisitChildren, &prefixFingerprint, &prefixCost, &prefixSubtypes, &prefixFromJSON, &prefixToJSON, &prefixFromFulfillment, &prefixToFulfillment, &prefixIsFulfilled, &prefixFree }; diff --git a/src/cryptoconditions/src/preimage.c b/src/cryptoconditions/src/preimage.c index 95f19c09d..639bd1009 100644 --- a/src/cryptoconditions/src/preimage.c +++ b/src/cryptoconditions/src/preimage.c @@ -7,7 +7,7 @@ #include "cryptoconditions.h" -struct CCType cc_preimageType; +struct CCType CC_PreimageType; static CC *preimageFromJSON(const cJSON *params, unsigned char *err) { @@ -19,7 +19,7 @@ static CC *preimageFromJSON(const cJSON *params, unsigned char *err) { unsigned char *preimage_b64 = preimage_item->valuestring; CC *cond = calloc(1, sizeof(CC)); - cond->type = &cc_preimageType; + cond->type = &CC_PreimageType; cond->preimage = base64_decode(preimage_b64, &cond->preimageLength); return cond; } @@ -46,7 +46,7 @@ static unsigned char *preimageFingerprint(const CC *cond) { static CC *preimageFromFulfillment(const Fulfillment_t *ffill) { CC *cond = calloc(1, sizeof(CC)); - cond->type = &cc_preimageType; + cond->type = &CC_PreimageType; PreimageFulfillment_t p = ffill->choice.preimageSha256; cond->preimage = calloc(1, p.preimage.size); memcpy(cond->preimage, p.preimage.buf, p.preimage.size); @@ -79,4 +79,4 @@ static uint32_t preimageSubtypes(const CC *cond) { } -struct CCType cc_preimageType = { 0, "preimage-sha-256", Condition_PR_preimageSha256, 0, &preimageFingerprint, &preimageCost, &preimageSubtypes, &preimageFromJSON, &preimageToJSON, &preimageFromFulfillment, &preimageToFulfillment, &preimageIsFulfilled, &preimageFree }; +struct CCType CC_PreimageType = { 0, "preimage-sha-256", Condition_PR_preimageSha256, 0, &preimageFingerprint, &preimageCost, &preimageSubtypes, &preimageFromJSON, &preimageToJSON, &preimageFromFulfillment, &preimageToFulfillment, &preimageIsFulfilled, &preimageFree }; diff --git a/src/cryptoconditions/src/secp256k1.c b/src/cryptoconditions/src/secp256k1.c index 4a7588a89..f83397db8 100644 --- a/src/cryptoconditions/src/secp256k1.c +++ b/src/cryptoconditions/src/secp256k1.c @@ -15,7 +15,7 @@ #include "internal.h" -struct CCType cc_secp256k1Type; +struct CCType CC_Secp256k1Type; static const size_t SECP256K1_PK_SIZE = 33; @@ -74,7 +74,7 @@ static unsigned char *secp256k1Fingerprint(const CC *cond) { int secp256k1Verify(CC *cond, CCVisitor visitor) { - if (cond->type->typeId != cc_secp256k1Type.typeId) return 1; + if (cond->type->typeId != CC_Secp256k1Type.typeId) return 1; initVerify(); int rc; @@ -99,8 +99,8 @@ int secp256k1Verify(CC *cond, CCVisitor visitor) { static int cc_secp256k1VerifyTreeMsg32(const CC *cond, const unsigned char *msg32) { int subtypes = cc_typeMask(cond); - if (subtypes & (1 << cc_prefixType.typeId) && - subtypes & (1 << cc_secp256k1Type.typeId)) { + if (subtypes & (1 << CC_PrefixType.typeId) && + subtypes & (1 << CC_Secp256k1Type.typeId)) { // No support for prefix currently, due to pending protocol decision on // how to combine message and prefix into 32 byte hash return 0; @@ -203,7 +203,7 @@ static CC *cc_secp256k1Condition(const unsigned char *publicKey, const unsigned } CC *cond = calloc(1, sizeof(CC)); - cond->type = &cc_secp256k1Type; + cond->type = &CC_Secp256k1Type; cond->publicKey = pk; cond->signature = sig; return cond; @@ -281,4 +281,4 @@ static uint32_t secp256k1Subtypes(const CC *cond) { } -struct CCType cc_secp256k1Type = { 5, "secp256k1-sha-256", Condition_PR_secp256k1Sha256, 0, &secp256k1Fingerprint, &secp256k1Cost, &secp256k1Subtypes, &secp256k1FromJSON, &secp256k1ToJSON, &secp256k1FromFulfillment, &secp256k1ToFulfillment, &secp256k1IsFulfilled, &secp256k1Free }; +struct CCType CC_Secp256k1Type = { 5, "secp256k1-sha-256", Condition_PR_secp256k1Sha256, 0, &secp256k1Fingerprint, &secp256k1Cost, &secp256k1Subtypes, &secp256k1FromJSON, &secp256k1ToJSON, &secp256k1FromFulfillment, &secp256k1ToFulfillment, &secp256k1IsFulfilled, &secp256k1Free }; diff --git a/src/cryptoconditions/src/threshold.c b/src/cryptoconditions/src/threshold.c index 1efe9f9e8..82ef3d736 100644 --- a/src/cryptoconditions/src/threshold.c +++ b/src/cryptoconditions/src/threshold.c @@ -8,7 +8,7 @@ #include "internal.h" -struct CCType cc_thresholdType; +struct CCType CC_ThresholdType; static uint32_t thresholdSubtypes(const CC *cond) { @@ -120,7 +120,7 @@ static CC *thresholdFromFulfillment(const Fulfillment_t *ffill) { } CC *cond = calloc(1, sizeof(CC)); - cond->type = &cc_thresholdType; + cond->type = &CC_ThresholdType; cond->threshold = threshold; cond->size = size; cond->subconditions = subconditions; @@ -174,7 +174,7 @@ static CC *thresholdFromJSON(const cJSON *params, unsigned char *err) { } CC *cond = calloc(1, sizeof(CC)); - cond->type = &cc_thresholdType; + cond->type = &CC_ThresholdType; cond->threshold = (long) threshold_item->valuedouble; cond->size = cJSON_GetArraySize(subfulfillments_item); cond->subconditions = calloc(cond->size, sizeof(CC*)); @@ -222,4 +222,4 @@ static void thresholdFree(CC *cond) { } -struct CCType cc_thresholdType = { 2, "threshold-sha-256", Condition_PR_thresholdSha256, &thresholdVisitChildren, &thresholdFingerprint, &thresholdCost, &thresholdSubtypes, &thresholdFromJSON, &thresholdToJSON, &thresholdFromFulfillment, &thresholdToFulfillment, &thresholdIsFulfilled, &thresholdFree }; +struct CCType CC_ThresholdType = { 2, "threshold-sha-256", Condition_PR_thresholdSha256, &thresholdVisitChildren, &thresholdFingerprint, &thresholdCost, &thresholdSubtypes, &thresholdFromJSON, &thresholdToJSON, &thresholdFromFulfillment, &thresholdToFulfillment, &thresholdIsFulfilled, &thresholdFree }; From 375927407bca42e268e7e2f6072563b472c31205 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Tue, 3 Apr 2018 04:48:24 -0300 Subject: [PATCH 057/339] betprotocol functions --- src/cc/betprotocol.cpp | 240 ++++++++++++++++++ src/cc/importpayout.cpp | 31 +-- src/cc/importpayout.h | 26 ++ src/cryptoconditions/README.md | 2 +- .../include/cryptoconditions.h | 2 +- src/cryptoconditions/src/anon.c | 3 +- src/cryptoconditions/src/cryptoconditions.c | 7 +- src/cryptoconditions/src/ed25519.c | 6 +- src/cryptoconditions/src/eval.c | 6 +- src/cryptoconditions/src/prefix.c | 6 +- src/cryptoconditions/src/preimage.c | 6 +- src/cryptoconditions/src/secp256k1.c | 3 +- src/cryptoconditions/src/threshold.c | 6 +- src/komodo_notary.h | 1 + src/rpcblockchain.cpp | 78 ++++++ src/rpcclient.cpp | 1 + src/rpcserver.cpp | 1 + src/rpcserver.h | 1 + 18 files changed, 371 insertions(+), 55 deletions(-) create mode 100644 src/cc/betprotocol.cpp create mode 100644 src/cc/importpayout.h diff --git a/src/cc/betprotocol.cpp b/src/cc/betprotocol.cpp new file mode 100644 index 000000000..024b4c001 --- /dev/null +++ b/src/cc/betprotocol.cpp @@ -0,0 +1,240 @@ +#include + +#include "primitives/transaction.h" + + +class DisputeHeader +{ +public: + int waitBlocks; + std::vector vmParams; + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(VARINT(waitBlocks)); + READWRITE(vmParams); + } +}; + + +static CScript CCPubKey(const CC *cond) +{ + unsigned char buf[1000]; + size_t len = cc_conditionBinary(cond, buf); + return CScript() << std::vector(buf, buf+len) << OP_CHECKCRYPTOCONDITION; +} + + +static CScript CCSig(const CC *cond) +{ + unsigned char buf[1000]; + size_t len = cc_fulfillmentBinary(cond, buf, 1000); + auto ffill = std::vector(buf, buf+len); + ffill.push_back(SIGHASH_ALL); + return CScript() << ffill; +} + + +static unsigned char* CopyPubKey(CPubKey pkIn) +{ + auto *pk = malloc(33); + memcpy(pk, pkIn.begin(), 33); // TODO: compressed? + return pk; +} + + +class PokerProtocol +{ +public: + CAmount MINFEE = 1; + std::vector players; + DisputeHeader disputeHeader; + + // on PANGEA + CC* MakeDisputeCond(); + CMutableTransaction MakeSessionTx(CTxIn dealerInput); + CMutableTransaction MakeDisputeTx(uint256 signedSessionTxHash); + CMutableTransaction MakePostEvidenceTx(uint256 signedSessionTxHash, + CPubKey playerKey, std::vector state); + + // on KMD + CC* MakePayoutCond(); + CMutableTransaction MakeStakeTx(CAmount totalPayout, std::vector playerInputs, + uint256 signedSessionTx); + CMutableTransaction MakeAgreePayoutTx(std::vector payouts, + CC *signedPayoutCond, uint256 signedStakeTxHash); + CMutableTransaction MakeImportPayoutTx(std::vector payouts, + CC *signedPayoutCond, CTransaction signedDisputeTx); +} + + +CC* PokerProtocol::MakeDisputeCond() +{ + CC *disputePoker = cond->subconditions[0] = cc_new(CC_Eval); + char err[1000]; + std::vector headerData; + disputeHeader >> CDataStream(headerData, SER_DISK, PROTOCOL_VERSION); + disputePoker->paramsBin = malloc(headerData.size()); + memcpy(disputePoker->paramsBin, headerData.data()); + disputePoker.paramsBinLength = headerData.size(); + + CC *spendSig = cond->subconditions[1] = cc_new(CC_Threshold); + spendSig->threshold = 1; + spendSig->size = players.size() + 1; + spendSig->subconditions = malloc(spendSig->size, sizeof(CC*)); + + for (int i=0; isubconditions[i] = cc_new(CC_Secp256k1); + sub->publicKey = CopyPubKey(players[i]); + } + + CC *cond = cc_new(CC_Threshold); + cond->threshold = 2; + cond->size = 2; + cond->subconditions = calloc(2, sizeof(CC*)); + cond->subconditions[0] = disputePoker; + cond->subconditions[1] = spendSig; + return cond; +} + + +CMutableTransaction PokerProtocol::MakeSessionTx(CTxIn dealerInput) +{ + CMutableTransaction mtx; + mtx.vin.push_back(dealerInput); + + CC *disputeCond = MakeDisputeCond(players, disputeHeader); + mtx.vout.push_back(CTxOut(MINFEE, CCPubKey(disputeCond))); + cc_free(disputeCond); + + for (int i=0; ipublicKey = CopyPubKey(players[i]); + mtx.vout.push_back(CTxOut(MINFEE, CCPubKey(cond))); + cc_free(cond); + } + return mtx; +} + + +CMutableTransaction PokerProtocol::MakeDisputeTx(uint256 signedSessionTxHash, CC *signedDisputeCond, uint256 vmResultHash) +{ + CMutableTransaction mtx; + + CC *disputeCond = MakeDisputeCond(); + mtx.vin.push_back(CTxIn(signedSessionTxHash, 0, CCSig(signedDisputeCond))); + + std::vector result(vmResultHash.begin(), vmResultHash.begin()+32); + mtx.vout.push_back(CTxOut(0, CScript() << OP_RETURN << result)); + return mtx; +} + + +CMutableTransaction PokerProtocol::MakePostEvidenceTx(uint256 signedSessionTxHash, + int playerIdx, std::vector state) +{ + CMutableTransaction mtx; + + CC *cond = cc_new(CC_Secp256k1); + cond->publicKey = CopyPubKey(players[i]); + mtx.vin.push_back(CTxIn(signedSessionTxHash, playerIdx+1, CCSig(cond))); + + mtx.vout.push_back(CTxOut(0, CScript() << OP_RETURN << state)); + + return mtx; +} + +CC* CCNewThreshold(int t, std::vector v) +{ + CC *cond = cc_new(CC_Threshold); + cond->threshold = t; + cond->size = v.size(); + cond->subconditions = calloc(1, sizeof(CC*)); + memcpy(cond->subconditions, v.data(), v.size() * sizeof(CC*)); + return cond; +} + + +CCNewSecp256k1(CPubKey &k) +{ + cond = cc_new(CC_Secp256k1); + cond->publicKey = CopyPubKey(players[i]); + return cond; +} + + +CCNewEval(char *method, unsigned char* paramsBin, size_t len) +{ + CC *cond = cc_new(CC_Eval); + strcpy(cond->method, method); + cond->paramsBin = malloc(32); + memcpy(cond->paramsBin, bin, len); + cond->paramsBinLength = len; + return cond; +} + + +CC* MakePayoutCond(uint256 signedSessionTx) +{ + CC* agree; + { + // TODO: 2/3 majority + std::vector subs; + for (int i=0; i subs; + for (int i=0; i playerInputs, + uint256 signedSessionTx) +{ + CMutableTransaction mtx; + mtx.vin = playerInputs; + + CC *payoutCond = MakePayoutCond(signedSessionTx);push + mtx.vout.push_back(CTxOut(totalPayout, CCPubKey(payoutCond))); + cc_free(payoutCond); + + return mtx; +} + + +CMutableTransaction PokerProtocol::MakeAgreePayoutTx(std::vector payouts, + CC *signedPayoutCond, uint256 signedStakeTxHash) +{ + CMutableTransaction mtx; + mtx.vin.push_back(CTxIn(signedStakeTxHash, 0, CCSig(signedPayoutCond))); + mtx.vouts = payouts; + return mtx; +} + + +CMutableTransaction PokerProtocol::MakeImportPayoutTx(std::vector payouts, + CC *signedPayoutCond, CTransaction signedDisputeTx, uint256 signedStakeTxHash) +{ + std::vector vDisputeTx; + signedDisputeTx >> CDataStream(vDisputeTx, SER_DISK, PROTOCOL_VERSION); + CMutableTransaction mtx; + mtx.vin.push_back(CTxInput(signedStakeTxHash, 0, CCSig(signedPayoutCond))); + mtx.vout = payouts; + CMutableTransaction.vout.insert(0, CTxOutput(0, CScript() << OP_RETURN << "PROOF HERE")); + CMutableTransaction.vout.insert(1, CTxOutput(0, CScript() << OP_RETURN << vDisputeTx)); +} diff --git a/src/cc/importpayout.cpp b/src/cc/importpayout.cpp index ee8913744..f05abb943 100644 --- a/src/cc/importpayout.cpp +++ b/src/cc/importpayout.cpp @@ -3,27 +3,10 @@ #include "chain.h" #include "main.h" #include "cc/eval.h" +#include "cc/importpayout.h" #include "cryptoconditions/include/cryptoconditions.h" -class MomProof -{ -public: - uint256 notaryHash; - int nPos; // Position of imported tx in MoM - std::vector branch; - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(notaryHash); - READWRITE(VARINT(nPos)); - READWRITE(branch); - } -}; - - extern int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp); bool DerefNotaryPubkey(const COutPoint &prevout, char *pk33) @@ -89,11 +72,7 @@ bool GetMoM(const uint256 notaryHash, uint256 &mom) return 1; } - -uint256 ExecMerkle(uint256 hash, const std::vector& vMerkleBranch, int nIndex) -{ - return CBlock::CheckMerkleBranch(hash, vMerkleBranch, nIndex); -} +#define ExecMerkle CBlock::CheckMerkleBranch /* @@ -157,13 +136,13 @@ bool CheckImportPayout(const CC *cond, const CTransaction *payoutTx, int nIn) std::vector vchMomProof; if (!GetOpReturnData(payoutTx->vout[0].scriptPubKey, vchMomProof)) return 0; - MomProof momProof; + MoMProof momProof; CDataStream(vchMomProof, SER_DISK, PROTOCOL_VERSION) >> momProof; uint256 mom; - if (!GetMoM(momProof.notaryHash, mom)) return 0; + if (!GetMoM(momProof.notarisationHash, mom)) return 0; - uint256 proofResult = ExecMerkle(disputeTx.GetHash(), momProof.branch, momProof.nPos); + uint256 proofResult = ExecMerkle(disputeTx.GetHash(), momProof.branch, momProof.nIndex); if (proofResult != mom) return 0; } diff --git a/src/cc/importpayout.h b/src/cc/importpayout.h new file mode 100644 index 000000000..3ae094e80 --- /dev/null +++ b/src/cc/importpayout.h @@ -0,0 +1,26 @@ +#ifndef KOMODO_TXPROOF_H +#define KOMODO_TXPROOF_H + + +class MoMProof +{ +public: + int nIndex; + std::vector branch; + uint256 notarisationHash; + + MoMProof() {} + MoMProof(int i, std::vector b, uint256 n) : notarisationHash(n), nIndex(i), branch(b) {} + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(VARINT(nIndex)); + READWRITE(branch); + READWRITE(notarisationHash); + } +}; + + +#endif /* KOMODO_TXPROOF_H */ diff --git a/src/cryptoconditions/README.md b/src/cryptoconditions/README.md index 45418b62a..9ec2a6a5f 100644 --- a/src/cryptoconditions/README.md +++ b/src/cryptoconditions/README.md @@ -17,7 +17,7 @@ make ## Status -JSON interface not particularly safe. The rest is getting there. +JSON interface may not be particularly safe. The rest is pretty good now. ## Embedding diff --git a/src/cryptoconditions/include/cryptoconditions.h b/src/cryptoconditions/include/cryptoconditions.h index 1af542b03..439fe3f4a 100644 --- a/src/cryptoconditions/include/cryptoconditions.h +++ b/src/cryptoconditions/include/cryptoconditions.h @@ -16,7 +16,7 @@ struct CCType; enum CCTypeId { - CC_Condition = -1, + CC_Anon = -1, CC_Preimage = 0, CC_Prefix = 1, CC_Threshold = 2, diff --git a/src/cryptoconditions/src/anon.c b/src/cryptoconditions/src/anon.c index c9baa6245..38f8e8543 100644 --- a/src/cryptoconditions/src/anon.c +++ b/src/cryptoconditions/src/anon.c @@ -17,8 +17,7 @@ static CC *mkAnon(const Condition_t *asnCond) { printf("Unknown ASN type: %i", asnCond->present); return 0; } - CC *cond = calloc(1, sizeof(CC)); - cond->type = &CC_AnonType; + CC *cond = cc_new(CC_Anon); cond->conditionType = realType; const CompoundSha256Condition_t *deets = &asnCond->choice.thresholdSha256; memcpy(cond->fingerprint, deets->fingerprint.buf, 32); diff --git a/src/cryptoconditions/src/cryptoconditions.c b/src/cryptoconditions/src/cryptoconditions.c index f993b277f..622f09530 100644 --- a/src/cryptoconditions/src/cryptoconditions.c +++ b/src/cryptoconditions/src/cryptoconditions.c @@ -255,7 +255,7 @@ CC *cc_readConditionBinary(const unsigned char *cond_bin, size_t length) { int cc_isAnon(const CC *cond) { - return cond->type->typeId == CC_Condition; + return cond->type->typeId == CC_Anon; } @@ -281,9 +281,10 @@ char *cc_typeName(const CC *cond) { return cc_isAnon(cond) ? cond->conditionType->name : cond->type->name; } + CC *cc_new(int typeId) { - CC *cond = malloc(sizeof(CC*)); - cond->type = CCTypeRegistry[type]; + CC *cond = calloc(1, sizeof(CC)); + cond->type = CCTypeRegistry[typeId]; return cond; } diff --git a/src/cryptoconditions/src/ed25519.c b/src/cryptoconditions/src/ed25519.c index 541c9b896..18a75fd5c 100644 --- a/src/cryptoconditions/src/ed25519.c +++ b/src/cryptoconditions/src/ed25519.c @@ -104,8 +104,7 @@ static CC *ed25519FromJSON(const cJSON *params, unsigned char *err) { } } - CC *cond = calloc(1, sizeof(CC)); - cond->type = &CC_Ed25519Type; + CC *cond = cc_new(CC_Ed25519); cond->publicKey = pk; cond->signature = sig; return cond; @@ -125,8 +124,7 @@ static void ed25519ToJSON(const CC *cond, cJSON *params) { static CC *ed25519FromFulfillment(const Fulfillment_t *ffill) { - CC *cond = calloc(1, sizeof(CC)); - cond->type = &CC_Ed25519Type; + CC *cond = cc_new(CC_Ed25519); cond->publicKey = malloc(32); memcpy(cond->publicKey, ffill->choice.ed25519Sha256.publicKey.buf, 32); cond->signature = malloc(64); diff --git a/src/cryptoconditions/src/eval.c b/src/cryptoconditions/src/eval.c index 14db14c70..92a1c6e70 100644 --- a/src/cryptoconditions/src/eval.c +++ b/src/cryptoconditions/src/eval.c @@ -42,11 +42,10 @@ static CC *evalFromJSON(const cJSON *params, unsigned char *err) { return NULL; } - CC *cond = calloc(1, sizeof(CC)); + CC *cond = cc_new(CC_Eval); strcpy(cond->method, method_item->valuestring); cond->paramsBin = paramsBin; cond->paramsBinLength = paramsBinLength; - cond->type = &CC_EvalType; return cond; } @@ -64,8 +63,7 @@ static void evalToJSON(const CC *cond, cJSON *params) { static CC *evalFromFulfillment(const Fulfillment_t *ffill) { - CC *cond = calloc(1, sizeof(CC)); - cond->type = &CC_EvalType; + CC *cond = cc_new(CC_Eval); EvalFulfillment_t *eval = &ffill->choice.evalSha256; diff --git a/src/cryptoconditions/src/prefix.c b/src/cryptoconditions/src/prefix.c index d8d8b7aad..15a7fa2b7 100644 --- a/src/cryptoconditions/src/prefix.c +++ b/src/cryptoconditions/src/prefix.c @@ -42,8 +42,7 @@ static CC *prefixFromFulfillment(const Fulfillment_t *ffill) { PrefixFulfillment_t *p = ffill->choice.prefixSha256; CC *sub = fulfillmentToCC(p->subfulfillment); if (!sub) return 0; - CC *cond = calloc(1, sizeof(CC)); - cond->type = &CC_PrefixType; + CC *cond = cc_new(CC_Prefix); cond->maxMessageLength = p->maxMessageLength; cond->prefix = calloc(1, p->prefix.size); memcpy(cond->prefix, p->prefix.buf, p->prefix.size); @@ -88,8 +87,7 @@ static CC *prefixFromJSON(const cJSON *params, unsigned char *err) { return NULL; } - CC *cond = calloc(1, sizeof(CC)); - cond->type = &CC_PrefixType; + CC *cond = cc_new(CC_Prefix); cond->maxMessageLength = (unsigned long) mml_item->valuedouble; cond->subcondition = sub; diff --git a/src/cryptoconditions/src/preimage.c b/src/cryptoconditions/src/preimage.c index 639bd1009..39953e815 100644 --- a/src/cryptoconditions/src/preimage.c +++ b/src/cryptoconditions/src/preimage.c @@ -18,8 +18,7 @@ static CC *preimageFromJSON(const cJSON *params, unsigned char *err) { } unsigned char *preimage_b64 = preimage_item->valuestring; - CC *cond = calloc(1, sizeof(CC)); - cond->type = &CC_PreimageType; + CC *cond = cc_new(CC_Preimage); cond->preimage = base64_decode(preimage_b64, &cond->preimageLength); return cond; } @@ -45,8 +44,7 @@ static unsigned char *preimageFingerprint(const CC *cond) { static CC *preimageFromFulfillment(const Fulfillment_t *ffill) { - CC *cond = calloc(1, sizeof(CC)); - cond->type = &CC_PreimageType; + CC *cond = cc_new(CC_Preimage); PreimageFulfillment_t p = ffill->choice.preimageSha256; cond->preimage = calloc(1, p.preimage.size); memcpy(cond->preimage, p.preimage.buf, p.preimage.size); diff --git a/src/cryptoconditions/src/secp256k1.c b/src/cryptoconditions/src/secp256k1.c index f83397db8..78fbd7602 100644 --- a/src/cryptoconditions/src/secp256k1.c +++ b/src/cryptoconditions/src/secp256k1.c @@ -202,8 +202,7 @@ static CC *cc_secp256k1Condition(const unsigned char *publicKey, const unsigned memcpy(sig, signature, SECP256K1_SIG_SIZE); } - CC *cond = calloc(1, sizeof(CC)); - cond->type = &CC_Secp256k1Type; + CC *cond = cc_new(CC_Secp256k1); cond->publicKey = pk; cond->signature = sig; return cond; diff --git a/src/cryptoconditions/src/threshold.c b/src/cryptoconditions/src/threshold.c index 82ef3d736..da8a3027a 100644 --- a/src/cryptoconditions/src/threshold.c +++ b/src/cryptoconditions/src/threshold.c @@ -119,8 +119,7 @@ static CC *thresholdFromFulfillment(const Fulfillment_t *ffill) { } } - CC *cond = calloc(1, sizeof(CC)); - cond->type = &CC_ThresholdType; + CC *cond = cc_new(CC_Threshold); cond->threshold = threshold; cond->size = size; cond->subconditions = subconditions; @@ -173,8 +172,7 @@ static CC *thresholdFromJSON(const cJSON *params, unsigned char *err) { return NULL; } - CC *cond = calloc(1, sizeof(CC)); - cond->type = &CC_ThresholdType; + CC *cond = cc_new(CC_Threshold); cond->threshold = (long) threshold_item->valuedouble; cond->size = cJSON_GetArraySize(subfulfillments_item); cond->subconditions = calloc(cond->size, sizeof(CC*)); diff --git a/src/komodo_notary.h b/src/komodo_notary.h index 638327e81..dbaa5f2e4 100644 --- a/src/komodo_notary.h +++ b/src/komodo_notary.h @@ -419,6 +419,7 @@ int32_t komodo_notarized_height(uint256 *hashp,uint256 *txidp) } } + int32_t komodo_MoMdata(int32_t *notarized_htp,uint256 *MoMp,uint256 *kmdtxidp,int32_t height) { int32_t i; char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; struct komodo_state *sp; struct notarized_checkpoint *np = 0; diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 1254217ac..30d2c0aab 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -8,6 +8,7 @@ #include "chainparams.h" #include "checkpoints.h" #include "consensus/validation.h" +#include "cc/importpayout.h" #include "main.h" #include "primitives/transaction.h" #include "rpcserver.h" @@ -621,6 +622,83 @@ UniValue height_MoM(const UniValue& params, bool fHelp) return ret; } +UniValue txMoMproof(const UniValue& params, bool fHelp) +{ + uint256 hash, notarisationHash, MoM; + int32_t notarisedHeight, depth; + CBlockIndex* blockIndex; + std::vector branch; + int nIndex; + + // parse params and get notarisation data for tx + { + if ( fHelp || params.size() != 1) + throw runtime_error("txmomproof needs a txid"); + + uint256 hash(uint256S(params[0].get_str())); + + uint256 blockHash; + CTransaction tx; + if (!GetTransaction(hash, tx, blockHash, true)) + throw runtime_error("cannot find transaction"); + + blockIndex = mapBlockIndex[blockHash]; + + depth = komodo_MoM(¬arisedHeight, &MoM, ¬arisationHash, blockIndex->nHeight); + + if (!depth) + throw runtime_error("notarisation not found"); + + // index of block in MoM leaves + nIndex = notarisedHeight - blockIndex->nHeight; + } + + // build merkle chain from blocks to MoM + { + // since the merkle branch code is tied up in a block class + // and we want to make a merkle branch for something that isnt transactions + CBlock fakeBlock; + for (int i=0; ihashMerkleRoot; + CTransaction fakeTx; + // first value in CTransaction memory is it's hash + memcpy((void*)&fakeTx, mRoot.begin(), 32); + fakeBlock.vtx.push_back(fakeTx); + } + branch = fakeBlock.GetMerkleBranch(nIndex); + } + + // Now get the tx merkle branch + { + CBlock block; + + if (fHavePruned && !(blockIndex->nStatus & BLOCK_HAVE_DATA) && blockIndex->nTx > 0) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Block not available (pruned data)"); + + if(!ReadBlockFromDisk(block, blockIndex)) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); + + // Locate the transaction in the block + int nTxIndex; + for (nTxIndex = 0; nTxIndex < (int)block.vtx.size(); nTxIndex++) + if (block.vtx[nTxIndex].GetHash() == hash) + break; + + if (nTxIndex == (int)block.vtx.size()) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Error locating tx in block"); + + // concatenate branches + std::vector txBranch = block.GetMerkleBranch(nTxIndex); + nIndex = nIndex << txBranch.size() + nTxIndex; + branch.insert(branch.begin(), txBranch.begin(), txBranch.end()); + } + + // Encode and return + CDataStream ssProof(SER_NETWORK, PROTOCOL_VERSION); + ssProof << MoMProof(nIndex, branch, notarisationHash); + return HexStr(ssProof.begin(), ssProof.end()); +} + 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]; diff --git a/src/rpcclient.cpp b/src/rpcclient.cpp index 13e9c357b..6a83e8c19 100644 --- a/src/rpcclient.cpp +++ b/src/rpcclient.cpp @@ -126,6 +126,7 @@ static const CRPCConvertParam vRPCConvertParams[] = { "paxpending", 0 }, { "notaries", 2 }, { "height_MoM", 1 }, + { "txMoMproof", 1 }, { "minerids", 1 }, { "kvsearch", 1 }, { "kvupdate", 4 }, diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 716992082..5d573f62b 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -297,6 +297,7 @@ static const CRPCCommand vRPCCommands[] = { "blockchain", "paxprices", &paxprices, true }, { "blockchain", "notaries", ¬aries, true }, { "blockchain", "height_MoM", &height_MoM, true }, + { "blockchain", "txMoMproof", &txMoMproof, true }, { "blockchain", "minerids", &minerids, true }, { "blockchain", "kvsearch", &kvsearch, true }, { "blockchain", "kvupdate", &kvupdate, true }, diff --git a/src/rpcserver.h b/src/rpcserver.h index 1f6bd2f94..b4e6ed8fc 100644 --- a/src/rpcserver.h +++ b/src/rpcserver.h @@ -305,6 +305,7 @@ extern UniValue z_getpaymentdisclosure(const UniValue& params, bool fHelp); // i extern UniValue z_validatepaymentdisclosure(const UniValue ¶ms, bool fHelp); // in rpcdisclosure.cpp extern UniValue height_MoM(const UniValue& params, bool fHelp); +extern UniValue txMoMproof(const UniValue& params, bool fHelp); extern UniValue notaries(const UniValue& params, bool fHelp); extern UniValue minerids(const UniValue& params, bool fHelp); extern UniValue kvsearch(const UniValue& params, bool fHelp); From 50045b3671d71e6ee18ee9e8b9650f40e5820a32 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 4 Apr 2018 18:59:09 +0300 Subject: [PATCH 058/339] Disable cross chain checking of notarization, libscott says it is ok --- src/komodo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo.h b/src/komodo.h index ded368381..8ec38587c 100644 --- a/src/komodo.h +++ b/src/komodo.h @@ -573,7 +573,7 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr { notarized = 1; } - if ( notarized != 0 && *notarizedheightp > sp->NOTARIZED_HEIGHT && *notarizedheightp < height && (height < sp->CURRENT_HEIGHT-64 || komodo_verifynotarization(ASSETCHAINS_SYMBOL[0]==0?(char *)"KMD":ASSETCHAINS_SYMBOL,(char *)(ASSETCHAINS_SYMBOL[0] == 0 ? "BTC" : "KMD"),height,*notarizedheightp,kmdtxid,desttxid) == 0) ) + if ( notarized != 0 && *notarizedheightp > sp->NOTARIZED_HEIGHT && *notarizedheightp < height ) //&& (height < sp->CURRENT_HEIGHT-64 || komodo_verifynotarization(ASSETCHAINS_SYMBOL[0]==0?(char *)"KMD":ASSETCHAINS_SYMBOL,(char *)(ASSETCHAINS_SYMBOL[0] == 0 ? "BTC" : "KMD"),height,*notarizedheightp,kmdtxid,desttxid) == 0) ) { int32_t nameoffset = (int32_t)strlen(ASSETCHAINS_SYMBOL) + 1; sp->NOTARIZED_HEIGHT = *notarizedheightp; From a3bf7b967a7bd532ba39b7aa4cbd757012ce74cd Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 4 Apr 2018 19:36:16 +0300 Subject: [PATCH 059/339] Enable KMD validation for KMD --- src/komodo.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/komodo.h b/src/komodo.h index 8ec38587c..78e0006ba 100644 --- a/src/komodo.h +++ b/src/komodo.h @@ -573,7 +573,12 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr { notarized = 1; } - if ( notarized != 0 && *notarizedheightp > sp->NOTARIZED_HEIGHT && *notarizedheightp < height ) //&& (height < sp->CURRENT_HEIGHT-64 || komodo_verifynotarization(ASSETCHAINS_SYMBOL[0]==0?(char *)"KMD":ASSETCHAINS_SYMBOL,(char *)(ASSETCHAINS_SYMBOL[0] == 0 ? "BTC" : "KMD"),height,*notarizedheightp,kmdtxid,desttxid) == 0) ) + int32_t validated = 0; + if ( ASSETCHAINS_SYMBOL[0] != 0 ) + validated = 1; + else if ( height < sp->CURRENT_HEIGHT-64 || komodo_verifynotarization((char *)"KMD",(char *)"BTC",height,*notarizedheightp,kmdtxid,desttxid) == 0 ) + validated = 1; + if ( notarized != 0 && *notarizedheightp > sp->NOTARIZED_HEIGHT && *notarizedheightp < height && validated != 0 ) { int32_t nameoffset = (int32_t)strlen(ASSETCHAINS_SYMBOL) + 1; sp->NOTARIZED_HEIGHT = *notarizedheightp; From 561f3e18c1ec34e379640e491ddf836a3e3fd5e2 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Thu, 5 Apr 2018 05:06:22 -0300 Subject: [PATCH 060/339] tests for bet protocol done; verify notarisation still to test --- src/Makefile.am | 2 +- src/Makefile.ktest.include | 3 +- src/cc/betprotocol.cpp | 229 +++---- src/cc/betprotocol.h | 85 +++ src/cc/disputepayout.cpp | 88 ++- src/cc/eval.cpp | 137 +++- src/cc/eval.h | 92 ++- src/cc/importpayout.cpp | 136 +--- src/cc/importpayout.h | 26 - .../include/cryptoconditions.h | 1 + src/cryptoconditions/src/cryptoconditions.c | 2 +- src/cryptoconditions/src/threshold.c | 12 +- src/komodo_cc.cpp | 69 ++ src/komodo_cc.h | 39 ++ src/rpcblockchain.cpp | 2 +- src/script/interpreter.cpp | 16 +- src/script/interpreter.h | 5 +- src/script/serverchecker.cpp | 11 +- src/script/serverchecker.h | 7 +- src/test-komodo/main.cpp | 10 +- src/test-komodo/test_bet.cpp | 596 ++++++++++++++++++ src/test-komodo/test_cryptoconditions.cpp | 55 +- src/test-komodo/testutils.h | 15 + 23 files changed, 1195 insertions(+), 443 deletions(-) create mode 100644 src/cc/betprotocol.h delete mode 100644 src/cc/importpayout.h create mode 100644 src/test-komodo/test_bet.cpp create mode 100644 src/test-komodo/testutils.h diff --git a/src/Makefile.am b/src/Makefile.am index 092015600..07150d0c6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -163,7 +163,6 @@ BITCOIN_CORE_H = \ init.h \ key.h \ keystore.h \ - komodo_cc.h \ leveldbwrapper.h \ limitedmap.h \ main.h \ @@ -253,6 +252,7 @@ libbitcoin_server_a_SOURCES = \ cc/eval.cpp \ cc/importpayout.cpp \ cc/disputepayout.cpp \ + cc/betprotocol.cpp \ chain.cpp \ checkpoints.cpp \ deprecation.cpp \ diff --git a/src/Makefile.ktest.include b/src/Makefile.ktest.include index 3ae3d9be8..cef80b0d1 100644 --- a/src/Makefile.ktest.include +++ b/src/Makefile.ktest.include @@ -5,7 +5,8 @@ bin_PROGRAMS += komodo-test # tool for generating our public parameters komodo_test_SOURCES = \ test-komodo/main.cpp \ - test-komodo/test_cryptoconditions.cpp + test-komodo/test_cryptoconditions.cpp \ + test-komodo/test_bet.cpp komodo_test_CPPFLAGS = $(komodod_CPPFLAGS) diff --git a/src/cc/betprotocol.cpp b/src/cc/betprotocol.cpp index 024b4c001..92ec961ee 100644 --- a/src/cc/betprotocol.cpp +++ b/src/cc/betprotocol.cpp @@ -1,117 +1,79 @@ #include +#include "streams.h" +#include "komodo_cc.h" +#include "cc/eval.h" +#include "cc/betprotocol.h" #include "primitives/transaction.h" -class DisputeHeader -{ -public: - int waitBlocks; - std::vector vmParams; - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(VARINT(waitBlocks)); - READWRITE(vmParams); - } -}; - - -static CScript CCPubKey(const CC *cond) -{ - unsigned char buf[1000]; - size_t len = cc_conditionBinary(cond, buf); - return CScript() << std::vector(buf, buf+len) << OP_CHECKCRYPTOCONDITION; -} - - -static CScript CCSig(const CC *cond) -{ - unsigned char buf[1000]; - size_t len = cc_fulfillmentBinary(cond, buf, 1000); - auto ffill = std::vector(buf, buf+len); - ffill.push_back(SIGHASH_ALL); - return CScript() << ffill; -} - - static unsigned char* CopyPubKey(CPubKey pkIn) { - auto *pk = malloc(33); + unsigned char* pk = (unsigned char*) malloc(33); memcpy(pk, pkIn.begin(), 33); // TODO: compressed? return pk; } -class PokerProtocol +CC* CCNewThreshold(int t, std::vector v) { -public: - CAmount MINFEE = 1; - std::vector players; - DisputeHeader disputeHeader; - - // on PANGEA - CC* MakeDisputeCond(); - CMutableTransaction MakeSessionTx(CTxIn dealerInput); - CMutableTransaction MakeDisputeTx(uint256 signedSessionTxHash); - CMutableTransaction MakePostEvidenceTx(uint256 signedSessionTxHash, - CPubKey playerKey, std::vector state); - - // on KMD - CC* MakePayoutCond(); - CMutableTransaction MakeStakeTx(CAmount totalPayout, std::vector playerInputs, - uint256 signedSessionTx); - CMutableTransaction MakeAgreePayoutTx(std::vector payouts, - CC *signedPayoutCond, uint256 signedStakeTxHash); - CMutableTransaction MakeImportPayoutTx(std::vector payouts, - CC *signedPayoutCond, CTransaction signedDisputeTx); -} - - -CC* PokerProtocol::MakeDisputeCond() -{ - CC *disputePoker = cond->subconditions[0] = cc_new(CC_Eval); - char err[1000]; - std::vector headerData; - disputeHeader >> CDataStream(headerData, SER_DISK, PROTOCOL_VERSION); - disputePoker->paramsBin = malloc(headerData.size()); - memcpy(disputePoker->paramsBin, headerData.data()); - disputePoker.paramsBinLength = headerData.size(); - - CC *spendSig = cond->subconditions[1] = cc_new(CC_Threshold); - spendSig->threshold = 1; - spendSig->size = players.size() + 1; - spendSig->subconditions = malloc(spendSig->size, sizeof(CC*)); - - for (int i=0; isubconditions[i] = cc_new(CC_Secp256k1); - sub->publicKey = CopyPubKey(players[i]); - } - CC *cond = cc_new(CC_Threshold); - cond->threshold = 2; - cond->size = 2; - cond->subconditions = calloc(2, sizeof(CC*)); - cond->subconditions[0] = disputePoker; - cond->subconditions[1] = spendSig; + cond->threshold = t; + cond->size = v.size(); + cond->subconditions = (CC**) calloc(v.size(), sizeof(CC*)); + memcpy(cond->subconditions, v.data(), v.size() * sizeof(CC*)); return cond; } -CMutableTransaction PokerProtocol::MakeSessionTx(CTxIn dealerInput) +CC* CCNewSecp256k1(CPubKey k) +{ + CC *cond = cc_new(CC_Secp256k1); + cond->publicKey = CopyPubKey(k); + return cond; +} + + +CC* CCNewEval(std::string method, std::vector paramsBin) +{ + CC *cond = cc_new(CC_Eval); + strcpy(cond->method, method.data()); + cond->paramsBin = (unsigned char*) malloc(paramsBin.size()); + memcpy(cond->paramsBin, paramsBin.data(), paramsBin.size()); + cond->paramsBinLength = paramsBin.size(); + return cond; +} + + +std::vector BetProtocol::PlayerConditions() +{ + std::vector subs; + for (int i=0; ipublicKey = CopyPubKey(players[i]); + CC *cond = CCNewSecp256k1(players[i]); mtx.vout.push_back(CTxOut(MINFEE, CCPubKey(cond))); cc_free(cond); } @@ -119,12 +81,12 @@ CMutableTransaction PokerProtocol::MakeSessionTx(CTxIn dealerInput) } -CMutableTransaction PokerProtocol::MakeDisputeTx(uint256 signedSessionTxHash, CC *signedDisputeCond, uint256 vmResultHash) +CMutableTransaction BetProtocol::MakeDisputeTx(uint256 signedSessionTxHash, uint256 vmResultHash) { CMutableTransaction mtx; CC *disputeCond = MakeDisputeCond(); - mtx.vin.push_back(CTxIn(signedSessionTxHash, 0, CCSig(signedDisputeCond))); + mtx.vin.push_back(CTxIn(signedSessionTxHash, 0, CScript())); std::vector result(vmResultHash.begin(), vmResultHash.begin()+32); mtx.vout.push_back(CTxOut(0, CScript() << OP_RETURN << result)); @@ -132,69 +94,29 @@ CMutableTransaction PokerProtocol::MakeDisputeTx(uint256 signedSessionTxHash, CC } -CMutableTransaction PokerProtocol::MakePostEvidenceTx(uint256 signedSessionTxHash, +CMutableTransaction BetProtocol::MakePostEvidenceTx(uint256 signedSessionTxHash, int playerIdx, std::vector state) { CMutableTransaction mtx; - CC *cond = cc_new(CC_Secp256k1); - cond->publicKey = CopyPubKey(players[i]); - mtx.vin.push_back(CTxIn(signedSessionTxHash, playerIdx+1, CCSig(cond))); - + mtx.vin.push_back(CTxIn(signedSessionTxHash, playerIdx+1, CScript())); mtx.vout.push_back(CTxOut(0, CScript() << OP_RETURN << state)); return mtx; } -CC* CCNewThreshold(int t, std::vector v) + +CC* BetProtocol::MakePayoutCond(uint256 signedSessionTxHash) { - CC *cond = cc_new(CC_Threshold); - cond->threshold = t; - cond->size = v.size(); - cond->subconditions = calloc(1, sizeof(CC*)); - memcpy(cond->subconditions, v.data(), v.size() * sizeof(CC*)); - return cond; -} - - -CCNewSecp256k1(CPubKey &k) -{ - cond = cc_new(CC_Secp256k1); - cond->publicKey = CopyPubKey(players[i]); - return cond; -} - - -CCNewEval(char *method, unsigned char* paramsBin, size_t len) -{ - CC *cond = cc_new(CC_Eval); - strcpy(cond->method, method); - cond->paramsBin = malloc(32); - memcpy(cond->paramsBin, bin, len); - cond->paramsBinLength = len; - return cond; -} - - -CC* MakePayoutCond(uint256 signedSessionTx) -{ - CC* agree; - { - // TODO: 2/3 majority - std::vector subs; - for (int i=0; i vHash(signedSessionTxHash.begin(), signedSessionTxHash.end()); + CC *importEval = CCNewEval("ImportPayout", vHash); - std::vector subs; - for (int i=0; i playerInputs, - uint256 signedSessionTx) +CMutableTransaction BetProtocol::MakeStakeTx(CAmount totalPayout, uint256 signedSessionTxHash) { CMutableTransaction mtx; - mtx.vin = playerInputs; - CC *payoutCond = MakePayoutCond(signedSessionTx);push + CC *payoutCond = MakePayoutCond(signedSessionTxHash); mtx.vout.push_back(CTxOut(totalPayout, CCPubKey(payoutCond))); cc_free(payoutCond); @@ -217,24 +137,23 @@ CMutableTransaction PokerProtocol::MakeStakeTx(CAmount totalPayout, std::vector< } -CMutableTransaction PokerProtocol::MakeAgreePayoutTx(std::vector payouts, - CC *signedPayoutCond, uint256 signedStakeTxHash) +CMutableTransaction BetProtocol::MakeAgreePayoutTx(std::vector payouts, + uint256 signedStakeTxHash) { CMutableTransaction mtx; - mtx.vin.push_back(CTxIn(signedStakeTxHash, 0, CCSig(signedPayoutCond))); - mtx.vouts = payouts; + mtx.vin.push_back(CTxIn(signedStakeTxHash, 0, CScript())); + mtx.vout = payouts; return mtx; } -CMutableTransaction PokerProtocol::MakeImportPayoutTx(std::vector payouts, - CC *signedPayoutCond, CTransaction signedDisputeTx, uint256 signedStakeTxHash) +CMutableTransaction BetProtocol::MakeImportPayoutTx(std::vector payouts, + CTransaction signedDisputeTx, uint256 signedStakeTxHash, MoMProof momProof) { - std::vector vDisputeTx; - signedDisputeTx >> CDataStream(vDisputeTx, SER_DISK, PROTOCOL_VERSION); CMutableTransaction mtx; - mtx.vin.push_back(CTxInput(signedStakeTxHash, 0, CCSig(signedPayoutCond))); + mtx.vin.push_back(CTxIn(signedStakeTxHash, 0, CScript())); mtx.vout = payouts; - CMutableTransaction.vout.insert(0, CTxOutput(0, CScript() << OP_RETURN << "PROOF HERE")); - CMutableTransaction.vout.insert(1, CTxOutput(0, CScript() << OP_RETURN << vDisputeTx)); + mtx.vout.insert(mtx.vout.begin(), CTxOut(0, CScript() << OP_RETURN << CheckSerialize(momProof))); + mtx.vout.insert(mtx.vout.begin()+1, CTxOut(0, CScript() << OP_RETURN << CheckSerialize(signedDisputeTx))); + return mtx; } diff --git a/src/cc/betprotocol.h b/src/cc/betprotocol.h new file mode 100644 index 000000000..dcbb6ec4e --- /dev/null +++ b/src/cc/betprotocol.h @@ -0,0 +1,85 @@ +#ifndef BETPROTOCOL_H +#define BETPROTOCOL_H + +#include "pubkey.h" +#include "primitives/transaction.h" +#include "cryptoconditions/include/cryptoconditions.h" + + +#define ExecMerkle CBlock::CheckMerkleBranch + + +class MoMProof +{ +public: + int nIndex; + std::vector branch; + uint256 notarisationHash; + + MoMProof() {} + MoMProof(int i, std::vector b, uint256 n) : notarisationHash(n), nIndex(i), branch(b) {} + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(VARINT(nIndex)); + READWRITE(branch); + READWRITE(notarisationHash); + } +}; + + +class DisputeHeader +{ +public: + int waitBlocks; + std::vector vmParams; + + DisputeHeader() {} + DisputeHeader(int w, std::vector vmp) : waitBlocks(w), vmParams(vmp) {} + + ADD_SERIALIZE_METHODS; + + template + inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { + READWRITE(VARINT(waitBlocks)); + READWRITE(vmParams); + } +}; + + +class BetProtocol +{ +protected: + char* disputeFunc = (char*) "DisputeBet"; + std::vector playerConditions(); +public: + CAmount MINFEE = 1; + std::vector players; + DisputeHeader disputeHeader; + + // Utility + BetProtocol(std::vector ps, DisputeHeader dh) : players(ps), disputeHeader(dh) {} + std::vector PlayerConditions(); + + // on PANGEA + CC* MakeDisputeCond(); + CMutableTransaction MakeSessionTx(); + CMutableTransaction MakeDisputeTx(uint256 signedSessionTxHash, uint256 vmResultHash); + CMutableTransaction MakePostEvidenceTx(uint256 signedSessionTxHash, + int playerIndex, std::vector state); + + // on KMD + CC* MakePayoutCond(uint256 signedSessionTxHash); + CMutableTransaction MakeStakeTx(CAmount totalPayout, uint256 signedSessionTx); + CMutableTransaction MakeAgreePayoutTx(std::vector payouts, uint256 signedStakeTxHash); + CMutableTransaction MakeImportPayoutTx(std::vector payouts, + CTransaction signedDisputeTx, uint256 signedStakeTxHash, MoMProof momProof); +}; + + +CC* CCNewSecp256k1(CPubKey k); + + +#endif /* BETPROTOCOL_H */ diff --git a/src/cc/disputepayout.cpp b/src/cc/disputepayout.cpp index 36a5e1723..ea34ed23c 100644 --- a/src/cc/disputepayout.cpp +++ b/src/cc/disputepayout.cpp @@ -1,34 +1,27 @@ -#include "primitives/transaction.h" -#include "streams.h" +#include + +#include "hash.h" #include "chain.h" -#include "main.h" +#include "version.h" +#include "komodo_cc.h" #include "cc/eval.h" -#include "cryptoconditions/include/cryptoconditions.h" +#include "cc/betprotocol.h" +#include "primitives/transaction.h" -bool GetSpends(uint256 hash, std::vector> &spends) +class DisputeHeader; + + +static bool GetOpReturnHash(CScript script, uint256 &hash) { - // NOT IMPLEMENTED - return false; + std::vector vHash; + GetOpReturnData(script, vHash); + if (vHash.size() != 32) return false; + memcpy(hash.begin(), vHash.data(), 32); + return true; } -class DisputeHeader -{ -public: - int waitBlocks; - std::vector vmHeader; - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(VARINT(waitBlocks)); - READWRITE(vmHeader); - } -}; - - /* * Crypto-Condition EVAL method that resolves a dispute of a session * @@ -42,48 +35,51 @@ public: * in 0: Spends Session TX first output, reveals DisputeHeader * out 0: OP_RETURN hash of payouts */ -bool DisputePayout(AppVM &vm, const CC *cond, const CTransaction *disputeTx, int nIn) +bool Eval::DisputePayout(AppVM &vm, const CC *cond, const CTransaction &disputeTx, unsigned int nIn) { - // TODO: Error messages! - if (disputeTx->vout.size() < 2) return 0; + if (disputeTx.vout.size() == 0) return Invalid("no-vouts"); // get payouts hash - std::vector vPayoutHash; uint256 payoutHash; - if (!GetOpReturnData(disputeTx->vout[0].scriptPubKey, vPayoutHash)) return 0; - memcpy(payoutHash.begin(), vPayoutHash.data(), 32); + if (!GetOpReturnHash(disputeTx.vout[0].scriptPubKey, payoutHash)) + return Invalid("invalid-payout-hash"); // load dispute header DisputeHeader disputeHeader; std::vector headerData(cond->paramsBin, cond->paramsBin+cond->paramsBinLength); - CDataStream(headerData, SER_DISK, PROTOCOL_VERSION) >> disputeHeader; - // TODO: exception? end of stream? + if (!CheckDeserialize(headerData, disputeHeader)) + return Invalid("invalid-dispute-header"); // ensure that enough time has passed CTransaction sessionTx; uint256 sessionBlockHash; - if (!GetTransaction(disputeTx->vin[0].prevout.hash, sessionTx, sessionBlockHash, false)) - return false; // wth? TODO: log TODO: MUST be upsteam of disputeTx, how to ensure? - // below does this by looking up block in blockindex - // what if GetTransaction returns from mempool, maybe theres no block? - CBlockIndex* sessionBlockIndex = mapBlockIndex[sessionBlockHash]; - if (chainActive.Height() < sessionBlockIndex->nHeight + disputeHeader.waitBlocks) - return false; // Not yet + CBlockIndex sessionBlock; + + if (!GetTx(disputeTx.vin[0].prevout.hash, sessionTx, sessionBlockHash, false)) + return Error("couldnt-get-parent"); + // TODO: This may not be an error, if both txs are to go into the same block... + // Probably change it to Invalid + if (!GetBlock(sessionBlockHash, sessionBlock)) + return Error("couldnt-get-block"); + + if (GetCurrentHeight() < sessionBlock.nHeight + disputeHeader.waitBlocks) + return Invalid("dispute-too-soon"); // Not yet // get spends - std::vector> spends; - if (!GetSpends(disputeTx->vin[0].prevout.hash, spends)) return 0; + std::vector spends; + if (!GetSpends(disputeTx.vin[0].prevout.hash, spends)) + return Error("couldnt-get-spends"); // verify result from VM int maxLength = -1; uint256 bestPayout; for (int i=1; i vmBody; - if (!GetOpReturnData(spends[i]->vout[0].scriptPubKey, vmBody)) continue; - auto out = vm.evaluate(disputeHeader.vmHeader, vmBody); + std::vector vmState; + if (!spends[i].vout.size() > 0) continue; + if (!GetOpReturnData(spends[i].vout[0].scriptPubKey, vmState)) continue; + auto out = vm.evaluate(disputeHeader.vmParams, vmState); uint256 resultHash = SerializeHash(out.second); if (out.first > maxLength) { maxLength = out.first; @@ -98,5 +94,7 @@ bool DisputePayout(AppVM &vm, const CC *cond, const CTransaction *disputeTx, int } } - return bestPayout == payoutHash; + if (maxLength == -1) return Invalid("no-evidence"); + + return bestPayout == payoutHash ? Valid() : Invalid("wrong-payout"); } diff --git a/src/cc/eval.cpp b/src/cc/eval.cpp index f61a7c241..589a362c0 100644 --- a/src/cc/eval.cpp +++ b/src/cc/eval.cpp @@ -1,56 +1,151 @@ +#include +#include + #include "primitives/transaction.h" #include "komodo_cc.h" #include "cc/eval.h" -#include +#include "main.h" +#include "chain.h" + + +Eval* EVAL_TEST = 0; + + +bool RunCCEval(const CC *cond, const CTransaction &tx, unsigned int nIn) +{ + Eval eval_; + Eval *eval = EVAL_TEST; + if (!eval) eval = &eval_; + + bool out = eval->Dispatch(cond, tx, nIn); + assert(eval->state.IsValid() == out); + + if (eval->state.IsValid()) return true; + + std::string lvl = eval->state.IsInvalid() ? "Invalid" : "Error!"; + fprintf(stderr, "CC Eval %s %s: %s in tx %s\n", lvl.data(), cond->method, + eval->state.GetRejectReason().data(), tx.GetHash().GetHex().data()); + return false; +} /* * Test the validity of an Eval node */ -bool EvalConditionValidity(const CC *cond, const CTransaction *txTo, int nIn) +bool Eval::Dispatch(const CC *cond, const CTransaction &txTo, unsigned int nIn) { if (strcmp(cond->method, "TestEval") == 0) { - return cond->paramsBinLength == 8 && - memcmp(cond->paramsBin, "TestEval", 8) == 0; + bool valid = cond->paramsBinLength == 8 && memcmp(cond->paramsBin, "TestEval", 8) == 0; + return valid ? Valid() : Invalid("testing"); } if (strcmp(cond->method, "ImportPayout") == 0) { - return CheckImportPayout(cond, txTo, nIn); + return ImportPayout(cond, txTo, nIn); } /* Example of how you might call DisputePayout - if (strcmp(ASSETCHAINS_SYMBOL, "PANGEA") == 0) { if (strcmp(cond->method, "DisputePoker") == 0) { return DisputePayout(PokerVM(), cond, txTo, nIn); } } - */ - fprintf(stderr, "no defined behaviour for method: %s\n", cond->method); - return 0; + return Invalid("no-such-method"); } - -bool GetPushData(const CScript &sig, std::vector &data) +bool Eval::GetSpends(uint256 hash, std::vector &spends) const { - opcodetype opcode; - auto pc = sig.begin(); - if (sig.GetOp(pc, opcode, data)) return opcode > OP_0 && opcode <= OP_PUSHDATA4; + // NOT IMPLEMENTED return false; } -bool GetOpReturnData(const CScript &sig, std::vector &data) +bool Eval::GetTx(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow) const { - auto pc = sig.begin(); - opcodetype opcode; - if (sig.GetOp2(pc, opcode, NULL)) - if (opcode == OP_RETURN) - if (sig.GetOp(pc, opcode, data)) - return opcode > OP_0 && opcode <= OP_PUSHDATA4; + return GetTransaction(hash, txOut, hashBlock, fAllowSlow); +} + + +unsigned int Eval::GetCurrentHeight() const +{ + return chainActive.Height(); +} + + +bool Eval::GetBlock(uint256 hash, CBlockIndex& blockIdx) const +{ + auto r = mapBlockIndex.find(hash); + if (r != mapBlockIndex.end()) { + blockIdx = *r->second; + return true; + } return false; } + +extern int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp); + + +bool Eval::CheckNotaryInputs(const CTransaction &tx, uint32_t height, uint32_t timestamp) const +{ + if (tx.vin.size() < 11) return false; + + uint8_t notaries[64][33]; + uint8_t seenNotaries[64]; + int nNotaries = komodo_notaries(notaries, height, timestamp); + char pk[33]; + + BOOST_FOREACH(const CTxIn &txIn, tx.vin) + { + // Get notary pubkey + CTransaction tx; + uint256 hashBlock; + if (!GetTx(txIn.prevout.hash, tx, hashBlock, false)) return false; + if (tx.vout.size() < txIn.prevout.n) return false; + const unsigned char *script = tx.vout[txIn.prevout.n].scriptPubKey.data(); + if (script[0] != 33) return false; + memcpy(pk, script+1, 33); + return true; + + // Check it's a notary + for (int i=0; i opret; + if (!GetOpReturnData(notarisationTx.vout[0].scriptPubKey, opret)) return 0; + if (opret.size() < 36) return 0; // In reality it is more than 36, but at the moment I + // only know where it is relative to the end, and this + // is enough to prevent a memory fault. In the case that + // the assumption about the presence of a MoM at this + // offset fails, we will return random other data that is + // not more likely to generate a false positive. + memcpy(mom.begin(), opret.data()+opret.size()-36, 32); + return 1; +} diff --git a/src/cc/eval.h b/src/cc/eval.h index aadb2e85f..2060d76ca 100644 --- a/src/cc/eval.h +++ b/src/cc/eval.h @@ -1,18 +1,56 @@ #ifndef CC_EVAL_H #define CC_EVAL_H -#include "cryptoconditions/include/cryptoconditions.h" +#include + +#include "chain.h" +#include "streams.h" +#include "version.h" +#include "consensus/validation.h" #include "primitives/transaction.h" -/* - * Test validity of a CC_Eval node - */ -bool EvalConditionValidity(const CC *cond, const CTransaction *tx, int nIn); -/* - * Test an ImportPayout CC Eval condition - */ -bool CheckImportPayout(const CC *cond, const CTransaction *payoutTx, int nIn); +class AppVM; + + +class Eval +{ +public: + CValidationState state; + + bool Invalid(std::string s) { return state.Invalid(false, 0, s); } + bool Error(std::string s) { return state.Error(s); } + bool Valid() { return true; } + + /* + * Test validity of a CC_Eval node + */ + virtual bool Dispatch(const CC *cond, const CTransaction &tx, unsigned int nIn); + + /* + * Dispute a payout using a VM + */ + bool DisputePayout(AppVM &vm, const CC *cond, const CTransaction &disputeTx, unsigned int nIn); + + /* + * Test an ImportPayout CC Eval condition + */ + bool ImportPayout(const CC *cond, const CTransaction &payoutTx, unsigned int nIn); + + /* + * IO functions + */ + virtual bool GetTx(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow) const; + virtual unsigned int GetCurrentHeight() const; + virtual bool GetSpends(uint256 hash, std::vector &spends) const; + virtual bool GetBlock(uint256 hash, CBlockIndex& blockIdx) const; + virtual bool GetMoM(uint256 notarisationHash, uint256& MoM) const; + virtual bool CheckNotaryInputs(const CTransaction &tx, uint32_t height, uint32_t timestamp) const; +}; + + +bool RunCCEval(const CC *cond, const CTransaction &tx, unsigned int nIn); + /* * Virtual machine to use in the case of on-chain app evaluation @@ -30,20 +68,36 @@ public: evaluate(std::vector header, std::vector body) = 0; }; -/* - * Test a DisputePayout CC Eval condition, using a provided AppVM - */ -bool DisputePayout(AppVM &vm, const CC *cond, const CTransaction *disputeTx, int nIn); /* - * Get PUSHDATA from a script + * Serialisation boilerplate */ -bool GetPushData(const CScript &sig, std::vector &data); +template +std::vector CheckSerialize(T &in); +template +bool CheckDeserialize(std::vector vIn, T &out); -/* - * Get OP_RETURN data from a script - */ -bool GetOpReturnData(const CScript &sig, std::vector &data); + + +template +std::vector CheckSerialize(T &in) +{ + CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); + ss << in; + return std::vector(ss.begin(), ss.end()); +} + + +template +bool CheckDeserialize(std::vector vIn, T &out) +{ + CDataStream ss(vIn, SER_NETWORK, PROTOCOL_VERSION); + try { + ss >> out; + if (ss.eof()) return true; + } catch(...) {} + return false; +} #endif /* CC_EVAL_H */ diff --git a/src/cc/importpayout.cpp b/src/cc/importpayout.cpp index f05abb943..5251f1dfd 100644 --- a/src/cc/importpayout.cpp +++ b/src/cc/importpayout.cpp @@ -1,78 +1,11 @@ -#include "primitives/transaction.h" -#include "streams.h" -#include "chain.h" +#include + #include "main.h" +#include "chain.h" +#include "streams.h" #include "cc/eval.h" -#include "cc/importpayout.h" -#include "cryptoconditions/include/cryptoconditions.h" - - -extern int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp); - -bool DerefNotaryPubkey(const COutPoint &prevout, char *pk33) -{ - CTransaction tx; - uint256 hashBlock; - if (!GetTransaction(prevout.hash, tx, hashBlock, false)) return false; - if (tx.vout.size() < prevout.n) return false; - const unsigned char *script = tx.vout[prevout.n].scriptPubKey.data(); - if (script[0] != 33) return false; - memcpy(pk33, script+1, 33); - return true; -} - -bool CheckNotaryInputs(const CTransaction &tx, uint32_t height, uint32_t timestamp) -{ - if (tx.vin.size() < 11) return false; - - uint8_t notaries[64][33]; - uint8_t seenNotaries[64]; - int nNotaries = komodo_notaries(notaries, height, timestamp); - char *pk; - - BOOST_FOREACH(const CTxIn &txIn, tx.vin) - { - if (!DerefNotaryPubkey(txIn.prevout, pk)) return false; - - for (int i=0; inHeight, blockindex->nTime)) { - return false; - } - if (!notarisationTx.vout.size() < 1) return 0; - std::vector opret; - if (!GetOpReturnData(notarisationTx.vout[0].scriptPubKey, opret)) return 0; - if (opret.size() < 36) return 0; // In reality it is more than 36, but at the moment I - // only know where it is relative to the end, and this - // is enough to prevent a memory fault. In the case that - // the assumption about the presence of a MoM at this - // offset fails, we will return random other data that is - // not more likely to generate a false positive. - memcpy(mom.begin(), opret.data()+opret.size()-36, 32); - return 1; -} - -#define ExecMerkle CBlock::CheckMerkleBranch +#include "cc/betprotocol.h" +#include "primitives/transaction.h" /* @@ -97,54 +30,51 @@ bool GetMoM(const uint256 notaryHash, uint256 &mom) * out 0: OP_RETURN hash of payouts * out 1-: anything */ -bool CheckImportPayout(const CC *cond, const CTransaction *payoutTx, int nIn) +bool Eval::ImportPayout(const CC *cond, const CTransaction &payoutTx, unsigned int nIn) { // TODO: Error messages! - if (payoutTx->vin.size() != 1) return 0; - if (payoutTx->vout.size() < 2) return 0; - - // Get hash of payouts - std::vector payouts(payoutTx->vout.begin() + 2, payoutTx->vout.end()); - uint256 payoutsHash = SerializeHash(payouts); - std::vector vPayoutsHash(payoutsHash.begin(), payoutsHash.end()); + if (payoutTx.vout.size() < 2) return Invalid("need-2-vouts"); // load disputeTx from vout[1] CTransaction disputeTx; - { - std::vector exportData; - if (!GetOpReturnData(payoutTx->vout[1].scriptPubKey, exportData)) return 0; - CDataStream(exportData, SER_DISK, PROTOCOL_VERSION) >> disputeTx; - // TODO: end of stream? exception? - } + std::vector exportData; + GetOpReturnData(payoutTx.vout[1].scriptPubKey, exportData); + if (!CheckDeserialize(exportData, disputeTx)) + return Invalid("invalid-dispute-tx"); - // Check disputeTx.0 is vPayoutsHash - std::vector exportPayoutsHash; - if (!GetOpReturnData(disputeTx.vout[0].scriptPubKey, exportPayoutsHash)) return 0; - if (exportPayoutsHash != vPayoutsHash) return 0; + // Check disputeTx.0 shows correct payouts + { + std::vector payouts(payoutTx.vout.begin() + 2, payoutTx.vout.end()); + uint256 payoutsHash = SerializeHash(payouts); + std::vector vPayoutsHash(payoutsHash.begin(), payoutsHash.end()); + + if (disputeTx.vout[0].scriptPubKey != CScript() << OP_RETURN << vPayoutsHash) + return Invalid("wrong-payouts"); + } // Check disputeTx spends sessionTx.0 // condition ImportPayout params is session ID from other chain { - if (cond->paramsBinLength != 32) return 0; + if (cond->paramsBinLength != 32) return Invalid("malformed-params"); COutPoint prevout = disputeTx.vin[0].prevout; if (memcmp(prevout.hash.begin(), cond->paramsBin, 32) != 0 || - prevout.n != 0) return 0; + prevout.n != 0) return Invalid("wrong-session"); } // Check disputeTx solves momproof from vout[0] { - std::vector vchMomProof; - if (!GetOpReturnData(payoutTx->vout[0].scriptPubKey, vchMomProof)) return 0; + std::vector vProof; + GetOpReturnData(payoutTx.vout[0].scriptPubKey, vProof); + MoMProof proof; + if (!CheckDeserialize(vProof, proof)) + return Invalid("invalid-mom-proof-payload"); - MoMProof momProof; - CDataStream(vchMomProof, SER_DISK, PROTOCOL_VERSION) >> momProof; - - uint256 mom; - if (!GetMoM(momProof.notarisationHash, mom)) return 0; + uint256 MoM; + if (!GetMoM(proof.notarisationHash, MoM)) return Invalid("coudnt-load-mom"); - uint256 proofResult = ExecMerkle(disputeTx.GetHash(), momProof.branch, momProof.nIndex); - if (proofResult != mom) return 0; + if (MoM != ExecMerkle(disputeTx.GetHash(), proof.branch, proof.nIndex)) + return Invalid("mom-check-fail"); } - return 1; + return Valid(); } diff --git a/src/cc/importpayout.h b/src/cc/importpayout.h deleted file mode 100644 index 3ae094e80..000000000 --- a/src/cc/importpayout.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef KOMODO_TXPROOF_H -#define KOMODO_TXPROOF_H - - -class MoMProof -{ -public: - int nIndex; - std::vector branch; - uint256 notarisationHash; - - MoMProof() {} - MoMProof(int i, std::vector b, uint256 n) : notarisationHash(n), nIndex(i), branch(b) {} - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(VARINT(nIndex)); - READWRITE(branch); - READWRITE(notarisationHash); - } -}; - - -#endif /* KOMODO_TXPROOF_H */ diff --git a/src/cryptoconditions/include/cryptoconditions.h b/src/cryptoconditions/include/cryptoconditions.h index 439fe3f4a..a192b06c2 100644 --- a/src/cryptoconditions/include/cryptoconditions.h +++ b/src/cryptoconditions/include/cryptoconditions.h @@ -96,6 +96,7 @@ char* cc_typeName(const CC *cond); enum CCTypeId cc_typeId(const CC *cond); unsigned long cc_getCost(const CC *cond); uint32_t cc_typeMask(const CC *cond); +int cc_isAnon(const CC *cond); void cc_free(struct CC *cond); #ifdef __cplusplus diff --git a/src/cryptoconditions/src/cryptoconditions.c b/src/cryptoconditions/src/cryptoconditions.c index 622f09530..6a6513b59 100644 --- a/src/cryptoconditions/src/cryptoconditions.c +++ b/src/cryptoconditions/src/cryptoconditions.c @@ -284,7 +284,7 @@ char *cc_typeName(const CC *cond) { CC *cc_new(int typeId) { CC *cond = calloc(1, sizeof(CC)); - cond->type = CCTypeRegistry[typeId]; + cond->type = typeId == CC_Anon ? &CC_AnonType : CCTypeRegistry[typeId]; return cond; } diff --git a/src/cryptoconditions/src/threshold.c b/src/cryptoconditions/src/threshold.c index da8a3027a..f4684cd7b 100644 --- a/src/cryptoconditions/src/threshold.c +++ b/src/cryptoconditions/src/threshold.c @@ -130,15 +130,19 @@ static CC *thresholdFromFulfillment(const Fulfillment_t *ffill) { static Fulfillment_t *thresholdToFulfillment(const CC *cond) { CC *sub; Fulfillment_t *fulfillment; + + // Make a copy of subconditions so we can leave original order alone + CC** subconditions = malloc(cond->size*sizeof(CC*)); + memcpy(subconditions, cond->subconditions, cond->size*sizeof(CC*)); - qsort(cond->subconditions, cond->size, sizeof(CC*), cmpConditionCost); + qsort(subconditions, cond->size, sizeof(CC*), cmpConditionCost); ThresholdFulfillment_t *tf = calloc(1, sizeof(ThresholdFulfillment_t)); int needed = cond->threshold; for (int i=0; isize; i++) { - sub = cond->subconditions[i]; + sub = subconditions[i]; if (needed && (fulfillment = asnFulfillmentNew(sub))) { asn_set_add(&tf->subfulfillments, fulfillment); needed--; @@ -147,6 +151,8 @@ static Fulfillment_t *thresholdToFulfillment(const CC *cond) { } } + free(subconditions); + if (needed) { ASN_STRUCT_FREE(asn_DEF_ThresholdFulfillment, tf); return NULL; @@ -200,7 +206,7 @@ static void thresholdToJSON(const CC *cond, cJSON *params) { static int thresholdIsFulfilled(const CC *cond) { int nFulfilled = 0; - for (int i=0; ithreshold; i++) { + for (int i=0; isize; i++) { if (cc_isFulfilled(cond->subconditions[i])) { nFulfilled++; } diff --git a/src/komodo_cc.cpp b/src/komodo_cc.cpp index 81459fe2b..e7b166eba 100644 --- a/src/komodo_cc.cpp +++ b/src/komodo_cc.cpp @@ -30,3 +30,72 @@ bool IsSignedCryptoCondition(const CC *cond) if (IsSignedCryptoCondition(cond->subconditions[i])) return true; return false; } + + + +CScript CCPubKey(const CC *cond) +{ + unsigned char buf[1000]; + size_t len = cc_conditionBinary(cond, buf); + return CScript() << std::vector(buf, buf+len) << OP_CHECKCRYPTOCONDITION; +} + + +CScript CCSig(const CC *cond) +{ + unsigned char buf[1000]; + size_t len = cc_fulfillmentBinary(cond, buf, 1000); + auto ffill = std::vector(buf, buf+len); + ffill.push_back(1); // SIGHASH_ALL + return CScript() << ffill; +} + + +std::string CCShowStructure(CC *cond) +{ + std::string out; + if (cc_isAnon(cond)) { + out = "A" + std::to_string(cc_typeId(cond)); + } + else if (cc_typeId(cond) == CC_Threshold) { + out += "(" + std::to_string(cond->threshold) + " of "; + for (int i=0; isize; i++) { + out += CCShowStructure(cond->subconditions[i]); + if (i < cond->size - 1) out += ","; + } + out += ")"; + } + else { + out = std::to_string(cc_typeId(cond)); + } + return out; +} + + +CC* CCPrune(CC *cond) +{ + std::vector ffillBin; + GetPushData(CCSig(cond), ffillBin); + return cc_readFulfillmentBinary(ffillBin.data(), ffillBin.size()-1); +} + + +bool GetPushData(const CScript &sig, std::vector &data) +{ + opcodetype opcode; + auto pc = sig.begin(); + if (sig.GetOp(pc, opcode, data)) return opcode > OP_0 && opcode <= OP_PUSHDATA4; + return false; +} + + +bool GetOpReturnData(const CScript &sig, std::vector &data) +{ + auto pc = sig.begin(); + opcodetype opcode; + if (sig.GetOp2(pc, opcode, NULL)) + if (opcode == OP_RETURN) + if (sig.GetOp(pc, opcode, data)) + return opcode > OP_0 && opcode <= OP_PUSHDATA4; + return false; +} diff --git a/src/komodo_cc.h b/src/komodo_cc.h index 62e584a94..78cb4401a 100644 --- a/src/komodo_cc.h +++ b/src/komodo_cc.h @@ -1,6 +1,7 @@ #ifndef KOMODO_CC_H #define KOMODO_CC_H +#include "script/script.h" #include "cryptoconditions/include/cryptoconditions.h" @@ -31,4 +32,42 @@ bool IsSupportedCryptoCondition(const CC *cond); bool IsSignedCryptoCondition(const CC *cond); +/* + * Turn a condition into a scriptPubKey + */ +CScript CCPubKey(const CC *cond); + + +/* + * Turn a condition into a scriptSig + * + * Note: This will fail in undefined ways if the condition is missing signatures + */ +CScript CCSig(const CC *cond); + + +/* + * Produces a string showing the structure of a CC condition + */ +std::string CCShowStructure(CC *cond); + + +/* + * Take a signed CC, encode it, and decode it again. This has the effect + * of removing branches unneccesary for fulfillment. + */ +CC* CCPrune(CC *cond); + + +/* + * Get PUSHDATA from a script + */ +bool GetPushData(const CScript &sig, std::vector &data); + +/* + * Get OP_RETURN data from a script + */ +bool GetOpReturnData(const CScript &sig, std::vector &data); + + #endif /* KOMODO_CC_H */ diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 30d2c0aab..f353d549d 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -8,7 +8,7 @@ #include "chainparams.h" #include "checkpoints.h" #include "consensus/validation.h" -#include "cc/importpayout.h" +#include "cc/betprotocol.h" #include "main.h" #include "primitives/transaction.h" #include "rpcserver.h" diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 851904eb3..31a7fdbd0 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1310,18 +1310,22 @@ int TransactionSignatureChecker::CheckCryptoCondition( } catch (logic_error ex) { return 0; } + + VerifyEval eval = [] (CC *cond, void *checker) { + return ((TransactionSignatureChecker*)checker)->CheckEvalCondition(cond); + }; + int out = cc_verify(cond, (const unsigned char*)&sighash, 32, 0, - condBin.data(), condBin.size(), GetCCEval(), (void*)this); + condBin.data(), condBin.size(), eval, (void*)this); cc_free(cond); return out; } -VerifyEval TransactionSignatureChecker::GetCCEval() const { - return [] (CC *cond, void *checker) { - fprintf(stderr, "Cannot check crypto-condition Eval outside of server\n"); - return 0; - }; +int TransactionSignatureChecker::CheckEvalCondition(const CC *cond) const +{ + fprintf(stderr, "Cannot check crypto-condition Eval outside of server\n"); + return 0; } diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 57051f797..46c0818d2 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -142,13 +142,12 @@ public: class TransactionSignatureChecker : public BaseSignatureChecker { -private: +protected: const CTransaction* txTo; unsigned int nIn; const CAmount amount; const PrecomputedTransactionData* txdata; -protected: virtual bool VerifySignature(const std::vector& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const; public: @@ -161,7 +160,7 @@ public: const std::vector& ffillBin, const CScript& scriptCode, uint32_t consensusBranchId) const; - virtual VerifyEval GetCCEval() const; + virtual int CheckEvalCondition(const CC *cond) const; }; class MutableTransactionSignatureChecker : public TransactionSignatureChecker diff --git a/src/script/serverchecker.cpp b/src/script/serverchecker.cpp index 852895305..0baaee9f5 100644 --- a/src/script/serverchecker.cpp +++ b/src/script/serverchecker.cpp @@ -100,14 +100,7 @@ bool ServerTransactionSignatureChecker::VerifySignature(const std::vectorCheckEvalCondition(cond); - }; -} - -int ServerTransactionSignatureChecker::CheckEvalCondition(CC *cond) const -{ - return EvalConditionValidity(cond, txTo, nIn); + return RunCCEval(cond, *txTo, nIn); } diff --git a/src/script/serverchecker.h b/src/script/serverchecker.h index c680da7ce..107586689 100644 --- a/src/script/serverchecker.h +++ b/src/script/serverchecker.h @@ -16,15 +16,12 @@ class ServerTransactionSignatureChecker : public TransactionSignatureChecker { private: bool store; - const CTransaction* txTo; - unsigned int nIn; public: - ServerTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, const CAmount& amount, bool storeIn, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nInIn, amount, txdataIn), store(storeIn) {} + ServerTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nIn, const CAmount& amount, bool storeIn, PrecomputedTransactionData& txdataIn) : TransactionSignatureChecker(txToIn, nIn, amount, txdataIn), store(storeIn) {} bool VerifySignature(const std::vector& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const; - int CheckEvalCondition(CC *cond) const; - VerifyEval GetCCEval() const; + int CheckEvalCondition(const CC *cond) const; }; #endif // BITCOIN_SCRIPT_SERVERCHECKER_H diff --git a/src/test-komodo/main.cpp b/src/test-komodo/main.cpp index 2a83e47fa..527d7666e 100644 --- a/src/test-komodo/main.cpp +++ b/src/test-komodo/main.cpp @@ -1,12 +1,14 @@ #include "key.h" +#include "chainparams.h" #include "gtest/gtest.h" #include "crypto/common.h" int main(int argc, char **argv) { - assert(init_and_check_sodium() != -1); - ECC_Start(); + assert(init_and_check_sodium() != -1); + ECC_Start(); + SelectParams(CBaseChainParams::REGTEST); - testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); } diff --git a/src/test-komodo/test_bet.cpp b/src/test-komodo/test_bet.cpp new file mode 100644 index 000000000..d0072ad38 --- /dev/null +++ b/src/test-komodo/test_bet.cpp @@ -0,0 +1,596 @@ +#include +#include + +#include "cc/betprotocol.h" +#include "cc/eval.h" +#include "base58.h" +#include "key.h" +#include "main.h" +#include "komodo_cc.h" +#include "primitives/transaction.h" +#include "script/interpreter.h" +#include "script/serverchecker.h" + +#include "testutils.h" + + + +static std::vector playerSecrets; +static std::vector players; + +static int Dealer = 0, Player1 = 1, Player2 = 2; + + +int CCSign(CMutableTransaction &tx, unsigned int nIn, CC *cond, std::vector keyIds) { + PrecomputedTransactionData txdata(tx); + uint256 sighash = SignatureHash(CCPubKey(cond), tx, nIn, SIGHASH_ALL, 0, 0, &txdata); + int nSigned = 0; + for (int i=0; i> evaluate( + std::vector header, std::vector body) + { + std::vector outs; + if (memcmp(header.data(), "BetHeader", 9)) { + printf("Wrong VM header\n"); + return std::make_pair(0, outs); + } + outs.push_back(CTxOut(2, CScript() << OP_RETURN << body.size())); + return std::make_pair(body.size(), outs); + } +}; + + +class EvalMock : public Eval +{ +public: + uint256 MoM; + int currentHeight; + std::map txs; + std::map blocks; + std::map> spends; + + bool Dispatch(const CC *cond, const CTransaction &txTo, unsigned int nIn) + { + if (strcmp(cond->method, "DisputeBet") == 0) { + MockVM vm; + return DisputePayout(vm, cond, txTo, nIn); + } + if (strcmp(cond->method, "ImportPayout") == 0) { + return ImportPayout(cond, txTo, nIn); + } + return Invalid("invalid-method"); + } + + bool GetSpends(uint256 hash, std::vector &spendsOut) const + { + auto r = spends.find(hash); + if (r != spends.end()) { + spendsOut = r->second; + return true; + } + return false; + } + + bool GetTx(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow) const + { + auto r = txs.find(hash); + if (r != txs.end()) { + txOut = r->second; + hashBlock = hash; + return true; + } + return false; + } + + unsigned int GetCurrentHeight() const { return currentHeight; } + + bool GetBlock(uint256 hash, CBlockIndex& blockIdx) const + { + auto r = blocks.find(hash); + if (r == blocks.end()) return false; + blockIdx = r->second; + return true; + } + + bool GetMoM(uint256 notarisationHash, uint256& _MoM) const + { + if (notarisationHash == NotarisationHash()) { + _MoM = MoM; + return true; + } + return false; + } + + static uint256 NotarisationHash() + { + uint256 h; + h.begin()[0] = 123; + return h; + } +}; + + +extern Eval* EVAL_TEST; + + +/* + * Generates example data that we will test with and shows how to call BetProtocol. + */ +class ExampleBet +{ +public: + BetProtocol bet; + CAmount totalPayout; + + ExampleBet() : bet(BetProtocol(players, DisputeHeader(2, VCH("BetHeader", 9)))), totalPayout(100) {} + ~ExampleBet() {}; + + CTransaction SessionTx() + { + return CTransaction(bet.MakeSessionTx()); + } + + CC* DisputeCond() + { + return bet.MakeDisputeCond(); + } + + CC* PayoutCond() + { + return bet.MakePayoutCond(SessionTx().GetHash()); + } + + CTransaction StakeTx() + { + return CTransaction(bet.MakeStakeTx(totalPayout, SessionTx().GetHash())); + } + + std::vector PlayerState(int playerIdx) + { + std::vector state; + for (int i=0; i Payouts(int playerIdx) + { + return MockVM().evaluate(bet.disputeHeader.vmParams, PlayerState(playerIdx)).second; + } + + CMutableTransaction DisputeTx(int playerIdx) + { + return bet.MakeDisputeTx(SessionTx().GetHash(), SerializeHash(Payouts(playerIdx))); + } + + CMutableTransaction PostEvidenceTx(int playerIdx) + { + return bet.MakePostEvidenceTx(SessionTx().GetHash(), playerIdx, PlayerState(playerIdx)); + } + + CMutableTransaction AgreePayoutTx() + { + std::vector v; + return bet.MakeAgreePayoutTx(v, uint256()); + } + + MoMProof GetMoMProof() + { + int nIndex = 5; + std::vector vBranch; + vBranch.resize(3); + return MoMProof(nIndex, vBranch, EvalMock::NotarisationHash()); + } + + CMutableTransaction ImportPayoutTx() + { + CMutableTransaction disputeTx = DisputeTx(Player2); + return bet.MakeImportPayoutTx(Payouts(Player2), disputeTx, uint256(), GetMoMProof()); + } + + EvalMock SetEvalMock(int currentHeight) + { + EvalMock eval; + CTransaction sessionTx = SessionTx(); + + eval.txs[sessionTx.GetHash()] = sessionTx; + + CBlockIndex sessionBlock; + sessionBlock.nHeight = 10; + eval.blocks[sessionTx.GetHash()] = sessionBlock; + + std::vector sessionSpends; + sessionSpends.push_back(CTransaction(PostEvidenceTx(Dealer))); + sessionSpends.push_back(CTransaction()); // Invalid, should be ignored + sessionSpends.push_back(CTransaction(PostEvidenceTx(Player2))); + eval.spends[sessionTx.GetHash()] = sessionSpends; + + eval.currentHeight = currentHeight; + + MoMProof proof = GetMoMProof(); + eval.MoM = ExecMerkle(DisputeTx(Player2).GetHash(), proof.branch, proof.nIndex); + + EVAL_TEST = &eval; + return eval; + } +}; + + +ExampleBet ebet; + + +class TestBet : public ::testing::Test { +protected: + static void SetUpTestCase() { + // Make playerSecrets + CBitcoinSecret vchSecret; + auto addKey = [&] (std::string k) { vchSecret.SetString(k); playerSecrets.push_back(vchSecret.GetKey()); }; + addKey("UwFBKf4d6wC3yqdnk3LoGrFjy7gwxrWerBT8jTFamrBbem8wSw9L"); + addKey("Up6GpWwrmx2VpqF8rD3snJXToKT56Dzc8YSoL24osXnfNdCucaMR"); + addKey("UxEHwki3A95PSHHVRzE2N67eHTeoUcqLkovxp6yDPVViv54skF8c"); + // Make playerpubkeys + for (int i=0; isubconditions[0]->paramsBin, 11)); + for (int i=0; isubconditions[1]->subconditions[i])); +} + + +TEST_F(TestBet, testSignDisputeCond) +{ + // Only one key needed to dispute + CMutableTransaction disputeTx = ebet.DisputeTx(Player1); + CC *disputeCond = ebet.DisputeCond(); + EXPECT_EQ(1, CCSign(disputeTx, 0, disputeCond, {Player1})); + + EXPECT_EQ(1, cc_isFulfilled(disputeCond->subconditions[0])); + EXPECT_EQ(1, cc_isFulfilled(disputeCond->subconditions[1])); + EXPECT_EQ(0, cc_isFulfilled(disputeCond->subconditions[1]->subconditions[0])); + EXPECT_EQ(1, cc_isFulfilled(disputeCond->subconditions[1]->subconditions[1])); + EXPECT_EQ(0, cc_isFulfilled(disputeCond->subconditions[1]->subconditions[2])); + EXPECT_EQ(1, cc_isFulfilled(disputeCond)); +} + + +TEST_F(TestBet, testDispute) +{ + EvalMock eval = ebet.SetEvalMock(12); + + // Only one key needed to dispute + CMutableTransaction disputeTx = ebet.DisputeTx(Player2); + CC *disputeCond = ebet.DisputeCond(); + EXPECT_EQ(1, CCSign(disputeTx, 0, disputeCond, {Player2})); + + // Success + EXPECT_TRUE(TestCC(disputeTx, 0, disputeCond)); + + // Set result hash to some rubbish and check false + uint256 rubbishHash; + std::vector rubbish(rubbishHash.begin(), rubbishHash.end()); + disputeTx.vout[0].scriptPubKey = CScript() << OP_RETURN << rubbish; + EXPECT_EQ(1, CCSign(disputeTx, 0, disputeCond, {Player2})); + EXPECT_FALSE(TestCC(disputeTx, 0, disputeCond)); + EXPECT_EQ("wrong-payout", eval.state.GetRejectReason()); +} + + +TEST_F(TestBet, testDisputeInvalidOutput) +{ + EvalMock eval = ebet.SetEvalMock(11); + + // Only one key needed to dispute + CMutableTransaction disputeTx = ebet.DisputeTx(Dealer); + CC *disputeCond = ebet.DisputeCond(); + + // invalid payout hash + std::vector invalidHash = {0,1,2}; + disputeTx.vout[0].scriptPubKey = CScript() << OP_RETURN << invalidHash; + ASSERT_EQ(1, CCSign(disputeTx, 0, disputeCond, {Player1})); + EXPECT_FALSE(TestCC(disputeTx, 0, disputeCond)); + EXPECT_EQ("invalid-payout-hash", eval.state.GetRejectReason()); + + // no vout at all + disputeTx.vout.resize(0); + ASSERT_EQ(1, CCSign(disputeTx, 0, disputeCond, {Player1})); + EXPECT_FALSE(TestCC(disputeTx, 0, disputeCond)); + EXPECT_EQ("no-vouts", eval.state.GetRejectReason()); +} + + +TEST_F(TestBet, testDisputeEarly) +{ + EvalMock eval = ebet.SetEvalMock(11); + + // Only one key needed to dispute + CMutableTransaction disputeTx = ebet.DisputeTx(Dealer); + CC *disputeCond = ebet.DisputeCond(); + EXPECT_EQ(1, CCSign(disputeTx, 0, disputeCond, {Player1})); + + EXPECT_FALSE(TestCC(disputeTx, 0, disputeCond)); + EXPECT_EQ("dispute-too-soon", eval.state.GetRejectReason()); +} + + +TEST_F(TestBet, testDisputeInvalidParams) +{ + EvalMock eval = ebet.SetEvalMock(12); + + CMutableTransaction disputeTx = ebet.DisputeTx(Player2); + CC *disputeCond = ebet.DisputeCond(); + CC *evalCond = disputeCond->subconditions[0]; + + // too long + evalCond->paramsBin = (unsigned char*) realloc(evalCond->paramsBin, ++evalCond->paramsBinLength); + ASSERT_EQ(1, CCSign(disputeTx, 0, disputeCond, {Player2})); + EXPECT_FALSE(TestCC(disputeTx, 0, disputeCond)); + EXPECT_EQ("invalid-dispute-header", eval.state.GetRejectReason()); + + // too short + eval.state = CValidationState(); + evalCond->paramsBinLength = 1; + ASSERT_EQ(1, CCSign(disputeTx, 0, disputeCond, {Player2})); + EXPECT_FALSE(TestCC(disputeTx, 0, disputeCond)); + EXPECT_EQ("invalid-dispute-header", eval.state.GetRejectReason()); + + // is fine + eval.state = CValidationState(); + evalCond->paramsBinLength = 11; + ASSERT_EQ(1, CCSign(disputeTx, 0, disputeCond, {Player2})); + EXPECT_TRUE(TestCC(disputeTx, 0, disputeCond)); +} + + +TEST_F(TestBet, testDisputeInvalidEvidence) +{ + EvalMock eval = ebet.SetEvalMock(12); + + CMutableTransaction disputeTx = ebet.DisputeTx(Player2); + CC *disputeCond = ebet.DisputeCond(); + CCSign(disputeTx, 0, disputeCond, {Player2}); + + CMutableTransaction mtx; + + mtx.vout.resize(1); + mtx.vout[0].scriptPubKey = CScript(); + eval.spends[ebet.SessionTx().GetHash()][1] = CTransaction(mtx); + ASSERT_TRUE(TestCC(disputeTx, 0, disputeCond)); + + mtx.vout[0].scriptPubKey << OP_RETURN; + eval.spends[ebet.SessionTx().GetHash()][1] = CTransaction(mtx); + ASSERT_TRUE(TestCC(disputeTx, 0, disputeCond)); + + mtx.vout[0].scriptPubKey = CScript() << 0; + eval.spends[ebet.SessionTx().GetHash()][1] = CTransaction(mtx); + ASSERT_TRUE(TestCC(disputeTx, 0, disputeCond)); + + eval.spends[ebet.SessionTx().GetHash()].resize(1); + eval.spends[ebet.SessionTx().GetHash()][0] = CTransaction(); + ASSERT_FALSE(TestCC(disputeTx, 0, disputeCond)); + EXPECT_EQ("no-evidence", eval.state.GetRejectReason()); +} + + +TEST_F(TestBet, testMakeStakeTx) +{ + CTransaction stakeTx = ebet.StakeTx(); + EXPECT_EQ(0, stakeTx.vin.size()); + EXPECT_EQ(1, stakeTx.vout.size()); + EXPECT_EQ(ebet.totalPayout, stakeTx.vout[0].nValue); + EXPECT_EQ(CCPubKey(ebet.PayoutCond()), stakeTx.vout[0].scriptPubKey); +} + + +TEST_F(TestBet, testMakePayoutCond) +{ + CC *payoutCond = ebet.PayoutCond(); + EXPECT_EQ("(1 of (3 of 5,5,5),(2 of (1 of 5,5,5),15))", CCShowStructure(payoutCond)); + EXPECT_EQ(0, memcmp(payoutCond->subconditions[1]->subconditions[1]->paramsBin, + ebet.SessionTx().GetHash().begin(), 32)); +} + + +TEST_F(TestBet, testSignPayout) +{ + + CMutableTransaction payoutTx = ebet.AgreePayoutTx(); + CC *payoutCond = ebet.PayoutCond(); + + EXPECT_EQ(0, cc_isFulfilled(payoutCond->subconditions[0])); + EXPECT_EQ(0, cc_isFulfilled(payoutCond->subconditions[1])); + EXPECT_EQ(0, cc_isFulfilled(payoutCond)); + + EXPECT_EQ(2, CCSign(payoutTx, 0, payoutCond, {Player1})); + EXPECT_EQ(0, cc_isFulfilled(payoutCond->subconditions[0])); + EXPECT_EQ(1, cc_isFulfilled(payoutCond->subconditions[1])); + EXPECT_EQ(1, cc_isFulfilled(payoutCond)); + + EXPECT_EQ(2, CCSign(payoutTx, 0, payoutCond, {Player2})); + EXPECT_EQ(0, cc_isFulfilled(payoutCond->subconditions[0])); + + EXPECT_EQ(2, CCSign(payoutTx, 0, payoutCond, {Dealer})); + EXPECT_EQ(1, cc_isFulfilled(payoutCond->subconditions[0])); +} + + +TEST_F(TestBet, testAgreePayout) +{ + EvalMock eval = ebet.SetEvalMock(12); + + CMutableTransaction payoutTx = ebet.AgreePayoutTx(); + CC *payoutCond = ebet.PayoutCond(); + + EXPECT_EQ(2, CCSign(payoutTx, 0, payoutCond, {Dealer})); + EXPECT_FALSE(TestCC(payoutTx, 0, payoutCond)); + EXPECT_EQ("(1 of (2 of (1 of 5,A5,A5),15),A2)", + CCShowStructure(CCPrune(payoutCond))); + + EXPECT_EQ(2, CCSign(payoutTx, 0, payoutCond, {Player1})); + EXPECT_FALSE(TestCC(payoutTx, 0, payoutCond)); + EXPECT_EQ("(1 of (2 of (1 of 5,A5,A5),15),A2)", + CCShowStructure(CCPrune(payoutCond))); + + EXPECT_EQ(2, CCSign(payoutTx, 0, payoutCond, {Player2})); + EXPECT_TRUE( TestCC(payoutTx, 0, payoutCond)); + EXPECT_EQ("(1 of (3 of 5,5,5),A2)", + CCShowStructure(CCPrune(payoutCond))); +} + + +TEST_F(TestBet, testImportPayout) +{ + EvalMock eval = ebet.SetEvalMock(12); + + CMutableTransaction importTx = ebet.ImportPayoutTx(); + CC *payoutCond = ebet.PayoutCond(); + EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); + EXPECT_TRUE(TestCC(importTx, 0, payoutCond)); +} + + +TEST_F(TestBet, testImportPayoutFewVouts) +{ + EvalMock eval = ebet.SetEvalMock(12); + + CMutableTransaction importTx = ebet.ImportPayoutTx(); + importTx.vout.resize(1); + CC *payoutCond = ebet.PayoutCond(); + EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); + EXPECT_FALSE(TestCC(importTx, 0, payoutCond)); + EXPECT_EQ("need-2-vouts", eval.state.GetRejectReason()); +} + + +TEST_F(TestBet, testImportPayoutInvalidDisputeTx) +{ + EvalMock eval = ebet.SetEvalMock(12); + + CMutableTransaction importTx = ebet.ImportPayoutTx(); + importTx.vout[1].scriptPubKey.pop_back(); + CC *payoutCond = ebet.PayoutCond(); + EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); + EXPECT_FALSE(TestCC(importTx, 0, payoutCond)); + EXPECT_EQ("invalid-dispute-tx", eval.state.GetRejectReason()); +} + + +TEST_F(TestBet, testImportPayoutWrongPayouts) +{ + EvalMock eval = ebet.SetEvalMock(12); + + CMutableTransaction importTx = ebet.ImportPayoutTx(); + importTx.vout[2].nValue = 7; + CC *payoutCond = ebet.PayoutCond(); + EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); + ASSERT_FALSE(TestCC(importTx, 0, payoutCond)); + EXPECT_EQ("wrong-payouts", eval.state.GetRejectReason()); +} + + +TEST_F(TestBet, testImportPayoutMangleSessionId) +{ + EvalMock eval = ebet.SetEvalMock(12); + + CMutableTransaction importTx = ebet.ImportPayoutTx(); + CC *payoutCond = ebet.PayoutCond(); + payoutCond->subconditions[1]->subconditions[1]->paramsBinLength = 31; + EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); + ASSERT_FALSE(TestCC(importTx, 0, payoutCond)); + EXPECT_EQ("malformed-params", eval.state.GetRejectReason()); + + payoutCond = ebet.PayoutCond(); + memset(payoutCond->subconditions[1]->subconditions[1]->paramsBin, 1, 32); + EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); + ASSERT_FALSE(TestCC(importTx, 0, payoutCond)); + EXPECT_EQ("wrong-session", eval.state.GetRejectReason()); +} + + +TEST_F(TestBet, testImportPayoutInvalidProofPayload) +{ + EvalMock eval = ebet.SetEvalMock(12); + + CMutableTransaction importTx = ebet.ImportPayoutTx(); + importTx.vout[0].scriptPubKey.pop_back(); + CC *payoutCond = ebet.PayoutCond(); + EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); + EXPECT_FALSE(TestCC(importTx, 0, payoutCond)); + EXPECT_EQ("invalid-mom-proof-payload", eval.state.GetRejectReason()); +} + + +TEST_F(TestBet, testImportPayoutInvalidNotarisationHash) +{ + EvalMock eval = ebet.SetEvalMock(12); + + CMutableTransaction importTx = ebet.ImportPayoutTx(); + MoMProof proof = ebet.GetMoMProof(); + proof.notarisationHash = uint256(); + importTx.vout[0].scriptPubKey = CScript() << OP_RETURN << CheckSerialize(proof); + CC *payoutCond = ebet.PayoutCond(); + EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); + EXPECT_FALSE(TestCC(importTx, 0, payoutCond)); + EXPECT_EQ("coudnt-load-mom", eval.state.GetRejectReason()); +} + + +TEST_F(TestBet, testImportPayoutMomFail) +{ + EvalMock eval = ebet.SetEvalMock(12); + + CMutableTransaction importTx = ebet.ImportPayoutTx(); + MoMProof proof = ebet.GetMoMProof(); + proof.nIndex ^= 1; + importTx.vout[0].scriptPubKey = CScript() << OP_RETURN << CheckSerialize(proof); + CC *payoutCond = ebet.PayoutCond(); + EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); + EXPECT_FALSE(TestCC(importTx, 0, payoutCond)); + EXPECT_EQ("mom-check-fail", eval.state.GetRejectReason()); +} diff --git a/src/test-komodo/test_cryptoconditions.cpp b/src/test-komodo/test_cryptoconditions.cpp index 9ab4b676c..f22d50be3 100644 --- a/src/test-komodo/test_cryptoconditions.cpp +++ b/src/test-komodo/test_cryptoconditions.cpp @@ -8,60 +8,35 @@ #include "script/interpreter.h" #include "script/serverchecker.h" +#include "testutils.h" -#define VCH(a,b) std::vector(a, a + b) + +CKey notaryKey; std::string pubkey = "0205a8ad0c1dbc515f149af377981aab58b836af008d4d7ab21bd76faf80550b47"; std::string secret = "UxFWWxsf1d7w7K5TvAWSkeX4H95XQKwdwGv49DXwWUTzPTTjHBbU"; -CKey notaryKey; - - -char ccjsonerr[1000] = "\0"; -#define CCFromJson(o,s) \ - o = cc_conditionFromJSONString(s, ccjsonerr); \ - if (!o) FAIL() << "bad json: " << ccjsonerr; - - -CScript CCPubKey(const CC *cond) { - unsigned char buf[1000]; - size_t len = cc_conditionBinary(cond, buf); - return CScript() << VCH(buf, len) << OP_CHECKCRYPTOCONDITION; -} - - -CScript CCSig(const CC *cond) { - unsigned char buf[1000]; - size_t len = cc_fulfillmentBinary(cond, buf, 1000); - auto ffill = VCH(buf, len); - ffill.push_back(SIGHASH_ALL); - return CScript() << ffill; -} - - -void CCSign(CMutableTransaction &tx, CC *cond) { - tx.vin.resize(1); - PrecomputedTransactionData txdata(tx); - uint256 sighash = SignatureHash(CCPubKey(cond), tx, 0, SIGHASH_ALL, 0, 0, &txdata); - - int out = cc_signTreeSecp256k1Msg32(cond, notaryKey.begin(), sighash.begin()); - tx.vin[0].scriptSig = CCSig(cond); -} class CCTest : public ::testing::Test { +public: + void CCSign(CMutableTransaction &tx, CC *cond) { + tx.vin.resize(1); + PrecomputedTransactionData txdata(tx); + uint256 sighash = SignatureHash(CCPubKey(cond), tx, 0, SIGHASH_ALL, 0, 0, &txdata); + + int out = cc_signTreeSecp256k1Msg32(cond, notaryKey.begin(), sighash.begin()); + tx.vin[0].scriptSig = CCSig(cond); + } protected: - static void SetUpTestCase() { - SelectParams(CBaseChainParams::REGTEST); + virtual void SetUp() { + // enable CC + ASSETCHAINS_CC = 1; // Notary key CBitcoinSecret vchSecret; // this returns false due to network prefix mismatch but works anyway vchSecret.SetString(secret); notaryKey = vchSecret.GetKey(); } - virtual void SetUp() { - // enable CC - ASSETCHAINS_CC = 1; - } }; diff --git a/src/test-komodo/testutils.h b/src/test-komodo/testutils.h new file mode 100644 index 000000000..7c38526a3 --- /dev/null +++ b/src/test-komodo/testutils.h @@ -0,0 +1,15 @@ +#ifndef TESTUTILS_H +#define TESTUTILS_H + +#include "komodo_cc.h" + + +#define VCH(a,b) std::vector(a, a + b) + +static char ccjsonerr[1000] = "\0"; +#define CCFromJson(o,s) \ + o = cc_conditionFromJSONString(s, ccjsonerr); \ + if (!o) FAIL() << "bad json: " << ccjsonerr; + + +#endif /* TESTUTILS_H */ From acb93848cd19c2f8630451d9027fb2eff3d94e4d Mon Sep 17 00:00:00 2001 From: jl777 Date: Thu, 5 Apr 2018 14:39:07 +0300 Subject: [PATCH 061/339] Tweak notarization checks --- src/komodo_notary.h | 4 ++-- src/komodo_utils.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/komodo_notary.h b/src/komodo_notary.h index 638327e81..0d07cef52 100644 --- a/src/komodo_notary.h +++ b/src/komodo_notary.h @@ -205,7 +205,7 @@ int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestam timestamp = komodo_heightstamp(height); if ( height >= KOMODO_NOTARIES_HARDCODED || ASSETCHAINS_SYMBOL[0] != 0 ) { - if ( (timestamp != 0 && timestamp <= KOMODO_NOTARIES_TIMESTAMP1) || height <= KOMODO_NOTARIES_HEIGHT1 ) + if ( (timestamp != 0 && timestamp <= KOMODO_NOTARIES_TIMESTAMP1) || (ASSETCHAINS_SYMBOL[0] == 0 && height <= KOMODO_NOTARIES_HEIGHT1) ) { if ( did0 == 0 ) { @@ -381,7 +381,7 @@ int32_t komodo_chosennotary(int32_t *notaryidp,int32_t height,uint8_t *pubkey33, void komodo_notarized_update(struct komodo_state *sp,int32_t nHeight,int32_t notarized_height,uint256 notarized_hash,uint256 notarized_desttxid,uint256 MoM,int32_t MoMdepth) { struct notarized_checkpoint *np; - if ( notarized_height > nHeight ) + if ( notarized_height >= nHeight ) { printf("komodo_notarized_update REJECT notarized_height %d > %d nHeight\n",notarized_height,nHeight); return; diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 1270b3e55..999200c13 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1365,7 +1365,7 @@ void komodo_configfile(char *symbol,uint16_t port) #ifndef FROM_CLI if ( (fp= fopen(fname,"wb")) != 0 ) { - fprintf(fp,"rpcuser=user%u\nrpcpassword=pass%s\nrpcport=%u\nserver=1\ntxindex=1\nrpcworkqueue=64\n",crc,password,port); + fprintf(fp,"rpcuser=user%u\nrpcpassword=pass%s\nrpcport=%u\nserver=1\ntxindex=1\nrpcworkqueue=64\nrpcallowip=127.0.0.1\n",crc,password,port); fclose(fp); printf("Created (%s)\n",fname); } else printf("Couldnt create (%s)\n",fname); From e625be68a90373527085b8c06b9f88fe26666f46 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Fri, 6 Apr 2018 02:55:47 -0300 Subject: [PATCH 062/339] allow larger PUSHDATA for CC fulfillment --- src/komodo_cc.cpp | 41 +++++++++++++++++++++-- src/komodo_cc.h | 10 ++++++ src/script/interpreter.cpp | 38 ++++++++++++++++++++- src/script/script.h | 3 ++ src/test-komodo/test_cryptoconditions.cpp | 27 +++++++++++++++ 5 files changed, 116 insertions(+), 3 deletions(-) diff --git a/src/komodo_cc.cpp b/src/komodo_cc.cpp index e7b166eba..1ebcd7e89 100644 --- a/src/komodo_cc.cpp +++ b/src/komodo_cc.cpp @@ -32,6 +32,43 @@ bool IsSignedCryptoCondition(const CC *cond) } +static unsigned char* CopyPubKey(CPubKey pkIn) +{ + unsigned char* pk = (unsigned char*) malloc(33); + memcpy(pk, pkIn.begin(), 33); // TODO: compressed? + return pk; +} + + +CC* CCNewThreshold(int t, std::vector v) +{ + CC *cond = cc_new(CC_Threshold); + cond->threshold = t; + cond->size = v.size(); + cond->subconditions = (CC**) calloc(v.size(), sizeof(CC*)); + memcpy(cond->subconditions, v.data(), v.size() * sizeof(CC*)); + return cond; +} + + +CC* CCNewSecp256k1(CPubKey k) +{ + CC *cond = cc_new(CC_Secp256k1); + cond->publicKey = CopyPubKey(k); + return cond; +} + + +CC* CCNewEval(std::string method, std::vector paramsBin) +{ + CC *cond = cc_new(CC_Eval); + strcpy(cond->method, method.data()); + cond->paramsBin = (unsigned char*) malloc(paramsBin.size()); + memcpy(cond->paramsBin, paramsBin.data(), paramsBin.size()); + cond->paramsBinLength = paramsBin.size(); + return cond; +} + CScript CCPubKey(const CC *cond) { @@ -43,8 +80,8 @@ CScript CCPubKey(const CC *cond) CScript CCSig(const CC *cond) { - unsigned char buf[1000]; - size_t len = cc_fulfillmentBinary(cond, buf, 1000); + unsigned char buf[10000]; + size_t len = cc_fulfillmentBinary(cond, buf, 10000); auto ffill = std::vector(buf, buf+len); ffill.push_back(1); // SIGHASH_ALL return CScript() << ffill; diff --git a/src/komodo_cc.h b/src/komodo_cc.h index 78cb4401a..af9efef1c 100644 --- a/src/komodo_cc.h +++ b/src/komodo_cc.h @@ -1,6 +1,7 @@ #ifndef KOMODO_CC_H #define KOMODO_CC_H +#include "pubkey.h" #include "script/script.h" #include "cryptoconditions/include/cryptoconditions.h" @@ -32,6 +33,15 @@ bool IsSupportedCryptoCondition(const CC *cond); bool IsSignedCryptoCondition(const CC *cond); +/* + * Construct crypto conditions + */ +CC* CCNewPreimage(std::vector preimage); +CC* CCNewEval(std::string method, std::vector paramsBin); +CC* CCNewSecp256k1(CPubKey k); +CC* CCNewThreshold(int t, std::vector v); + + /* * Turn a condition into a scriptPubKey */ diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 31a7fdbd0..5438102c3 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1372,6 +1372,37 @@ bool TransactionSignatureChecker::CheckLockTime(const CScriptNum& nLockTime) con } +/* + * Allow larger opcode in case of crypto condition scriptSig + */ +bool EvalCryptoConditionSig( + vector >& stack, + const CScript& scriptSig, + ScriptError* serror) +{ + CScript::const_iterator pc = scriptSig.begin(); + opcodetype opcode; + valtype vchPushValue; + set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR); + + if (!scriptSig.GetOp(pc, opcode, vchPushValue)) + return set_error(serror, SCRIPT_ERR_BAD_OPCODE); + + if (opcode == 0 || opcode > OP_PUSHDATA4) + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); + + if (pc != scriptSig.end()) + return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); + + if (vchPushValue.size() > MAX_SCRIPT_CRYPTOCONDITION_FULFILLMENT_SIZE) + return set_error(serror, SCRIPT_ERR_PUSH_SIZE); + + stack.push_back(vchPushValue); + + return true; +} + + bool VerifyScript( const CScript& scriptSig, const CScript& scriptPubKey, @@ -1387,7 +1418,12 @@ bool VerifyScript( } vector > stack, stackCopy; - if (!EvalScript(stack, scriptSig, flags, checker, consensusBranchId, serror)) + if (IsCryptoConditionsEnabled() && scriptPubKey.IsPayToCryptoCondition()) { + if (!EvalCryptoConditionSig(stack, scriptSig, serror)) + // serror is set + return false; + } + else if (!EvalScript(stack, scriptSig, flags, checker, consensusBranchId, serror)) // serror is set return false; if (flags & SCRIPT_VERIFY_P2SH) diff --git a/src/script/script.h b/src/script/script.h index b7442a419..6b8c07b07 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -19,6 +19,9 @@ static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520; // bytes +// Max size of pushdata in a CC sig in bytes +static const unsigned int MAX_SCRIPT_CRYPTOCONDITION_FULFILLMENT_SIZE = 2048; + // Maximum script length in bytes static const int MAX_SCRIPT_SIZE = 10000; diff --git a/src/test-komodo/test_cryptoconditions.cpp b/src/test-komodo/test_cryptoconditions.cpp index f22d50be3..6f31914df 100644 --- a/src/test-komodo/test_cryptoconditions.cpp +++ b/src/test-komodo/test_cryptoconditions.cpp @@ -199,3 +199,30 @@ TEST_F(CCTest, testCryptoConditionsDisabled) ASSETCHAINS_CC = 0; ASSERT_FALSE(Verify(cond)); } + + +TEST_F(CCTest, testLargeCondition) +{ + CC *cond; + ScriptError error; + CMutableTransaction mtxTo; + + auto Verify = [&] (const CC *cond) { + CAmount amount; + CTransaction txTo(mtxTo); + PrecomputedTransactionData txdata(txTo); + auto checker = ServerTransactionSignatureChecker(&txTo, 0, amount, false, txdata); + return VerifyScript(CCSig(cond), CCPubKey(cond), 0, checker, 0, &error); + }; + + std::vector ccs; + for (int i=0; i<18; i++) { + ccs.push_back(CCNewSecp256k1(notaryKey.GetPubKey())); + } + cond = CCNewThreshold(16, ccs); + CCSign(mtxTo, cond); + EXPECT_EQ("(16 of 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,A5,A5)", + CCShowStructure(CCPrune(cond))); + EXPECT_EQ(1744, CCSig(cond).size()); + ASSERT_TRUE(Verify(cond)); +} From 9bf132a5a849472c672661cc18fbc1bb6d88223b Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Fri, 6 Apr 2018 03:52:30 -0300 Subject: [PATCH 063/339] tests for getting MoM in Eval and fixes --- src/Makefile.ktest.include | 3 +- src/cc/betprotocol.cpp | 38 ---- src/cc/betprotocol.h | 8 +- src/cc/eval.cpp | 74 ++++--- src/cc/eval.h | 28 ++- src/cc/importpayout.cpp | 6 +- src/rpcblockchain.cpp | 19 +- .../{test_bet.cpp => test_eval_bet.cpp} | 19 +- src/test-komodo/test_eval_notarisation.cpp | 203 ++++++++++++++++++ 9 files changed, 307 insertions(+), 91 deletions(-) rename src/test-komodo/{test_bet.cpp => test_eval_bet.cpp} (98%) create mode 100644 src/test-komodo/test_eval_notarisation.cpp diff --git a/src/Makefile.ktest.include b/src/Makefile.ktest.include index cef80b0d1..06aab54dc 100644 --- a/src/Makefile.ktest.include +++ b/src/Makefile.ktest.include @@ -6,7 +6,8 @@ bin_PROGRAMS += komodo-test komodo_test_SOURCES = \ test-komodo/main.cpp \ test-komodo/test_cryptoconditions.cpp \ - test-komodo/test_bet.cpp + test-komodo/test_eval_bet.cpp \ + test-komodo/test_eval_notarisation.cpp komodo_test_CPPFLAGS = $(komodod_CPPFLAGS) diff --git a/src/cc/betprotocol.cpp b/src/cc/betprotocol.cpp index 92ec961ee..12637ebbd 100644 --- a/src/cc/betprotocol.cpp +++ b/src/cc/betprotocol.cpp @@ -7,44 +7,6 @@ #include "primitives/transaction.h" -static unsigned char* CopyPubKey(CPubKey pkIn) -{ - unsigned char* pk = (unsigned char*) malloc(33); - memcpy(pk, pkIn.begin(), 33); // TODO: compressed? - return pk; -} - - -CC* CCNewThreshold(int t, std::vector v) -{ - CC *cond = cc_new(CC_Threshold); - cond->threshold = t; - cond->size = v.size(); - cond->subconditions = (CC**) calloc(v.size(), sizeof(CC*)); - memcpy(cond->subconditions, v.data(), v.size() * sizeof(CC*)); - return cond; -} - - -CC* CCNewSecp256k1(CPubKey k) -{ - CC *cond = cc_new(CC_Secp256k1); - cond->publicKey = CopyPubKey(k); - return cond; -} - - -CC* CCNewEval(std::string method, std::vector paramsBin) -{ - CC *cond = cc_new(CC_Eval); - strcpy(cond->method, method.data()); - cond->paramsBin = (unsigned char*) malloc(paramsBin.size()); - memcpy(cond->paramsBin, paramsBin.data(), paramsBin.size()); - cond->paramsBinLength = paramsBin.size(); - return cond; -} - - std::vector BetProtocol::PlayerConditions() { std::vector subs; diff --git a/src/cc/betprotocol.h b/src/cc/betprotocol.h index dcbb6ec4e..67a1979c3 100644 --- a/src/cc/betprotocol.h +++ b/src/cc/betprotocol.h @@ -2,13 +2,11 @@ #define BETPROTOCOL_H #include "pubkey.h" +#include "primitives/block.h" #include "primitives/transaction.h" #include "cryptoconditions/include/cryptoconditions.h" -#define ExecMerkle CBlock::CheckMerkleBranch - - class MoMProof { public: @@ -18,6 +16,7 @@ public: MoMProof() {} MoMProof(int i, std::vector b, uint256 n) : notarisationHash(n), nIndex(i), branch(b) {} + uint256 Exec(uint256 hash) const { return CBlock::CheckMerkleBranch(hash, branch, nIndex); } ADD_SERIALIZE_METHODS; @@ -79,7 +78,4 @@ public: }; -CC* CCNewSecp256k1(CPubKey k); - - #endif /* BETPROTOCOL_H */ diff --git a/src/cc/eval.cpp b/src/cc/eval.cpp index 589a362c0..3c605e1af 100644 --- a/src/cc/eval.cpp +++ b/src/cc/eval.cpp @@ -88,14 +88,19 @@ bool Eval::GetBlock(uint256 hash, CBlockIndex& blockIdx) const extern int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp); +int32_t Eval::GetNotaries(uint8_t pubkeys[64][33], int32_t height, uint32_t timestamp) const +{ + return komodo_notaries(pubkeys, height, timestamp); +} + + bool Eval::CheckNotaryInputs(const CTransaction &tx, uint32_t height, uint32_t timestamp) const { if (tx.vin.size() < 11) return false; + uint8_t seenNotaries[64] = {0}; uint8_t notaries[64][33]; - uint8_t seenNotaries[64]; - int nNotaries = komodo_notaries(notaries, height, timestamp); - char pk[33]; + int nNotaries = GetNotaries(notaries, height, timestamp); BOOST_FOREACH(const CTxIn &txIn, tx.vin) { @@ -104,10 +109,11 @@ bool Eval::CheckNotaryInputs(const CTransaction &tx, uint32_t height, uint32_t t uint256 hashBlock; if (!GetTx(txIn.prevout.hash, tx, hashBlock, false)) return false; if (tx.vout.size() < txIn.prevout.n) return false; - const unsigned char *script = tx.vout[txIn.prevout.n].scriptPubKey.data(); - if (script[0] != 33) return false; - memcpy(pk, script+1, 33); - return true; + CScript spk = tx.vout[txIn.prevout.n].scriptPubKey; + if (spk.size() != 35) return false; + const unsigned char *pk = spk.data(); + if (pk++[0] != 33) return false; + if (pk[33] != OP_CHECKSIG) return false; // Check it's a notary for (int i=0; i vdata; + if (!GetOpReturnData(scriptPK, vdata)) return false; + + CDataStream ss(vdata, SER_NETWORK, PROTOCOL_VERSION); + + try { + ss >> blockHash; + ss >> height; + + char *nullPos = (char*) memchr(&ss[0], 0, ss.size()); + if (!nullPos) return false; + ss.read(symbol, nullPos-&ss[0]+1); + + if (ss.size() != 36) return false; + ss >> MoM; + ss >> MoMDepth; + } catch (...) { + return false; + } + return true; +} + + + /* * Get MoM from a notarisation tx hash */ -bool Eval::GetMoM(const uint256 notaryHash, uint256 &mom) const +bool Eval::GetNotarisationData(const uint256 notaryHash, NotarisationData &data) const { CTransaction notarisationTx; uint256 notarisationBlock; - if (!GetTx(notaryHash, notarisationTx, notarisationBlock, true)) return 0; + if (!GetTx(notaryHash, notarisationTx, notarisationBlock, true)) return false; CBlockIndex block; - if (!GetBlock(notarisationBlock, block)) return 0; - if (!CheckNotaryInputs(notarisationTx, block.nHeight, block.nTime)) { - return false; - } - if (!notarisationTx.vout.size() < 1) return 0; - std::vector opret; - if (!GetOpReturnData(notarisationTx.vout[0].scriptPubKey, opret)) return 0; - if (opret.size() < 36) return 0; // In reality it is more than 36, but at the moment I - // only know where it is relative to the end, and this - // is enough to prevent a memory fault. In the case that - // the assumption about the presence of a MoM at this - // offset fails, we will return random other data that is - // not more likely to generate a false positive. - memcpy(mom.begin(), opret.data()+opret.size()-36, 32); - return 1; + if (!GetBlock(notarisationBlock, block)) return false; + if (!CheckNotaryInputs(notarisationTx, block.nHeight, block.nTime)) return false; + if (notarisationTx.vout.size() < 2) return false; + if (!data.Parse(notarisationTx.vout[1].scriptPubKey)) return false; + return true; } diff --git a/src/cc/eval.h b/src/cc/eval.h index 2060d76ca..55d45153c 100644 --- a/src/cc/eval.h +++ b/src/cc/eval.h @@ -11,6 +11,7 @@ class AppVM; +class NotarisationData; class Eval @@ -44,7 +45,8 @@ public: virtual unsigned int GetCurrentHeight() const; virtual bool GetSpends(uint256 hash, std::vector &spends) const; virtual bool GetBlock(uint256 hash, CBlockIndex& blockIdx) const; - virtual bool GetMoM(uint256 notarisationHash, uint256& MoM) const; + virtual int32_t GetNotaries(uint8_t pubkeys[64][33], int32_t height, uint32_t timestamp) const; + virtual bool GetNotarisationData(uint256 notarisationHash, NotarisationData &data) const; virtual bool CheckNotaryInputs(const CTransaction &tx, uint32_t height, uint32_t timestamp) const; }; @@ -69,16 +71,25 @@ public: }; +/* + * Data from notarisation OP_RETURN + */ +class NotarisationData { +public: + uint256 blockHash; + uint32_t height; + uint256 txHash; + char symbol[64]; + uint256 MoM; + uint32_t MoMDepth; + + bool Parse(CScript scriptPubKey); +}; + + /* * Serialisation boilerplate */ -template -std::vector CheckSerialize(T &in); -template -bool CheckDeserialize(std::vector vIn, T &out); - - - template std::vector CheckSerialize(T &in) { @@ -87,7 +98,6 @@ std::vector CheckSerialize(T &in) return std::vector(ss.begin(), ss.end()); } - template bool CheckDeserialize(std::vector vIn, T &out) { diff --git a/src/cc/importpayout.cpp b/src/cc/importpayout.cpp index 5251f1dfd..3be0cdaf7 100644 --- a/src/cc/importpayout.cpp +++ b/src/cc/importpayout.cpp @@ -69,10 +69,10 @@ bool Eval::ImportPayout(const CC *cond, const CTransaction &payoutTx, unsigned i if (!CheckDeserialize(vProof, proof)) return Invalid("invalid-mom-proof-payload"); - uint256 MoM; - if (!GetMoM(proof.notarisationHash, MoM)) return Invalid("coudnt-load-mom"); + NotarisationData data; + if (!GetNotarisationData(proof.notarisationHash, data)) return Invalid("coudnt-load-mom"); - if (MoM != ExecMerkle(disputeTx.GetHash(), proof.branch, proof.nIndex)) + if (data.MoM != proof.Exec(disputeTx.GetHash())) return Invalid("mom-check-fail"); } diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index f353d549d..343b651f0 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -635,7 +635,7 @@ UniValue txMoMproof(const UniValue& params, bool fHelp) if ( fHelp || params.size() != 1) throw runtime_error("txmomproof needs a txid"); - uint256 hash(uint256S(params[0].get_str())); + hash = uint256S(params[0].get_str()); uint256 blockHash; CTransaction tx; @@ -666,6 +666,10 @@ UniValue txMoMproof(const UniValue& params, bool fHelp) fakeBlock.vtx.push_back(fakeTx); } branch = fakeBlock.GetMerkleBranch(nIndex); + + // Check branch + if (MoM != CBlock::CheckMerkleBranch(blockIndex->hashMerkleRoot, branch, nIndex)) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Failed merkle block->MoM"); } // Now get the tx merkle branch @@ -687,12 +691,21 @@ UniValue txMoMproof(const UniValue& params, bool fHelp) if (nTxIndex == (int)block.vtx.size()) throw JSONRPCError(RPC_INTERNAL_ERROR, "Error locating tx in block"); - // concatenate branches std::vector txBranch = block.GetMerkleBranch(nTxIndex); - nIndex = nIndex << txBranch.size() + nTxIndex; + + // Check branch + if (block.hashMerkleRoot != CBlock::CheckMerkleBranch(hash, txBranch, nTxIndex)) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Failed merkle tx->block"); + + // concatenate branches + nIndex = (nIndex << txBranch.size()) + nTxIndex; branch.insert(branch.begin(), txBranch.begin(), txBranch.end()); } + // Check the proof + if (MoM != CBlock::CheckMerkleBranch(hash, branch, nIndex)) + throw JSONRPCError(RPC_INTERNAL_ERROR, "Failed validating MoM"); + // Encode and return CDataStream ssProof(SER_NETWORK, PROTOCOL_VERSION); ssProof << MoMProof(nIndex, branch, notarisationHash); diff --git a/src/test-komodo/test_bet.cpp b/src/test-komodo/test_eval_bet.cpp similarity index 98% rename from src/test-komodo/test_bet.cpp rename to src/test-komodo/test_eval_bet.cpp index d0072ad38..25fea5d84 100644 --- a/src/test-komodo/test_bet.cpp +++ b/src/test-komodo/test_eval_bet.cpp @@ -14,6 +14,11 @@ #include "testutils.h" +extern Eval* EVAL_TEST; + + +namespace TestBet { + static std::vector playerSecrets; static std::vector players; @@ -72,7 +77,7 @@ public: std::map blocks; std::map> spends; - bool Dispatch(const CC *cond, const CTransaction &txTo, unsigned int nIn) + bool Dispatch(const CC *cond, const CTransaction &txTo, unsigned int nIn) { if (strcmp(cond->method, "DisputeBet") == 0) { MockVM vm; @@ -115,10 +120,10 @@ public: return true; } - bool GetMoM(uint256 notarisationHash, uint256& _MoM) const + bool GetNotarisationData(uint256 notarisationHash, NotarisationData &data) const { if (notarisationHash == NotarisationHash()) { - _MoM = MoM; + data.MoM = MoM; return true; } return false; @@ -133,9 +138,6 @@ public: }; -extern Eval* EVAL_TEST; - - /* * Generates example data that we will test with and shows how to call BetProtocol. */ @@ -230,7 +232,7 @@ public: eval.currentHeight = currentHeight; MoMProof proof = GetMoMProof(); - eval.MoM = ExecMerkle(DisputeTx(Player2).GetHash(), proof.branch, proof.nIndex); + eval.MoM = proof.Exec(DisputeTx(Player2).GetHash()); EVAL_TEST = &eval; return eval; @@ -594,3 +596,6 @@ TEST_F(TestBet, testImportPayoutMomFail) EXPECT_FALSE(TestCC(importTx, 0, payoutCond)); EXPECT_EQ("mom-check-fail", eval.state.GetRejectReason()); } + + +} /* namespace TestBet */ diff --git a/src/test-komodo/test_eval_notarisation.cpp b/src/test-komodo/test_eval_notarisation.cpp new file mode 100644 index 000000000..736e28931 --- /dev/null +++ b/src/test-komodo/test_eval_notarisation.cpp @@ -0,0 +1,203 @@ +#include +#include + +#include "cc/betprotocol.h" +#include "cc/eval.h" +#include "base58.h" +#include "core_io.h" +#include "key.h" +#include "main.h" +#include "komodo_cc.h" +#include "primitives/transaction.h" +#include "script/interpreter.h" +#include "script/serverchecker.h" + +#include "testutils.h" + + +extern Eval* EVAL_TEST; +extern int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp); + + +namespace TestEvalNotarisation { + + +class EvalMock : public Eval +{ +public: + uint32_t nNotaries; + uint8_t notaries[64][33]; + std::map txs; + std::map blocks; + + int32_t GetNotaries(uint8_t pubkeys[64][33], int32_t height, uint32_t timestamp) const + { + memcpy(pubkeys, notaries, sizeof(notaries)); + return nNotaries; + } + + bool GetTx(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow) const + { + auto r = txs.find(hash); + if (r != txs.end()) { + txOut = r->second; + hashBlock = hash; + return true; + } + return false; + } + + bool GetBlock(uint256 hash, CBlockIndex& blockIdx) const + { + auto r = blocks.find(hash); + if (r == blocks.end()) return false; + blockIdx = r->second; + return true; + } +}; + +static auto noop = [&](CMutableTransaction &mtx){}; + + +template +void SetEval(EvalMock &eval, CMutableTransaction ¬ary, Modifier modify) +{ + eval.nNotaries = komodo_notaries(eval.notaries, 780060, 1522946781); + + // make fake notary inputs + notary.vin.resize(11); + for (int i=0; i Date: Fri, 6 Apr 2018 03:59:03 -0300 Subject: [PATCH 064/339] make log messages more useful --- src/cc/eval.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/cc/eval.cpp b/src/cc/eval.cpp index 3c605e1af..352a64c4b 100644 --- a/src/cc/eval.cpp +++ b/src/cc/eval.cpp @@ -6,6 +6,7 @@ #include "cc/eval.h" #include "main.h" #include "chain.h" +#include "core_io.h" Eval* EVAL_TEST = 0; @@ -23,8 +24,9 @@ bool RunCCEval(const CC *cond, const CTransaction &tx, unsigned int nIn) if (eval->state.IsValid()) return true; std::string lvl = eval->state.IsInvalid() ? "Invalid" : "Error!"; - fprintf(stderr, "CC Eval %s %s: %s in tx %s\n", lvl.data(), cond->method, - eval->state.GetRejectReason().data(), tx.GetHash().GetHex().data()); + fprintf(stderr, "CC Eval %s %s: %s spending tx %s\n", lvl.data(), cond->method, + eval->state.GetRejectReason().data(), tx.vin[nIn].prevout.hash.GetHex().data()); + if (eval->state.IsError()) fprintf(stderr, "Culprit: %s\n", EncodeHexTx(tx).data()); return false; } From 88d4a95ae72bfcbaf47ed373706ac68107040c3d Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 6 Apr 2018 12:40:00 +0300 Subject: [PATCH 065/339] Test --- src/komodo_gateway.h | 4 ++++ src/komodo_kv.h | 2 +- src/komodo_notary.h | 55 +++++++++++++++++++++++++------------------- 3 files changed, 36 insertions(+), 25 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 2b3d382ac..055959cc9 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -711,6 +711,10 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block) // verify above if ( height >= activation ) return(-1); } + else if ( block.nBits == KOMODO_MINDIFF_NBITS && total > 0 ) + { + fprintf(stderr,"notary mined ht.%d with extra %.8f\n",height,dstr(total)); + } } else { diff --git a/src/komodo_kv.h b/src/komodo_kv.h index 9aca2d387..453608cc1 100644 --- a/src/komodo_kv.h +++ b/src/komodo_kv.h @@ -171,7 +171,7 @@ void komodo_kvupdate(uint8_t *opretbuf,int32_t opretlen,uint64_t value) memcpy(ptr->key,key,keylen); newflag = 1; HASH_ADD_KEYPTR(hh,KOMODO_KV,ptr->key,ptr->keylen,ptr); - //printf("KV add.(%s) (%s)\n",ptr->key,valueptr); + printf("KV add.(%s) (%s)\n",ptr->key,valueptr); } if ( newflag != 0 || (ptr->flags & KOMODO_KVPROTECTED) == 0 ) { diff --git a/src/komodo_notary.h b/src/komodo_notary.h index 0d07cef52..6b75a39d5 100644 --- a/src/komodo_notary.h +++ b/src/komodo_notary.h @@ -131,8 +131,8 @@ const char *Notaries_elected0[][2] = const char *Notaries_elected1[][2] = { - { "0_jl777_testB", "02ebfc784a4ba768aad88d44d1045d240d47b26e248cafaf1c5169a42d7a61d344" }, { "0_jl777_testA", "03b7621b44118017a16043f19b30cc8a4cfe068ac4e42417bae16ba460c80f3828" }, + { "0_jl777_testB", "02ebfc784a4ba768aad88d44d1045d240d47b26e248cafaf1c5169a42d7a61d344" }, { "0_kolo_testA", "0287aa4b73988ba26cf6565d815786caf0d2c4af704d7883d163ee89cd9977edec" }, { "artik_AR", "029acf1dcd9f5ff9c455f8bb717d4ae0c703e089d16cf8424619c491dff5994c90" }, { "artik_EU", "03f54b2c24f82632e3cdebe4568ba0acf487a80f8a89779173cdb78f74514847ce" }, @@ -378,29 +378,6 @@ int32_t komodo_chosennotary(int32_t *notaryidp,int32_t height,uint8_t *pubkey33, return(modval); } -void komodo_notarized_update(struct komodo_state *sp,int32_t nHeight,int32_t notarized_height,uint256 notarized_hash,uint256 notarized_desttxid,uint256 MoM,int32_t MoMdepth) -{ - struct notarized_checkpoint *np; - if ( notarized_height >= nHeight ) - { - printf("komodo_notarized_update REJECT notarized_height %d > %d nHeight\n",notarized_height,nHeight); - return; - } - if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 ) - printf("[%s] komodo_notarized_update nHeight.%d notarized_height.%d\n",ASSETCHAINS_SYMBOL,nHeight,notarized_height); - portable_mutex_lock(&komodo_mutex); - sp->NPOINTS = (struct notarized_checkpoint *)realloc(sp->NPOINTS,(sp->NUM_NPOINTS+1) * sizeof(*sp->NPOINTS)); - np = &sp->NPOINTS[sp->NUM_NPOINTS++]; - memset(np,0,sizeof(*np)); - np->nHeight = nHeight; - sp->NOTARIZED_HEIGHT = np->notarized_height = notarized_height; - sp->NOTARIZED_HASH = np->notarized_hash = notarized_hash; - sp->NOTARIZED_DESTTXID = np->notarized_desttxid = notarized_desttxid; - sp->MoM = np->MoM = MoM; - sp->MoMdepth = np->MoMdepth = MoMdepth; - portable_mutex_unlock(&komodo_mutex); -} - //struct komodo_state *komodo_stateptr(char *symbol,char *dest); int32_t komodo_notarized_height(uint256 *hashp,uint256 *txidp) { @@ -499,6 +476,36 @@ int32_t komodo_notarizeddata(int32_t nHeight,uint256 *notarized_hashp,uint256 *n return(0); } +void komodo_notarized_update(struct komodo_state *sp,int32_t nHeight,int32_t notarized_height,uint256 notarized_hash,uint256 notarized_desttxid,uint256 MoM,int32_t MoMdepth) +{ + struct notarized_checkpoint *np; uint256 hash,desttxid; int32_t ht; + if ( notarized_height >= nHeight ) + { + fprintf(stderr,"komodo_notarized_update REJECT notarized_height %d > %d nHeight\n",notarized_height,nHeight); + return; + } + if ( (ht= komodo_notarizeddata(notarized_height,&hash,&desttxid)) > 0 ) + { + fprintf(stderr,"komodo_notarized_update %d already there ht.%d hash %s vs %s\n",notarized_height,ht,hash.ToString().cstr(),desttxid.ToString().cstr()); + } + else + { + if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 ) + fprintf(stderr,"[%s] komodo_notarized_update nHeight.%d notarized_height.%d\n",ASSETCHAINS_SYMBOL,nHeight,notarized_height); + portable_mutex_lock(&komodo_mutex); + sp->NPOINTS = (struct notarized_checkpoint *)realloc(sp->NPOINTS,(sp->NUM_NPOINTS+1) * sizeof(*sp->NPOINTS)); + np = &sp->NPOINTS[sp->NUM_NPOINTS++]; + memset(np,0,sizeof(*np)); + np->nHeight = nHeight; + sp->NOTARIZED_HEIGHT = np->notarized_height = notarized_height; + sp->NOTARIZED_HASH = np->notarized_hash = notarized_hash; + sp->NOTARIZED_DESTTXID = np->notarized_desttxid = notarized_desttxid; + sp->MoM = np->MoM = MoM; + sp->MoMdepth = np->MoMdepth = MoMdepth; + portable_mutex_unlock(&komodo_mutex); + } +} + void komodo_init(int32_t height) { static int didinit; uint256 zero; int32_t k,n; uint8_t pubkeys[64][33]; From bd08718ae870016189d6feaa4c9ef2958990b7f3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 6 Apr 2018 12:41:48 +0300 Subject: [PATCH 066/339] Test --- src/komodo_notary.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_notary.h b/src/komodo_notary.h index 6b75a39d5..a1b5aaadd 100644 --- a/src/komodo_notary.h +++ b/src/komodo_notary.h @@ -486,7 +486,7 @@ void komodo_notarized_update(struct komodo_state *sp,int32_t nHeight,int32_t not } if ( (ht= komodo_notarizeddata(notarized_height,&hash,&desttxid)) > 0 ) { - fprintf(stderr,"komodo_notarized_update %d already there ht.%d hash %s vs %s\n",notarized_height,ht,hash.ToString().cstr(),desttxid.ToString().cstr()); + fprintf(stderr,"komodo_notarized_update %d already there ht.%d hash %s vs %s\n",notarized_height,ht,hash.ToString().c_str(),desttxid.ToString().c_str()); } else { From 54ecb7e4e653cd02aadceae9f21dec1bab37eac7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 6 Apr 2018 12:45:36 +0300 Subject: [PATCH 067/339] Test --- src/komodo_gateway.h | 2 ++ src/komodo_notary.h | 33 +++++++++++++-------------------- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 055959cc9..7b9403d72 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -714,6 +714,8 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block) // verify above else if ( block.nBits == KOMODO_MINDIFF_NBITS && total > 0 ) { fprintf(stderr,"notary mined ht.%d with extra %.8f\n",height,dstr(total)); + if ( height > KOMODO_NOTARIES_HEIGHT1 ) + return(-1); } } else diff --git a/src/komodo_notary.h b/src/komodo_notary.h index a1b5aaadd..6388c1b7f 100644 --- a/src/komodo_notary.h +++ b/src/komodo_notary.h @@ -484,26 +484,19 @@ void komodo_notarized_update(struct komodo_state *sp,int32_t nHeight,int32_t not fprintf(stderr,"komodo_notarized_update REJECT notarized_height %d > %d nHeight\n",notarized_height,nHeight); return; } - if ( (ht= komodo_notarizeddata(notarized_height,&hash,&desttxid)) > 0 ) - { - fprintf(stderr,"komodo_notarized_update %d already there ht.%d hash %s vs %s\n",notarized_height,ht,hash.ToString().c_str(),desttxid.ToString().c_str()); - } - else - { - if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 ) - fprintf(stderr,"[%s] komodo_notarized_update nHeight.%d notarized_height.%d\n",ASSETCHAINS_SYMBOL,nHeight,notarized_height); - portable_mutex_lock(&komodo_mutex); - sp->NPOINTS = (struct notarized_checkpoint *)realloc(sp->NPOINTS,(sp->NUM_NPOINTS+1) * sizeof(*sp->NPOINTS)); - np = &sp->NPOINTS[sp->NUM_NPOINTS++]; - memset(np,0,sizeof(*np)); - np->nHeight = nHeight; - sp->NOTARIZED_HEIGHT = np->notarized_height = notarized_height; - sp->NOTARIZED_HASH = np->notarized_hash = notarized_hash; - sp->NOTARIZED_DESTTXID = np->notarized_desttxid = notarized_desttxid; - sp->MoM = np->MoM = MoM; - sp->MoMdepth = np->MoMdepth = MoMdepth; - portable_mutex_unlock(&komodo_mutex); - } + if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 ) + fprintf(stderr,"[%s] komodo_notarized_update nHeight.%d notarized_height.%d\n",ASSETCHAINS_SYMBOL,nHeight,notarized_height); + portable_mutex_lock(&komodo_mutex); + sp->NPOINTS = (struct notarized_checkpoint *)realloc(sp->NPOINTS,(sp->NUM_NPOINTS+1) * sizeof(*sp->NPOINTS)); + np = &sp->NPOINTS[sp->NUM_NPOINTS++]; + memset(np,0,sizeof(*np)); + np->nHeight = nHeight; + sp->NOTARIZED_HEIGHT = np->notarized_height = notarized_height; + sp->NOTARIZED_HASH = np->notarized_hash = notarized_hash; + sp->NOTARIZED_DESTTXID = np->notarized_desttxid = notarized_desttxid; + sp->MoM = np->MoM = MoM; + sp->MoMdepth = np->MoMdepth = MoMdepth; + portable_mutex_unlock(&komodo_mutex); } void komodo_init(int32_t height) From 858a837fc8835afae720fdd02e115cb3811e9120 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 6 Apr 2018 12:46:08 +0300 Subject: [PATCH 068/339] Test --- src/komodo_notary.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_notary.h b/src/komodo_notary.h index 6388c1b7f..789c588f2 100644 --- a/src/komodo_notary.h +++ b/src/komodo_notary.h @@ -478,7 +478,7 @@ int32_t komodo_notarizeddata(int32_t nHeight,uint256 *notarized_hashp,uint256 *n void komodo_notarized_update(struct komodo_state *sp,int32_t nHeight,int32_t notarized_height,uint256 notarized_hash,uint256 notarized_desttxid,uint256 MoM,int32_t MoMdepth) { - struct notarized_checkpoint *np; uint256 hash,desttxid; int32_t ht; + struct notarized_checkpoint *np; if ( notarized_height >= nHeight ) { fprintf(stderr,"komodo_notarized_update REJECT notarized_height %d > %d nHeight\n",notarized_height,nHeight); From 5c079fa330ef5f3d27c38785aed62f646171d075 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 6 Apr 2018 13:18:38 +0300 Subject: [PATCH 069/339] Test --- src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 151c42383..8dd3688fc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2585,8 +2585,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime1 - nTimeStart), 0.001 * (nTime1 - nTimeStart) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime1 - nTimeStart) / (nInputs-1), nTimeConnect * 0.000001); CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus()); - if (block.vtx[0].vout[0].nValue > blockReward) - //if (block.vtx[0].GetValueOut() > blockReward) + //if (block.vtx[0].vout[0].nValue > blockReward) + if (block.vtx[0].GetValueOut() > blockReward) return state.DoS(100, error("ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)", block.vtx[0].GetValueOut(), blockReward), From 0b652b660a3dd8ad732e4d9156ef5eb6fbbb418c Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 6 Apr 2018 13:22:26 +0300 Subject: [PATCH 070/339] Test --- src/main.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 8dd3688fc..a82f42fbb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2585,13 +2585,16 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime1 - nTimeStart), 0.001 * (nTime1 - nTimeStart) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime1 - nTimeStart) / (nInputs-1), nTimeConnect * 0.000001); CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus()); - //if (block.vtx[0].vout[0].nValue > blockReward) - if (block.vtx[0].GetValueOut() > blockReward) - return state.DoS(100, + if ( block.vtx[0].GetValueOut() > blockReward) + { + if ( nHeight < KOMODO_NOTARIES_HEIGHT1 || block.vtx[0].vout[0].nValue > blockReward ) + { + return state.DoS(100, error("ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)", block.vtx[0].GetValueOut(), blockReward), REJECT_INVALID, "bad-cb-amount"); - + } else fprintf(stderr,"nHeight.%d coinbase %.8f vs %.8f\n",(int32_t)nHeight,dstr(block.vtx[0].GetValueOut()),dstr(blockReward)); + } if (!control.Wait()) return state.DoS(100, false); int64_t nTime2 = GetTimeMicros(); nTimeVerify += nTime2 - nTimeStart; From 5ba45a00f1e6afde6bac601f0f2bce0914343e48 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 6 Apr 2018 13:23:39 +0300 Subject: [PATCH 071/339] Test --- src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index a82f42fbb..3ffd1b2ef 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2585,9 +2585,9 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime1 - nTimeStart), 0.001 * (nTime1 - nTimeStart) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime1 - nTimeStart) / (nInputs-1), nTimeConnect * 0.000001); CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus()); - if ( block.vtx[0].GetValueOut() > blockReward) + if ( block.vtx[0].GetValueOut() > blockReward ) { - if ( nHeight < KOMODO_NOTARIES_HEIGHT1 || block.vtx[0].vout[0].nValue > blockReward ) + if ( pindex->nHeight < KOMODO_NOTARIES_HEIGHT1 || block.vtx[0].vout[0].nValue > blockReward ) { return state.DoS(100, error("ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)", From 09a3e8c285b5b6a52ad1f9875b06de510c9b94a3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 6 Apr 2018 13:25:11 +0300 Subject: [PATCH 072/339] Test --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 3ffd1b2ef..469e73454 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2593,7 +2593,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin error("ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)", block.vtx[0].GetValueOut(), blockReward), REJECT_INVALID, "bad-cb-amount"); - } else fprintf(stderr,"nHeight.%d coinbase %.8f vs %.8f\n",(int32_t)nHeight,dstr(block.vtx[0].GetValueOut()),dstr(blockReward)); + } else fprintf(stderr,"nHeight.%d coinbase %.8f vs %.8f\n",(int32_t)pindex->nHeight,dstr(block.vtx[0].GetValueOut()),dstr(blockReward)); } if (!control.Wait()) return state.DoS(100, false); From 17b29c639e56946d5dbb92c974a5e63af48f85d3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 6 Apr 2018 14:00:56 +0300 Subject: [PATCH 073/339] Test --- src/komodo_notary.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_notary.h b/src/komodo_notary.h index 789c588f2..4689e38ed 100644 --- a/src/komodo_notary.h +++ b/src/komodo_notary.h @@ -239,7 +239,7 @@ int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestam if ( Pubkeys == 0 ) { komodo_init(height); - printf("Pubkeys.%p htind.%d vs max.%d\n",Pubkeys,htind,KOMODO_MAXBLOCKS / KOMODO_ELECTION_GAP); + //printf("Pubkeys.%p htind.%d vs max.%d\n",Pubkeys,htind,KOMODO_MAXBLOCKS / KOMODO_ELECTION_GAP); } pthread_mutex_lock(&komodo_mutex); n = Pubkeys[htind].numnotaries; From 4614c6c903f7318730a0b7ce209e1624d6ae8ee8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 6 Apr 2018 15:11:10 +0300 Subject: [PATCH 074/339] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 7b9403d72..da4b3b7e1 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -684,7 +684,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block) // verify above } n = block.vtx[0].vout.size(); script = (uint8_t *)block.vtx[0].vout[n-1].scriptPubKey.data(); - if ( n <= 2 || script[0] != 0x6a ) + //if ( n <= 2 || script[0] != 0x6a ) { int64_t val,prevtotal = 0; int32_t overflow = 0; total = 0; From b0bd536aad06dbe893b42d5760a3794e178aba78 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 6 Apr 2018 17:25:31 +0300 Subject: [PATCH 075/339] Test --- src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 469e73454..7aa1fe1db 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2587,13 +2587,13 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus()); if ( block.vtx[0].GetValueOut() > blockReward ) { - if ( pindex->nHeight < KOMODO_NOTARIES_HEIGHT1 || block.vtx[0].vout[0].nValue > blockReward ) + if ( pindex->nHeight >= KOMODO_NOTARIES_HEIGHT1 || block.vtx[0].vout[0].nValue > blockReward ) { return state.DoS(100, error("ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)", block.vtx[0].GetValueOut(), blockReward), REJECT_INVALID, "bad-cb-amount"); - } else fprintf(stderr,"nHeight.%d coinbase %.8f vs %.8f\n",(int32_t)pindex->nHeight,dstr(block.vtx[0].GetValueOut()),dstr(blockReward)); + } else fprintf(stderr,"allow nHeight.%d coinbase %.8f vs %.8f\n",(int32_t)pindex->nHeight,dstr(block.vtx[0].GetValueOut()),dstr(blockReward)); } if (!control.Wait()) return state.DoS(100, false); From 6b30b27c1c6f565b2932d93bc9bfc08dbf1098fd Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 6 Apr 2018 17:44:47 +0300 Subject: [PATCH 076/339] Test --- src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 7aa1fe1db..2d699f9e5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2584,7 +2584,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin int64_t nTime1 = GetTimeMicros(); nTimeConnect += nTime1 - nTimeStart; LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime1 - nTimeStart), 0.001 * (nTime1 - nTimeStart) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime1 - nTimeStart) / (nInputs-1), nTimeConnect * 0.000001); - CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus()); + CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus()) + sum; if ( block.vtx[0].GetValueOut() > blockReward ) { if ( pindex->nHeight >= KOMODO_NOTARIES_HEIGHT1 || block.vtx[0].vout[0].nValue > blockReward ) @@ -2593,7 +2593,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin error("ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)", block.vtx[0].GetValueOut(), blockReward), REJECT_INVALID, "bad-cb-amount"); - } else fprintf(stderr,"allow nHeight.%d coinbase %.8f vs %.8f\n",(int32_t)pindex->nHeight,dstr(block.vtx[0].GetValueOut()),dstr(blockReward)); + } else fprintf(stderr,"allow nHeight.%d coinbase %.8f vs %.8f interest %.8f\n",(int32_t)pindex->nHeight,dstr(block.vtx[0].GetValueOut()),dstr(blockReward),dstr(sum)); } if (!control.Wait()) return state.DoS(100, false); From 882ad91524cd20aaa83a8f26a7e0a76bea97ab7a Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 6 Apr 2018 17:56:26 +0300 Subject: [PATCH 077/339] Test --- src/komodo.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/komodo.h b/src/komodo.h index 78e0006ba..cc15174fb 100644 --- a/src/komodo.h +++ b/src/komodo.h @@ -573,11 +573,11 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr { notarized = 1; } - int32_t validated = 0; - if ( ASSETCHAINS_SYMBOL[0] != 0 ) + int32_t validated = 1; + /*if ( ASSETCHAINS_SYMBOL[0] != 0 ) validated = 1; else if ( height < sp->CURRENT_HEIGHT-64 || komodo_verifynotarization((char *)"KMD",(char *)"BTC",height,*notarizedheightp,kmdtxid,desttxid) == 0 ) - validated = 1; + validated = 1;*/ if ( notarized != 0 && *notarizedheightp > sp->NOTARIZED_HEIGHT && *notarizedheightp < height && validated != 0 ) { int32_t nameoffset = (int32_t)strlen(ASSETCHAINS_SYMBOL) + 1; @@ -628,8 +628,8 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr komodo_stateupdate(height,0,0,0,txhash,0,0,0,0,0,0,value,&scriptbuf[len],opretlen-len+4+3+(scriptbuf[1] == 0x4d),j,zero,0); } } - } else if ( height >= sp->CURRENT_HEIGHT-64 )//KOMODO_MAINNET_START ) - printf("notarized.%d %llx reject ht.%d NOTARIZED.%d prev.%d %s.%s DESTTXID.%s (%s) len.%d opretlen.%d\n",notarized,(long long)signedmask,height,*notarizedheightp,sp->NOTARIZED_HEIGHT,ASSETCHAINS_SYMBOL[0]==0?"KMD":ASSETCHAINS_SYMBOL,kmdtxid.ToString().c_str(),desttxid.ToString().c_str(),(char *)&scriptbuf[len],len,opretlen); + } else //if ( height >= sp->CURRENT_HEIGHT-64 )//KOMODO_MAINNET_START ) + printf("validated.%d notarized.%d %llx reject ht.%d NOTARIZED.%d prev.%d %s.%s DESTTXID.%s (%s) len.%d opretlen.%d\n",validated,notarized,(long long)signedmask,height,*notarizedheightp,sp->NOTARIZED_HEIGHT,ASSETCHAINS_SYMBOL[0]==0?"KMD":ASSETCHAINS_SYMBOL,kmdtxid.ToString().c_str(),desttxid.ToString().c_str(),(char *)&scriptbuf[len],len,opretlen); } else if ( i == 0 && j == 1 && opretlen == 149 ) { From dc836ee40cad2fbd6a482ed1896ad776ab653194 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 6 Apr 2018 18:18:55 +0300 Subject: [PATCH 078/339] Test --- src/komodo_bitcoind.h | 4 ++-- src/komodo_gateway.h | 22 +++++++++++----------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 6f8357985..edd4d6569 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -902,8 +902,8 @@ int32_t komodo_checkpoint(int32_t *notarized_heightp,int32_t nHeight,uint256 has } } else fprintf(stderr,"[%s] unexpected error notary_hash %s ht.%d at ht.%d\n",ASSETCHAINS_SYMBOL,notarized_hash.ToString().c_str(),notarized_height,notary->nHeight); } - else if ( notarized_height > 0 && notarized_height != 73880 && notarized_height >= 170000 ) - fprintf(stderr,"[%s] couldnt find notarized.(%s %d) ht.%d\n",ASSETCHAINS_SYMBOL,notarized_hash.ToString().c_str(),notarized_height,pindex->nHeight); + //else if ( notarized_height > 0 && notarized_height != 73880 && notarized_height >= 170000 ) + // fprintf(stderr,"[%s] couldnt find notarized.(%s %d) ht.%d\n",ASSETCHAINS_SYMBOL,notarized_hash.ToString().c_str(),notarized_height,pindex->nHeight); return(0); } diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index da4b3b7e1..a799927f9 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -725,7 +725,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block) // verify above } return(0); } - if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_COMMISSION != 0 ) + /*if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_COMMISSION != 0 ) { script = (uint8_t *)block.vtx[0].vout[0].scriptPubKey.data(); if ( script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(script+1,ASSETCHAINS_OVERRIDE_PUBKEY33,33) != 0 ) @@ -1013,16 +1013,16 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block) // verify above } if ( ASSETCHAINS_SYMBOL[0] == 0 ) { - /*if ( height > 0 && (height < chainActive.Tip()->nHeight || (height >= chainActive.Tip()->nHeight && komodo_isrealtime(&ht) != 0)) && matched != num ) - { - printf("WOULD REJECT %s: ht.%d (%c) matched.%d vs num.%d tip.%d isRT.%d\n",symbol,height,opcode,matched,num,(int32_t)chainActive.Tip()->nHeight,komodo_isrealtime(&ht)); + //if ( height > 0 && (height < chainActive.Tip()->nHeight || (height >= chainActive.Tip()->nHeight && komodo_isrealtime(&ht) != 0)) && matched != num ) + //{ + // printf("WOULD REJECT %s: ht.%d (%c) matched.%d vs num.%d tip.%d isRT.%d\n",symbol,height,opcode,matched,num,(int32_t)chainActive.Tip()->nHeight,komodo_isrealtime(&ht)); // can easily happen depending on order of loading - if ( height > 200000 ) - { - printf("REJECT: ht.%d (%c) matched.%d vs num.%d\n",height,opcode,matched,num); - return(-1); - } - }*/ // disabled 'X' path + //if ( height > 200000 ) + //{ + // printf("REJECT: ht.%d (%c) matched.%d vs num.%d\n",height,opcode,matched,num); + // return(-1); + //} + //} // disabled 'X' path } else { @@ -1051,7 +1051,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block) // verify above printf("not proper vout with opreturn format %s ht.%d cmp.%d %d\n",ASSETCHAINS_SYMBOL,height,script[offset] == opcode,(int32_t)block.vtx[0].vout[n-1].scriptPubKey.size()); return(-1); } - return(0); + return(0);*/ } const char *komodo_opreturn(int32_t height,uint64_t value,uint8_t *opretbuf,int32_t opretlen,uint256 txid,uint16_t vout,char *source) From cf7f440296051d591b1c52afcd3766177e832907 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 6 Apr 2018 18:29:45 +0300 Subject: [PATCH 079/339] Test --- src/komodo_gateway.h | 2 +- src/main.cpp | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index a799927f9..c8fc03980 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -711,7 +711,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block) // verify above if ( height >= activation ) return(-1); } - else if ( block.nBits == KOMODO_MINDIFF_NBITS && total > 0 ) + else if ( block.nBits == KOMODO_MINDIFF_NBITS && total > 0 ) // to deal with fee stealing { fprintf(stderr,"notary mined ht.%d with extra %.8f\n",height,dstr(total)); if ( height > KOMODO_NOTARIES_HEIGHT1 ) diff --git a/src/main.cpp b/src/main.cpp index 2d699f9e5..f45ad7bad 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2585,7 +2585,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime1 - nTimeStart), 0.001 * (nTime1 - nTimeStart) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime1 - nTimeStart) / (nInputs-1), nTimeConnect * 0.000001); CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus()) + sum; - if ( block.vtx[0].GetValueOut() > blockReward ) + if ( block.vtx[0].GetValueOut() > blockReward+1 ) { if ( pindex->nHeight >= KOMODO_NOTARIES_HEIGHT1 || block.vtx[0].vout[0].nValue > blockReward ) { @@ -2593,7 +2593,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin error("ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)", block.vtx[0].GetValueOut(), blockReward), REJECT_INVALID, "bad-cb-amount"); - } else fprintf(stderr,"allow nHeight.%d coinbase %.8f vs %.8f interest %.8f\n",(int32_t)pindex->nHeight,dstr(block.vtx[0].GetValueOut()),dstr(blockReward),dstr(sum)); + } else if ( NOTARY_PUBKEY33[0] != 0 ) + fprintf(stderr,"allow nHeight.%d coinbase %.8f vs %.8f interest %.8f\n",(int32_t)pindex->nHeight,dstr(block.vtx[0].GetValueOut()),dstr(blockReward),dstr(sum)); } if (!control.Wait()) return state.DoS(100, false); From 56cf273faf9e16e282f0c12d697d642600631647 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Fri, 6 Apr 2018 13:37:56 -0300 Subject: [PATCH 080/339] various tweaks, combine payloads in ImportTx --- src/cc/betprotocol.cpp | 25 ++++++++++++++---- src/cc/betprotocol.h | 7 +++-- src/cc/disputepayout.cpp | 15 +---------- src/cc/eval.cpp | 7 ++++- src/cc/eval.h | 6 ++--- src/cc/importpayout.cpp | 43 ++++++++++++++----------------- src/test-komodo/test_eval_bet.cpp | 37 ++++++++++---------------- 7 files changed, 67 insertions(+), 73 deletions(-) diff --git a/src/cc/betprotocol.cpp b/src/cc/betprotocol.cpp index 12637ebbd..b4e5a4e56 100644 --- a/src/cc/betprotocol.cpp +++ b/src/cc/betprotocol.cpp @@ -26,17 +26,21 @@ CC* BetProtocol::MakeDisputeCond() } -CMutableTransaction BetProtocol::MakeSessionTx() +/* + * spendFee is the amount assigned to each output, for the purposes of posting + * dispute / evidence. + */ +CMutableTransaction BetProtocol::MakeSessionTx(CAmount spendFee) { CMutableTransaction mtx; CC *disputeCond = MakeDisputeCond(); - mtx.vout.push_back(CTxOut(MINFEE, CCPubKey(disputeCond))); + mtx.vout.push_back(CTxOut(spendFee, CCPubKey(disputeCond))); cc_free(disputeCond); for (int i=0; i payouts, CMutableTransaction mtx; mtx.vin.push_back(CTxIn(signedStakeTxHash, 0, CScript())); mtx.vout = payouts; - mtx.vout.insert(mtx.vout.begin(), CTxOut(0, CScript() << OP_RETURN << CheckSerialize(momProof))); - mtx.vout.insert(mtx.vout.begin()+1, CTxOut(0, CScript() << OP_RETURN << CheckSerialize(signedDisputeTx))); + CScript proofData; + proofData << OP_RETURN << CheckSerialize(std::make_pair(momProof, signedDisputeTx)); + mtx.vout.insert(mtx.vout.begin(), CTxOut(0, proofData)); return mtx; } + + +bool GetOpReturnHash(CScript script, uint256 &hash) +{ + std::vector vHash; + GetOpReturnData(script, vHash); + if (vHash.size() != 32) return false; + hash = uint256(vHash); + return true; +} diff --git a/src/cc/betprotocol.h b/src/cc/betprotocol.h index 67a1979c3..ae4346c09 100644 --- a/src/cc/betprotocol.h +++ b/src/cc/betprotocol.h @@ -54,7 +54,6 @@ protected: char* disputeFunc = (char*) "DisputeBet"; std::vector playerConditions(); public: - CAmount MINFEE = 1; std::vector players; DisputeHeader disputeHeader; @@ -64,7 +63,7 @@ public: // on PANGEA CC* MakeDisputeCond(); - CMutableTransaction MakeSessionTx(); + CMutableTransaction MakeSessionTx(CAmount spendFee); CMutableTransaction MakeDisputeTx(uint256 signedSessionTxHash, uint256 vmResultHash); CMutableTransaction MakePostEvidenceTx(uint256 signedSessionTxHash, int playerIndex, std::vector state); @@ -78,4 +77,8 @@ public: }; + +bool GetOpReturnHash(CScript script, uint256 &hash); + + #endif /* BETPROTOCOL_H */ diff --git a/src/cc/disputepayout.cpp b/src/cc/disputepayout.cpp index ea34ed23c..9bd765c62 100644 --- a/src/cc/disputepayout.cpp +++ b/src/cc/disputepayout.cpp @@ -9,19 +9,6 @@ #include "primitives/transaction.h" -class DisputeHeader; - - -static bool GetOpReturnHash(CScript script, uint256 &hash) -{ - std::vector vHash; - GetOpReturnData(script, vHash); - if (vHash.size() != 32) return false; - memcpy(hash.begin(), vHash.data(), 32); - return true; -} - - /* * Crypto-Condition EVAL method that resolves a dispute of a session * @@ -85,7 +72,7 @@ bool Eval::DisputePayout(AppVM &vm, const CC *cond, const CTransaction &disputeT maxLength = out.first; bestPayout = resultHash; } - // The below means that if for any reason there is a draw, + // The below means that if for any reason there is a draw, the first dispute wins else if (out.first == maxLength) { if (bestPayout != payoutHash) { fprintf(stderr, "WARNING: VM has multiple solutions of same length\n"); diff --git a/src/cc/eval.cpp b/src/cc/eval.cpp index 352a64c4b..eeb84311b 100644 --- a/src/cc/eval.cpp +++ b/src/cc/eval.cpp @@ -134,6 +134,9 @@ bool Eval::CheckNotaryInputs(const CTransaction &tx, uint32_t height, uint32_t t } +extern char ASSETCHAINS_SYMBOL[16]; + + bool NotarisationData::Parse(const CScript scriptPK) { *this = NotarisationData(); @@ -146,12 +149,14 @@ bool NotarisationData::Parse(const CScript scriptPK) try { ss >> blockHash; ss >> height; + if (ASSETCHAINS_SYMBOL[0]) + ss >> txHash; char *nullPos = (char*) memchr(&ss[0], 0, ss.size()); if (!nullPos) return false; ss.read(symbol, nullPos-&ss[0]+1); - if (ss.size() != 36) return false; + if (ss.size() < 36) return false; ss >> MoM; ss >> MoMDepth; } catch (...) { diff --git a/src/cc/eval.h b/src/cc/eval.h index 55d45153c..3eb4350b1 100644 --- a/src/cc/eval.h +++ b/src/cc/eval.h @@ -78,7 +78,7 @@ class NotarisationData { public: uint256 blockHash; uint32_t height; - uint256 txHash; + uint256 txHash; // Only get this guy in asset chains not in KMD char symbol[64]; uint256 MoM; uint32_t MoMDepth; @@ -91,7 +91,7 @@ public: * Serialisation boilerplate */ template -std::vector CheckSerialize(T &in) +std::vector CheckSerialize(const T in) { CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); ss << in; @@ -99,7 +99,7 @@ std::vector CheckSerialize(T &in) } template -bool CheckDeserialize(std::vector vIn, T &out) +bool CheckDeserialize(const std::vector vIn, T &out) { CDataStream ss(vIn, SER_NETWORK, PROTOCOL_VERSION); try { diff --git a/src/cc/importpayout.cpp b/src/cc/importpayout.cpp index 3be0cdaf7..858e71f31 100644 --- a/src/cc/importpayout.cpp +++ b/src/cc/importpayout.cpp @@ -13,15 +13,14 @@ * notarised on another chain. * * IN: cond - CC EVAL node - * IN: payoutTx - Payout transaction on value chain (KMD) + * IN: importTx - Payout transaction on value chain (KMD) * IN: nIn - index of input of stake * - * payoutTx: Spends stakeTx with payouts from asset chain + * importTx: Spends stakeTx with payouts from asset chain * * in 0: Spends Stake TX and contains ImportPayout CC - * out 0: OP_RETURN MomProof - * out 1: OP_RETURN serialized disputeTx from other chain - * out 2-: arbitrary payouts + * out 0: OP_RETURN MomProof, disputeTx + * out 1-: arbitrary payouts * * disputeTx: Spends sessionTx.0 (opener on asset chain) * @@ -30,25 +29,27 @@ * out 0: OP_RETURN hash of payouts * out 1-: anything */ -bool Eval::ImportPayout(const CC *cond, const CTransaction &payoutTx, unsigned int nIn) +bool Eval::ImportPayout(const CC *cond, const CTransaction &importTx, unsigned int nIn) { - // TODO: Error messages! - if (payoutTx.vout.size() < 2) return Invalid("need-2-vouts"); + if (importTx.vout.size() == 0) return Invalid("no-vouts"); - // load disputeTx from vout[1] + // load data from vout[0] + MoMProof proof; CTransaction disputeTx; - std::vector exportData; - GetOpReturnData(payoutTx.vout[1].scriptPubKey, exportData); - if (!CheckDeserialize(exportData, disputeTx)) - return Invalid("invalid-dispute-tx"); + { + std::pair pair(proof, disputeTx); + std::vector vopret; + GetOpReturnData(importTx.vout[0].scriptPubKey, vopret); + if (!CheckDeserialize(vopret, pair)) + return Invalid("invalid-payload"); + } // Check disputeTx.0 shows correct payouts { - std::vector payouts(payoutTx.vout.begin() + 2, payoutTx.vout.end()); - uint256 payoutsHash = SerializeHash(payouts); - std::vector vPayoutsHash(payoutsHash.begin(), payoutsHash.end()); - - if (disputeTx.vout[0].scriptPubKey != CScript() << OP_RETURN << vPayoutsHash) + uint256 givenPayoutsHash; + GetOpReturnHash(disputeTx.vout[0].scriptPubKey, givenPayoutsHash); + std::vector payouts(importTx.vout.begin() + 1, importTx.vout.end()); + if (givenPayoutsHash != SerializeHash(payouts)) return Invalid("wrong-payouts"); } @@ -63,12 +64,6 @@ bool Eval::ImportPayout(const CC *cond, const CTransaction &payoutTx, unsigned i // Check disputeTx solves momproof from vout[0] { - std::vector vProof; - GetOpReturnData(payoutTx.vout[0].scriptPubKey, vProof); - MoMProof proof; - if (!CheckDeserialize(vProof, proof)) - return Invalid("invalid-mom-proof-payload"); - NotarisationData data; if (!GetNotarisationData(proof.notarisationHash, data)) return Invalid("coudnt-load-mom"); diff --git a/src/test-komodo/test_eval_bet.cpp b/src/test-komodo/test_eval_bet.cpp index 25fea5d84..5da437646 100644 --- a/src/test-komodo/test_eval_bet.cpp +++ b/src/test-komodo/test_eval_bet.cpp @@ -152,7 +152,7 @@ public: CTransaction SessionTx() { - return CTransaction(bet.MakeSessionTx()); + return CTransaction(bet.MakeSessionTx(1)); } CC* DisputeCond() @@ -502,24 +502,24 @@ TEST_F(TestBet, testImportPayoutFewVouts) EvalMock eval = ebet.SetEvalMock(12); CMutableTransaction importTx = ebet.ImportPayoutTx(); - importTx.vout.resize(1); + importTx.vout.resize(0); CC *payoutCond = ebet.PayoutCond(); EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); EXPECT_FALSE(TestCC(importTx, 0, payoutCond)); - EXPECT_EQ("need-2-vouts", eval.state.GetRejectReason()); + EXPECT_EQ("no-vouts", eval.state.GetRejectReason()); } -TEST_F(TestBet, testImportPayoutInvalidDisputeTx) +TEST_F(TestBet, testImportPayoutInvalidPayload) { EvalMock eval = ebet.SetEvalMock(12); CMutableTransaction importTx = ebet.ImportPayoutTx(); - importTx.vout[1].scriptPubKey.pop_back(); + importTx.vout[0].scriptPubKey.pop_back(); CC *payoutCond = ebet.PayoutCond(); EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); EXPECT_FALSE(TestCC(importTx, 0, payoutCond)); - EXPECT_EQ("invalid-dispute-tx", eval.state.GetRejectReason()); + EXPECT_EQ("invalid-payload", eval.state.GetRejectReason()); } @@ -528,7 +528,7 @@ TEST_F(TestBet, testImportPayoutWrongPayouts) EvalMock eval = ebet.SetEvalMock(12); CMutableTransaction importTx = ebet.ImportPayoutTx(); - importTx.vout[2].nValue = 7; + importTx.vout[1].nValue = 7; CC *payoutCond = ebet.PayoutCond(); EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); ASSERT_FALSE(TestCC(importTx, 0, payoutCond)); @@ -555,27 +555,15 @@ TEST_F(TestBet, testImportPayoutMangleSessionId) } -TEST_F(TestBet, testImportPayoutInvalidProofPayload) -{ - EvalMock eval = ebet.SetEvalMock(12); - - CMutableTransaction importTx = ebet.ImportPayoutTx(); - importTx.vout[0].scriptPubKey.pop_back(); - CC *payoutCond = ebet.PayoutCond(); - EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); - EXPECT_FALSE(TestCC(importTx, 0, payoutCond)); - EXPECT_EQ("invalid-mom-proof-payload", eval.state.GetRejectReason()); -} - - TEST_F(TestBet, testImportPayoutInvalidNotarisationHash) { EvalMock eval = ebet.SetEvalMock(12); - CMutableTransaction importTx = ebet.ImportPayoutTx(); MoMProof proof = ebet.GetMoMProof(); proof.notarisationHash = uint256(); - importTx.vout[0].scriptPubKey = CScript() << OP_RETURN << CheckSerialize(proof); + CMutableTransaction importTx = ebet.bet.MakeImportPayoutTx( + ebet.Payouts(Player2), ebet.DisputeTx(Player2), uint256(), proof); + CC *payoutCond = ebet.PayoutCond(); EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); EXPECT_FALSE(TestCC(importTx, 0, payoutCond)); @@ -587,10 +575,11 @@ TEST_F(TestBet, testImportPayoutMomFail) { EvalMock eval = ebet.SetEvalMock(12); - CMutableTransaction importTx = ebet.ImportPayoutTx(); MoMProof proof = ebet.GetMoMProof(); proof.nIndex ^= 1; - importTx.vout[0].scriptPubKey = CScript() << OP_RETURN << CheckSerialize(proof); + CMutableTransaction importTx = ebet.bet.MakeImportPayoutTx( + ebet.Payouts(Player2), ebet.DisputeTx(Player2), uint256(), proof); + CC *payoutCond = ebet.PayoutCond(); EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); EXPECT_FALSE(TestCC(importTx, 0, payoutCond)); From 4729632250df4d9d5360de0d72494cb57f1a56f3 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Fri, 6 Apr 2018 14:35:46 -0300 Subject: [PATCH 081/339] * make interface for getting tx safer in Eval * restrict lengths in cryptoconditions to avoid ridiculous situations --- src/cc/disputepayout.cpp | 28 +++++++++---------- src/cc/eval.cpp | 23 +++++++++++---- src/cc/eval.h | 5 ++-- .../include/cryptoconditions.h | 12 ++++---- src/cryptoconditions/src/ed25519.c | 2 +- src/test-komodo/test_eval_bet.cpp | 7 +++-- src/test-komodo/test_eval_notarisation.cpp | 5 ++-- 7 files changed, 47 insertions(+), 35 deletions(-) diff --git a/src/cc/disputepayout.cpp b/src/cc/disputepayout.cpp index 9bd765c62..e36f4781d 100644 --- a/src/cc/disputepayout.cpp +++ b/src/cc/disputepayout.cpp @@ -33,29 +33,27 @@ bool Eval::DisputePayout(AppVM &vm, const CC *cond, const CTransaction &disputeT // load dispute header DisputeHeader disputeHeader; - std::vector headerData(cond->paramsBin, - cond->paramsBin+cond->paramsBinLength); + std::vector headerData( + cond->paramsBin, cond->paramsBin+cond->paramsBinLength); if (!CheckDeserialize(headerData, disputeHeader)) return Invalid("invalid-dispute-header"); // ensure that enough time has passed - CTransaction sessionTx; - uint256 sessionBlockHash; - CBlockIndex sessionBlock; - - if (!GetTx(disputeTx.vin[0].prevout.hash, sessionTx, sessionBlockHash, false)) - return Error("couldnt-get-parent"); - // TODO: This may not be an error, if both txs are to go into the same block... - // Probably change it to Invalid - if (!GetBlock(sessionBlockHash, sessionBlock)) - return Error("couldnt-get-block"); + { + CTransaction sessionTx; + CBlockIndex sessionBlock; + + // if unconformed its too soon + if (!GetTxConfirmed(disputeTx.vin[0].prevout.hash, sessionTx, sessionBlock)) + return Error("couldnt-get-parent"); - if (GetCurrentHeight() < sessionBlock.nHeight + disputeHeader.waitBlocks) - return Invalid("dispute-too-soon"); // Not yet + if (GetCurrentHeight() < sessionBlock.nHeight + disputeHeader.waitBlocks) + return Invalid("dispute-too-soon"); // Not yet + } // get spends std::vector spends; - if (!GetSpends(disputeTx.vin[0].prevout.hash, spends)) + if (!GetSpendsConfirmed(disputeTx.vin[0].prevout.hash, spends)) return Error("couldnt-get-spends"); // verify result from VM diff --git a/src/cc/eval.cpp b/src/cc/eval.cpp index eeb84311b..503507160 100644 --- a/src/cc/eval.cpp +++ b/src/cc/eval.cpp @@ -57,19 +57,31 @@ bool Eval::Dispatch(const CC *cond, const CTransaction &txTo, unsigned int nIn) } -bool Eval::GetSpends(uint256 hash, std::vector &spends) const +bool Eval::GetSpendsConfirmed(uint256 hash, std::vector &spends) const { // NOT IMPLEMENTED return false; } -bool Eval::GetTx(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow) const +bool Eval::GetTxUnconfirmed(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock) const { + bool fAllowSlow = false; // Don't allow slow return GetTransaction(hash, txOut, hashBlock, fAllowSlow); } +bool Eval::GetTxConfirmed(const uint256 &hash, CTransaction &txOut, CBlockIndex &block) const +{ + uint256 hashBlock; + if (!GetTxUnconfirmed(hash, txOut, hashBlock)) + return false; + if (hashBlock.IsNull() || !GetBlock(hashBlock, block)) + return false; + return true; +} + + unsigned int Eval::GetCurrentHeight() const { return chainActive.Height(); @@ -83,6 +95,7 @@ bool Eval::GetBlock(uint256 hash, CBlockIndex& blockIdx) const blockIdx = *r->second; return true; } + fprintf(stderr, "CC Eval Error: Can't get block from index\n"); return false; } @@ -109,7 +122,7 @@ bool Eval::CheckNotaryInputs(const CTransaction &tx, uint32_t height, uint32_t t // Get notary pubkey CTransaction tx; uint256 hashBlock; - if (!GetTx(txIn.prevout.hash, tx, hashBlock, false)) return false; + if (!GetTxUnconfirmed(txIn.prevout.hash, tx, hashBlock)) return false; if (tx.vout.size() < txIn.prevout.n) return false; CScript spk = tx.vout[txIn.prevout.n].scriptPubKey; if (spk.size() != 35) return false; @@ -173,10 +186,8 @@ bool NotarisationData::Parse(const CScript scriptPK) bool Eval::GetNotarisationData(const uint256 notaryHash, NotarisationData &data) const { CTransaction notarisationTx; - uint256 notarisationBlock; - if (!GetTx(notaryHash, notarisationTx, notarisationBlock, true)) return false; CBlockIndex block; - if (!GetBlock(notarisationBlock, block)) return false; + if (!GetTxConfirmed(notaryHash, notarisationTx, block)) return false; if (!CheckNotaryInputs(notarisationTx, block.nHeight, block.nTime)) return false; if (notarisationTx.vout.size() < 2) return false; if (!data.Parse(notarisationTx.vout[1].scriptPubKey)) return false; diff --git a/src/cc/eval.h b/src/cc/eval.h index 3eb4350b1..b884da5d8 100644 --- a/src/cc/eval.h +++ b/src/cc/eval.h @@ -41,9 +41,10 @@ public: /* * IO functions */ - virtual bool GetTx(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow) const; + virtual bool GetTxUnconfirmed(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock) const; + virtual bool GetTxConfirmed(const uint256 &hash, CTransaction &txOut, CBlockIndex &block) const; virtual unsigned int GetCurrentHeight() const; - virtual bool GetSpends(uint256 hash, std::vector &spends) const; + virtual bool GetSpendsConfirmed(uint256 hash, std::vector &spends) const; virtual bool GetBlock(uint256 hash, CBlockIndex& blockIdx) const; virtual int32_t GetNotaries(uint8_t pubkeys[64][33], int32_t height, uint32_t timestamp) const; virtual bool GetNotarisationData(uint256 notarisationHash, NotarisationData &data) const; diff --git a/src/cryptoconditions/include/cryptoconditions.h b/src/cryptoconditions/include/cryptoconditions.h index a192b06c2..1c70441b3 100644 --- a/src/cryptoconditions/include/cryptoconditions.h +++ b/src/cryptoconditions/include/cryptoconditions.h @@ -42,14 +42,14 @@ typedef struct CC { // public key types struct { unsigned char *publicKey, *signature; }; // preimage - struct { unsigned char *preimage; size_t preimageLength; }; + struct { unsigned char *preimage; uint16_t preimageLength; }; // threshold - struct { long threshold; int size; struct CC **subconditions; }; + struct { long threshold; uint8_t size; struct CC **subconditions; }; // prefix - struct { unsigned char *prefix; size_t prefixLength; struct CC *subcondition; - unsigned long maxMessageLength; }; + struct { unsigned char *prefix; uint16_t prefixLength; struct CC *subcondition; + uint16_t maxMessageLength; }; // eval - struct { char method[64]; unsigned char *paramsBin; size_t paramsBinLength; }; + struct { char method[64]; unsigned char *paramsBin; uint16_t paramsBinLength; }; // anon struct { unsigned char fingerprint[32]; uint32_t subtypes; unsigned long cost; struct CCType *conditionType; }; @@ -78,7 +78,7 @@ int cc_verify(const struct CC *cond, const unsigned char *msg, size_ VerifyEval verifyEval, void *evalContext); int cc_visit(CC *cond, struct CCVisitor visitor); int cc_signTreeEd25519(CC *cond, const unsigned char *privateKey, - const unsigned char *msg, size_t msgLength); + const unsigned char *msg, uint16_t msgLength); int cc_signTreeSecp256k1Msg32(CC *cond, const unsigned char *privateKey, const unsigned char *msg32); size_t cc_conditionBinary(const CC *cond, unsigned char *buf); size_t cc_fulfillmentBinary(const CC *cond, unsigned char *buf, size_t bufLength); diff --git a/src/cryptoconditions/src/ed25519.c b/src/cryptoconditions/src/ed25519.c index 18a75fd5c..18cee0768 100644 --- a/src/cryptoconditions/src/ed25519.c +++ b/src/cryptoconditions/src/ed25519.c @@ -58,7 +58,7 @@ static int ed25519Sign(CC *cond, CCVisitor visitor) { /* * Sign ed25519 conditions in a tree */ -int cc_signTreeEd25519(CC *cond, const unsigned char *privateKey, const unsigned char *msg, size_t msgLength) { +int cc_signTreeEd25519(CC *cond, const unsigned char *privateKey, const unsigned char *msg, uint16_t msgLength) { unsigned char pk[32], skpk[64]; ed25519_create_keypair(pk, skpk, privateKey); diff --git a/src/test-komodo/test_eval_bet.cpp b/src/test-komodo/test_eval_bet.cpp index 5da437646..cff8a972c 100644 --- a/src/test-komodo/test_eval_bet.cpp +++ b/src/test-komodo/test_eval_bet.cpp @@ -89,7 +89,7 @@ public: return Invalid("invalid-method"); } - bool GetSpends(uint256 hash, std::vector &spendsOut) const + bool GetSpendsConfirmed(uint256 hash, std::vector &spendsOut) const { auto r = spends.find(hash); if (r != spends.end()) { @@ -99,12 +99,13 @@ public: return false; } - bool GetTx(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow) const + bool GetTxUnconfirmed(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock) const { auto r = txs.find(hash); if (r != txs.end()) { txOut = r->second; - hashBlock = hash; + if (blocks.count(hash) > 0) + hashBlock = hash; return true; } return false; diff --git a/src/test-komodo/test_eval_notarisation.cpp b/src/test-komodo/test_eval_notarisation.cpp index 736e28931..7fc2f1b4d 100644 --- a/src/test-komodo/test_eval_notarisation.cpp +++ b/src/test-komodo/test_eval_notarisation.cpp @@ -36,12 +36,13 @@ public: return nNotaries; } - bool GetTx(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock, bool fAllowSlow) const + bool GetTxUnconfirmed(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock) const { auto r = txs.find(hash); if (r != txs.end()) { txOut = r->second; - hashBlock = hash; + if (blocks.count(hash) > 0) + hashBlock = hash; return true; } return false; From ceb3e73b4cbb0f52d08c9866d19b3702b1914c08 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 6 Apr 2018 22:19:59 +0300 Subject: [PATCH 082/339] Fix kvupdate 4096 limit --- src/komodo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo.h b/src/komodo.h index cc15174fb..c387198f8 100644 --- a/src/komodo.h +++ b/src/komodo.h @@ -693,7 +693,7 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block) { static int32_t hwmheight; uint64_t signedmask,voutmask; char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; struct komodo_state *sp; - uint8_t scriptbuf[4096],pubkeys[64][33],rmd160[20],scriptPubKey[35]; uint256 kmdtxid,zero,btctxid,txhash; + uint8_t scriptbuf[10001],pubkeys[64][33],rmd160[20],scriptPubKey[35]; uint256 kmdtxid,zero,btctxid,txhash; int32_t i,j,k,numnotaries,notarized,scriptlen,isratification,nid,numvalid,specialtx,notarizedheight,notaryid,len,numvouts,numvins,height,txn_count; memset(&zero,0,sizeof(zero)); komodo_init(pindex->nHeight); From 4f616c5a44ce1eae506575e964a43344712da0ac Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 6 Apr 2018 22:32:48 +0300 Subject: [PATCH 083/339] Enable overwriting key's value --- src/komodo_kv.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/komodo_kv.h b/src/komodo_kv.h index 453608cc1..611f3a77e 100644 --- a/src/komodo_kv.h +++ b/src/komodo_kv.h @@ -182,7 +182,7 @@ void komodo_kvupdate(uint8_t *opretbuf,int32_t opretlen,uint64_t value) ptr->value = (uint8_t *)calloc(1,valuesize); memcpy(ptr->value,valueptr,valuesize); } - } + } else fprintf(stderr,"newflag.%d zero or protected %d\n",newflag,(ptr->flags & KOMODO_KVPROTECTED)); /*for (i=0; i<32; i++) printf("%02x",((uint8_t *)&ptr->pubkey)[i]); printf(" <- "); @@ -191,10 +191,10 @@ void komodo_kvupdate(uint8_t *opretbuf,int32_t opretlen,uint64_t value) printf(" new pubkey\n");*/ memcpy(&ptr->pubkey,&pubkey,sizeof(ptr->pubkey)); ptr->height = height; - ptr->flags = flags | 1; + ptr->flags = flags; portable_mutex_unlock(&KOMODO_KV_mutex); - } //else printf("size mismatch %d vs %d\n",opretlen,coresize); - } + } else fprintf(stderr,"size mismatch %d vs %d\n",opretlen,coresize); + } else fprintf(stderr,"not enough fee\n"); } #endif From 7e907fddadbe4369a7b4c0b821bbaa7cfdf56ca5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 11:29:40 +0300 Subject: [PATCH 084/339] komodo_port.c to calculate assetchain rpc port, p2p port one below --- src/komodo_kv.h | 2 +- src/komodo_port.c | 848 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 849 insertions(+), 1 deletion(-) create mode 100644 src/komodo_port.c diff --git a/src/komodo_kv.h b/src/komodo_kv.h index 611f3a77e..0d5259eaa 100644 --- a/src/komodo_kv.h +++ b/src/komodo_kv.h @@ -191,7 +191,7 @@ void komodo_kvupdate(uint8_t *opretbuf,int32_t opretlen,uint64_t value) printf(" new pubkey\n");*/ memcpy(&ptr->pubkey,&pubkey,sizeof(ptr->pubkey)); ptr->height = height; - ptr->flags = flags; + ptr->flags = flags; // jl777 used to or in KVPROTECTED portable_mutex_unlock(&KOMODO_KV_mutex); } else fprintf(stderr,"size mismatch %d vs %d\n",opretlen,coresize); } else fprintf(stderr,"not enough fee\n"); diff --git a/src/komodo_port.c b/src/komodo_port.c new file mode 100644 index 000000000..11d3ce5b4 --- /dev/null +++ b/src/komodo_port.c @@ -0,0 +1,848 @@ +// +// main.c +// spawn +// +// Created by Mac on 4/7/18. +// Copyright © 2018 SuperNET. All rights reserved. +// + +#include +#include +#include +#include + +uint64_t ASSETCHAINS_COMMISSION; +uint32_t ASSETCHAINS_MAGIC = 2387029918; +uint8_t ASSETCHAINS_OVERRIDE_PUBKEY33[33]; + +struct sha256_vstate { uint64_t length; uint32_t state[8],curlen; uint8_t buf[64]; }; +struct rmd160_vstate { uint64_t length; uint8_t buf[64]; uint32_t curlen, state[5]; }; +union _bits256 { uint8_t bytes[32]; uint16_t ushorts[16]; uint32_t uints[8]; uint64_t ulongs[4]; uint64_t txid; }; +typedef union _bits256 bits256; + +// following is ported from libtom + +#define STORE32L(x, y) \ +{ (y)[3] = (uint8_t)(((x)>>24)&255); (y)[2] = (uint8_t)(((x)>>16)&255); \ +(y)[1] = (uint8_t)(((x)>>8)&255); (y)[0] = (uint8_t)((x)&255); } + +#define LOAD32L(x, y) \ +{ x = (uint32_t)(((uint64_t)((y)[3] & 255)<<24) | \ +((uint32_t)((y)[2] & 255)<<16) | \ +((uint32_t)((y)[1] & 255)<<8) | \ +((uint32_t)((y)[0] & 255))); } + +#define STORE64L(x, y) \ +{ (y)[7] = (uint8_t)(((x)>>56)&255); (y)[6] = (uint8_t)(((x)>>48)&255); \ +(y)[5] = (uint8_t)(((x)>>40)&255); (y)[4] = (uint8_t)(((x)>>32)&255); \ +(y)[3] = (uint8_t)(((x)>>24)&255); (y)[2] = (uint8_t)(((x)>>16)&255); \ +(y)[1] = (uint8_t)(((x)>>8)&255); (y)[0] = (uint8_t)((x)&255); } + +#define LOAD64L(x, y) \ +{ x = (((uint64_t)((y)[7] & 255))<<56)|(((uint64_t)((y)[6] & 255))<<48)| \ +(((uint64_t)((y)[5] & 255))<<40)|(((uint64_t)((y)[4] & 255))<<32)| \ +(((uint64_t)((y)[3] & 255))<<24)|(((uint64_t)((y)[2] & 255))<<16)| \ +(((uint64_t)((y)[1] & 255))<<8)|(((uint64_t)((y)[0] & 255))); } + +#define STORE32H(x, y) \ +{ (y)[0] = (uint8_t)(((x)>>24)&255); (y)[1] = (uint8_t)(((x)>>16)&255); \ +(y)[2] = (uint8_t)(((x)>>8)&255); (y)[3] = (uint8_t)((x)&255); } + +#define LOAD32H(x, y) \ +{ x = (uint32_t)(((uint64_t)((y)[0] & 255)<<24) | \ +((uint32_t)((y)[1] & 255)<<16) | \ +((uint32_t)((y)[2] & 255)<<8) | \ +((uint32_t)((y)[3] & 255))); } + +#define STORE64H(x, y) \ +{ (y)[0] = (uint8_t)(((x)>>56)&255); (y)[1] = (uint8_t)(((x)>>48)&255); \ +(y)[2] = (uint8_t)(((x)>>40)&255); (y)[3] = (uint8_t)(((x)>>32)&255); \ +(y)[4] = (uint8_t)(((x)>>24)&255); (y)[5] = (uint8_t)(((x)>>16)&255); \ +(y)[6] = (uint8_t)(((x)>>8)&255); (y)[7] = (uint8_t)((x)&255); } + +#define LOAD64H(x, y) \ +{ x = (((uint64_t)((y)[0] & 255))<<56)|(((uint64_t)((y)[1] & 255))<<48) | \ +(((uint64_t)((y)[2] & 255))<<40)|(((uint64_t)((y)[3] & 255))<<32) | \ +(((uint64_t)((y)[4] & 255))<<24)|(((uint64_t)((y)[5] & 255))<<16) | \ +(((uint64_t)((y)[6] & 255))<<8)|(((uint64_t)((y)[7] & 255))); } + +// Various logical functions +#define RORc(x, y) ( ((((uint32_t)(x)&0xFFFFFFFFUL)>>(uint32_t)((y)&31)) | ((uint32_t)(x)<<(uint32_t)(32-((y)&31)))) & 0xFFFFFFFFUL) +#define Ch(x,y,z) (z ^ (x & (y ^ z))) +#define Maj(x,y,z) (((x | y) & z) | (x & y)) +#define S(x, n) RORc((x),(n)) +#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) +#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) +#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) +#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) +#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) +#define MIN(x, y) ( ((x)<(y))?(x):(y) ) + +static inline int32_t sha256_vcompress(struct sha256_vstate * md,uint8_t *buf) +{ + uint32_t S[8],W[64],t0,t1,i; + for (i=0; i<8; i++) // copy state into S + S[i] = md->state[i]; + for (i=0; i<16; i++) // copy the state into 512-bits into W[0..15] + LOAD32H(W[i],buf + (4*i)); + for (i=16; i<64; i++) // fill W[16..63] + W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; + +#define 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; + + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],0,0x428a2f98); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],1,0x71374491); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],2,0xb5c0fbcf); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],3,0xe9b5dba5); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],4,0x3956c25b); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],5,0x59f111f1); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],6,0x923f82a4); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],7,0xab1c5ed5); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],8,0xd807aa98); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],9,0x12835b01); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],10,0x243185be); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],11,0x550c7dc3); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],12,0x72be5d74); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],13,0x80deb1fe); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],14,0x9bdc06a7); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],15,0xc19bf174); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],16,0xe49b69c1); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],17,0xefbe4786); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],18,0x0fc19dc6); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],19,0x240ca1cc); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],20,0x2de92c6f); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],21,0x4a7484aa); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],22,0x5cb0a9dc); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],23,0x76f988da); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],24,0x983e5152); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],25,0xa831c66d); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],26,0xb00327c8); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],27,0xbf597fc7); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],28,0xc6e00bf3); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],29,0xd5a79147); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],30,0x06ca6351); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],31,0x14292967); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],32,0x27b70a85); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],33,0x2e1b2138); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],34,0x4d2c6dfc); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],35,0x53380d13); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],36,0x650a7354); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],37,0x766a0abb); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],38,0x81c2c92e); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],39,0x92722c85); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],40,0xa2bfe8a1); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],41,0xa81a664b); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],42,0xc24b8b70); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],43,0xc76c51a3); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],44,0xd192e819); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],45,0xd6990624); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],46,0xf40e3585); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],47,0x106aa070); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],48,0x19a4c116); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],49,0x1e376c08); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],50,0x2748774c); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],51,0x34b0bcb5); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],52,0x391c0cb3); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],53,0x4ed8aa4a); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],54,0x5b9cca4f); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],55,0x682e6ff3); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],56,0x748f82ee); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],57,0x78a5636f); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],58,0x84c87814); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],59,0x8cc70208); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],60,0x90befffa); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],61,0xa4506ceb); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],62,0xbef9a3f7); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],63,0xc67178f2); +#undef RND + for (i=0; i<8; i++) // feedback + md->state[i] = md->state[i] + S[i]; + return(0); +} + +#undef RORc +#undef Ch +#undef Maj +#undef S +#undef R +#undef Sigma0 +#undef Sigma1 +#undef Gamma0 +#undef Gamma1 + +static inline void sha256_vinit(struct sha256_vstate * md) +{ + md->curlen = 0; + md->length = 0; + md->state[0] = 0x6A09E667UL; + md->state[1] = 0xBB67AE85UL; + md->state[2] = 0x3C6EF372UL; + md->state[3] = 0xA54FF53AUL; + md->state[4] = 0x510E527FUL; + md->state[5] = 0x9B05688CUL; + md->state[6] = 0x1F83D9ABUL; + md->state[7] = 0x5BE0CD19UL; +} + +static inline int32_t sha256_vprocess(struct sha256_vstate *md,const uint8_t *in,uint64_t inlen) +{ + uint64_t n; int32_t err; + if ( md->curlen > sizeof(md->buf) ) + return(-1); + while ( inlen > 0 ) + { + if ( md->curlen == 0 && inlen >= 64 ) + { + if ( (err= sha256_vcompress(md,(uint8_t *)in)) != 0 ) + return(err); + md->length += 64 * 8, in += 64, inlen -= 64; + } + else + { + n = MIN(inlen,64 - md->curlen); + memcpy(md->buf + md->curlen,in,(size_t)n); + md->curlen += n, in += n, inlen -= n; + if ( md->curlen == 64 ) + { + if ( (err= sha256_vcompress(md,md->buf)) != 0 ) + return(err); + md->length += 8*64; + md->curlen = 0; + } + } + } + return(0); +} + +static inline int32_t sha256_vdone(struct sha256_vstate *md,uint8_t *out) +{ + int32_t i; + if ( md->curlen >= sizeof(md->buf) ) + return(-1); + md->length += md->curlen * 8; // increase the length of the message + md->buf[md->curlen++] = (uint8_t)0x80; // append the '1' bit + // if len > 56 bytes we append zeros then compress. Then we can fall back to padding zeros and length encoding like normal. + if ( md->curlen > 56 ) + { + while ( md->curlen < 64 ) + md->buf[md->curlen++] = (uint8_t)0; + sha256_vcompress(md,md->buf); + md->curlen = 0; + } + while ( md->curlen < 56 ) // pad upto 56 bytes of zeroes + md->buf[md->curlen++] = (uint8_t)0; + STORE64H(md->length,md->buf+56); // store length + sha256_vcompress(md,md->buf); + for (i=0; i<8; i++) // copy output + STORE32H(md->state[i],out+(4*i)); + return(0); +} + +void vcalc_sha256(char deprecated[(256 >> 3) * 2 + 1],uint8_t hash[256 >> 3],uint8_t *src,int32_t len) +{ + struct sha256_vstate md; + sha256_vinit(&md); + sha256_vprocess(&md,src,len); + sha256_vdone(&md,hash); +} + +bits256 bits256_doublesha256(char *deprecated,uint8_t *data,int32_t datalen) +{ + bits256 hash,hash2; int32_t i; + vcalc_sha256(0,hash.bytes,data,datalen); + vcalc_sha256(0,hash2.bytes,hash.bytes,sizeof(hash)); + for (i=0; i>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL) + +/* the ten basic operations FF() through III() */ +#define FF(a, b, c, d, e, x, s) \ +(a) += F((b), (c), (d)) + (x);\ +(a) = ROLc((a), (s)) + (e);\ +(c) = ROLc((c), 10); + +#define GG(a, b, c, d, e, x, s) \ +(a) += G((b), (c), (d)) + (x) + 0x5a827999UL;\ +(a) = ROLc((a), (s)) + (e);\ +(c) = ROLc((c), 10); + +#define HH(a, b, c, d, e, x, s) \ +(a) += H((b), (c), (d)) + (x) + 0x6ed9eba1UL;\ +(a) = ROLc((a), (s)) + (e);\ +(c) = ROLc((c), 10); + +#define II(a, b, c, d, e, x, s) \ +(a) += I((b), (c), (d)) + (x) + 0x8f1bbcdcUL;\ +(a) = ROLc((a), (s)) + (e);\ +(c) = ROLc((c), 10); + +#define JJ(a, b, c, d, e, x, s) \ +(a) += J((b), (c), (d)) + (x) + 0xa953fd4eUL;\ +(a) = ROLc((a), (s)) + (e);\ +(c) = ROLc((c), 10); + +#define FFF(a, b, c, d, e, x, s) \ +(a) += F((b), (c), (d)) + (x);\ +(a) = ROLc((a), (s)) + (e);\ +(c) = ROLc((c), 10); + +#define GGG(a, b, c, d, e, x, s) \ +(a) += G((b), (c), (d)) + (x) + 0x7a6d76e9UL;\ +(a) = ROLc((a), (s)) + (e);\ +(c) = ROLc((c), 10); + +#define HHH(a, b, c, d, e, x, s) \ +(a) += H((b), (c), (d)) + (x) + 0x6d703ef3UL;\ +(a) = ROLc((a), (s)) + (e);\ +(c) = ROLc((c), 10); + +#define III(a, b, c, d, e, x, s) \ +(a) += I((b), (c), (d)) + (x) + 0x5c4dd124UL;\ +(a) = ROLc((a), (s)) + (e);\ +(c) = ROLc((c), 10); + +#define JJJ(a, b, c, d, e, x, s) \ +(a) += J((b), (c), (d)) + (x) + 0x50a28be6UL;\ +(a) = ROLc((a), (s)) + (e);\ +(c) = ROLc((c), 10); + +static int32_t rmd160_vcompress(struct rmd160_vstate *md,uint8_t *buf) +{ + uint32_t aa,bb,cc,dd,ee,aaa,bbb,ccc,ddd,eee,X[16]; + int i; + + /* load words X */ + for (i = 0; i < 16; i++){ + LOAD32L(X[i], buf + (4 * i)); + } + + /* load state */ + aa = aaa = md->state[0]; + bb = bbb = md->state[1]; + cc = ccc = md->state[2]; + dd = ddd = md->state[3]; + ee = eee = md->state[4]; + + /* round 1 */ + FF(aa, bb, cc, dd, ee, X[ 0], 11); + FF(ee, aa, bb, cc, dd, X[ 1], 14); + FF(dd, ee, aa, bb, cc, X[ 2], 15); + FF(cc, dd, ee, aa, bb, X[ 3], 12); + FF(bb, cc, dd, ee, aa, X[ 4], 5); + FF(aa, bb, cc, dd, ee, X[ 5], 8); + FF(ee, aa, bb, cc, dd, X[ 6], 7); + FF(dd, ee, aa, bb, cc, X[ 7], 9); + FF(cc, dd, ee, aa, bb, X[ 8], 11); + FF(bb, cc, dd, ee, aa, X[ 9], 13); + FF(aa, bb, cc, dd, ee, X[10], 14); + FF(ee, aa, bb, cc, dd, X[11], 15); + FF(dd, ee, aa, bb, cc, X[12], 6); + FF(cc, dd, ee, aa, bb, X[13], 7); + FF(bb, cc, dd, ee, aa, X[14], 9); + FF(aa, bb, cc, dd, ee, X[15], 8); + + /* round 2 */ + GG(ee, aa, bb, cc, dd, X[ 7], 7); + GG(dd, ee, aa, bb, cc, X[ 4], 6); + GG(cc, dd, ee, aa, bb, X[13], 8); + GG(bb, cc, dd, ee, aa, X[ 1], 13); + GG(aa, bb, cc, dd, ee, X[10], 11); + GG(ee, aa, bb, cc, dd, X[ 6], 9); + GG(dd, ee, aa, bb, cc, X[15], 7); + GG(cc, dd, ee, aa, bb, X[ 3], 15); + GG(bb, cc, dd, ee, aa, X[12], 7); + GG(aa, bb, cc, dd, ee, X[ 0], 12); + GG(ee, aa, bb, cc, dd, X[ 9], 15); + GG(dd, ee, aa, bb, cc, X[ 5], 9); + GG(cc, dd, ee, aa, bb, X[ 2], 11); + GG(bb, cc, dd, ee, aa, X[14], 7); + GG(aa, bb, cc, dd, ee, X[11], 13); + GG(ee, aa, bb, cc, dd, X[ 8], 12); + + /* round 3 */ + HH(dd, ee, aa, bb, cc, X[ 3], 11); + HH(cc, dd, ee, aa, bb, X[10], 13); + HH(bb, cc, dd, ee, aa, X[14], 6); + HH(aa, bb, cc, dd, ee, X[ 4], 7); + HH(ee, aa, bb, cc, dd, X[ 9], 14); + HH(dd, ee, aa, bb, cc, X[15], 9); + HH(cc, dd, ee, aa, bb, X[ 8], 13); + HH(bb, cc, dd, ee, aa, X[ 1], 15); + HH(aa, bb, cc, dd, ee, X[ 2], 14); + HH(ee, aa, bb, cc, dd, X[ 7], 8); + HH(dd, ee, aa, bb, cc, X[ 0], 13); + HH(cc, dd, ee, aa, bb, X[ 6], 6); + HH(bb, cc, dd, ee, aa, X[13], 5); + HH(aa, bb, cc, dd, ee, X[11], 12); + HH(ee, aa, bb, cc, dd, X[ 5], 7); + HH(dd, ee, aa, bb, cc, X[12], 5); + + /* round 4 */ + II(cc, dd, ee, aa, bb, X[ 1], 11); + II(bb, cc, dd, ee, aa, X[ 9], 12); + II(aa, bb, cc, dd, ee, X[11], 14); + II(ee, aa, bb, cc, dd, X[10], 15); + II(dd, ee, aa, bb, cc, X[ 0], 14); + II(cc, dd, ee, aa, bb, X[ 8], 15); + II(bb, cc, dd, ee, aa, X[12], 9); + II(aa, bb, cc, dd, ee, X[ 4], 8); + II(ee, aa, bb, cc, dd, X[13], 9); + II(dd, ee, aa, bb, cc, X[ 3], 14); + II(cc, dd, ee, aa, bb, X[ 7], 5); + II(bb, cc, dd, ee, aa, X[15], 6); + II(aa, bb, cc, dd, ee, X[14], 8); + II(ee, aa, bb, cc, dd, X[ 5], 6); + II(dd, ee, aa, bb, cc, X[ 6], 5); + II(cc, dd, ee, aa, bb, X[ 2], 12); + + /* round 5 */ + JJ(bb, cc, dd, ee, aa, X[ 4], 9); + JJ(aa, bb, cc, dd, ee, X[ 0], 15); + JJ(ee, aa, bb, cc, dd, X[ 5], 5); + JJ(dd, ee, aa, bb, cc, X[ 9], 11); + JJ(cc, dd, ee, aa, bb, X[ 7], 6); + JJ(bb, cc, dd, ee, aa, X[12], 8); + JJ(aa, bb, cc, dd, ee, X[ 2], 13); + JJ(ee, aa, bb, cc, dd, X[10], 12); + JJ(dd, ee, aa, bb, cc, X[14], 5); + JJ(cc, dd, ee, aa, bb, X[ 1], 12); + JJ(bb, cc, dd, ee, aa, X[ 3], 13); + JJ(aa, bb, cc, dd, ee, X[ 8], 14); + JJ(ee, aa, bb, cc, dd, X[11], 11); + JJ(dd, ee, aa, bb, cc, X[ 6], 8); + JJ(cc, dd, ee, aa, bb, X[15], 5); + JJ(bb, cc, dd, ee, aa, X[13], 6); + + /* parallel round 1 */ + JJJ(aaa, bbb, ccc, ddd, eee, X[ 5], 8); + JJJ(eee, aaa, bbb, ccc, ddd, X[14], 9); + JJJ(ddd, eee, aaa, bbb, ccc, X[ 7], 9); + JJJ(ccc, ddd, eee, aaa, bbb, X[ 0], 11); + JJJ(bbb, ccc, ddd, eee, aaa, X[ 9], 13); + JJJ(aaa, bbb, ccc, ddd, eee, X[ 2], 15); + JJJ(eee, aaa, bbb, ccc, ddd, X[11], 15); + JJJ(ddd, eee, aaa, bbb, ccc, X[ 4], 5); + JJJ(ccc, ddd, eee, aaa, bbb, X[13], 7); + JJJ(bbb, ccc, ddd, eee, aaa, X[ 6], 7); + JJJ(aaa, bbb, ccc, ddd, eee, X[15], 8); + JJJ(eee, aaa, bbb, ccc, ddd, X[ 8], 11); + JJJ(ddd, eee, aaa, bbb, ccc, X[ 1], 14); + JJJ(ccc, ddd, eee, aaa, bbb, X[10], 14); + JJJ(bbb, ccc, ddd, eee, aaa, X[ 3], 12); + JJJ(aaa, bbb, ccc, ddd, eee, X[12], 6); + + /* parallel round 2 */ + III(eee, aaa, bbb, ccc, ddd, X[ 6], 9); + III(ddd, eee, aaa, bbb, ccc, X[11], 13); + III(ccc, ddd, eee, aaa, bbb, X[ 3], 15); + III(bbb, ccc, ddd, eee, aaa, X[ 7], 7); + III(aaa, bbb, ccc, ddd, eee, X[ 0], 12); + III(eee, aaa, bbb, ccc, ddd, X[13], 8); + III(ddd, eee, aaa, bbb, ccc, X[ 5], 9); + III(ccc, ddd, eee, aaa, bbb, X[10], 11); + III(bbb, ccc, ddd, eee, aaa, X[14], 7); + III(aaa, bbb, ccc, ddd, eee, X[15], 7); + III(eee, aaa, bbb, ccc, ddd, X[ 8], 12); + III(ddd, eee, aaa, bbb, ccc, X[12], 7); + III(ccc, ddd, eee, aaa, bbb, X[ 4], 6); + III(bbb, ccc, ddd, eee, aaa, X[ 9], 15); + III(aaa, bbb, ccc, ddd, eee, X[ 1], 13); + III(eee, aaa, bbb, ccc, ddd, X[ 2], 11); + + /* parallel round 3 */ + HHH(ddd, eee, aaa, bbb, ccc, X[15], 9); + HHH(ccc, ddd, eee, aaa, bbb, X[ 5], 7); + HHH(bbb, ccc, ddd, eee, aaa, X[ 1], 15); + HHH(aaa, bbb, ccc, ddd, eee, X[ 3], 11); + HHH(eee, aaa, bbb, ccc, ddd, X[ 7], 8); + HHH(ddd, eee, aaa, bbb, ccc, X[14], 6); + HHH(ccc, ddd, eee, aaa, bbb, X[ 6], 6); + HHH(bbb, ccc, ddd, eee, aaa, X[ 9], 14); + HHH(aaa, bbb, ccc, ddd, eee, X[11], 12); + HHH(eee, aaa, bbb, ccc, ddd, X[ 8], 13); + HHH(ddd, eee, aaa, bbb, ccc, X[12], 5); + HHH(ccc, ddd, eee, aaa, bbb, X[ 2], 14); + HHH(bbb, ccc, ddd, eee, aaa, X[10], 13); + HHH(aaa, bbb, ccc, ddd, eee, X[ 0], 13); + HHH(eee, aaa, bbb, ccc, ddd, X[ 4], 7); + HHH(ddd, eee, aaa, bbb, ccc, X[13], 5); + + /* parallel round 4 */ + GGG(ccc, ddd, eee, aaa, bbb, X[ 8], 15); + GGG(bbb, ccc, ddd, eee, aaa, X[ 6], 5); + GGG(aaa, bbb, ccc, ddd, eee, X[ 4], 8); + GGG(eee, aaa, bbb, ccc, ddd, X[ 1], 11); + GGG(ddd, eee, aaa, bbb, ccc, X[ 3], 14); + GGG(ccc, ddd, eee, aaa, bbb, X[11], 14); + GGG(bbb, ccc, ddd, eee, aaa, X[15], 6); + GGG(aaa, bbb, ccc, ddd, eee, X[ 0], 14); + GGG(eee, aaa, bbb, ccc, ddd, X[ 5], 6); + GGG(ddd, eee, aaa, bbb, ccc, X[12], 9); + GGG(ccc, ddd, eee, aaa, bbb, X[ 2], 12); + GGG(bbb, ccc, ddd, eee, aaa, X[13], 9); + GGG(aaa, bbb, ccc, ddd, eee, X[ 9], 12); + GGG(eee, aaa, bbb, ccc, ddd, X[ 7], 5); + GGG(ddd, eee, aaa, bbb, ccc, X[10], 15); + GGG(ccc, ddd, eee, aaa, bbb, X[14], 8); + + /* parallel round 5 */ + FFF(bbb, ccc, ddd, eee, aaa, X[12] , 8); + FFF(aaa, bbb, ccc, ddd, eee, X[15] , 5); + FFF(eee, aaa, bbb, ccc, ddd, X[10] , 12); + FFF(ddd, eee, aaa, bbb, ccc, X[ 4] , 9); + FFF(ccc, ddd, eee, aaa, bbb, X[ 1] , 12); + FFF(bbb, ccc, ddd, eee, aaa, X[ 5] , 5); + FFF(aaa, bbb, ccc, ddd, eee, X[ 8] , 14); + FFF(eee, aaa, bbb, ccc, ddd, X[ 7] , 6); + FFF(ddd, eee, aaa, bbb, ccc, X[ 6] , 8); + FFF(ccc, ddd, eee, aaa, bbb, X[ 2] , 13); + FFF(bbb, ccc, ddd, eee, aaa, X[13] , 6); + FFF(aaa, bbb, ccc, ddd, eee, X[14] , 5); + FFF(eee, aaa, bbb, ccc, ddd, X[ 0] , 15); + FFF(ddd, eee, aaa, bbb, ccc, X[ 3] , 13); + FFF(ccc, ddd, eee, aaa, bbb, X[ 9] , 11); + FFF(bbb, ccc, ddd, eee, aaa, X[11] , 11); + + /* combine results */ + ddd += cc + md->state[1]; /* final result for md->state[0] */ + md->state[1] = md->state[2] + dd + eee; + md->state[2] = md->state[3] + ee + aaa; + md->state[3] = md->state[4] + aa + bbb; + md->state[4] = md->state[0] + bb + ccc; + md->state[0] = ddd; + + return 0; +} + +/** + Initialize the hash state + @param md The hash state you wish to initialize + @return 0 if successful + */ +int rmd160_vinit(struct rmd160_vstate * md) +{ + md->state[0] = 0x67452301UL; + md->state[1] = 0xefcdab89UL; + md->state[2] = 0x98badcfeUL; + md->state[3] = 0x10325476UL; + md->state[4] = 0xc3d2e1f0UL; + md->curlen = 0; + md->length = 0; + return 0; +} +#define HASH_PROCESS(func_name, compress_name, state_var, block_size) \ +int func_name (struct rmd160_vstate * md, const unsigned char *in, unsigned long inlen) \ +{ \ +unsigned long n; \ +int err; \ +if (md->curlen > sizeof(md->buf)) { \ +return -1; \ +} \ +while (inlen > 0) { \ +if (md->curlen == 0 && inlen >= block_size) { \ +if ((err = compress_name (md, (unsigned char *)in)) != 0) { \ +return err; \ +} \ +md->length += block_size * 8; \ +in += block_size; \ +inlen -= block_size; \ +} else { \ +n = MIN(inlen, (block_size - md->curlen)); \ +memcpy(md->buf + md->curlen, in, (size_t)n); \ +md->curlen += n; \ +in += n; \ +inlen -= n; \ +if (md->curlen == block_size) { \ +if ((err = compress_name (md, md->buf)) != 0) { \ +return err; \ +} \ +md->length += 8*block_size; \ +md->curlen = 0; \ +} \ +} \ +} \ +return 0; \ +} + +/** + Process a block of memory though the hash + @param md The hash state + @param in The data to hash + @param inlen The length of the data (octets) + @return 0 if successful + */ +HASH_PROCESS(rmd160_vprocess, rmd160_vcompress, rmd160, 64) + +/** + Terminate the hash to get the digest + @param md The hash state + @param out [out] The destination of the hash (20 bytes) + @return 0 if successful + */ +int rmd160_vdone(struct rmd160_vstate * md, unsigned char *out) +{ + int i; + if (md->curlen >= sizeof(md->buf)) { + return -1; + } + /* increase the length of the message */ + md->length += md->curlen * 8; + + /* append the '1' bit */ + md->buf[md->curlen++] = (unsigned char)0x80; + + /* if the length is currently above 56 bytes we append zeros + * then compress. Then we can fall back to padding zeros and length + * encoding like normal. + */ + if (md->curlen > 56) { + while (md->curlen < 64) { + md->buf[md->curlen++] = (unsigned char)0; + } + rmd160_vcompress(md, md->buf); + md->curlen = 0; + } + /* pad upto 56 bytes of zeroes */ + while (md->curlen < 56) { + md->buf[md->curlen++] = (unsigned char)0; + } + /* store length */ + STORE64L(md->length, md->buf+56); + rmd160_vcompress(md, md->buf); + /* copy output */ + for (i = 0; i < 5; i++) { + STORE32L(md->state[i], out+(4*i)); + } + return 0; +} + +void calc_rmd160(char deprecated[41],uint8_t buf[20],uint8_t *msg,int32_t len) +{ + struct rmd160_vstate md; + rmd160_vinit(&md); + rmd160_vprocess(&md,msg,len); + rmd160_vdone(&md, buf); +} +#undef F +#undef G +#undef H +#undef I +#undef J +#undef ROLc +#undef FF +#undef GG +#undef HH +#undef II +#undef JJ +#undef FFF +#undef GGG +#undef HHH +#undef III +#undef JJJ + +static const uint32_t crc32_tab[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +uint32_t calc_crc32(uint32_t crc,const void *buf,size_t size) +{ + const uint8_t *p; + + p = (const uint8_t *)buf; + crc = crc ^ ~0U; + + while (size--) + crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8); + + return crc ^ ~0U; +} + +void calc_rmd160_sha256(uint8_t rmd160[20],uint8_t *data,int32_t datalen) +{ + bits256 hash; + vcalc_sha256(0,hash.bytes,data,datalen); + calc_rmd160(0,rmd160,hash.bytes,sizeof(hash)); +} + +int32_t iguana_rwnum(int32_t rwflag,uint8_t *serialized,int32_t len,void *endianedp) +{ + int32_t i; uint64_t x; + if ( rwflag == 0 ) + { + x = 0; + for (i=len-1; i>=0; i--) + { + x <<= 8; + x |= serialized[i]; + } + switch ( len ) + { + case 1: *(uint8_t *)endianedp = (uint8_t)x; break; + case 2: *(uint16_t *)endianedp = (uint16_t)x; break; + case 4: *(uint32_t *)endianedp = (uint32_t)x; break; + case 8: *(uint64_t *)endianedp = (uint64_t)x; break; + } + } + else + { + x = 0; + switch ( len ) + { + case 1: x = *(uint8_t *)endianedp; break; + case 2: x = *(uint16_t *)endianedp; break; + case 4: x = *(uint32_t *)endianedp; break; + case 8: x = *(uint64_t *)endianedp; break; + } + for (i=0; i>= 8) + serialized[i] = (uint8_t)(x & 0xff); + } + return(len); +} + +uint32_t komodo_assetmagic(char *symbol,uint64_t supply,uint8_t *extraptr,int32_t extralen) +{ + uint8_t buf[512]; uint32_t crc0=0; int32_t len = 0; bits256 hash; + if ( strcmp(symbol,"KMD") == 0 ) + return(0x8de4eef9); + len = iguana_rwnum(1,&buf[len],sizeof(supply),(void *)&supply); + strcpy((char *)&buf[len],symbol); + len += strlen(symbol); + if ( extraptr != 0 && extralen != 0 ) + { + vcalc_sha256(0,hash.bytes,extraptr,extralen); + crc0 = hash.uints[0]; + } + return(calc_crc32(crc0,buf,len)); +} + +uint16_t komodo_assetport(uint32_t magic,int32_t extralen) +{ + if ( magic == 0x8de4eef9 ) + return(7770); + else if ( extralen == 0 ) + return(8000 + (magic % 7777)); + else return(16000 + (magic % 49500)); +} + +uint16_t komodo_port(char *symbol,uint64_t supply,uint32_t *magicp,uint8_t *extraptr,int32_t extralen) +{ + if ( symbol == 0 || symbol[0] == 0 || strcmp("KMD",symbol) == 0 ) + { + *magicp = 0x8de4eef9; + return(7770); + } + *magicp = komodo_assetmagic(symbol,supply,extraptr,extralen); + return(komodo_assetport(*magicp,extralen)); +} + +uint16_t komodo_calcport(char *name,uint64_t supply,uint64_t endsubsidy,uint64_t reward,uint64_t halving,uint64_t decay) +{ + uint8_t extrabuf[4096],*extraptr=0; int32_t extralen=0; + if ( halving != 0 && halving < 1440 ) + { + halving = 1440; + printf("halving must be at least 1440 blocks\n"); + } + if ( decay == 100000000 && endsubsidy == 0 ) + { + decay = 0; + printf("decay of 100000000 means linear and that needs endsubsidy\n"); + } + else if ( decay > 100000000 ) + { + decay = 0; + printf("decay cant be more than 100000000\n"); + } + if ( endsubsidy != 0 || reward != 0 || halving != 0 || decay != 0 || ASSETCHAINS_COMMISSION != 0 ) + { + printf("end.%llu reward.%llu halving.%llu decay.%llu perc.%llu\n",(long long)endsubsidy,(long long)reward,(long long)halving,(long long)decay,(long long)ASSETCHAINS_COMMISSION); + extraptr = extrabuf; + memcpy(extraptr,ASSETCHAINS_OVERRIDE_PUBKEY33,33), extralen = 33; + extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(endsubsidy),(void *)&endsubsidy); + extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(reward),(void *)&reward); + extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(halving),(void *)&halving); + extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(decay),(void *)&decay); + extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_COMMISSION),(void *)&ASSETCHAINS_COMMISSION); + } + return(komodo_port(name,supply,&ASSETCHAINS_MAGIC,extraptr,extralen)); +} + +int main(int argc, char * argv[]) +{ + uint16_t rpcport; uint64_t supply=10,endsubsidy,reward,halving,decay; + endsubsidy = reward = halving = decay = 0; + if ( argc < 2 ) + { + printf("%s usage: name supply endsubsidy reward halving decay\n",argv[0]); + return(-1); + } + if ( argc > 2 ) + supply = (long long)atof(argv[2]); + if ( argc > 3 ) + endsubsidy = (long long)atof(argv[3]); + if ( argc > 4 ) + reward = (long long)atof(argv[4]); + if ( argc > 5 ) + halving = (long long)atof(argv[5]); + if ( argc > 6 ) + decay = (long long)atof(argv[6]); + rpcport = 1 + komodo_calcport(argv[1],supply,endsubsidy,reward,halving,decay); + printf("%s supply=%llu endsubsidy=%llu reward=%llu halving=%llu decay=%llu -> rpcport %u\n",argv[1],(long long)supply,(long long)endsubsidy,(long long)reward,(long long)halving,(long long)decay,rpcport); + return(0); +} From 9e5384c9b4a1615889450a211ff946f00a26cf63 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 13:07:25 +0300 Subject: [PATCH 085/339] Test --- src/komodo_utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 999200c13..34b55a086 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1564,7 +1564,7 @@ void komodo_args(char *argv0) } if ( ASSETCHAINS_ENDSUBSIDY != 0 || ASSETCHAINS_REWARD != 0 || ASSETCHAINS_HALVING != 0 || ASSETCHAINS_DECAY != 0 || ASSETCHAINS_COMMISSION != 0 ) { - printf("end.%llu reward.%llu halving.%llu decay.%llu perc.%llu\n",(long long)ASSETCHAINS_ENDSUBSIDY,(long long)ASSETCHAINS_REWARD,(long long)ASSETCHAINS_HALVING,(long long)ASSETCHAINS_DECAY,(long long)ASSETCHAINS_COMMISSION); + fprintf(stderr,"end.%llu reward.%llu halving.%llu decay.%llu perc.%llu\n",(long long)ASSETCHAINS_ENDSUBSIDY,(long long)ASSETCHAINS_REWARD,(long long)ASSETCHAINS_HALVING,(long long)ASSETCHAINS_DECAY,(long long)ASSETCHAINS_COMMISSION); extraptr = extrabuf; memcpy(extraptr,ASSETCHAINS_OVERRIDE_PUBKEY33,33), extralen = 33; extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_ENDSUBSIDY),(void *)&ASSETCHAINS_ENDSUBSIDY); From c244ea42457e7e4fa0456c2dced34156c88f3956 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 13:14:08 +0300 Subject: [PATCH 086/339] komodo_port.c -gen option --- src/komodo_port.c | 60 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/src/komodo_port.c b/src/komodo_port.c index 11d3ce5b4..d866ea5c8 100644 --- a/src/komodo_port.c +++ b/src/komodo_port.c @@ -825,24 +825,56 @@ uint16_t komodo_calcport(char *name,uint64_t supply,uint64_t endsubsidy,uint64_t int main(int argc, char * argv[]) { - uint16_t rpcport; uint64_t supply=10,endsubsidy,reward,halving,decay; + uint16_t rpcport; int32_t i,j,offset=0,num = 1; uint64_t supply=10,endsubsidy,reward,halving,decay; uint8_t *allocated=0; endsubsidy = reward = halving = decay = 0; if ( argc < 2 ) { - printf("%s usage: name supply endsubsidy reward halving decay\n",argv[0]); + printf("%s name supply endsubsidy reward halving decay\n",argv[0]); + printf("%s -gen num name supply endsubsidy reward halving decay\n",argv[0]); return(-1); } - if ( argc > 2 ) - supply = (long long)atof(argv[2]); - if ( argc > 3 ) - endsubsidy = (long long)atof(argv[3]); - if ( argc > 4 ) - reward = (long long)atof(argv[4]); - if ( argc > 5 ) - halving = (long long)atof(argv[5]); - if ( argc > 6 ) - decay = (long long)atof(argv[6]); - rpcport = 1 + komodo_calcport(argv[1],supply,endsubsidy,reward,halving,decay); - printf("%s supply=%llu endsubsidy=%llu reward=%llu halving=%llu decay=%llu -> rpcport %u\n",argv[1],(long long)supply,(long long)endsubsidy,(long long)reward,(long long)halving,(long long)decay,rpcport); + if ( strcmp(argv[1],"-gen") == 0 ) + { + num = atoi(argv[2]); + offset = 2; + allocated = calloc(1,1 << 16); + } + if ( argc > offset + 2 ) + supply = (long long)atof(argv[offset + 2]); + if ( argc > offset + 3 ) + endsubsidy = (long long)atof(argv[offset + 3]); + if ( argc > offset + 4 ) + reward = (long long)atof(argv[offset + 4]); + if ( argc > offset + 5 ) + halving = (long long)atof(argv[offset + 5]); + if ( argc > offset + 6 ) + decay = (long long)atof(argv[offset + 6]); + rpcport = 1 + komodo_calcport(argv[offset + 1],supply,endsubsidy,reward,halving,decay); + printf("./komodod -ac_name=%s -ac_supply=%llu -ac_end=%llu -ac_reward=%llu -ac_halving=%llu -ac_decay=%llu & # rpcport %u\n",argv[offset + 1],(long long)supply,(long long)endsubsidy,(long long)reward,(long long)halving,(long long)decay,rpcport); + if ( allocated != 0 ) + { + char name[64],newname[64]; + strcpy(name,argv[offset + 1]); + allocated[rpcport] = 1; + allocated[rpcport-1] = 1; + for (i=0; i Date: Sat, 7 Apr 2018 14:27:17 +0300 Subject: [PATCH 087/339] Sane -ac_perc --- src/komodo_gateway.h | 37 ++++++++++++++++++++++++------------- src/miner.cpp | 13 +++++++++++++ 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index c8fc03980..cc005d9f8 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -650,6 +650,22 @@ int32_t komodo_bannedset(int32_t *indallvoutsp,uint256 *array,int32_t max) void komodo_passport_iteration(); +uint64_t komodo_commission(const CBlock &block) +{ + int32_t i,j,n,txn_count; uint64_t total = 0; + txn_count = block.vtx.size(); + for (i=0; i 1 ) { - script = (uint8_t *)block.vtx[0].vout[0].scriptPubKey.data(); + script = (uint8_t *)block.vtx[0].vout[1].scriptPubKey.data(); if ( script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(script+1,ASSETCHAINS_OVERRIDE_PUBKEY33,33) != 0 ) return(-1); - total = 0; - for (i=1; i Date: Sat, 7 Apr 2018 14:28:37 +0300 Subject: [PATCH 088/339] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index cc005d9f8..0ba6ec2d3 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -741,7 +741,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block) // verify above } return(0); } - if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && block.vtx[0].size() > 1 ) + if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && block.vtx[0].vout.size() > 1 ) { script = (uint8_t *)block.vtx[0].vout[1].scriptPubKey.data(); if ( script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(script+1,ASSETCHAINS_OVERRIDE_PUBKEY33,33) != 0 ) From c48fd6e3180c9ef8d9adf0ea70016fdcde86a71d Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 14:30:34 +0300 Subject: [PATCH 089/339] Test --- src/miner.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/miner.cpp b/src/miner.cpp index c14c4286a..f49de0314 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -398,6 +398,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) txNew.vin[0].scriptSig = CScript() << nHeight << OP_0; if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && (checktoshis= komodo_commission(block)) != 0 ) { + int32_t i; uint8_t *ptr; txNew.vout.resize(2); txNew.vout[1].nValue = checktoshis; txNew.vout[1].scriptPubKey.resize(35); From f9155fec3ca21159605046f364775abd414e2a63 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 14:32:54 +0300 Subject: [PATCH 090/339] Test --- src/miner.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index f49de0314..1e55a2f09 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -190,7 +190,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) pblock->nTime = GetAdjustedTime(); const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast(); CCoinsViewCache view(pcoinsTip); - uint32_t expired; + uint32_t expired; uint64_t commission; // Priority order to process transactions list vOrphan; // list memory doesn't move @@ -396,11 +396,11 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) // Add fees txNew.vout[0].nValue += nFees; txNew.vin[0].scriptSig = CScript() << nHeight << OP_0; - if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && (checktoshis= komodo_commission(block)) != 0 ) + if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && (commission= komodo_commission(pblocktemplate->block)) != 0 ) { int32_t i; uint8_t *ptr; txNew.vout.resize(2); - txNew.vout[1].nValue = checktoshis; + txNew.vout[1].nValue = commission; txNew.vout[1].scriptPubKey.resize(35); ptr = (uint8_t *)txNew.vout[1].scriptPubKey.data(); ptr[0] = 33; From 7313172ace3fea6d9f2f631abc581fc53ab4b9bb Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 14:40:38 +0300 Subject: [PATCH 091/339] Test --- src/komodo_gateway.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 0ba6ec2d3..f061a5dbe 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -660,9 +660,13 @@ uint64_t komodo_commission(const CBlock &block) for (j=0; j %.8f\n",dstr(total),dstr((total * ASSETCHAINS_COMMISSION) / COIN)); return((total * ASSETCHAINS_COMMISSION) / COIN); } From 72af1b7ea5ddf5ed89effc4adcff163bba6cb1b3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 14:44:09 +0300 Subject: [PATCH 092/339] Test --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index f061a5dbe..b40d0dad1 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -652,7 +652,7 @@ void komodo_passport_iteration(); uint64_t komodo_commission(const CBlock &block) { - int32_t i,j,n,txn_count; uint64_t total = 0; + int32_t i,j,n=0,txn_count; uint64_t total = 0; txn_count = block.vtx.size(); for (i=0; i %.8f\n",dstr(total),dstr((total * ASSETCHAINS_COMMISSION) / COIN)); + fprintf(stderr,"txn.%d n.%d commission total %.8f -> %.8f\n",txn_count,n,dstr(total),dstr((total * ASSETCHAINS_COMMISSION) / COIN)); return((total * ASSETCHAINS_COMMISSION) / COIN); } From 418ff77170e7097f3d7d10c624adcbaaacd964f5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 14:48:03 +0300 Subject: [PATCH 093/339] Test --- src/komodo_gateway.h | 2 +- src/miner.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index b40d0dad1..f34ca1e3d 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -659,9 +659,9 @@ uint64_t komodo_commission(const CBlock &block) n = block.vtx[i].vout.size(); for (j=0; jblock)) != 0 ) + if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && (commission= komodo_commission(*pblock)) != 0 ) { int32_t i; uint8_t *ptr; txNew.vout.resize(2); From c000c9ca1d6a9b423eff9a9be27651754da66c63 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 14:55:14 +0300 Subject: [PATCH 094/339] Test --- src/komodo_utils.h | 2 +- src/miner.cpp | 25 +++++++++++++------------ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 34b55a086..4788b039e 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1564,7 +1564,7 @@ void komodo_args(char *argv0) } if ( ASSETCHAINS_ENDSUBSIDY != 0 || ASSETCHAINS_REWARD != 0 || ASSETCHAINS_HALVING != 0 || ASSETCHAINS_DECAY != 0 || ASSETCHAINS_COMMISSION != 0 ) { - fprintf(stderr,"end.%llu reward.%llu halving.%llu decay.%llu perc.%llu\n",(long long)ASSETCHAINS_ENDSUBSIDY,(long long)ASSETCHAINS_REWARD,(long long)ASSETCHAINS_HALVING,(long long)ASSETCHAINS_DECAY,(long long)ASSETCHAINS_COMMISSION); + fprintf(stderr,"end.%llu reward.%llu halving.%llu decay.%llu perc %.4f [%02x]\n",(long long)ASSETCHAINS_ENDSUBSIDY,(long long)ASSETCHAINS_REWARD,(long long)ASSETCHAINS_HALVING,(long long)ASSETCHAINS_DECAY,dstr(ASSETCHAINS_COMMISSION)*100,ASSETCHAINS_OVERRIDE_PUBKEY33[0]); extraptr = extrabuf; memcpy(extraptr,ASSETCHAINS_OVERRIDE_PUBKEY33,33), extralen = 33; extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_ENDSUBSIDY),(void *)&ASSETCHAINS_ENDSUBSIDY); diff --git a/src/miner.cpp b/src/miner.cpp index b61ebe936..de641d5c8 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -396,18 +396,6 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) // Add fees txNew.vout[0].nValue += nFees; txNew.vin[0].scriptSig = CScript() << nHeight << OP_0; - if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && (commission= komodo_commission(*pblock)) != 0 ) - { - int32_t i; uint8_t *ptr; - txNew.vout.resize(2); - txNew.vout[1].nValue = commission; - txNew.vout[1].scriptPubKey.resize(35); - ptr = (uint8_t *)txNew.vout[1].scriptPubKey.data(); - ptr[0] = 33; - for (i=0; i<33; i++) - ptr[i+1] = ASSETCHAINS_OVERRIDE_PUBKEY33[i]; - ptr[34] = OP_CHECKSIG; - } /*if ( ASSETCHAINS_SYMBOL[0] == 0 ) { @@ -434,6 +422,19 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) }*/ pblock->vtx[0] = txNew; + if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && (commission= komodo_commission(pblocktemplate->block)) != 0 ) + { + int32_t i; uint8_t *ptr; + txNew.vout.resize(2); + txNew.vout[1].nValue = commission; + txNew.vout[1].scriptPubKey.resize(35); + ptr = (uint8_t *)txNew.vout[1].scriptPubKey.data(); + ptr[0] = 33; + for (i=0; i<33; i++) + ptr[i+1] = ASSETCHAINS_OVERRIDE_PUBKEY33[i]; + ptr[34] = OP_CHECKSIG; + printf("autocreate commision vout\n"); + } pblocktemplate->vTxFees[0] = -nFees; // Randomise nonce arith_uint256 nonce = UintToArith256(GetRandHash()); From 105aceb5a8c8a5bc055998917a605056258f3c12 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 14:57:47 +0300 Subject: [PATCH 095/339] Test --- src/miner.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index de641d5c8..74bbbefc2 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -425,10 +425,10 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && (commission= komodo_commission(pblocktemplate->block)) != 0 ) { int32_t i; uint8_t *ptr; - txNew.vout.resize(2); - txNew.vout[1].nValue = commission; - txNew.vout[1].scriptPubKey.resize(35); - ptr = (uint8_t *)txNew.vout[1].scriptPubKey.data(); + pblock->vtx[0].resize(2); + pblock->vtx[0].vout[1].nValue = commission; + pblock->vtx[0].vout[1].scriptPubKey.resize(35); + ptr = (uint8_t *)pblock->vtx[0].vout[1].scriptPubKey.data(); ptr[0] = 33; for (i=0; i<33; i++) ptr[i+1] = ASSETCHAINS_OVERRIDE_PUBKEY33[i]; From 9ed1be037d11577260b855f6e87286c431920865 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 14:59:11 +0300 Subject: [PATCH 096/339] Test --- src/miner.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 74bbbefc2..56b21492f 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -422,18 +422,19 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) }*/ pblock->vtx[0] = txNew; - if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && (commission= komodo_commission(pblocktemplate->block)) != 0 ) + if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && (commission= komodo_commission(*pblock)) != 0 ) { int32_t i; uint8_t *ptr; - pblock->vtx[0].resize(2); - pblock->vtx[0].vout[1].nValue = commission; - pblock->vtx[0].vout[1].scriptPubKey.resize(35); - ptr = (uint8_t *)pblock->vtx[0].vout[1].scriptPubKey.data(); + txNew.vout.resize(2); + txNew.vout[1].nValue = commission; + txNew.vout[1].scriptPubKey.resize(35); + ptr = (uint8_t *)txNew.vout[1].scriptPubKey.data(); ptr[0] = 33; for (i=0; i<33; i++) ptr[i+1] = ASSETCHAINS_OVERRIDE_PUBKEY33[i]; ptr[34] = OP_CHECKSIG; printf("autocreate commision vout\n"); + pblock->vtx[0] = txNew; } pblocktemplate->vTxFees[0] = -nFees; // Randomise nonce From 852af44bb5fa02f38997e7344b4aa041af05482b Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 15:00:40 +0300 Subject: [PATCH 097/339] Test --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index 56b21492f..22f1ed10c 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -422,7 +422,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) }*/ pblock->vtx[0] = txNew; - if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && (commission= komodo_commission(*pblock)) != 0 ) + if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && (commission= komodo_commission(pblocktemplate->block)) != 0 ) { int32_t i; uint8_t *ptr; txNew.vout.resize(2); From c4c3dbe2502e74d8eeb7a62589a044e16a3b2b31 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 15:08:32 +0300 Subject: [PATCH 098/339] Test --- src/komodo_utils.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 4788b039e..4e4cf1440 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1582,6 +1582,7 @@ void komodo_args(char *argv0) else if ( ASSETCHAINS_REWARD == 0 ) MAX_MONEY = (ASSETCHAINS_SUPPLY+1) * SATOSHIDEN; else MAX_MONEY = (ASSETCHAINS_SUPPLY+1) * SATOSHIDEN + ASSETCHAINS_REWARD * (ASSETCHAINS_ENDSUBSIDY==0 ? 10000000 : ASSETCHAINS_ENDSUBSIDY); + MAX_MONEY += (MAX_MONEY * ASSETCHAINS_COMMISSOION) / COIN; //printf("baseid.%d MAX_MONEY.%s %.8f\n",baseid,ASSETCHAINS_SYMBOL,(double)MAX_MONEY/SATOSHIDEN); ASSETCHAINS_PORT = komodo_port(ASSETCHAINS_SYMBOL,ASSETCHAINS_SUPPLY,&ASSETCHAINS_MAGIC,extraptr,extralen); while ( (dirname= (char *)GetDataDir(false).string().c_str()) == 0 || dirname[0] == 0 ) From ecf5f2b37268d30a604c27f39e132318ea11b700 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 15:09:17 +0300 Subject: [PATCH 099/339] Test --- src/komodo_utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 4e4cf1440..6268c6108 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1582,7 +1582,7 @@ void komodo_args(char *argv0) else if ( ASSETCHAINS_REWARD == 0 ) MAX_MONEY = (ASSETCHAINS_SUPPLY+1) * SATOSHIDEN; else MAX_MONEY = (ASSETCHAINS_SUPPLY+1) * SATOSHIDEN + ASSETCHAINS_REWARD * (ASSETCHAINS_ENDSUBSIDY==0 ? 10000000 : ASSETCHAINS_ENDSUBSIDY); - MAX_MONEY += (MAX_MONEY * ASSETCHAINS_COMMISSOION) / COIN; + MAX_MONEY += (MAX_MONEY * ASSETCHAINS_COMMISSION) / COIN; //printf("baseid.%d MAX_MONEY.%s %.8f\n",baseid,ASSETCHAINS_SYMBOL,(double)MAX_MONEY/SATOSHIDEN); ASSETCHAINS_PORT = komodo_port(ASSETCHAINS_SYMBOL,ASSETCHAINS_SUPPLY,&ASSETCHAINS_MAGIC,extraptr,extralen); while ( (dirname= (char *)GetDataDir(false).string().c_str()) == 0 || dirname[0] == 0 ) From 10ad05f68ae75f7d41c25531b74d9892d11cc9ff Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 15:10:24 +0300 Subject: [PATCH 100/339] Test --- src/komodo_utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 6268c6108..7c189be50 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1582,7 +1582,7 @@ void komodo_args(char *argv0) else if ( ASSETCHAINS_REWARD == 0 ) MAX_MONEY = (ASSETCHAINS_SUPPLY+1) * SATOSHIDEN; else MAX_MONEY = (ASSETCHAINS_SUPPLY+1) * SATOSHIDEN + ASSETCHAINS_REWARD * (ASSETCHAINS_ENDSUBSIDY==0 ? 10000000 : ASSETCHAINS_ENDSUBSIDY); - MAX_MONEY += (MAX_MONEY * ASSETCHAINS_COMMISSION) / COIN; + MAX_MONEY += (MAX_MONEY * ASSETCHAINS_COMMISSION) / SATOSHIDEN; //printf("baseid.%d MAX_MONEY.%s %.8f\n",baseid,ASSETCHAINS_SYMBOL,(double)MAX_MONEY/SATOSHIDEN); ASSETCHAINS_PORT = komodo_port(ASSETCHAINS_SYMBOL,ASSETCHAINS_SUPPLY,&ASSETCHAINS_MAGIC,extraptr,extralen); while ( (dirname= (char *)GetDataDir(false).string().c_str()) == 0 || dirname[0] == 0 ) From a43401b400f8f90bfdf5bbe5f3367eb616f17b4c Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 15:19:20 +0300 Subject: [PATCH 101/339] Test --- src/komodo_gateway.h | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index f34ca1e3d..89b4b0c93 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -740,25 +740,25 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block) // verify above } else { - if ( overflow != 0 || total > 0 ) + if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && block.vtx[0].vout.size() > 1 ) + { + script = (uint8_t *)block.vtx[0].vout[1].scriptPubKey.data(); + if ( script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(script+1,ASSETCHAINS_OVERRIDE_PUBKEY33,33) != 0 ) + return(-1); + if ( (checktoshis = komodo_commission(block)) != 0 ) + { + if ( block.vtx[0].vout.size() < 2 || block.vtx[0].vout[1].nValue != checktoshis ) + { + fprintf(stderr,"checktoshis %.8f vs actual vout[1] %.8f\n",dstr(checktoshis),dstr(block.vtx[0].vout[1].nValue)); + return(-1); + } + } + } + else if ( overflow != 0 || total > 0 ) return(-1); } return(0); } - if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && block.vtx[0].vout.size() > 1 ) - { - script = (uint8_t *)block.vtx[0].vout[1].scriptPubKey.data(); - if ( script[0] != 33 || script[34] != OP_CHECKSIG || memcmp(script+1,ASSETCHAINS_OVERRIDE_PUBKEY33,33) != 0 ) - return(-1); - if ( (checktoshis = komodo_commission(block)) != 0 ) - { - if ( block.vtx[0].vout.size() < 2 || block.vtx[0].vout[1].nValue != checktoshis ) - { - fprintf(stderr,"checktoshis %.8f vs actual vout[1] %.8f\n",dstr(checktoshis),dstr(block.vtx[0].vout[1].nValue)); - return(-1); - } - } - } /* //fprintf(stderr,"ht.%d n.%d nValue %.8f (%d %d %d)\n",height,n,dstr(block.vtx[0].vout[1].nValue),KOMODO_PAX,komodo_isrealtime(&ht),KOMODO_PASSPORT_INITDONE); offset += komodo_scriptitemlen(&opretlen,&script[offset]); From 0587a0e53778cf4253d53f9f59668d1d51d3184c Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 15:25:09 +0300 Subject: [PATCH 102/339] CTEST --- src/ctest | 1 + 1 file changed, 1 insertion(+) create mode 100755 src/ctest diff --git a/src/ctest b/src/ctest new file mode 100755 index 000000000..1bb1a92a8 --- /dev/null +++ b/src/ctest @@ -0,0 +1 @@ +./komodod -ac_name=CTEST -ac_supply=1000000 -ac_perc=100000 -ac_pubkey=02ebc786cb83de8dc3922ab83c21f3f8a2f3216940c3bf9da43ce39e2a3a882c92 -ac_reward=300000000 -addnode=136.243.58.134 & From 146d2aa22d13dfa14ba8b93e6e87f30efc3ba12a Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 15:26:50 +0300 Subject: [PATCH 103/339] Test --- src/komodo_gateway.h | 4 ++-- src/miner.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 89b4b0c93..7e4666d4b 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -659,14 +659,14 @@ uint64_t komodo_commission(const CBlock &block) n = block.vtx[i].vout.size(); for (j=0; j %.8f\n",txn_count,n,dstr(total),dstr((total * ASSETCHAINS_COMMISSION) / COIN)); + //fprintf(stderr,"txn.%d n.%d commission total %.8f -> %.8f\n",txn_count,n,dstr(total),dstr((total * ASSETCHAINS_COMMISSION) / COIN)); return((total * ASSETCHAINS_COMMISSION) / COIN); } diff --git a/src/miner.cpp b/src/miner.cpp index 22f1ed10c..46fcc342a 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -433,7 +433,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) for (i=0; i<33; i++) ptr[i+1] = ASSETCHAINS_OVERRIDE_PUBKEY33[i]; ptr[34] = OP_CHECKSIG; - printf("autocreate commision vout\n"); + //printf("autocreate commision vout\n"); pblock->vtx[0] = txNew; } pblocktemplate->vTxFees[0] = -nFees; From de4a435c680da069eaff08adb35f7986a1cf7dbe Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 15:42:18 +0300 Subject: [PATCH 104/339] Test --- src/komodo_gateway.h | 4 ++-- src/main.cpp | 12 +++++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 7e4666d4b..50641b589 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -751,10 +751,10 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block) // verify above { fprintf(stderr,"checktoshis %.8f vs actual vout[1] %.8f\n",dstr(checktoshis),dstr(block.vtx[0].vout[1].nValue)); return(-1); - } + } else return(0); } } - else if ( overflow != 0 || total > 0 ) + if ( overflow != 0 || total > 0 ) return(-1); } return(0); diff --git a/src/main.cpp b/src/main.cpp index f45ad7bad..a0b4084e8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2585,6 +2585,16 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs]\n", (unsigned)block.vtx.size(), 0.001 * (nTime1 - nTimeStart), 0.001 * (nTime1 - nTimeStart) / block.vtx.size(), nInputs <= 1 ? 0 : 0.001 * (nTime1 - nTimeStart) / (nInputs-1), nTimeConnect * 0.000001); CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus()) + sum; + if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && block.vtx[0].vout.size() > 1 ) + { + uint64_t checktoshis; + if ( (checktoshis = komodo_commission(block)) != 0 ) + { + if ( block.vtx[0].vout.size() == 2 && block.vtx[0].vout[1].nValue == checktoshis ) + { + } else fprintf(stderr,"checktoshis %.8f vs actual vout[1] %.8f\n",dstr(checktoshis),dstr(block.vtx[0].vout[1].nValue)); + } + } if ( block.vtx[0].GetValueOut() > blockReward+1 ) { if ( pindex->nHeight >= KOMODO_NOTARIES_HEIGHT1 || block.vtx[0].vout[0].nValue > blockReward ) @@ -2593,7 +2603,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin error("ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)", block.vtx[0].GetValueOut(), blockReward), REJECT_INVALID, "bad-cb-amount"); - } else if ( NOTARY_PUBKEY33[0] != 0 ) + } //else if ( NOTARY_PUBKEY33[0] != 0 ) fprintf(stderr,"allow nHeight.%d coinbase %.8f vs %.8f interest %.8f\n",(int32_t)pindex->nHeight,dstr(block.vtx[0].GetValueOut()),dstr(blockReward),dstr(sum)); } if (!control.Wait()) From 479f8ea9b8e96978e9a9decd0a15cdaa90dd6724 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 15:48:02 +0300 Subject: [PATCH 105/339] Test --- src/komodo_utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 7c189be50..3973bf305 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1564,7 +1564,7 @@ void komodo_args(char *argv0) } if ( ASSETCHAINS_ENDSUBSIDY != 0 || ASSETCHAINS_REWARD != 0 || ASSETCHAINS_HALVING != 0 || ASSETCHAINS_DECAY != 0 || ASSETCHAINS_COMMISSION != 0 ) { - fprintf(stderr,"end.%llu reward.%llu halving.%llu decay.%llu perc %.4f [%02x]\n",(long long)ASSETCHAINS_ENDSUBSIDY,(long long)ASSETCHAINS_REWARD,(long long)ASSETCHAINS_HALVING,(long long)ASSETCHAINS_DECAY,dstr(ASSETCHAINS_COMMISSION)*100,ASSETCHAINS_OVERRIDE_PUBKEY33[0]); + fprintf(stderr,"end.%llu blocks, reward %.8f halving.%llu blocks, decay.%llu perc %.4f%% ac_pub=[%02x...]\n",(long long)ASSETCHAINS_ENDSUBSIDY,dstr(ASSETCHAINS_REWARD),(long long)ASSETCHAINS_HALVING,(long long)ASSETCHAINS_DECAY,dstr(ASSETCHAINS_COMMISSION)*100,ASSETCHAINS_OVERRIDE_PUBKEY33[0]); extraptr = extrabuf; memcpy(extraptr,ASSETCHAINS_OVERRIDE_PUBKEY33,33), extralen = 33; extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_ENDSUBSIDY),(void *)&ASSETCHAINS_ENDSUBSIDY); From b7dc56995ed0a7861bb5150d880b51407197f92c Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 15:48:51 +0300 Subject: [PATCH 106/339] Test --- src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index a0b4084e8..fd9443f7c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2591,8 +2591,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin if ( (checktoshis = komodo_commission(block)) != 0 ) { if ( block.vtx[0].vout.size() == 2 && block.vtx[0].vout[1].nValue == checktoshis ) - { - } else fprintf(stderr,"checktoshis %.8f vs actual vout[1] %.8f\n",dstr(checktoshis),dstr(block.vtx[0].vout[1].nValue)); + blockReward += checktoshis; + else fprintf(stderr,"checktoshis %.8f vs actual vout[1] %.8f\n",dstr(checktoshis),dstr(block.vtx[0].vout[1].nValue)); } } if ( block.vtx[0].GetValueOut() > blockReward+1 ) From ea1244288b9a478f0942e1ca9ff8e7ee38252527 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 15:50:31 +0300 Subject: [PATCH 107/339] Test --- src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index fd9443f7c..f6b8feba0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2597,13 +2597,13 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin } if ( block.vtx[0].GetValueOut() > blockReward+1 ) { - if ( pindex->nHeight >= KOMODO_NOTARIES_HEIGHT1 || block.vtx[0].vout[0].nValue > blockReward ) + if ( ASSETCHAINS_SYMBOL[0] != 0 || pindex->nHeight >= KOMODO_NOTARIES_HEIGHT1 || block.vtx[0].vout[0].nValue > blockReward ) { return state.DoS(100, error("ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)", block.vtx[0].GetValueOut(), blockReward), REJECT_INVALID, "bad-cb-amount"); - } //else if ( NOTARY_PUBKEY33[0] != 0 ) + } else if ( NOTARY_PUBKEY33[0] != 0 ) fprintf(stderr,"allow nHeight.%d coinbase %.8f vs %.8f interest %.8f\n",(int32_t)pindex->nHeight,dstr(block.vtx[0].GetValueOut()),dstr(blockReward),dstr(sum)); } if (!control.Wait()) From ce5dd5473e55cbbbaa9aed62bb4147ec904eb218 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 18:53:54 +0300 Subject: [PATCH 108/339] Test --- src/komodo_bitcoind.h | 5 ++++- src/komodo_gateway.h | 11 +++++++++-- src/komodo_globals.h | 2 +- src/komodo_kv.h | 2 +- src/komodo_utils.h | 6 ++++-- src/main.cpp | 5 +++-- src/pow.cpp | 12 ------------ src/rpcblockchain.cpp | 1 - 8 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index edd4d6569..cd780e172 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -557,10 +557,11 @@ uint64_t komodo_seed(int32_t height) return(seed); } -uint32_t komodo_txtime(uint256 hash) +uint32_t komodo_txtime(uint64_t *valuep,uint256 hash,int32_t n) { CTransaction tx; uint256 hashBlock; + *valuep = 0; if (!GetTransaction(hash, tx, #ifndef KOMODO_ZCASH Params().GetConsensus(), @@ -568,6 +569,8 @@ uint32_t komodo_txtime(uint256 hash) hashBlock, true)) { //printf("null GetTransaction\n"); + if ( n < tx.vout.size() ) + *valuep = tx.vout[n].nValue; return(tx.nLockTime); } return(0); diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 50641b589..a4d839c91 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -670,7 +670,7 @@ uint64_t komodo_commission(const CBlock &block) return((total * ASSETCHAINS_COMMISSION) / COIN); } -int32_t komodo_check_deposit(int32_t height,const CBlock& block) // verify above block is valid pax pricing +int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtime) // verify above block is valid pax pricing { static uint256 array[64]; static int32_t numbanned,indallvouts; int32_t i,j,k,n,ht,baseid,txn_count,activation,num,opretlen,offset=1,errs=0,matched=0,kmdheights[256],otherheights[256]; uint256 hash,txids[256]; char symbol[KOMODO_ASSETCHAIN_MAXLEN],base[KOMODO_ASSETCHAIN_MAXLEN]; uint16_t vouts[256]; int8_t baseids[256]; uint8_t *script,opcode,rmd160s[256*20]; uint64_t total,subsidy,available,deposited,issued,withdrawn,approved,redeemed,checktoshis,seed; int64_t values[256],srcvalues[256]; struct pax_transaction *pax; struct komodo_state *sp; @@ -740,6 +740,13 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block) // verify above } else { + if ( ASSETCHAINS_STAKED != 0 ) + { + uint32_t txtime,minutes; uint64_t value; + txtime = komodo_txtime(&value,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n); + minutes = (block.nTime - txtime) / 60; + fprintf(stderr,"txn_count.%d txtime.%u blocktime.%u prev.%u gap.%d minutes.%d %.8f\n",txn_count,txtime,block.nTime,prevtime,(int32_t)(block.nTime-prevtime),minutes,dstr(value)); + } if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && block.vtx[0].vout.size() > 1 ) { script = (uint8_t *)block.vtx[0].vout[1].scriptPubKey.data(); @@ -747,7 +754,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block) // verify above return(-1); if ( (checktoshis = komodo_commission(block)) != 0 ) { - if ( block.vtx[0].vout.size() < 2 || block.vtx[0].vout[1].nValue != checktoshis ) + if ( block.vtx[0].vout[1].nValue != checktoshis ) { fprintf(stderr,"checktoshis %.8f vs actual vout[1] %.8f\n",dstr(checktoshis),dstr(block.vtx[0].vout[1].nValue)); return(-1); diff --git a/src/komodo_globals.h b/src/komodo_globals.h index 518d22cbd..4f8433f03 100644 --- a/src/komodo_globals.h +++ b/src/komodo_globals.h @@ -54,7 +54,7 @@ char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; uint16_t ASSETCHAINS_PORT; uint32_t ASSETCHAIN_INIT; uint32_t ASSETCHAINS_MAGIC = 2387029918; -uint64_t ASSETCHAINS_ENDSUBSIDY,ASSETCHAINS_REWARD,ASSETCHAINS_HALVING,ASSETCHAINS_DECAY,ASSETCHAINS_COMMISSION,ASSETCHAINS_SUPPLY = 10; +uint64_t ASSETCHAINS_ENDSUBSIDY,ASSETCHAINS_REWARD,ASSETCHAINS_HALVING,ASSETCHAINS_DECAY,ASSETCHAINS_COMMISSION,ASSETCHAINS_STAKED,ASSETCHAINS_SUPPLY = 10; uint32_t KOMODO_INITDONE; char KMDUSERPASS[4096],BTCUSERPASS[4096]; uint16_t KMD_PORT = 7771,BITCOIND_PORT = 7771; diff --git a/src/komodo_kv.h b/src/komodo_kv.h index 0d5259eaa..7c20becb1 100644 --- a/src/komodo_kv.h +++ b/src/komodo_kv.h @@ -171,7 +171,7 @@ void komodo_kvupdate(uint8_t *opretbuf,int32_t opretlen,uint64_t value) memcpy(ptr->key,key,keylen); newflag = 1; HASH_ADD_KEYPTR(hh,KOMODO_KV,ptr->key,ptr->keylen,ptr); - printf("KV add.(%s) (%s)\n",ptr->key,valueptr); + //printf("KV add.(%s) (%s)\n",ptr->key,valueptr); } if ( newflag != 0 || (ptr->flags & KOMODO_KVPROTECTED) == 0 ) { diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 3973bf305..47da06c0d 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1501,7 +1501,7 @@ char *argv0names[] = void komodo_args(char *argv0) { extern int64_t MAX_MONEY; - std::string name,addn; char *dirname,fname[512],arg0str[64],magicstr[9]; uint8_t magic[4],extrabuf[256],*extraptr=0; FILE *fp; int32_t i,baseid,len,n,extralen = 0; + std::string name,addn; char *dirname,fname[512],arg0str[64],magicstr[9]; uint8_t magic[4],extrabuf[256],*extraptr=0; FILE *fp; uint64_t val; int32_t i,baseid,len,n,extralen = 0; IS_KOMODO_NOTARY = GetBoolArg("-notary", false); if ( (KOMODO_EXCHANGEWALLET= GetBoolArg("-exchange", false)) != 0 ) fprintf(stderr,"KOMODO_EXCHANGEWALLET mode active\n"); @@ -1540,6 +1540,7 @@ void komodo_args(char *argv0) ASSETCHAINS_DECAY = GetArg("-ac_decay",0); ASSETCHAINS_COMMISSION = GetArg("-ac_perc",0); ASSETCHAINS_OVERRIDE_PUBKEY = GetArg("-ac_pubkey",""); + ASSETCHAINS_STAKED = GetArg("-ac_staked",0); if ( ASSETCHAINS_HALVING != 0 && ASSETCHAINS_HALVING < 1440 ) { ASSETCHAINS_HALVING = 1440; @@ -1571,7 +1572,8 @@ void komodo_args(char *argv0) extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_REWARD),(void *)&ASSETCHAINS_REWARD); extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_HALVING),(void *)&ASSETCHAINS_HALVING); extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_DECAY),(void *)&ASSETCHAINS_DECAY); - extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_COMMISSION),(void *)&ASSETCHAINS_COMMISSION); + val = ASSETCHAINS_COMMISSION | ((ASSETCHAINS_STAKED & 0xffff) << 32); + extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(val),(void *)&val); } addn = GetArg("-seednode",""); if ( strlen(addn.c_str()) > 0 ) diff --git a/src/main.cpp b/src/main.cpp index f6b8feba0..3266bf4e4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3506,7 +3506,8 @@ bool CheckBlockHeader(int32_t height,CBlockIndex *pindex, const CBlockHeader& bl return true; } -int32_t komodo_check_deposit(int32_t height,const CBlock& block); +int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtime); + bool CheckBlock(int32_t height,CBlockIndex *pindex,const CBlock& block, CValidationState& state, libzcash::ProofVerifier& verifier, bool fCheckPOW, bool fCheckMerkleRoot) @@ -3568,7 +3569,7 @@ bool CheckBlock(int32_t height,CBlockIndex *pindex,const CBlock& block, CValidat if (nSigOps > MAX_BLOCK_SIGOPS) return state.DoS(100, error("CheckBlock(): out-of-bounds SigOpCount"), REJECT_INVALID, "bad-blk-sigops", true); - if ( komodo_check_deposit(ASSETCHAINS_SYMBOL[0] == 0 ? height : pindex != 0 ? (int32_t)pindex->nHeight : chainActive.Tip()->nHeight+1,block) < 0 ) + if ( komodo_check_deposit(ASSETCHAINS_SYMBOL[0] == 0 ? height : pindex != 0 ? (int32_t)pindex->nHeight : chainActive.Tip()->nHeight+1,block,pindex==0||pindex->pprev==0?0:pindex->pprev->nTime) < 0 ) { static uint32_t counter; if ( counter++ < 100 ) diff --git a/src/pow.cpp b/src/pow.cpp index 76960933d..63806033d 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -190,18 +190,6 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned in } else fprintf(stderr,"skip return error height.%d loading.%d\n",height,KOMODO_LOADINGBLOCKS); } //else fprintf(stderr,"skip height.%d loading.%d\n",height,KOMODO_LOADINGBLOCKS); } - if ( 0 && height > 248000 ) - { - for (i=31; i>=0; i--) - fprintf(stderr,"%02x",((uint8_t *)&hash)[i]); - fprintf(stderr," hash vs "); - for (i=31; i>=0; i--) - fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); - fprintf(stderr," POW ok for ht.%d notaryid.%d: ",height,notaryid); - for (i=0; i<33; i++) - fprintf(stderr,"%02x",pubkey33[i]); - fprintf(stderr,"\n"); - } return true; } diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 1254217ac..168c00f32 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -544,7 +544,6 @@ UniValue gettxoutsetinfo(const UniValue& params, bool fHelp) #define KOMODO_KVBINARY 2 extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; uint64_t komodo_interest(int32_t txheight,uint64_t nValue,uint32_t nLockTime,uint32_t tiptime); -uint32_t komodo_txtime(uint256 hash); 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); From d078d0baa8b174d7dfe154c9d4e7269b2fc4224d Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 19:05:19 +0300 Subject: [PATCH 109/339] Test --- src/komodo_gateway.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index a4d839c91..927a8fd36 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -742,7 +742,12 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim { if ( ASSETCHAINS_STAKED != 0 ) { - uint32_t txtime,minutes; uint64_t value; + uint32_t txtime,minutes; uint64_t value; CBlockIndex *previndex; + if ( prevtime == 0 ) + { + if ( (previndex= mapBlockIndex[block.GetHash()]) != 0 ) + prevtime = (uint32_t)previndex->nTime; + } txtime = komodo_txtime(&value,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n); minutes = (block.nTime - txtime) / 60; fprintf(stderr,"txn_count.%d txtime.%u blocktime.%u prev.%u gap.%d minutes.%d %.8f\n",txn_count,txtime,block.nTime,prevtime,(int32_t)(block.nTime-prevtime),minutes,dstr(value)); From 56832841c2706e1f7d89c87a21826632538de1c2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 19:07:27 +0300 Subject: [PATCH 110/339] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 927a8fd36..818b171f0 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -750,7 +750,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim } txtime = komodo_txtime(&value,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n); minutes = (block.nTime - txtime) / 60; - fprintf(stderr,"txn_count.%d txtime.%u blocktime.%u prev.%u gap.%d minutes.%d %.8f\n",txn_count,txtime,block.nTime,prevtime,(int32_t)(block.nTime-prevtime),minutes,dstr(value)); + fprintf(stderr,"ht.%d txn_count.%d txtime.%u blocktime.%u prev.%u gap.%d minutes.%d %.8f\n",(int32_t)block.nHeight,txn_count,txtime,block.nTime,prevtime,(int32_t)(block.nTime-prevtime),minutes,dstr(value)); } if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && block.vtx[0].vout.size() > 1 ) { From 0cffe79b2fd90801338876f7c9b0686ae68e5ebc Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 19:08:49 +0300 Subject: [PATCH 111/339] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 818b171f0..16e8152a8 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -750,7 +750,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim } txtime = komodo_txtime(&value,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n); minutes = (block.nTime - txtime) / 60; - fprintf(stderr,"ht.%d txn_count.%d txtime.%u blocktime.%u prev.%u gap.%d minutes.%d %.8f\n",(int32_t)block.nHeight,txn_count,txtime,block.nTime,prevtime,(int32_t)(block.nTime-prevtime),minutes,dstr(value)); + fprintf(stderr,"ht.%d txn_count.%d txtime.%u blocktime.%u prev.%u gap.%d minutes.%d %.8f\n",komodo_block2height(&block),txn_count,txtime,block.nTime,prevtime,(int32_t)(block.nTime-prevtime),minutes,dstr(value)); } if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && block.vtx[0].vout.size() > 1 ) { From 145d4d4eee2c6a9e6df675c358b231917acf001d Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 19:10:56 +0300 Subject: [PATCH 112/339] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 16e8152a8..0046042c0 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -750,7 +750,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim } txtime = komodo_txtime(&value,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n); minutes = (block.nTime - txtime) / 60; - fprintf(stderr,"ht.%d txn_count.%d txtime.%u blocktime.%u prev.%u gap.%d minutes.%d %.8f\n",komodo_block2height(&block),txn_count,txtime,block.nTime,prevtime,(int32_t)(block.nTime-prevtime),minutes,dstr(value)); + fprintf(stderr,"ht.%d txn_count.%d txtime.%u blocktime.%u prev.%u gap.%d minutes.%d %.8f\n",komodo_block2height((CBlock *)&block),txn_count,txtime,block.nTime,prevtime,(int32_t)(block.nTime-prevtime),minutes,dstr(value)); } if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && block.vtx[0].vout.size() > 1 ) { From a4a40a38adf9ab136fd5e31aead21fcad940e952 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 20:10:46 +0300 Subject: [PATCH 113/339] Test --- src/komodo_gateway.h | 2 +- src/miner.cpp | 32 ++++++++++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 0046042c0..3f22e20e5 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -745,7 +745,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim uint32_t txtime,minutes; uint64_t value; CBlockIndex *previndex; if ( prevtime == 0 ) { - if ( (previndex= mapBlockIndex[block.GetHash()]) != 0 ) + if ( (previndex= mapBlockIndex[block.hashPrevBlock]) != 0 ) prevtime = (uint32_t)previndex->nTime; } txtime = komodo_txtime(&value,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n); diff --git a/src/miner.cpp b/src/miner.cpp index 46fcc342a..46ea9f377 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -121,6 +121,11 @@ int32_t komodo_isrealtime(int32_t *kmdheightp); int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_t nTime,int32_t dispflag); uint64_t komodo_commission(const CBlock &block); +int32_t komodo_staked(uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) +{ + return(-1); +} + CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) { uint64_t deposits; int32_t isrealtime,kmdheight; const CChainParams& chainparams = Params(); @@ -309,7 +314,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) // Legacy limits on sigOps: unsigned int nTxSigOps = GetLegacySigOpCount(tx); - if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) + if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS-1) continue; // Skip free transactions if we're past the minimum block size: @@ -336,7 +341,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) CAmount nTxFees = view.GetValueIn(chainActive.Tip()->nHeight,&interest,tx,chainActive.Tip()->nTime)-tx.GetValueOut(); nTxSigOps += GetP2SHSigOpCount(tx, view); - if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS) + if (nBlockSigOps + nTxSigOps >= MAX_BLOCK_SIGOPS-1) continue; // Note that flags: we don't want to set mempool/IsStandard() @@ -384,6 +389,29 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) nLastBlockTx = nBlockTx; nLastBlockSize = nBlockSize; LogPrintf("CreateNewBlock(): total size %u\n", nBlockSize); + if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_STAKED != 0 && NOTARY_PUBKEY33[0] != 0 ) + { + uint64_t txfees,utxovalue; uint256 utxotxid; int32_t numsigs,utxovout; uint8_t utxosig[128]; + if ( komodo_staked(&utxotxid,&utxovout,&utxovalue,utxosig) == 0 ) + { + CMutableTransaction txStaked = CreateNewContextualCMutableTransaction(chainparams.GetConsensus(), nHeight); + CAmount txfees = view.GetValueIn(chainActive.Tip()->nHeight,&interest,txStaked,chainActive.Tip()->nTime)-txStaked.GetValueOut(); + txStaked.vin.resize(1); + txStaked.vout.resize(1); + txStaked.vin[0].prevout.hash = utxotxid; + txStaked.vin[0].prevout.n = utxovout; + txStaked.vin[0].scriptSig = utxosig; + txStaked.vout[0].scriptPubKey = CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG; + txStaked.vout[0].nValue = utxovalue - 10000; + txStaked.nLockTime = chainActive.Tip()->nTime + chainparams.GetConsensus().nPowTargetSpacing; + + pblock->vtx.push_back(txStaked); + numsigs = GetLegacySigOpCount(txStaked); + pblocktemplate->vTxFees.push_back(txfees); + pblocktemplate->vTxSigOps.push_back(numsigs); + nFees += txfees; + } + } // Create coinbase tx CMutableTransaction txNew = CreateNewContextualCMutableTransaction(chainparams.GetConsensus(), nHeight); From 44d2da57f21523804c455c28bfa214c6de3fa129 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 20:17:43 +0300 Subject: [PATCH 114/339] Test --- src/miner.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 46ea9f377..99ba3708a 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -106,7 +106,7 @@ void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, #include "komodo_defs.h" extern int32_t ASSETCHAINS_SEED,IS_KOMODO_NOTARY,USE_EXTERNAL_PUBKEY,KOMODO_CHOSEN_ONE,ASSETCHAIN_INIT,KOMODO_INITDONE,KOMODO_ON_DEMAND,KOMODO_INITDONE,KOMODO_PASSPORT_INITDONE; -extern uint32_t ASSETCHAINS_REWARD,ASSETCHAINS_COMMISSION; +extern uint64_t ASSETCHAINS_REWARD,ASSETCHAINS_COMMISSION,ASSETCHAINS_STAKED; extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; extern std::string NOTARY_PUBKEY; extern uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33]; @@ -123,7 +123,7 @@ uint64_t komodo_commission(const CBlock &block); int32_t komodo_staked(uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) { - return(-1); + return(0); } CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) @@ -391,18 +391,21 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) LogPrintf("CreateNewBlock(): total size %u\n", nBlockSize); if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_STAKED != 0 && NOTARY_PUBKEY33[0] != 0 ) { - uint64_t txfees,utxovalue; uint256 utxotxid; int32_t numsigs,utxovout; uint8_t utxosig[128]; - if ( komodo_staked(&utxotxid,&utxovout,&utxovalue,utxosig) == 0 ) + uint64_t txfees,utxovalue; uint256 utxotxid; int32_t siglen,numsigs,utxovout; uint8_t utxosig[128],*ptr; + if ( (siglen= komodo_staked(&utxotxid,&utxovout,&utxovalue,utxosig)) > 0 ) { CMutableTransaction txStaked = CreateNewContextualCMutableTransaction(chainparams.GetConsensus(), nHeight); - CAmount txfees = view.GetValueIn(chainActive.Tip()->nHeight,&interest,txStaked,chainActive.Tip()->nTime)-txStaked.GetValueOut(); + CAmount txfees = 10000; txStaked.vin.resize(1); txStaked.vout.resize(1); txStaked.vin[0].prevout.hash = utxotxid; txStaked.vin[0].prevout.n = utxovout; - txStaked.vin[0].scriptSig = utxosig; + txStaked.vin[0].scriptSig.resize(siglen); + ptr = (uint8_t *)txStaked.vin[0].scriptSig.data(); + for (i=0; inTime + chainparams.GetConsensus().nPowTargetSpacing; pblock->vtx.push_back(txStaked); From d913f07b6ea82f2bdabcfb1f52e447eb2c372ff4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 20:18:25 +0300 Subject: [PATCH 115/339] Test --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index 99ba3708a..57de5366c 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -391,7 +391,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) LogPrintf("CreateNewBlock(): total size %u\n", nBlockSize); if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_STAKED != 0 && NOTARY_PUBKEY33[0] != 0 ) { - uint64_t txfees,utxovalue; uint256 utxotxid; int32_t siglen,numsigs,utxovout; uint8_t utxosig[128],*ptr; + uint64_t txfees,utxovalue; uint256 utxotxid; int32_t i,siglen,numsigs,utxovout; uint8_t utxosig[128],*ptr; if ( (siglen= komodo_staked(&utxotxid,&utxovout,&utxovalue,utxosig)) > 0 ) { CMutableTransaction txStaked = CreateNewContextualCMutableTransaction(chainparams.GetConsensus(), nHeight); From ec5ed2f7b7ba466e15699aabfce056f70616458b Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 20:31:53 +0300 Subject: [PATCH 116/339] Test --- src/komodo_bitcoind.h | 10 ++++++++++ src/miner.cpp | 6 +----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index cd780e172..18ac579e3 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -987,3 +987,13 @@ int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_ } return(0); } + +int32_t komodo_staked(uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) +{ + memset(utxotxidp,0,sizeof(*utxotxidp)); + memset(utxovoutp,0,sizeof(*utxovoutp)); + memset(utxovaluep,0,sizeof(*utxovaluep)); + memset(utxosig,0,72); + return(72); +} + diff --git a/src/miner.cpp b/src/miner.cpp index 57de5366c..e14338641 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -120,11 +120,7 @@ int32_t komodo_gateway_deposits(CMutableTransaction *txNew,char *symbol,int32_t int32_t komodo_isrealtime(int32_t *kmdheightp); int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_t nTime,int32_t dispflag); uint64_t komodo_commission(const CBlock &block); - -int32_t komodo_staked(uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) -{ - return(0); -} +int32_t komodo_staked(uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig); CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) { From 85d77224f2093edb8916f8ef501a12bddf8d60ea Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 20:36:22 +0300 Subject: [PATCH 117/339] Test --- src/komodo_bitcoind.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 18ac579e3..217ac7194 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -990,9 +990,9 @@ int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_ int32_t komodo_staked(uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) { + *utxovaluep = 100000; memset(utxotxidp,0,sizeof(*utxotxidp)); memset(utxovoutp,0,sizeof(*utxovoutp)); - memset(utxovaluep,0,sizeof(*utxovaluep)); memset(utxosig,0,72); return(72); } From dfb57be5ece1550fce47b06ae7c76c550e34402d Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 20:48:53 +0300 Subject: [PATCH 118/339] Test --- src/komodo_bitcoind.h | 9 ++++++++- src/komodo_globals.h | 2 +- src/komodo_utils.h | 1 + 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 217ac7194..847ffceb4 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -990,10 +990,17 @@ int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_ int32_t komodo_staked(uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) { - *utxovaluep = 100000; + char *retstr; + *utxovaluep = 0; memset(utxotxidp,0,sizeof(*utxotxidp)); memset(utxovoutp,0,sizeof(*utxovoutp)); memset(utxosig,0,72); + if ( (retstr= komodo_issuemethod(KOMODO_USERPASS,"listunspent","[]",BITCOIND_PORT)) != 0 ) + { + fprintf(stderr,"listunspent.(%s)\n",retstr); + free(retstr); + *utxovaluep = 100000; + } return(72); } diff --git a/src/komodo_globals.h b/src/komodo_globals.h index 4f8433f03..cb8f61988 100644 --- a/src/komodo_globals.h +++ b/src/komodo_globals.h @@ -50,7 +50,7 @@ int32_t KOMODO_LASTMINED,prevKOMODO_LASTMINED,JUMBLR_PAUSE,ASSETCHAINS_CC; std::string NOTARY_PUBKEY,ASSETCHAINS_NOTARIES,ASSETCHAINS_OVERRIDE_PUBKEY; uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33]; -char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; +char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN],ASSETCHAINS_USERPASS[4096]; uint16_t ASSETCHAINS_PORT; uint32_t ASSETCHAIN_INIT; uint32_t ASSETCHAINS_MAGIC = 2387029918; diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 47da06c0d..f86a62a60 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1422,6 +1422,7 @@ uint16_t komodo_userpass(char *userpass,char *symbol) { port = komodo_userpass(username,password,fp); sprintf(userpass,"%s:%s",username,password); + strcpy(ASSETCHAINS_USERPASS,userpass); fclose(fp); return((int32_t)strlen(userpass)); } From b50b085aa843fc90854895acd0d0a000e7c010cb Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 20:49:54 +0300 Subject: [PATCH 119/339] Test --- src/komodo_bitcoind.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 847ffceb4..a15faeade 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -995,7 +995,7 @@ int32_t komodo_staked(uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep memset(utxotxidp,0,sizeof(*utxotxidp)); memset(utxovoutp,0,sizeof(*utxovoutp)); memset(utxosig,0,72); - if ( (retstr= komodo_issuemethod(KOMODO_USERPASS,"listunspent","[]",BITCOIND_PORT)) != 0 ) + if ( (retstr= komodo_issuemethod(ASSETCHAINS_USERPASS,"listunspent","[]",BITCOIND_PORT)) != 0 ) { fprintf(stderr,"listunspent.(%s)\n",retstr); free(retstr); From f16f9bb3688adcbcb0dd253e19f320c9f46f6627 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 20:51:42 +0300 Subject: [PATCH 120/339] Test --- src/komodo_bitcoind.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index a15faeade..13032a12e 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -995,7 +995,7 @@ int32_t komodo_staked(uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep memset(utxotxidp,0,sizeof(*utxotxidp)); memset(utxovoutp,0,sizeof(*utxovoutp)); memset(utxosig,0,72); - if ( (retstr= komodo_issuemethod(ASSETCHAINS_USERPASS,"listunspent","[]",BITCOIND_PORT)) != 0 ) + if ( (retstr= komodo_issuemethod(ASSETCHAINS_USERPASS,(char *)"listunspent",(char *)"[]",BITCOIND_PORT)) != 0 ) { fprintf(stderr,"listunspent.(%s)\n",retstr); free(retstr); From a643c0781042fc6c5e4df1ee281427a9af337c18 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 20:58:31 +0300 Subject: [PATCH 121/339] Test --- src/komodo_bitcoind.h | 1 + src/komodo_utils.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 13032a12e..04c68620d 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -995,6 +995,7 @@ int32_t komodo_staked(uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep memset(utxotxidp,0,sizeof(*utxotxidp)); memset(utxovoutp,0,sizeof(*utxovoutp)); memset(utxosig,0,72); + printf("%s port.%u %s\n",ASSETCHAINS_SYMBOL,BITCOIND_PORT,ASSETCHAINS_USERPASS); if ( (retstr= komodo_issuemethod(ASSETCHAINS_USERPASS,(char *)"listunspent",(char *)"[]",BITCOIND_PORT)) != 0 ) { fprintf(stderr,"listunspent.(%s)\n",retstr); diff --git a/src/komodo_utils.h b/src/komodo_utils.h index f86a62a60..16886a52c 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1422,7 +1422,8 @@ uint16_t komodo_userpass(char *userpass,char *symbol) { port = komodo_userpass(username,password,fp); sprintf(userpass,"%s:%s",username,password); - strcpy(ASSETCHAINS_USERPASS,userpass); + if ( strcmp(symbol,ASSETCHAINS_SYMBOL) == 0 ) + strcpy(ASSETCHAINS_USERPASS,userpass); fclose(fp); return((int32_t)strlen(userpass)); } From bbb607b4db1b6bf514fb8e68926563714a1414a3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 21:15:20 +0300 Subject: [PATCH 122/339] Test --- src/komodo_utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 16886a52c..0f18d5873 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1605,7 +1605,7 @@ void komodo_args(char *argv0) extern int COINBASE_MATURITY; komodo_configfile(ASSETCHAINS_SYMBOL,ASSETCHAINS_PORT + 1); COINBASE_MATURITY = 1; - LogPrintf("ASSETCHAINS_PORT %s %u\n",ASSETCHAINS_SYMBOL,ASSETCHAINS_PORT); + fprintf(stderr,"ASSETCHAINS_PORT %s %u (%s)\n",ASSETCHAINS_SYMBOL,ASSETCHAINS_PORT,ASSETCHAINS_USERPASS); } //ASSETCHAINS_NOTARIES = GetArg("-ac_notaries",""); //komodo_assetchain_pubkeys((char *)ASSETCHAINS_NOTARIES.c_str()); From 4d3e54094d4ccfbfec110e3d377504d902305ab5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 21:20:26 +0300 Subject: [PATCH 123/339] Test --- src/komodo_utils.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/komodo_utils.h b/src/komodo_utils.h index 0f18d5873..e8e801141 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1604,6 +1604,7 @@ void komodo_args(char *argv0) int32_t komodo_baseid(char *origbase); extern int COINBASE_MATURITY; komodo_configfile(ASSETCHAINS_SYMBOL,ASSETCHAINS_PORT + 1); + komodo_userpass(ASSETCHAINS_USERPASS,ASSETCHAINS_SYMBOL); COINBASE_MATURITY = 1; fprintf(stderr,"ASSETCHAINS_PORT %s %u (%s)\n",ASSETCHAINS_SYMBOL,ASSETCHAINS_PORT,ASSETCHAINS_USERPASS); } From 4fb123112bb36239215ec61801b402b287c0f3cf Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 21:23:53 +0300 Subject: [PATCH 124/339] Test --- src/komodo_bitcoind.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 04c68620d..f48879e85 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -1001,7 +1001,7 @@ int32_t komodo_staked(uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep fprintf(stderr,"listunspent.(%s)\n",retstr); free(retstr); *utxovaluep = 100000; - } + } else printf("null retstr\n"); return(72); } From e5b7a04e768abf788faa9db4d9c65bf1c73e0c25 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 21:31:33 +0300 Subject: [PATCH 125/339] Test --- src/komodo_bitcoind.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index f48879e85..d7949cc7e 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -336,7 +336,7 @@ char *curl_post(CURL **cHandlep,char *url,char *userpass,char *postfields,char * char *komodo_issuemethod(char *userpass,char *method,char *params,uint16_t port) { - //static void *cHandle; + static void *cHandle; char url[512],*retstr=0,*retstr2=0,postdata[8192]; if ( params == 0 || params[0] == 0 ) params = (char *)"[]"; @@ -344,9 +344,9 @@ char *komodo_issuemethod(char *userpass,char *method,char *params,uint16_t port) { sprintf(url,(char *)"http://127.0.0.1:%u",port); sprintf(postdata,"{\"method\":\"%s\",\"params\":%s}",method,params); - //printf("[%s] (%s) postdata.(%s) params.(%s) USERPASS.(%s)\n",ASSETCHAINS_SYMBOL,url,postdata,params,KMDUSERPASS); - retstr2 = bitcoind_RPC(&retstr,(char *)"debug",url,userpass,method,params); - //retstr = curl_post(&cHandle,url,USERPASS,postdata,0,0,0,0); + printf("[%s] (%s) postdata.(%s) params.(%s) USERPASS.(%s)\n",ASSETCHAINS_SYMBOL,url,postdata,params,userpass); + //retstr2 = bitcoind_RPC(&retstr,(char *)"debug",url,userpass,method,params); + retstr2 = curl_post(&cHandle,url,userpass,postdata,0,0,0,0); } return(retstr2); } From 50653d13c69263411795c84d1a710443f12069e7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 21:34:06 +0300 Subject: [PATCH 126/339] Test --- src/komodo_bitcoind.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index d7949cc7e..579a2809e 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -336,7 +336,7 @@ char *curl_post(CURL **cHandlep,char *url,char *userpass,char *postfields,char * char *komodo_issuemethod(char *userpass,char *method,char *params,uint16_t port) { - static void *cHandle; + //static void *cHandle; char url[512],*retstr=0,*retstr2=0,postdata[8192]; if ( params == 0 || params[0] == 0 ) params = (char *)"[]"; @@ -344,9 +344,9 @@ char *komodo_issuemethod(char *userpass,char *method,char *params,uint16_t port) { sprintf(url,(char *)"http://127.0.0.1:%u",port); sprintf(postdata,"{\"method\":\"%s\",\"params\":%s}",method,params); - printf("[%s] (%s) postdata.(%s) params.(%s) USERPASS.(%s)\n",ASSETCHAINS_SYMBOL,url,postdata,params,userpass); - //retstr2 = bitcoind_RPC(&retstr,(char *)"debug",url,userpass,method,params); - retstr2 = curl_post(&cHandle,url,userpass,postdata,0,0,0,0); + //printf("[%s] (%s) postdata.(%s) params.(%s) USERPASS.(%s)\n",ASSETCHAINS_SYMBOL,url,postdata,params,KMDUSERPASS); + retstr2 = bitcoind_RPC(&retstr,(char *)"debug",url,userpass,method,params); + //retstr = curl_post(&cHandle,url,USERPASS,postdata,0,0,0,0); } return(retstr2); } @@ -996,12 +996,12 @@ int32_t komodo_staked(uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep memset(utxovoutp,0,sizeof(*utxovoutp)); memset(utxosig,0,72); printf("%s port.%u %s\n",ASSETCHAINS_SYMBOL,BITCOIND_PORT,ASSETCHAINS_USERPASS); - if ( (retstr= komodo_issuemethod(ASSETCHAINS_USERPASS,(char *)"listunspent",(char *)"[]",BITCOIND_PORT)) != 0 ) + if ( (retstr= komodo_issuemethod(ASSETCHAINS_USERPASS,(char *)"getinfo",(char *)"[]",BITCOIND_PORT)) != 0 ) { fprintf(stderr,"listunspent.(%s)\n",retstr); free(retstr); *utxovaluep = 100000; - } else printf("null retstr\n"); + } else fprintf(stderr,"null retstr\n"); return(72); } From aee5fd82c6a70926029f8b1fe2f8790385aaf4dd Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 21:49:35 +0300 Subject: [PATCH 127/339] Test --- src/komodo_bitcoind.h | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 579a2809e..498c8511b 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -988,20 +988,17 @@ int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_ return(0); } +UniValue listunspent(const UniValue& params, bool fHelp); + int32_t komodo_staked(uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) { - char *retstr; + char *retstr; UniValue ret,params = NullUniValue; *utxovaluep = 0; memset(utxotxidp,0,sizeof(*utxotxidp)); memset(utxovoutp,0,sizeof(*utxovoutp)); memset(utxosig,0,72); - printf("%s port.%u %s\n",ASSETCHAINS_SYMBOL,BITCOIND_PORT,ASSETCHAINS_USERPASS); - if ( (retstr= komodo_issuemethod(ASSETCHAINS_USERPASS,(char *)"getinfo",(char *)"[]",BITCOIND_PORT)) != 0 ) - { - fprintf(stderr,"listunspent.(%s)\n",retstr); - free(retstr); - *utxovaluep = 100000; - } else fprintf(stderr,"null retstr\n"); + ret = listunspent(params,false); + fprintf(stderr,"listunspent.(%s)\n",ret.get_str().c_str()); return(72); } From 701aa497dfbaff142fef10f157decb4a2038edf4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 21:55:15 +0300 Subject: [PATCH 128/339] Test --- src/komodo_bitcoind.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 498c8511b..6a5b2ce8f 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -992,13 +992,14 @@ UniValue listunspent(const UniValue& params, bool fHelp); int32_t komodo_staked(uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) { - char *retstr; UniValue ret,params = NullUniValue; + UniValue result,params = NullUniValue; *utxovaluep = 0; memset(utxotxidp,0,sizeof(*utxotxidp)); memset(utxovoutp,0,sizeof(*utxovoutp)); memset(utxosig,0,72); - ret = listunspent(params,false); - fprintf(stderr,"listunspent.(%s)\n",ret.get_str().c_str()); + fprintf(stderr,"call listunspent\n"); + result = listunspent(params,false); + fprintf(stderr,"listunspent.(%s)\n",result.get_str().c_str()); return(72); } From 9de70efe3a05513b79f65e872e6d13467f7205f5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 22:05:45 +0300 Subject: [PATCH 129/339] Test --- src/komodo_bitcoind.h | 9 ++++++--- src/komodo_utils.h | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 6a5b2ce8f..7737b1973 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -992,14 +992,17 @@ UniValue listunspent(const UniValue& params, bool fHelp); int32_t komodo_staked(uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) { - UniValue result,params = NullUniValue; + UniValue params = NullUniValue; *utxovaluep = 0; memset(utxotxidp,0,sizeof(*utxotxidp)); memset(utxovoutp,0,sizeof(*utxovoutp)); memset(utxosig,0,72); fprintf(stderr,"call listunspent\n"); - result = listunspent(params,false); - fprintf(stderr,"listunspent.(%s)\n",result.get_str().c_str()); + vector vecOutputs; + assert(pwalletMain != NULL); + LOCK2(cs_main, pwalletMain->cs_wallet); + pwalletMain->AvailableCoins(vecOutputs, false, NULL, true); + fprintf(stderr,"listunspent done\n"); return(72); } diff --git a/src/komodo_utils.h b/src/komodo_utils.h index e8e801141..c38df1411 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1606,7 +1606,7 @@ void komodo_args(char *argv0) komodo_configfile(ASSETCHAINS_SYMBOL,ASSETCHAINS_PORT + 1); komodo_userpass(ASSETCHAINS_USERPASS,ASSETCHAINS_SYMBOL); COINBASE_MATURITY = 1; - fprintf(stderr,"ASSETCHAINS_PORT %s %u (%s)\n",ASSETCHAINS_SYMBOL,ASSETCHAINS_PORT,ASSETCHAINS_USERPASS); + //fprintf(stderr,"ASSETCHAINS_PORT %s %u (%s)\n",ASSETCHAINS_SYMBOL,ASSETCHAINS_PORT,ASSETCHAINS_USERPASS); } //ASSETCHAINS_NOTARIES = GetArg("-ac_notaries",""); //komodo_assetchain_pubkeys((char *)ASSETCHAINS_NOTARIES.c_str()); From ee06bbb7b3db2436e9493119de34f7a232243adb Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 22:13:40 +0300 Subject: [PATCH 130/339] Test --- src/komodo_bitcoind.h | 55 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 7737b1973..326870f66 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -992,7 +992,7 @@ UniValue listunspent(const UniValue& params, bool fHelp); int32_t komodo_staked(uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) { - UniValue params = NullUniValue; + int32_t nMinDepth = 1,nMaxDepth = 9999999; *utxovaluep = 0; memset(utxotxidp,0,sizeof(*utxotxidp)); memset(utxovoutp,0,sizeof(*utxovoutp)); @@ -1002,6 +1002,59 @@ int32_t komodo_staked(uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep assert(pwalletMain != NULL); LOCK2(cs_main, pwalletMain->cs_wallet); pwalletMain->AvailableCoins(vecOutputs, false, NULL, true); + BOOST_FOREACH(const COutput& out, vecOutputs) + { + if ( out.nDepth < nMinDepth || out.nDepth > nMaxDepth ) + continue; + if ( setAddress.size() ) + { + CTxDestination address; + if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) + continue; + if (!setAddress.count(address)) + continue; + } + CAmount nValue = out.tx->vout[out.i].nValue; + const CScript& pk = out.tx->vout[out.i].scriptPubKey; + UniValue entry(UniValue::VOBJ); + entry.push_back(Pair("txid", out.tx->GetHash().GetHex())); + entry.push_back(Pair("vout", out.i)); + entry.push_back(Pair("generated", out.tx->IsCoinBase())); + CTxDestination address; + if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) { + entry.push_back(Pair("address", CBitcoinAddress(address).ToString())); + if (pwalletMain->mapAddressBook.count(address)) + entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name)); + } + entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end()))); + if (pk.IsPayToScriptHash()) + { + CTxDestination address; + if (ExtractDestination(pk, address)) { + const CScriptID& hash = boost::get(address); + CScript redeemScript; + if (pwalletMain->GetCScript(hash, redeemScript)) + entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end()))); + } + } + entry.push_back(Pair("amount",ValueFromAmount(nValue))); + if ( out.tx->nLockTime != 0 ) + { + BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); + CBlockIndex *tipindex,*pindex = it->second; + uint64_t interest; uint32_t locktime; int32_t txheight; + if ( pindex != 0 && (tipindex= chainActive.Tip()) != 0 ) + { + komodo_accrued_interest(&txheight,&locktime,out.tx->GetHash(),out.i,0,nValue,(int32_t)tipindex->nHeight); + interest = komodo_interest(txheight,nValue,out.tx->nLockTime,tipindex->nTime); + entry.push_back(Pair("interest",ValueFromAmount(interest))); + } + //fprintf(stderr,"nValue %.8f pindex.%p tipindex.%p locktime.%u txheight.%d pindexht.%d\n",(double)nValue/COIN,pindex,chainActive.Tip(),locktime,txheight,pindex->nHeight); + } + entry.push_back(Pair("confirmations",out.nDepth)); + entry.push_back(Pair("spendable", out.fSpendable)); + fprintf(stderr,"%s\n",results.get_str().c_str()); + } fprintf(stderr,"listunspent done\n"); return(72); } From f8d5490f7cd69dd394a6e5da52c35683840e8baf Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 22:14:34 +0300 Subject: [PATCH 131/339] Test --- src/komodo_bitcoind.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 326870f66..8c4b99a4b 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -1053,7 +1053,7 @@ int32_t komodo_staked(uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep } entry.push_back(Pair("confirmations",out.nDepth)); entry.push_back(Pair("spendable", out.fSpendable)); - fprintf(stderr,"%s\n",results.get_str().c_str()); + fprintf(stderr,"%s\n",entry.get_str().c_str()); } fprintf(stderr,"listunspent done\n"); return(72); From 700c389b13796f4ceb1b30640e25f04f74d27d2f Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 22:16:06 +0300 Subject: [PATCH 132/339] Test --- src/komodo_bitcoind.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 8c4b99a4b..a3a3788fa 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -988,11 +988,11 @@ int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_ return(0); } -UniValue listunspent(const UniValue& params, bool fHelp); +UniValue ValueFromAmount(const CAmount& amount); int32_t komodo_staked(uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) { - int32_t nMinDepth = 1,nMaxDepth = 9999999; + set setAddress; int32_t nMinDepth = 1,nMaxDepth = 9999999; *utxovaluep = 0; memset(utxotxidp,0,sizeof(*utxotxidp)); memset(utxovoutp,0,sizeof(*utxovoutp)); From a16386bc8ccb74ee280bac256fea762117883108 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 22:23:00 +0300 Subject: [PATCH 133/339] Test --- src/komodo_bitcoind.h | 62 ++-------------------------------------- src/wallet/rpcwallet.cpp | 62 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 59 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index a3a3788fa..4c75249b6 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -988,7 +988,7 @@ int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_ return(0); } -UniValue ValueFromAmount(const CAmount& amount); +void komodo_listunspent(); int32_t komodo_staked(uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) { @@ -997,64 +997,8 @@ int32_t komodo_staked(uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep memset(utxotxidp,0,sizeof(*utxotxidp)); memset(utxovoutp,0,sizeof(*utxovoutp)); memset(utxosig,0,72); - fprintf(stderr,"call listunspent\n"); - vector vecOutputs; - assert(pwalletMain != NULL); - LOCK2(cs_main, pwalletMain->cs_wallet); - pwalletMain->AvailableCoins(vecOutputs, false, NULL, true); - BOOST_FOREACH(const COutput& out, vecOutputs) - { - if ( out.nDepth < nMinDepth || out.nDepth > nMaxDepth ) - continue; - if ( setAddress.size() ) - { - CTxDestination address; - if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) - continue; - if (!setAddress.count(address)) - continue; - } - CAmount nValue = out.tx->vout[out.i].nValue; - const CScript& pk = out.tx->vout[out.i].scriptPubKey; - UniValue entry(UniValue::VOBJ); - entry.push_back(Pair("txid", out.tx->GetHash().GetHex())); - entry.push_back(Pair("vout", out.i)); - entry.push_back(Pair("generated", out.tx->IsCoinBase())); - CTxDestination address; - if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) { - entry.push_back(Pair("address", CBitcoinAddress(address).ToString())); - if (pwalletMain->mapAddressBook.count(address)) - entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name)); - } - entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end()))); - if (pk.IsPayToScriptHash()) - { - CTxDestination address; - if (ExtractDestination(pk, address)) { - const CScriptID& hash = boost::get(address); - CScript redeemScript; - if (pwalletMain->GetCScript(hash, redeemScript)) - entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end()))); - } - } - entry.push_back(Pair("amount",ValueFromAmount(nValue))); - if ( out.tx->nLockTime != 0 ) - { - BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); - CBlockIndex *tipindex,*pindex = it->second; - uint64_t interest; uint32_t locktime; int32_t txheight; - if ( pindex != 0 && (tipindex= chainActive.Tip()) != 0 ) - { - komodo_accrued_interest(&txheight,&locktime,out.tx->GetHash(),out.i,0,nValue,(int32_t)tipindex->nHeight); - interest = komodo_interest(txheight,nValue,out.tx->nLockTime,tipindex->nTime); - entry.push_back(Pair("interest",ValueFromAmount(interest))); - } - //fprintf(stderr,"nValue %.8f pindex.%p tipindex.%p locktime.%u txheight.%d pindexht.%d\n",(double)nValue/COIN,pindex,chainActive.Tip(),locktime,txheight,pindex->nHeight); - } - entry.push_back(Pair("confirmations",out.nDepth)); - entry.push_back(Pair("spendable", out.fSpendable)); - fprintf(stderr,"%s\n",entry.get_str().c_str()); - } + fprintf(stderr,"start listunspent\n"); + komodo_listunspent(); fprintf(stderr,"listunspent done\n"); return(72); } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 27e94134d..438b1f0be 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2691,6 +2691,68 @@ UniValue listunspent(const UniValue& params, bool fHelp) return results; } +void komodo_listunspent() +{ + fprintf(stderr,"call listunspent\n"); + vector vecOutputs; + assert(pwalletMain != NULL); + LOCK2(cs_main, pwalletMain->cs_wallet); + pwalletMain->AvailableCoins(vecOutputs, false, NULL, true); + BOOST_FOREACH(const COutput& out, vecOutputs) + { + if ( out.nDepth < nMinDepth || out.nDepth > nMaxDepth ) + continue; + if ( setAddress.size() ) + { + CTxDestination address; + if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) + continue; + if (!setAddress.count(address)) + continue; + } + CAmount nValue = out.tx->vout[out.i].nValue; + const CScript& pk = out.tx->vout[out.i].scriptPubKey; + UniValue entry(UniValue::VOBJ); + entry.push_back(Pair("txid", out.tx->GetHash().GetHex())); + entry.push_back(Pair("vout", out.i)); + entry.push_back(Pair("generated", out.tx->IsCoinBase())); + CTxDestination address; + if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) { + entry.push_back(Pair("address", CBitcoinAddress(address).ToString())); + if (pwalletMain->mapAddressBook.count(address)) + entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name)); + } + entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end()))); + if (pk.IsPayToScriptHash()) + { + CTxDestination address; + if (ExtractDestination(pk, address)) { + const CScriptID& hash = boost::get(address); + CScript redeemScript; + if (pwalletMain->GetCScript(hash, redeemScript)) + entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end()))); + } + } + entry.push_back(Pair("amount",ValueFromAmount(nValue))); + if ( out.tx->nLockTime != 0 ) + { + BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); + CBlockIndex *tipindex,*pindex = it->second; + uint64_t interest; uint32_t locktime; int32_t txheight; + if ( pindex != 0 && (tipindex= chainActive.Tip()) != 0 ) + { + komodo_accrued_interest(&txheight,&locktime,out.tx->GetHash(),out.i,0,nValue,(int32_t)tipindex->nHeight); + interest = komodo_interest(txheight,nValue,out.tx->nLockTime,tipindex->nTime); + entry.push_back(Pair("interest",ValueFromAmount(interest))); + } + fprintf(stderr,"nValue %.8f pindex.%p tipindex.%p locktime.%u txheight.%d pindexht.%d\n",(double)nValue/COIN,pindex,chainActive.Tip(),locktime,txheight,pindex->nHeight); + } + entry.push_back(Pair("confirmations",out.nDepth)); + entry.push_back(Pair("spendable", out.fSpendable)); + fprintf(stderr,"%s\n",entry.get_str().c_str()); + } +} + uint64_t komodo_interestsum() { uint64_t interest,sum = 0; From 073421433b0bd31817f11de3ed0806ac826af96b Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 22:25:09 +0300 Subject: [PATCH 134/339] Test --- src/komodo_bitcoind.h | 1 - src/wallet/rpcwallet.cpp | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 4c75249b6..53ec13b00 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -992,7 +992,6 @@ void komodo_listunspent(); int32_t komodo_staked(uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) { - set setAddress; int32_t nMinDepth = 1,nMaxDepth = 9999999; *utxovaluep = 0; memset(utxotxidp,0,sizeof(*utxotxidp)); memset(utxovoutp,0,sizeof(*utxovoutp)); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 438b1f0be..461b81c89 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2693,8 +2693,7 @@ UniValue listunspent(const UniValue& params, bool fHelp) void komodo_listunspent() { - fprintf(stderr,"call listunspent\n"); - vector vecOutputs; + set setAddress; int32_t nMinDepth = 1,nMaxDepth = 9999999; vector vecOutputs; assert(pwalletMain != NULL); LOCK2(cs_main, pwalletMain->cs_wallet); pwalletMain->AvailableCoins(vecOutputs, false, NULL, true); From 50a7fa9e125d5a3080cf3901567415c9796d08da Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 22:32:56 +0300 Subject: [PATCH 135/339] Test --- src/wallet/rpcwallet.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 461b81c89..d999e0d80 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2711,7 +2711,7 @@ void komodo_listunspent() } CAmount nValue = out.tx->vout[out.i].nValue; const CScript& pk = out.tx->vout[out.i].scriptPubKey; - UniValue entry(UniValue::VOBJ); + /*UniValue entry(UniValue::VOBJ); entry.push_back(Pair("txid", out.tx->GetHash().GetHex())); entry.push_back(Pair("vout", out.i)); entry.push_back(Pair("generated", out.tx->IsCoinBase())); @@ -2732,7 +2732,7 @@ void komodo_listunspent() entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end()))); } } - entry.push_back(Pair("amount",ValueFromAmount(nValue))); + entry.push_back(Pair("amount",ValueFromAmount(nValue)));*/ if ( out.tx->nLockTime != 0 ) { BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); @@ -2742,13 +2742,11 @@ void komodo_listunspent() { komodo_accrued_interest(&txheight,&locktime,out.tx->GetHash(),out.i,0,nValue,(int32_t)tipindex->nHeight); interest = komodo_interest(txheight,nValue,out.tx->nLockTime,tipindex->nTime); - entry.push_back(Pair("interest",ValueFromAmount(interest))); + //entry.push_back(Pair("interest",ValueFromAmount(interest))); } - fprintf(stderr,"nValue %.8f pindex.%p tipindex.%p locktime.%u txheight.%d pindexht.%d\n",(double)nValue/COIN,pindex,chainActive.Tip(),locktime,txheight,pindex->nHeight); + fprintf(stderr,"(%s) %s/v%d nValue %.8f locktime.%u txheight.%d pindexht.%d\n",CBitcoinAddress(address).ToString().c_str(),out.tx->GetHash().GetHex().c_str(),out.i,(double)nValue/COIN,locktime,txheight,pindex->nHeight); } - entry.push_back(Pair("confirmations",out.nDepth)); - entry.push_back(Pair("spendable", out.fSpendable)); - fprintf(stderr,"%s\n",entry.get_str().c_str()); + fprintf(stderr,"entry done\n"); } } From 74f0baa46875ff256fd743bca29a1c540a2446a6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 22:34:16 +0300 Subject: [PATCH 136/339] Test --- src/wallet/rpcwallet.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index d999e0d80..bf785e38c 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2693,7 +2693,7 @@ UniValue listunspent(const UniValue& params, bool fHelp) void komodo_listunspent() { - set setAddress; int32_t nMinDepth = 1,nMaxDepth = 9999999; vector vecOutputs; + set setAddress; int32_t nMinDepth = 1,nMaxDepth = 9999999; vector vecOutputs; CTxDestination address; assert(pwalletMain != NULL); LOCK2(cs_main, pwalletMain->cs_wallet); pwalletMain->AvailableCoins(vecOutputs, false, NULL, true); @@ -2703,7 +2703,6 @@ void komodo_listunspent() continue; if ( setAddress.size() ) { - CTxDestination address; if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) continue; if (!setAddress.count(address)) From c6e53b1ad31d475d06c94fb69af1b9f35019d15d Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 22:39:43 +0300 Subject: [PATCH 137/339] Test --- src/komodo_bitcoind.h | 2 -- src/wallet/rpcwallet.cpp | 20 +++++++++----------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 53ec13b00..6933be624 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -996,9 +996,7 @@ int32_t komodo_staked(uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep memset(utxotxidp,0,sizeof(*utxotxidp)); memset(utxovoutp,0,sizeof(*utxovoutp)); memset(utxosig,0,72); - fprintf(stderr,"start listunspent\n"); komodo_listunspent(); - fprintf(stderr,"listunspent done\n"); return(72); } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index bf785e38c..fee31efcd 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2693,7 +2693,7 @@ UniValue listunspent(const UniValue& params, bool fHelp) void komodo_listunspent() { - set setAddress; int32_t nMinDepth = 1,nMaxDepth = 9999999; vector vecOutputs; CTxDestination address; + set setAddress; int32_t nMinDepth = 1,nMaxDepth = 9999999; vector vecOutputs; assert(pwalletMain != NULL); LOCK2(cs_main, pwalletMain->cs_wallet); pwalletMain->AvailableCoins(vecOutputs, false, NULL, true); @@ -2703,6 +2703,7 @@ void komodo_listunspent() continue; if ( setAddress.size() ) { + CTxDestination address; if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) continue; if (!setAddress.count(address)) @@ -2710,17 +2711,15 @@ void komodo_listunspent() } CAmount nValue = out.tx->vout[out.i].nValue; const CScript& pk = out.tx->vout[out.i].scriptPubKey; - /*UniValue entry(UniValue::VOBJ); - entry.push_back(Pair("txid", out.tx->GetHash().GetHex())); - entry.push_back(Pair("vout", out.i)); - entry.push_back(Pair("generated", out.tx->IsCoinBase())); + //entry.push_back(Pair("generated", out.tx->IsCoinBase())); CTxDestination address; - if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) { - entry.push_back(Pair("address", CBitcoinAddress(address).ToString())); - if (pwalletMain->mapAddressBook.count(address)) - entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name)); + if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) + { + //entry.push_back(Pair("address", CBitcoinAddress(address).ToString())); + //if (pwalletMain->mapAddressBook.count(address)) + // entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name)); } - entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end()))); + /*entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end()))); if (pk.IsPayToScriptHash()) { CTxDestination address; @@ -2745,7 +2744,6 @@ void komodo_listunspent() } fprintf(stderr,"(%s) %s/v%d nValue %.8f locktime.%u txheight.%d pindexht.%d\n",CBitcoinAddress(address).ToString().c_str(),out.tx->GetHash().GetHex().c_str(),out.i,(double)nValue/COIN,locktime,txheight,pindex->nHeight); } - fprintf(stderr,"entry done\n"); } } From eb6c7bb831b7784cacafdf5b6a3fbdae5ae53d4b Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 22:46:38 +0300 Subject: [PATCH 138/339] Test --- src/komodo_bitcoind.h | 12 ------------ src/miner.cpp | 6 +++--- src/wallet/rpcwallet.cpp | 10 +++++++++- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 6933be624..46913d43e 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -988,15 +988,3 @@ int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_ return(0); } -void komodo_listunspent(); - -int32_t komodo_staked(uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) -{ - *utxovaluep = 0; - memset(utxotxidp,0,sizeof(*utxotxidp)); - memset(utxovoutp,0,sizeof(*utxovoutp)); - memset(utxosig,0,72); - komodo_listunspent(); - return(72); -} - diff --git a/src/miner.cpp b/src/miner.cpp index e14338641..2e6305f26 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -120,7 +120,7 @@ int32_t komodo_gateway_deposits(CMutableTransaction *txNew,char *symbol,int32_t int32_t komodo_isrealtime(int32_t *kmdheightp); int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_t nTime,int32_t dispflag); uint64_t komodo_commission(const CBlock &block); -int32_t komodo_staked(uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig); +int32_t komodo_staked(uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig); CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) { @@ -387,8 +387,8 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) LogPrintf("CreateNewBlock(): total size %u\n", nBlockSize); if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_STAKED != 0 && NOTARY_PUBKEY33[0] != 0 ) { - uint64_t txfees,utxovalue; uint256 utxotxid; int32_t i,siglen,numsigs,utxovout; uint8_t utxosig[128],*ptr; - if ( (siglen= komodo_staked(&utxotxid,&utxovout,&utxovalue,utxosig)) > 0 ) + uint64_t txfees,utxovalue; uint32_t txtime; uint256 utxotxid; int32_t i,siglen,numsigs,utxovout; uint8_t utxosig[128],*ptr; + if ( (siglen= komodo_staked(&txtime,&utxotxid,&utxovout,&utxovalue,utxosig)) > 0 ) { CMutableTransaction txStaked = CreateNewContextualCMutableTransaction(chainparams.GetConsensus(), nHeight); CAmount txfees = 10000; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index fee31efcd..c7cf5d52b 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2691,11 +2691,15 @@ UniValue listunspent(const UniValue& params, bool fHelp) return results; } -void komodo_listunspent() +int32_t komodo_staked(uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) { set setAddress; int32_t nMinDepth = 1,nMaxDepth = 9999999; vector vecOutputs; assert(pwalletMain != NULL); LOCK2(cs_main, pwalletMain->cs_wallet); + *utxovaluep = 0; + memset(utxotxidp,0,sizeof(*utxotxidp)); + memset(utxovoutp,0,sizeof(*utxovoutp)); + memset(utxosig,0,72); pwalletMain->AvailableCoins(vecOutputs, false, NULL, true); BOOST_FOREACH(const COutput& out, vecOutputs) { @@ -2712,6 +2716,10 @@ void komodo_listunspent() CAmount nValue = out.tx->vout[out.i].nValue; const CScript& pk = out.tx->vout[out.i].scriptPubKey; //entry.push_back(Pair("generated", out.tx->IsCoinBase())); + *utxovaluep = (uint64_t)nValue; + decode_hex(utxotxidp,32,out.tx->GetHash().GetHex().c_str()); + *utxovoutp = out.i; + *txtimep = (uint32_t)out.tx->nLockTime; CTxDestination address; if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) { From 478b0dadb10ccd4e1196f50e661d5b9dad67b0c6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 22:50:39 +0300 Subject: [PATCH 139/339] Test --- src/miner.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/miner.cpp b/src/miner.cpp index 2e6305f26..a87a82914 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -402,6 +402,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) ptr[i] = utxosig[i]; txStaked.vout[0].scriptPubKey = CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG; txStaked.vout[0].nValue = utxovalue - txfees; + fprintf(stderr,"utxovout.%d txtime.%u %.8f\n",utxovout,txtime,(double)utxovalue/COIN); txStaked.nLockTime = chainActive.Tip()->nTime + chainparams.GetConsensus().nPowTargetSpacing; pblock->vtx.push_back(txStaked); From 30092d77e2697c4d50db3b5e0e295105f81bd957 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 22:52:09 +0300 Subject: [PATCH 140/339] Test --- src/wallet/rpcwallet.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index c7cf5d52b..bf148e9d2 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2691,6 +2691,8 @@ UniValue listunspent(const UniValue& params, bool fHelp) return results; } +int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex); + int32_t komodo_staked(uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) { set setAddress; int32_t nMinDepth = 1,nMaxDepth = 9999999; vector vecOutputs; From 5611b8ff59c92d4d7bc4bf95ad20cb1569c1d927 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 22:53:26 +0300 Subject: [PATCH 141/339] Test --- src/wallet/rpcwallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index bf148e9d2..62b028042 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2719,7 +2719,7 @@ int32_t komodo_staked(uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,ui const CScript& pk = out.tx->vout[out.i].scriptPubKey; //entry.push_back(Pair("generated", out.tx->IsCoinBase())); *utxovaluep = (uint64_t)nValue; - decode_hex(utxotxidp,32,out.tx->GetHash().GetHex().c_str()); + decode_hex((uint8_t *)utxotxidp,32,out.tx->GetHash().GetHex().c_str()); *utxovoutp = out.i; *txtimep = (uint32_t)out.tx->nLockTime; CTxDestination address; From 565aa1b298324271b1f972a802928d891d6d7593 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 22:54:14 +0300 Subject: [PATCH 142/339] Test --- src/wallet/rpcwallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 62b028042..8067b429c 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2719,7 +2719,7 @@ int32_t komodo_staked(uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,ui const CScript& pk = out.tx->vout[out.i].scriptPubKey; //entry.push_back(Pair("generated", out.tx->IsCoinBase())); *utxovaluep = (uint64_t)nValue; - decode_hex((uint8_t *)utxotxidp,32,out.tx->GetHash().GetHex().c_str()); + decode_hex((uint8_t *)utxotxidp,32,(char *)out.tx->GetHash().GetHex().c_str()); *utxovoutp = out.i; *txtimep = (uint32_t)out.tx->nLockTime; CTxDestination address; From be7928150b3325870a4d202cb6c457e3034ff3b3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 22:58:10 +0300 Subject: [PATCH 143/339] Test --- src/komodo_gateway.h | 2 +- src/wallet/rpcwallet.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 3f22e20e5..29d8bd984 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -750,7 +750,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim } txtime = komodo_txtime(&value,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n); minutes = (block.nTime - txtime) / 60; - fprintf(stderr,"ht.%d txn_count.%d txtime.%u blocktime.%u prev.%u gap.%d minutes.%d %.8f\n",komodo_block2height((CBlock *)&block),txn_count,txtime,block.nTime,prevtime,(int32_t)(block.nTime-prevtime),minutes,dstr(value)); + fprintf(stderr,"txn_count.%d txtime.%u blocktime.%u prev.%u gap.%d minutes.%d %.8f\n",txn_count,txtime,block.nTime,prevtime,(int32_t)(block.nTime-prevtime),minutes,dstr(value)); } if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && block.vtx[0].vout.size() > 1 ) { diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 8067b429c..09b403f7f 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2755,6 +2755,7 @@ int32_t komodo_staked(uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,ui fprintf(stderr,"(%s) %s/v%d nValue %.8f locktime.%u txheight.%d pindexht.%d\n",CBitcoinAddress(address).ToString().c_str(),out.tx->GetHash().GetHex().c_str(),out.i,(double)nValue/COIN,locktime,txheight,pindex->nHeight); } } + return(72); } uint64_t komodo_interestsum() From 69530bb2c7cb40a7dcfd6eba8b0139321a38ba4e Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 7 Apr 2018 23:02:42 +0300 Subject: [PATCH 144/339] Test --- src/miner.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index a87a82914..6f59771bf 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -387,14 +387,16 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) LogPrintf("CreateNewBlock(): total size %u\n", nBlockSize); if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_STAKED != 0 && NOTARY_PUBKEY33[0] != 0 ) { - uint64_t txfees,utxovalue; uint32_t txtime; uint256 utxotxid; int32_t i,siglen,numsigs,utxovout; uint8_t utxosig[128],*ptr; + uint64_t txfees,utxovalue; uint32_t txtime; uint256 utxotxid,revtxid; int32_t i,siglen,numsigs,utxovout; uint8_t utxosig[128],*ptr; if ( (siglen= komodo_staked(&txtime,&utxotxid,&utxovout,&utxovalue,utxosig)) > 0 ) { CMutableTransaction txStaked = CreateNewContextualCMutableTransaction(chainparams.GetConsensus(), nHeight); CAmount txfees = 10000; txStaked.vin.resize(1); txStaked.vout.resize(1); - txStaked.vin[0].prevout.hash = utxotxid; + for (i=0; i<32; i++) + ((uint8_t *)&revtxid)[i] = ((uint8_t *)&utxotxid)[31 - i]; + txStaked.vin[0].prevout.hash = revtxid; txStaked.vin[0].prevout.n = utxovout; txStaked.vin[0].scriptSig.resize(siglen); ptr = (uint8_t *)txStaked.vin[0].scriptSig.data(); From 39c9911e9c2257a2afe748fd5225787df1a4c364 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Sat, 7 Apr 2018 18:07:52 -0300 Subject: [PATCH 145/339] change Eval data structure to single code blob --- src/cc/betprotocol.cpp | 11 ++- src/cc/betprotocol.h | 28 ++---- src/cc/disputepayout.cpp | 19 ++-- src/cc/eval.cpp | 68 ++++++++------ src/cc/eval.h | 41 ++++++-- src/cc/importpayout.cpp | 19 ++-- src/cryptoconditions/.gitignore | 1 + src/cryptoconditions/Makefile.am | 8 +- .../include/cryptoconditions.h | 34 +++---- src/cryptoconditions/src/anon.c | 2 +- .../src/asn/AuxFingerprintContents.c | 94 ------------------- .../src/asn/AuxFingerprintContents.h | 38 -------- src/cryptoconditions/src/asn/AuxFulfillment.c | 78 --------------- src/cryptoconditions/src/asn/AuxFulfillment.h | 39 -------- .../src/asn/AuxSha512Fulfillment.c | 78 --------------- .../src/asn/AuxSha512Fulfillment.h | 39 -------- .../src/asn/CryptoConditions.asn | 9 +- .../src/asn/EvalFingerprintContents.c | 94 ------------------- .../src/asn/EvalFingerprintContents.h | 38 -------- .../src/asn/EvalFulfillment.c | 46 +-------- .../src/asn/EvalFulfillment.h | 3 +- .../src/asn/Makefile.am.sample | 6 +- src/cryptoconditions/src/asn/asn_system.h | 10 -- src/cryptoconditions/src/cryptoconditions.c | 12 +-- src/cryptoconditions/src/ed25519.c | 5 +- src/cryptoconditions/src/eval.c | 63 +++++-------- src/cryptoconditions/src/internal.h | 17 ++-- src/cryptoconditions/src/prefix.c | 2 +- src/cryptoconditions/src/preimage.c | 4 +- src/cryptoconditions/src/secp256k1.c | 4 +- src/cryptoconditions/src/threshold.c | 2 +- .../1000_test-minimal-eval.json | 1 - src/komodo_cc.cpp | 9 +- src/komodo_cc.h | 2 +- src/test-komodo/test_cryptoconditions.cpp | 33 ++++--- src/test-komodo/test_eval_bet.cpp | 48 ++++++---- src/test-komodo/test_eval_notarisation.cpp | 2 +- 37 files changed, 239 insertions(+), 768 deletions(-) delete mode 100644 src/cryptoconditions/src/asn/AuxFingerprintContents.c delete mode 100644 src/cryptoconditions/src/asn/AuxFingerprintContents.h delete mode 100644 src/cryptoconditions/src/asn/AuxFulfillment.c delete mode 100644 src/cryptoconditions/src/asn/AuxFulfillment.h delete mode 100644 src/cryptoconditions/src/asn/AuxSha512Fulfillment.c delete mode 100644 src/cryptoconditions/src/asn/AuxSha512Fulfillment.h delete mode 100644 src/cryptoconditions/src/asn/EvalFingerprintContents.c delete mode 100644 src/cryptoconditions/src/asn/EvalFingerprintContents.h diff --git a/src/cc/betprotocol.cpp b/src/cc/betprotocol.cpp index b4e5a4e56..1b42321d7 100644 --- a/src/cc/betprotocol.cpp +++ b/src/cc/betprotocol.cpp @@ -18,7 +18,9 @@ std::vector BetProtocol::PlayerConditions() CC* BetProtocol::MakeDisputeCond() { - CC *disputePoker = CCNewEval(disputeFunc, CheckSerialize(disputeHeader)); + CC *disputePoker = CCNewEval(E_MARSHAL( + ss << disputeCode << VARINT(waitBlocks) << vmParams; + )); CC *anySig = CCNewThreshold(1, PlayerConditions()); @@ -79,8 +81,9 @@ CC* BetProtocol::MakePayoutCond(uint256 signedSessionTxHash) CC *import; { - std::vector vHash(signedSessionTxHash.begin(), signedSessionTxHash.end()); - CC *importEval = CCNewEval("ImportPayout", vHash); + CC *importEval = CCNewEval(E_MARSHAL( + ss << EVAL_IMPORTPAYOUT << signedSessionTxHash; + )); CC *oneof = CCNewThreshold(1, PlayerConditions()); @@ -120,7 +123,7 @@ CMutableTransaction BetProtocol::MakeImportPayoutTx(std::vector payouts, mtx.vin.push_back(CTxIn(signedStakeTxHash, 0, CScript())); mtx.vout = payouts; CScript proofData; - proofData << OP_RETURN << CheckSerialize(std::make_pair(momProof, signedDisputeTx)); + proofData << OP_RETURN << E_MARSHAL(ss << momProof << signedDisputeTx); mtx.vout.insert(mtx.vout.begin(), CTxOut(0, proofData)); return mtx; } diff --git a/src/cc/betprotocol.h b/src/cc/betprotocol.h index ae4346c09..b08783b85 100644 --- a/src/cc/betprotocol.h +++ b/src/cc/betprotocol.h @@ -1,6 +1,7 @@ #ifndef BETPROTOCOL_H #define BETPROTOCOL_H +#include "cc/eval.h" #include "pubkey.h" #include "primitives/block.h" #include "primitives/transaction.h" @@ -29,36 +30,19 @@ public: }; -class DisputeHeader -{ -public: - int waitBlocks; - std::vector vmParams; - - DisputeHeader() {} - DisputeHeader(int w, std::vector vmp) : waitBlocks(w), vmParams(vmp) {} - - ADD_SERIALIZE_METHODS; - - template - inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { - READWRITE(VARINT(waitBlocks)); - READWRITE(vmParams); - } -}; - - class BetProtocol { protected: - char* disputeFunc = (char*) "DisputeBet"; std::vector playerConditions(); public: + EvalCode disputeCode; std::vector players; - DisputeHeader disputeHeader; + std::vector vmParams; + uint32_t waitBlocks; // Utility - BetProtocol(std::vector ps, DisputeHeader dh) : players(ps), disputeHeader(dh) {} + BetProtocol(EvalCode dc, std::vector ps, uint32_t wb, std::vector vmp) + : disputeCode(dc), waitBlocks(wb), vmParams(vmp), players(ps) {} std::vector PlayerConditions(); // on PANGEA diff --git a/src/cc/disputepayout.cpp b/src/cc/disputepayout.cpp index e36f4781d..22ce333d4 100644 --- a/src/cc/disputepayout.cpp +++ b/src/cc/disputepayout.cpp @@ -13,7 +13,7 @@ * Crypto-Condition EVAL method that resolves a dispute of a session * * IN: vm - AppVM virtual machine to verify states - * IN: cond - CC EVAL node + * IN: params - condition params * IN: disputeTx - transaction attempting to resolve dispute * IN: nIn - index of input of dispute tx * @@ -22,7 +22,7 @@ * in 0: Spends Session TX first output, reveals DisputeHeader * out 0: OP_RETURN hash of payouts */ -bool Eval::DisputePayout(AppVM &vm, const CC *cond, const CTransaction &disputeTx, unsigned int nIn) +bool Eval::DisputePayout(AppVM &vm, std::vector params, const CTransaction &disputeTx, unsigned int nIn) { if (disputeTx.vout.size() == 0) return Invalid("no-vouts"); @@ -31,12 +31,11 @@ bool Eval::DisputePayout(AppVM &vm, const CC *cond, const CTransaction &disputeT if (!GetOpReturnHash(disputeTx.vout[0].scriptPubKey, payoutHash)) return Invalid("invalid-payout-hash"); - // load dispute header - DisputeHeader disputeHeader; - std::vector headerData( - cond->paramsBin, cond->paramsBin+cond->paramsBinLength); - if (!CheckDeserialize(headerData, disputeHeader)) - return Invalid("invalid-dispute-header"); + // load params + uint16_t waitBlocks; + std::vector vmParams; + if (!E_UNMARSHAL(params, ss >> VARINT(waitBlocks); ss >> vmParams)) + return Invalid("malformed-params"); // ensure that enough time has passed { @@ -47,7 +46,7 @@ bool Eval::DisputePayout(AppVM &vm, const CC *cond, const CTransaction &disputeT if (!GetTxConfirmed(disputeTx.vin[0].prevout.hash, sessionTx, sessionBlock)) return Error("couldnt-get-parent"); - if (GetCurrentHeight() < sessionBlock.nHeight + disputeHeader.waitBlocks) + if (GetCurrentHeight() < sessionBlock.nHeight + waitBlocks) return Invalid("dispute-too-soon"); // Not yet } @@ -64,7 +63,7 @@ bool Eval::DisputePayout(AppVM &vm, const CC *cond, const CTransaction &disputeT std::vector vmState; if (!spends[i].vout.size() > 0) continue; if (!GetOpReturnData(spends[i].vout[0].scriptPubKey, vmState)) continue; - auto out = vm.evaluate(disputeHeader.vmParams, vmState); + auto out = vm.evaluate(vmParams, vmState); uint256 resultHash = SerializeHash(out.second); if (out.first > maxLength) { maxLength = out.first; diff --git a/src/cc/eval.cpp b/src/cc/eval.cpp index 503507160..495ec8c79 100644 --- a/src/cc/eval.cpp +++ b/src/cc/eval.cpp @@ -24,8 +24,11 @@ bool RunCCEval(const CC *cond, const CTransaction &tx, unsigned int nIn) if (eval->state.IsValid()) return true; std::string lvl = eval->state.IsInvalid() ? "Invalid" : "Error!"; - fprintf(stderr, "CC Eval %s %s: %s spending tx %s\n", lvl.data(), cond->method, - eval->state.GetRejectReason().data(), tx.vin[nIn].prevout.hash.GetHex().data()); + fprintf(stderr, "CC Eval %s %s: %s spending tx %s\n", + EvalToStr(cond->code[0]).data(), + lvl.data(), + eval->state.GetRejectReason().data(), + tx.vin[nIn].prevout.hash.GetHex().data()); if (eval->state.IsError()) fprintf(stderr, "Culprit: %s\n", EncodeHexTx(tx).data()); return false; } @@ -36,24 +39,17 @@ bool RunCCEval(const CC *cond, const CTransaction &tx, unsigned int nIn) */ bool Eval::Dispatch(const CC *cond, const CTransaction &txTo, unsigned int nIn) { - if (strcmp(cond->method, "TestEval") == 0) { - bool valid = cond->paramsBinLength == 8 && memcmp(cond->paramsBin, "TestEval", 8) == 0; - return valid ? Valid() : Invalid("testing"); + if (cond->codeLength == 0) + return Invalid("empty-eval"); + + uint8_t ecode = cond->code[0]; + std::vector vparams(cond->code+1, cond->code+cond->codeLength); + + if (ecode == EVAL_IMPORTPAYOUT) { + return ImportPayout(vparams, txTo, nIn); } - if (strcmp(cond->method, "ImportPayout") == 0) { - return ImportPayout(cond, txTo, nIn); - } - - /* Example of how you might call DisputePayout - if (strcmp(ASSETCHAINS_SYMBOL, "PANGEA") == 0) { - if (strcmp(cond->method, "DisputePoker") == 0) { - return DisputePayout(PokerVM(), cond, txTo, nIn); - } - } - */ - - return Invalid("no-such-method"); + return Invalid("invalid-code"); } @@ -147,9 +143,26 @@ bool Eval::CheckNotaryInputs(const CTransaction &tx, uint32_t height, uint32_t t } -extern char ASSETCHAINS_SYMBOL[16]; +/* + * Get MoM from a notarisation tx hash + */ +bool Eval::GetNotarisationData(const uint256 notaryHash, NotarisationData &data) const +{ + CTransaction notarisationTx; + CBlockIndex block; + if (!GetTxConfirmed(notaryHash, notarisationTx, block)) return false; + if (!CheckNotaryInputs(notarisationTx, block.nHeight, block.nTime)) return false; + if (notarisationTx.vout.size() < 2) return false; + if (!data.Parse(notarisationTx.vout[1].scriptPubKey)) return false; + return true; +} +/* + * Notarisation data, ie, OP_RETURN payload in notarisation transactions + */ +extern char ASSETCHAINS_SYMBOL[16]; + bool NotarisationData::Parse(const CScript scriptPK) { *this = NotarisationData(); @@ -179,17 +192,14 @@ bool NotarisationData::Parse(const CScript scriptPK) } - /* - * Get MoM from a notarisation tx hash + * Misc */ -bool Eval::GetNotarisationData(const uint256 notaryHash, NotarisationData &data) const + +std::string EvalToStr(EvalCode c) { - CTransaction notarisationTx; - CBlockIndex block; - if (!GetTxConfirmed(notaryHash, notarisationTx, block)) return false; - if (!CheckNotaryInputs(notarisationTx, block.nHeight, block.nTime)) return false; - if (notarisationTx.vout.size() < 2) return false; - if (!data.Parse(notarisationTx.vout[1].scriptPubKey)) return false; - return true; + FOREACH_EVAL(EVAL_GENERATE_STRING); + char s[10]; + sprintf(s, "0x%x", c); + return std::string(s); } diff --git a/src/cc/eval.h b/src/cc/eval.h index b884da5d8..f998c9f3d 100644 --- a/src/cc/eval.h +++ b/src/cc/eval.h @@ -10,6 +10,22 @@ #include "primitives/transaction.h" +/* + * Eval codes + * + * Add to below macro to generate new code. + * + * If at some point a new interpretation model is introduced, + * there should be a code identifying it. For example, + * a possible code is EVAL_BITCOIN_SCRIPT, where the entire binary + * after the code is interpreted as a bitcoin script. + */ +#define FOREACH_EVAL(EVAL) \ + EVAL(EVAL_IMPORTPAYOUT, 0xe1) + +typedef uint8_t EvalCode; + + class AppVM; class NotarisationData; @@ -31,12 +47,12 @@ public: /* * Dispute a payout using a VM */ - bool DisputePayout(AppVM &vm, const CC *cond, const CTransaction &disputeTx, unsigned int nIn); + bool DisputePayout(AppVM &vm, std::vector params, const CTransaction &disputeTx, unsigned int nIn); /* * Test an ImportPayout CC Eval condition */ - bool ImportPayout(const CC *cond, const CTransaction &payoutTx, unsigned int nIn); + bool ImportPayout(std::vector params, const CTransaction &importTx, unsigned int nIn); /* * IO functions @@ -88,23 +104,36 @@ public: }; +/* + * Eval code utilities. + */ +#define EVAL_GENERATE_DEF(L,I) const uint8_t L = I; +#define EVAL_GENERATE_STRING(L,I) if (c == I) return #L; + +FOREACH_EVAL(EVAL_GENERATE_DEF); + +std::string EvalToStr(EvalCode c); + + /* * Serialisation boilerplate */ +#define E_MARSHAL(body) SerializeF([&] (CDataStream &ss) {body;}) template -std::vector CheckSerialize(const T in) +std::vector SerializeF(const T f) { CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - ss << in; + f(ss); return std::vector(ss.begin(), ss.end()); } +#define E_UNMARSHAL(params, body) DeserializeF(params, [&] (CDataStream &ss) {body;}) template -bool CheckDeserialize(const std::vector vIn, T &out) +bool DeserializeF(const std::vector vIn, T f) { CDataStream ss(vIn, SER_NETWORK, PROTOCOL_VERSION); try { - ss >> out; + f(ss); if (ss.eof()) return true; } catch(...) {} return false; diff --git a/src/cc/importpayout.cpp b/src/cc/importpayout.cpp index 858e71f31..1363eb924 100644 --- a/src/cc/importpayout.cpp +++ b/src/cc/importpayout.cpp @@ -12,7 +12,7 @@ * Crypto-Condition EVAL method that verifies a payout against a transaction * notarised on another chain. * - * IN: cond - CC EVAL node + * IN: params - condition params * IN: importTx - Payout transaction on value chain (KMD) * IN: nIn - index of input of stake * @@ -29,7 +29,7 @@ * out 0: OP_RETURN hash of payouts * out 1-: anything */ -bool Eval::ImportPayout(const CC *cond, const CTransaction &importTx, unsigned int nIn) +bool Eval::ImportPayout(const std::vector params, const CTransaction &importTx, unsigned int nIn) { if (importTx.vout.size() == 0) return Invalid("no-vouts"); @@ -37,10 +37,9 @@ bool Eval::ImportPayout(const CC *cond, const CTransaction &importTx, unsigned i MoMProof proof; CTransaction disputeTx; { - std::pair pair(proof, disputeTx); std::vector vopret; GetOpReturnData(importTx.vout[0].scriptPubKey, vopret); - if (!CheckDeserialize(vopret, pair)) + if (!E_UNMARSHAL(vopret, ss >> proof; ss >> disputeTx)) return Invalid("invalid-payload"); } @@ -56,16 +55,18 @@ bool Eval::ImportPayout(const CC *cond, const CTransaction &importTx, unsigned i // Check disputeTx spends sessionTx.0 // condition ImportPayout params is session ID from other chain { - if (cond->paramsBinLength != 32) return Invalid("malformed-params"); - COutPoint prevout = disputeTx.vin[0].prevout; - if (memcmp(prevout.hash.begin(), cond->paramsBin, 32) != 0 || - prevout.n != 0) return Invalid("wrong-session"); + uint256 sessionHash; + if (!E_UNMARSHAL(params, ss >> sessionHash)) + return Invalid("malformed-params"); + if (disputeTx.vin[0].prevout != COutPoint(sessionHash, 0)) + return Invalid("wrong-session"); } // Check disputeTx solves momproof from vout[0] { NotarisationData data; - if (!GetNotarisationData(proof.notarisationHash, data)) return Invalid("coudnt-load-mom"); + if (!GetNotarisationData(proof.notarisationHash, data)) + return Invalid("coudnt-load-mom"); if (data.MoM != proof.Exec(disputeTx.GetHash())) return Invalid("mom-check-fail"); diff --git a/src/cryptoconditions/.gitignore b/src/cryptoconditions/.gitignore index 1d84f2618..c70559748 100644 --- a/src/cryptoconditions/.gitignore +++ b/src/cryptoconditions/.gitignore @@ -22,3 +22,4 @@ converter-sample.c config.* .pytest_cache +src/asn/asn_system.h diff --git a/src/cryptoconditions/Makefile.am b/src/cryptoconditions/Makefile.am index 3b482b9c7..52f12eee0 100644 --- a/src/cryptoconditions/Makefile.am +++ b/src/cryptoconditions/Makefile.am @@ -48,7 +48,6 @@ libcryptoconditions_core_la_SOURCES = \ src/asn/ThresholdFingerprintContents.c \ src/asn/RsaFingerprintContents.c \ src/asn/Ed25519FingerprintContents.c \ - src/asn/EvalFingerprintContents.c \ src/asn/EvalFulfillment.c \ src/asn/Secp256k1FingerprintContents.c \ src/asn/Secp256k1Fulfillment.c \ @@ -83,3 +82,10 @@ test: test-debug-interactive: gdb -ex run --args python3 -m pytest -s -x -v + +asn: + cd src/asn; \ + mv asn_system.h asn_system.bak; \ + rm *.c *.h; \ + asn1c CryptoConditions.asn; \ + mv asn_system.bak asn_system.h diff --git a/src/cryptoconditions/include/cryptoconditions.h b/src/cryptoconditions/include/cryptoconditions.h index 1c70441b3..08f00a2ca 100644 --- a/src/cryptoconditions/include/cryptoconditions.h +++ b/src/cryptoconditions/include/cryptoconditions.h @@ -40,18 +40,18 @@ typedef struct CC { struct CCType *type; union { // public key types - struct { unsigned char *publicKey, *signature; }; + struct { uint8_t *publicKey, *signature; }; // preimage - struct { unsigned char *preimage; uint16_t preimageLength; }; + struct { uint8_t *preimage; size_t preimageLength; }; // threshold struct { long threshold; uint8_t size; struct CC **subconditions; }; // prefix - struct { unsigned char *prefix; uint16_t prefixLength; struct CC *subcondition; - uint16_t maxMessageLength; }; + struct { uint8_t *prefix; size_t prefixLength; struct CC *subcondition; + size_t maxMessageLength; }; // eval - struct { char method[64]; unsigned char *paramsBin; uint16_t paramsBinLength; }; + struct { uint8_t *code; size_t codeLength; }; // anon - struct { unsigned char fingerprint[32]; uint32_t subtypes; unsigned long cost; + struct { uint8_t fingerprint[32]; uint32_t subtypes; unsigned long cost; struct CCType *conditionType; }; }; } CC; @@ -63,7 +63,7 @@ typedef struct CC { */ typedef struct CCVisitor { int (*visit)(CC *cond, struct CCVisitor visitor); - const unsigned char *msg; + const uint8_t *msg; size_t msgLength; void *context; } CCVisitor; @@ -73,20 +73,20 @@ typedef struct CCVisitor { * Public methods */ int cc_isFulfilled(const CC *cond); -int cc_verify(const struct CC *cond, const unsigned char *msg, size_t msgLength, - int doHashMessage, const unsigned char *condBin, size_t condBinLength, +int cc_verify(const struct CC *cond, const uint8_t *msg, size_t msgLength, + int doHashMessage, const uint8_t *condBin, size_t condBinLength, VerifyEval verifyEval, void *evalContext); int cc_visit(CC *cond, struct CCVisitor visitor); -int cc_signTreeEd25519(CC *cond, const unsigned char *privateKey, - const unsigned char *msg, uint16_t msgLength); -int cc_signTreeSecp256k1Msg32(CC *cond, const unsigned char *privateKey, const unsigned char *msg32); -size_t cc_conditionBinary(const CC *cond, unsigned char *buf); -size_t cc_fulfillmentBinary(const CC *cond, unsigned char *buf, size_t bufLength); -static int cc_secp256k1VerifyTreeMsg32(const CC *cond, const unsigned char *msg32); +int cc_signTreeEd25519(CC *cond, const uint8_t *privateKey, const uint8_t *msg, + const size_t msgLength); +int cc_signTreeSecp256k1Msg32(CC *cond, const uint8_t *privateKey, const uint8_t *msg32); +int cc_secp256k1VerifyTreeMsg32(const CC *cond, const uint8_t *msg32); +size_t cc_conditionBinary(const CC *cond, uint8_t *buf); +size_t cc_fulfillmentBinary(const CC *cond, uint8_t *buf, size_t bufLength); struct CC* cc_conditionFromJSON(cJSON *params, char *err); struct CC* cc_conditionFromJSONString(const char *json, char *err); -struct CC* cc_readConditionBinary(const unsigned char *cond_bin, size_t cond_bin_len); -struct CC* cc_readFulfillmentBinary(const unsigned char *ffill_bin, size_t ffill_bin_len); +struct CC* cc_readConditionBinary(const uint8_t *cond_bin, size_t cond_bin_len); +struct CC* cc_readFulfillmentBinary(const uint8_t *ffill_bin, size_t ffill_bin_len); struct CC* cc_new(int typeId); struct cJSON* cc_conditionToJSON(const CC *cond); char* cc_conditionToJSONString(const CC *cond); diff --git a/src/cryptoconditions/src/anon.c b/src/cryptoconditions/src/anon.c index 38f8e8543..80161a36a 100644 --- a/src/cryptoconditions/src/anon.c +++ b/src/cryptoconditions/src/anon.c @@ -10,7 +10,7 @@ struct CCType CC_AnonType; -static CC *mkAnon(const Condition_t *asnCond) { +CC *mkAnon(const Condition_t *asnCond) { CCType *realType = getTypeByAsnEnum(asnCond->present); if (!realType) { diff --git a/src/cryptoconditions/src/asn/AuxFingerprintContents.c b/src/cryptoconditions/src/asn/AuxFingerprintContents.c deleted file mode 100644 index cc8aefa3f..000000000 --- a/src/cryptoconditions/src/asn/AuxFingerprintContents.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) - * From ASN.1 module "Crypto-Conditions" - * found in "CryptoConditions.asn" - */ - -#include "AuxFingerprintContents.h" - -static int -memb_method_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; - size_t size; - - if(!sptr) { - ASN__CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - size = st->size; - - if((size == 64)) { - /* Constraint check succeeded */ - return 0; - } else { - ASN__CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } -} - -static asn_TYPE_member_t asn_MBR_AuxFingerprintContents_1[] = { - { ATF_NOFLAGS, 0, offsetof(struct AuxFingerprintContents, method), - (ASN_TAG_CLASS_CONTEXT | (0 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_OCTET_STRING, - memb_method_constraint_1, - 0, /* PER is not compiled, use -gen-PER */ - 0, - "method" - }, - { ATF_NOFLAGS, 0, offsetof(struct AuxFingerprintContents, conditionAux), - (ASN_TAG_CLASS_CONTEXT | (1 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_OCTET_STRING, - 0, /* Defer constraints checking to the member type */ - 0, /* PER is not compiled, use -gen-PER */ - 0, - "conditionAux" - }, -}; -static const ber_tlv_tag_t asn_DEF_AuxFingerprintContents_tags_1[] = { - (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) -}; -static const asn_TYPE_tag2member_t asn_MAP_AuxFingerprintContents_tag2el_1[] = { - { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* method */ - { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* conditionAux */ -}; -static asn_SEQUENCE_specifics_t asn_SPC_AuxFingerprintContents_specs_1 = { - sizeof(struct AuxFingerprintContents), - offsetof(struct AuxFingerprintContents, _asn_ctx), - asn_MAP_AuxFingerprintContents_tag2el_1, - 2, /* Count of tags in the map */ - 0, 0, 0, /* Optional elements (not needed) */ - -1, /* Start extensions */ - -1 /* Stop extensions */ -}; -asn_TYPE_descriptor_t asn_DEF_AuxFingerprintContents = { - "AuxFingerprintContents", - "AuxFingerprintContents", - SEQUENCE_free, - SEQUENCE_print, - SEQUENCE_constraint, - SEQUENCE_decode_ber, - SEQUENCE_encode_der, - SEQUENCE_decode_xer, - SEQUENCE_encode_xer, - 0, 0, /* No PER support, use "-gen-PER" to enable */ - 0, /* Use generic outmost tag fetcher */ - asn_DEF_AuxFingerprintContents_tags_1, - sizeof(asn_DEF_AuxFingerprintContents_tags_1) - /sizeof(asn_DEF_AuxFingerprintContents_tags_1[0]), /* 1 */ - asn_DEF_AuxFingerprintContents_tags_1, /* Same as above */ - sizeof(asn_DEF_AuxFingerprintContents_tags_1) - /sizeof(asn_DEF_AuxFingerprintContents_tags_1[0]), /* 1 */ - 0, /* No PER visible constraints */ - asn_MBR_AuxFingerprintContents_1, - 2, /* Elements count */ - &asn_SPC_AuxFingerprintContents_specs_1 /* Additional specs */ -}; - diff --git a/src/cryptoconditions/src/asn/AuxFingerprintContents.h b/src/cryptoconditions/src/asn/AuxFingerprintContents.h deleted file mode 100644 index 9f14a1bac..000000000 --- a/src/cryptoconditions/src/asn/AuxFingerprintContents.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) - * From ASN.1 module "Crypto-Conditions" - * found in "CryptoConditions.asn" - */ - -#ifndef _AuxFingerprintContents_H_ -#define _AuxFingerprintContents_H_ - - -#include - -/* Including external dependencies */ -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* AuxFingerprintContents */ -typedef struct AuxFingerprintContents { - OCTET_STRING_t method; - OCTET_STRING_t conditionAux; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} AuxFingerprintContents_t; - -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_AuxFingerprintContents; - -#ifdef __cplusplus -} -#endif - -#endif /* _AuxFingerprintContents_H_ */ -#include diff --git a/src/cryptoconditions/src/asn/AuxFulfillment.c b/src/cryptoconditions/src/asn/AuxFulfillment.c deleted file mode 100644 index 84362f79d..000000000 --- a/src/cryptoconditions/src/asn/AuxFulfillment.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) - * From ASN.1 module "Crypto-Conditions" - * found in "CryptoConditions.asn" - */ - -#include "AuxFulfillment.h" - -static asn_TYPE_member_t asn_MBR_AuxFulfillment_1[] = { - { ATF_NOFLAGS, 0, offsetof(struct AuxFulfillment, method), - (ASN_TAG_CLASS_CONTEXT | (0 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_OCTET_STRING, - 0, /* Defer constraints checking to the member type */ - 0, /* PER is not compiled, use -gen-PER */ - 0, - "method" - }, - { ATF_NOFLAGS, 0, offsetof(struct AuxFulfillment, conditionAux), - (ASN_TAG_CLASS_CONTEXT | (1 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_OCTET_STRING, - 0, /* Defer constraints checking to the member type */ - 0, /* PER is not compiled, use -gen-PER */ - 0, - "conditionAux" - }, - { ATF_NOFLAGS, 0, offsetof(struct AuxFulfillment, fulfillmentAux), - (ASN_TAG_CLASS_CONTEXT | (2 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_OCTET_STRING, - 0, /* Defer constraints checking to the member type */ - 0, /* PER is not compiled, use -gen-PER */ - 0, - "fulfillmentAux" - }, -}; -static const ber_tlv_tag_t asn_DEF_AuxFulfillment_tags_1[] = { - (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) -}; -static const asn_TYPE_tag2member_t asn_MAP_AuxFulfillment_tag2el_1[] = { - { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* method */ - { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* conditionAux */ - { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* fulfillmentAux */ -}; -static asn_SEQUENCE_specifics_t asn_SPC_AuxFulfillment_specs_1 = { - sizeof(struct AuxFulfillment), - offsetof(struct AuxFulfillment, _asn_ctx), - asn_MAP_AuxFulfillment_tag2el_1, - 3, /* Count of tags in the map */ - 0, 0, 0, /* Optional elements (not needed) */ - -1, /* Start extensions */ - -1 /* Stop extensions */ -}; -asn_TYPE_descriptor_t asn_DEF_AuxFulfillment = { - "AuxFulfillment", - "AuxFulfillment", - SEQUENCE_free, - SEQUENCE_print, - SEQUENCE_constraint, - SEQUENCE_decode_ber, - SEQUENCE_encode_der, - SEQUENCE_decode_xer, - SEQUENCE_encode_xer, - 0, 0, /* No PER support, use "-gen-PER" to enable */ - 0, /* Use generic outmost tag fetcher */ - asn_DEF_AuxFulfillment_tags_1, - sizeof(asn_DEF_AuxFulfillment_tags_1) - /sizeof(asn_DEF_AuxFulfillment_tags_1[0]), /* 1 */ - asn_DEF_AuxFulfillment_tags_1, /* Same as above */ - sizeof(asn_DEF_AuxFulfillment_tags_1) - /sizeof(asn_DEF_AuxFulfillment_tags_1[0]), /* 1 */ - 0, /* No PER visible constraints */ - asn_MBR_AuxFulfillment_1, - 3, /* Elements count */ - &asn_SPC_AuxFulfillment_specs_1 /* Additional specs */ -}; - diff --git a/src/cryptoconditions/src/asn/AuxFulfillment.h b/src/cryptoconditions/src/asn/AuxFulfillment.h deleted file mode 100644 index 89b514b77..000000000 --- a/src/cryptoconditions/src/asn/AuxFulfillment.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) - * From ASN.1 module "Crypto-Conditions" - * found in "CryptoConditions.asn" - */ - -#ifndef _AuxFulfillment_H_ -#define _AuxFulfillment_H_ - - -#include - -/* Including external dependencies */ -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* AuxFulfillment */ -typedef struct AuxFulfillment { - OCTET_STRING_t method; - OCTET_STRING_t conditionAux; - OCTET_STRING_t fulfillmentAux; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} AuxFulfillment_t; - -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_AuxFulfillment; - -#ifdef __cplusplus -} -#endif - -#endif /* _AuxFulfillment_H_ */ -#include diff --git a/src/cryptoconditions/src/asn/AuxSha512Fulfillment.c b/src/cryptoconditions/src/asn/AuxSha512Fulfillment.c deleted file mode 100644 index 62ad8a76f..000000000 --- a/src/cryptoconditions/src/asn/AuxSha512Fulfillment.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) - * From ASN.1 module "Crypto-Conditions" - * found in "CryptoConditions.asn" - */ - -#include "AuxSha512Fulfillment.h" - -static asn_TYPE_member_t asn_MBR_AuxSha512Fulfillment_1[] = { - { ATF_NOFLAGS, 0, offsetof(struct AuxSha512Fulfillment, method), - (ASN_TAG_CLASS_CONTEXT | (0 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_OCTET_STRING, - 0, /* Defer constraints checking to the member type */ - 0, /* PER is not compiled, use -gen-PER */ - 0, - "method" - }, - { ATF_NOFLAGS, 0, offsetof(struct AuxSha512Fulfillment, conditionAux), - (ASN_TAG_CLASS_CONTEXT | (1 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_OCTET_STRING, - 0, /* Defer constraints checking to the member type */ - 0, /* PER is not compiled, use -gen-PER */ - 0, - "conditionAux" - }, - { ATF_NOFLAGS, 0, offsetof(struct AuxSha512Fulfillment, fulfillmentAux), - (ASN_TAG_CLASS_CONTEXT | (2 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_OCTET_STRING, - 0, /* Defer constraints checking to the member type */ - 0, /* PER is not compiled, use -gen-PER */ - 0, - "fulfillmentAux" - }, -}; -static const ber_tlv_tag_t asn_DEF_AuxSha512Fulfillment_tags_1[] = { - (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) -}; -static const asn_TYPE_tag2member_t asn_MAP_AuxSha512Fulfillment_tag2el_1[] = { - { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* method */ - { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 }, /* conditionAux */ - { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 2, 0, 0 } /* fulfillmentAux */ -}; -static asn_SEQUENCE_specifics_t asn_SPC_AuxSha512Fulfillment_specs_1 = { - sizeof(struct AuxSha512Fulfillment), - offsetof(struct AuxSha512Fulfillment, _asn_ctx), - asn_MAP_AuxSha512Fulfillment_tag2el_1, - 3, /* Count of tags in the map */ - 0, 0, 0, /* Optional elements (not needed) */ - -1, /* Start extensions */ - -1 /* Stop extensions */ -}; -asn_TYPE_descriptor_t asn_DEF_AuxSha512Fulfillment = { - "AuxSha512Fulfillment", - "AuxSha512Fulfillment", - SEQUENCE_free, - SEQUENCE_print, - SEQUENCE_constraint, - SEQUENCE_decode_ber, - SEQUENCE_encode_der, - SEQUENCE_decode_xer, - SEQUENCE_encode_xer, - 0, 0, /* No PER support, use "-gen-PER" to enable */ - 0, /* Use generic outmost tag fetcher */ - asn_DEF_AuxSha512Fulfillment_tags_1, - sizeof(asn_DEF_AuxSha512Fulfillment_tags_1) - /sizeof(asn_DEF_AuxSha512Fulfillment_tags_1[0]), /* 1 */ - asn_DEF_AuxSha512Fulfillment_tags_1, /* Same as above */ - sizeof(asn_DEF_AuxSha512Fulfillment_tags_1) - /sizeof(asn_DEF_AuxSha512Fulfillment_tags_1[0]), /* 1 */ - 0, /* No PER visible constraints */ - asn_MBR_AuxSha512Fulfillment_1, - 3, /* Elements count */ - &asn_SPC_AuxSha512Fulfillment_specs_1 /* Additional specs */ -}; - diff --git a/src/cryptoconditions/src/asn/AuxSha512Fulfillment.h b/src/cryptoconditions/src/asn/AuxSha512Fulfillment.h deleted file mode 100644 index 81a7fa140..000000000 --- a/src/cryptoconditions/src/asn/AuxSha512Fulfillment.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) - * From ASN.1 module "Crypto-Conditions" - * found in "CryptoConditions.asn" - */ - -#ifndef _AuxSha512Fulfillment_H_ -#define _AuxSha512Fulfillment_H_ - - -#include - -/* Including external dependencies */ -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* AuxSha512Fulfillment */ -typedef struct AuxSha512Fulfillment { - OCTET_STRING_t method; - OCTET_STRING_t conditionAux; - OCTET_STRING_t fulfillmentAux; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} AuxSha512Fulfillment_t; - -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_AuxSha512Fulfillment; - -#ifdef __cplusplus -} -#endif - -#endif /* _AuxSha512Fulfillment_H_ */ -#include diff --git a/src/cryptoconditions/src/asn/CryptoConditions.asn b/src/cryptoconditions/src/asn/CryptoConditions.asn index 8aa1e365b..42a3c88f1 100644 --- a/src/cryptoconditions/src/asn/CryptoConditions.asn +++ b/src/cryptoconditions/src/asn/CryptoConditions.asn @@ -78,14 +78,14 @@ Crypto-Conditions DEFINITIONS AUTOMATIC TAGS ::= BEGIN } EvalFulfillment ::= SEQUENCE { - method OCTET STRING (SIZE(64)), - paramsBin OCTET STRING + code OCTET STRING } -- Fingerprint Content -- The PREIMAGE-SHA-256 condition fingerprint content is not DER encoded -- The fingerprint content is the preimage + -- Same for Eval PrefixFingerprintContents ::= SEQUENCE { prefix OCTET STRING, @@ -110,9 +110,4 @@ Crypto-Conditions DEFINITIONS AUTOMATIC TAGS ::= BEGIN publicKey OCTET STRING (SIZE(33)) } - EvalFingerprintContents ::= SEQUENCE { - method OCTET STRING (SIZE(64)), - paramsBin OCTET STRING - } - END diff --git a/src/cryptoconditions/src/asn/EvalFingerprintContents.c b/src/cryptoconditions/src/asn/EvalFingerprintContents.c deleted file mode 100644 index d23e3c386..000000000 --- a/src/cryptoconditions/src/asn/EvalFingerprintContents.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) - * From ASN.1 module "Crypto-Conditions" - * found in "CryptoConditions.asn" - */ - -#include "EvalFingerprintContents.h" - -static int -memb_method_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; - size_t size; - - if(!sptr) { - ASN__CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - size = st->size; - - if((size == 64)) { - /* Constraint check succeeded */ - return 0; - } else { - ASN__CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } -} - -static asn_TYPE_member_t asn_MBR_EvalFingerprintContents_1[] = { - { ATF_NOFLAGS, 0, offsetof(struct EvalFingerprintContents, method), - (ASN_TAG_CLASS_CONTEXT | (0 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_OCTET_STRING, - memb_method_constraint_1, - 0, /* PER is not compiled, use -gen-PER */ - 0, - "method" - }, - { ATF_NOFLAGS, 0, offsetof(struct EvalFingerprintContents, paramsBin), - (ASN_TAG_CLASS_CONTEXT | (1 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_OCTET_STRING, - 0, /* Defer constraints checking to the member type */ - 0, /* PER is not compiled, use -gen-PER */ - 0, - "paramsBin" - }, -}; -static const ber_tlv_tag_t asn_DEF_EvalFingerprintContents_tags_1[] = { - (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) -}; -static const asn_TYPE_tag2member_t asn_MAP_EvalFingerprintContents_tag2el_1[] = { - { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* method */ - { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* paramsBin */ -}; -static asn_SEQUENCE_specifics_t asn_SPC_EvalFingerprintContents_specs_1 = { - sizeof(struct EvalFingerprintContents), - offsetof(struct EvalFingerprintContents, _asn_ctx), - asn_MAP_EvalFingerprintContents_tag2el_1, - 2, /* Count of tags in the map */ - 0, 0, 0, /* Optional elements (not needed) */ - -1, /* Start extensions */ - -1 /* Stop extensions */ -}; -asn_TYPE_descriptor_t asn_DEF_EvalFingerprintContents = { - "EvalFingerprintContents", - "EvalFingerprintContents", - SEQUENCE_free, - SEQUENCE_print, - SEQUENCE_constraint, - SEQUENCE_decode_ber, - SEQUENCE_encode_der, - SEQUENCE_decode_xer, - SEQUENCE_encode_xer, - 0, 0, /* No PER support, use "-gen-PER" to enable */ - 0, /* Use generic outmost tag fetcher */ - asn_DEF_EvalFingerprintContents_tags_1, - sizeof(asn_DEF_EvalFingerprintContents_tags_1) - /sizeof(asn_DEF_EvalFingerprintContents_tags_1[0]), /* 1 */ - asn_DEF_EvalFingerprintContents_tags_1, /* Same as above */ - sizeof(asn_DEF_EvalFingerprintContents_tags_1) - /sizeof(asn_DEF_EvalFingerprintContents_tags_1[0]), /* 1 */ - 0, /* No PER visible constraints */ - asn_MBR_EvalFingerprintContents_1, - 2, /* Elements count */ - &asn_SPC_EvalFingerprintContents_specs_1 /* Additional specs */ -}; - diff --git a/src/cryptoconditions/src/asn/EvalFingerprintContents.h b/src/cryptoconditions/src/asn/EvalFingerprintContents.h deleted file mode 100644 index 52fb9ba62..000000000 --- a/src/cryptoconditions/src/asn/EvalFingerprintContents.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Generated by asn1c-0.9.28 (http://lionet.info/asn1c) - * From ASN.1 module "Crypto-Conditions" - * found in "CryptoConditions.asn" - */ - -#ifndef _EvalFingerprintContents_H_ -#define _EvalFingerprintContents_H_ - - -#include - -/* Including external dependencies */ -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* EvalFingerprintContents */ -typedef struct EvalFingerprintContents { - OCTET_STRING_t method; - OCTET_STRING_t paramsBin; - - /* Context for parsing across buffer boundaries */ - asn_struct_ctx_t _asn_ctx; -} EvalFingerprintContents_t; - -/* Implementation */ -extern asn_TYPE_descriptor_t asn_DEF_EvalFingerprintContents; - -#ifdef __cplusplus -} -#endif - -#endif /* _EvalFingerprintContents_H_ */ -#include diff --git a/src/cryptoconditions/src/asn/EvalFulfillment.c b/src/cryptoconditions/src/asn/EvalFulfillment.c index e56b80317..f43b21e1f 100644 --- a/src/cryptoconditions/src/asn/EvalFulfillment.c +++ b/src/cryptoconditions/src/asn/EvalFulfillment.c @@ -6,64 +6,28 @@ #include "EvalFulfillment.h" -static int -memb_method_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr, - asn_app_constraint_failed_f *ctfailcb, void *app_key) { - const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; - size_t size; - - if(!sptr) { - ASN__CTFAIL(app_key, td, sptr, - "%s: value not given (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } - - size = st->size; - - if((size == 64)) { - /* Constraint check succeeded */ - return 0; - } else { - ASN__CTFAIL(app_key, td, sptr, - "%s: constraint failed (%s:%d)", - td->name, __FILE__, __LINE__); - return -1; - } -} - static asn_TYPE_member_t asn_MBR_EvalFulfillment_1[] = { - { ATF_NOFLAGS, 0, offsetof(struct EvalFulfillment, method), + { ATF_NOFLAGS, 0, offsetof(struct EvalFulfillment, code), (ASN_TAG_CLASS_CONTEXT | (0 << 2)), -1, /* IMPLICIT tag at current level */ &asn_DEF_OCTET_STRING, - memb_method_constraint_1, - 0, /* PER is not compiled, use -gen-PER */ - 0, - "method" - }, - { ATF_NOFLAGS, 0, offsetof(struct EvalFulfillment, paramsBin), - (ASN_TAG_CLASS_CONTEXT | (1 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_OCTET_STRING, 0, /* Defer constraints checking to the member type */ 0, /* PER is not compiled, use -gen-PER */ 0, - "paramsBin" + "code" }, }; static const ber_tlv_tag_t asn_DEF_EvalFulfillment_tags_1[] = { (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)) }; static const asn_TYPE_tag2member_t asn_MAP_EvalFulfillment_tag2el_1[] = { - { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* method */ - { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* paramsBin */ + { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 } /* code */ }; static asn_SEQUENCE_specifics_t asn_SPC_EvalFulfillment_specs_1 = { sizeof(struct EvalFulfillment), offsetof(struct EvalFulfillment, _asn_ctx), asn_MAP_EvalFulfillment_tag2el_1, - 2, /* Count of tags in the map */ + 1, /* Count of tags in the map */ 0, 0, 0, /* Optional elements (not needed) */ -1, /* Start extensions */ -1 /* Stop extensions */ @@ -88,7 +52,7 @@ asn_TYPE_descriptor_t asn_DEF_EvalFulfillment = { /sizeof(asn_DEF_EvalFulfillment_tags_1[0]), /* 1 */ 0, /* No PER visible constraints */ asn_MBR_EvalFulfillment_1, - 2, /* Elements count */ + 1, /* Elements count */ &asn_SPC_EvalFulfillment_specs_1 /* Additional specs */ }; diff --git a/src/cryptoconditions/src/asn/EvalFulfillment.h b/src/cryptoconditions/src/asn/EvalFulfillment.h index a513ed160..378baa367 100644 --- a/src/cryptoconditions/src/asn/EvalFulfillment.h +++ b/src/cryptoconditions/src/asn/EvalFulfillment.h @@ -20,8 +20,7 @@ extern "C" { /* EvalFulfillment */ typedef struct EvalFulfillment { - OCTET_STRING_t method; - OCTET_STRING_t paramsBin; + OCTET_STRING_t code; /* Context for parsing across buffer boundaries */ asn_struct_ctx_t _asn_ctx; diff --git a/src/cryptoconditions/src/asn/Makefile.am.sample b/src/cryptoconditions/src/asn/Makefile.am.sample index 0bf696a74..9ff904aca 100644 --- a/src/cryptoconditions/src/asn/Makefile.am.sample +++ b/src/cryptoconditions/src/asn/Makefile.am.sample @@ -15,8 +15,7 @@ ASN_MODULE_SOURCES= \ ThresholdFingerprintContents.c \ RsaFingerprintContents.c \ Ed25519FingerprintContents.c \ - Secp256k1FingerprintContents.c \ - EvalFingerprintContents.c + Secp256k1FingerprintContents.c ASN_MODULE_HEADERS= \ Condition.h \ @@ -35,8 +34,7 @@ ASN_MODULE_HEADERS= \ ThresholdFingerprintContents.h \ RsaFingerprintContents.h \ Ed25519FingerprintContents.h \ - Secp256k1FingerprintContents.h \ - EvalFingerprintContents.h + Secp256k1FingerprintContents.h ASN_MODULE_HEADERS+=INTEGER.h ASN_MODULE_HEADERS+=NativeEnumerated.h diff --git a/src/cryptoconditions/src/asn/asn_system.h b/src/cryptoconditions/src/asn/asn_system.h index 71596fc34..7e64ba109 100644 --- a/src/cryptoconditions/src/asn/asn_system.h +++ b/src/cryptoconditions/src/asn/asn_system.h @@ -125,14 +125,4 @@ typedef unsigned int uint32_t; #define offsetof(s, m) ((ptrdiff_t)&(((s *)0)->m) - (ptrdiff_t)((s *)0)) #endif /* offsetof */ - -//#ifndef MIN /* Suitable for comparing primitive types (integers) */ -//#if defined(__GNUC__) -//#define MIN(a,b) ({ __typeof a _a = a; __typeof b _b = b; \ -// ((_a)<(_b)?(_a):(_b)); }) -//#else /* !__GNUC__ */ -//#define MIN(a,b) ((a)<(b)?(a):(b)) /* Unsafe variant */ -//#endif /* __GNUC__ */ -//#endif /* MIN */ - #endif /* ASN_SYSTEM_H */ diff --git a/src/cryptoconditions/src/cryptoconditions.c b/src/cryptoconditions/src/cryptoconditions.c index 6a6513b59..2f136917e 100644 --- a/src/cryptoconditions/src/cryptoconditions.c +++ b/src/cryptoconditions/src/cryptoconditions.c @@ -69,7 +69,7 @@ char *cc_conditionUri(const CC *cond) { } -static ConditionTypes_t asnSubtypes(uint32_t mask) { +ConditionTypes_t asnSubtypes(uint32_t mask) { ConditionTypes_t types; uint8_t buf[4] = {0,0,0,0}; int maxId = 0; @@ -89,7 +89,7 @@ static ConditionTypes_t asnSubtypes(uint32_t mask) { } -static uint32_t fromAsnSubtypes(const ConditionTypes_t types) { +uint32_t fromAsnSubtypes(const ConditionTypes_t types) { uint32_t mask = 0; for (int i=0; i> 3] & (1 << (7 - i % 8))) { @@ -125,7 +125,7 @@ size_t cc_fulfillmentBinary(const CC *cond, unsigned char *buf, size_t length) { } -static void asnCondition(const CC *cond, Condition_t *asn) { +void asnCondition(const CC *cond, Condition_t *asn) { asn->present = cc_isAnon(cond) ? cond->conditionType->asnType : cond->type->asnType; // This may look a little weird - we dont have a reference here to the correct @@ -140,14 +140,14 @@ static void asnCondition(const CC *cond, Condition_t *asn) { } -static Condition_t *asnConditionNew(const CC *cond) { +Condition_t *asnConditionNew(const CC *cond) { Condition_t *asn = calloc(1, sizeof(Condition_t)); asnCondition(cond, asn); return asn; } -static Fulfillment_t *asnFulfillmentNew(const CC *cond) { +Fulfillment_t *asnFulfillmentNew(const CC *cond) { return cond->type->toFulfillment(cond); } @@ -167,7 +167,7 @@ CCType *getTypeByAsnEnum(Condition_PR present) { } -static CC *fulfillmentToCC(Fulfillment_t *ffill) { +CC *fulfillmentToCC(Fulfillment_t *ffill) { CCType *type = getTypeByAsnEnum(ffill->present); if (!type) { fprintf(stderr, "Unknown fulfillment type: %i\n", ffill->present); diff --git a/src/cryptoconditions/src/ed25519.c b/src/cryptoconditions/src/ed25519.c index 18cee0768..7ae99b226 100644 --- a/src/cryptoconditions/src/ed25519.c +++ b/src/cryptoconditions/src/ed25519.c @@ -58,7 +58,8 @@ static int ed25519Sign(CC *cond, CCVisitor visitor) { /* * Sign ed25519 conditions in a tree */ -int cc_signTreeEd25519(CC *cond, const unsigned char *privateKey, const unsigned char *msg, uint16_t msgLength) { +int cc_signTreeEd25519(CC *cond, const unsigned char *privateKey, const unsigned char *msg, + const size_t msgLength) { unsigned char pk[32], skpk[64]; ed25519_create_keypair(pk, skpk, privateKey); @@ -74,7 +75,7 @@ static unsigned long ed25519Cost(const CC *cond) { } -static CC *ed25519FromJSON(const cJSON *params, unsigned char *err) { +static CC *ed25519FromJSON(const cJSON *params, char *err) { size_t binsz; cJSON *pk_item = cJSON_GetObjectItem(params, "publicKey"); diff --git a/src/cryptoconditions/src/eval.c b/src/cryptoconditions/src/eval.c index 92a1c6e70..2c15b7c0e 100644 --- a/src/cryptoconditions/src/eval.c +++ b/src/cryptoconditions/src/eval.c @@ -1,7 +1,6 @@ #include "asn/Condition.h" #include "asn/Fulfillment.h" #include "asn/EvalFulfillment.h" -#include "asn/EvalFingerprintContents.h" #include "asn/OCTET_STRING.h" #include "cryptoconditions.h" #include "internal.h" @@ -12,10 +11,9 @@ struct CCType CC_EvalType; static unsigned char *evalFingerprint(const CC *cond) { - EvalFingerprintContents_t *fp = calloc(1, sizeof(EvalFingerprintContents_t)); - OCTET_STRING_fromBuf(&fp->method, cond->method, strlen(cond->method)); - OCTET_STRING_fromBuf(&fp->paramsBin, cond->paramsBin, cond->paramsBinLength); - return hashFingerprintContents(&asn_DEF_EvalFingerprintContents, fp); + unsigned char *hash = calloc(1, 32); + sha256(cond->code, cond->codeLength, hash); + return hash; } @@ -24,40 +22,26 @@ static unsigned long evalCost(const CC *cond) { } -static CC *evalFromJSON(const cJSON *params, unsigned char *err) { - size_t paramsBinLength; - unsigned char *paramsBin = 0; +static CC *evalFromJSON(const cJSON *params, char *err) { + size_t codeLength; + unsigned char *code = 0; - cJSON *method_item = cJSON_GetObjectItem(params, "method"); - if (!checkString(method_item, "method", err)) { - return NULL; - } - - if (strlen(method_item->valuestring) > 64) { - strcpy(err, "method must be less than or equal to 64 bytes"); - return NULL; - } - - if (!jsonGetBase64(params, "params", err, ¶msBin, ¶msBinLength)) { + if (!jsonGetBase64(params, "code", err, &code, &codeLength)) { return NULL; } CC *cond = cc_new(CC_Eval); - strcpy(cond->method, method_item->valuestring); - cond->paramsBin = paramsBin; - cond->paramsBinLength = paramsBinLength; + cond->code = code; + cond->codeLength = codeLength; return cond; } -static void evalToJSON(const CC *cond, cJSON *params) { +static void evalToJSON(const CC *cond, cJSON *code) { - // add method - cJSON_AddItemToObject(params, "method", cJSON_CreateString(cond->method)); - - // add params - unsigned char *b64 = base64_encode(cond->paramsBin, cond->paramsBinLength); - cJSON_AddItemToObject(params, "params", cJSON_CreateString(b64)); + // add code + unsigned char *b64 = base64_encode(cond->code, cond->codeLength); + cJSON_AddItemToObject(code, "code", cJSON_CreateString(b64)); free(b64); } @@ -67,13 +51,10 @@ static CC *evalFromFulfillment(const Fulfillment_t *ffill) { EvalFulfillment_t *eval = &ffill->choice.evalSha256; - memcpy(cond->method, eval->method.buf, eval->method.size); - cond->method[eval->method.size] = 0; - - OCTET_STRING_t octets = eval->paramsBin; - cond->paramsBinLength = octets.size; - cond->paramsBin = malloc(octets.size); - memcpy(cond->paramsBin, octets.buf, octets.size); + OCTET_STRING_t octets = eval->code; + cond->codeLength = octets.size; + cond->code = malloc(octets.size); + memcpy(cond->code, octets.buf, octets.size); return cond; } @@ -83,8 +64,7 @@ static Fulfillment_t *evalToFulfillment(const CC *cond) { Fulfillment_t *ffill = calloc(1, sizeof(Fulfillment_t)); ffill->present = Fulfillment_PR_evalSha256; EvalFulfillment_t *eval = &ffill->choice.evalSha256; - OCTET_STRING_fromBuf(&eval->method, cond->method, strlen(cond->method)); - OCTET_STRING_fromBuf(&eval->paramsBin, cond->paramsBin, cond->paramsBinLength); + OCTET_STRING_fromBuf(&eval->code, cond->code, cond->codeLength); return ffill; } @@ -95,7 +75,7 @@ int evalIsFulfilled(const CC *cond) { static void evalFree(CC *cond) { - free(cond->paramsBin); + free(cond->code); } @@ -108,9 +88,8 @@ static uint32_t evalSubtypes(const CC *cond) { * The JSON api doesn't contain custom verifiers, so a stub method is provided suitable for testing */ int jsonVerifyEval(CC *cond, void *context) { - if (strcmp(cond->method, "testEval") == 0) { - return memcmp(cond->paramsBin, "testEval", cond->paramsBinLength) == 0; - } + if (cond->codeLength == 9 && memcmp(cond->code, "TestEval", 8)) + return cond->code[8]; fprintf(stderr, "Cannot verify eval; user function unknown\n"); return 0; } diff --git a/src/cryptoconditions/src/internal.h b/src/cryptoconditions/src/internal.h index d8e09310a..90c997dfe 100644 --- a/src/cryptoconditions/src/internal.h +++ b/src/cryptoconditions/src/internal.h @@ -39,21 +39,20 @@ typedef struct CCType { /* * Globals */ -struct CCType *CCTypeRegistry[]; +struct CCType *CCTypeRegistry[32]; int CCTypeRegistryLength; /* * Internal API */ -static uint32_t fromAsnSubtypes(ConditionTypes_t types); -static CC *mkAnon(const Condition_t *asnCond); -static void asnCondition(const CC *cond, Condition_t *asn); -static Condition_t *asnConditionNew(const CC *cond); -static Fulfillment_t *asnFulfillmentNew(const CC *cond); -static cJSON *jsonEncodeCondition(cJSON *params, char *err); -static struct CC *fulfillmentToCC(Fulfillment_t *ffill); -static struct CCType *getTypeByAsnEnum(Condition_PR present); +uint32_t fromAsnSubtypes(ConditionTypes_t types); +CC *mkAnon(const Condition_t *asnCond); +void asnCondition(const CC *cond, Condition_t *asn); +Condition_t *asnConditionNew(const CC *cond); +Fulfillment_t *asnFulfillmentNew(const CC *cond); +struct CC *fulfillmentToCC(Fulfillment_t *ffill); +struct CCType *getTypeByAsnEnum(Condition_PR present); /* diff --git a/src/cryptoconditions/src/prefix.c b/src/cryptoconditions/src/prefix.c index 15a7fa2b7..66d432bd2 100644 --- a/src/cryptoconditions/src/prefix.c +++ b/src/cryptoconditions/src/prefix.c @@ -74,7 +74,7 @@ static uint32_t prefixSubtypes(const CC *cond) { } -static CC *prefixFromJSON(const cJSON *params, unsigned char *err) { +static CC *prefixFromJSON(const cJSON *params, char *err) { cJSON *mml_item = cJSON_GetObjectItem(params, "maxMessageLength"); if (!cJSON_IsNumber(mml_item)) { strcpy(err, "maxMessageLength must be a number"); diff --git a/src/cryptoconditions/src/preimage.c b/src/cryptoconditions/src/preimage.c index 39953e815..049e0eecc 100644 --- a/src/cryptoconditions/src/preimage.c +++ b/src/cryptoconditions/src/preimage.c @@ -10,13 +10,13 @@ struct CCType CC_PreimageType; -static CC *preimageFromJSON(const cJSON *params, unsigned char *err) { +static CC *preimageFromJSON(const cJSON *params, char *err) { cJSON *preimage_item = cJSON_GetObjectItem(params, "preimage"); if (!cJSON_IsString(preimage_item)) { strcpy(err, "preimage must be a string"); return NULL; } - unsigned char *preimage_b64 = preimage_item->valuestring; + char *preimage_b64 = preimage_item->valuestring; CC *cond = cc_new(CC_Preimage); cond->preimage = base64_decode(preimage_b64, &cond->preimageLength); diff --git a/src/cryptoconditions/src/secp256k1.c b/src/cryptoconditions/src/secp256k1.c index 78fbd7602..b62b2c178 100644 --- a/src/cryptoconditions/src/secp256k1.c +++ b/src/cryptoconditions/src/secp256k1.c @@ -97,7 +97,7 @@ int secp256k1Verify(CC *cond, CCVisitor visitor) { } -static int cc_secp256k1VerifyTreeMsg32(const CC *cond, const unsigned char *msg32) { +int cc_secp256k1VerifyTreeMsg32(const CC *cond, const unsigned char *msg32) { int subtypes = cc_typeMask(cond); if (subtypes & (1 << CC_PrefixType.typeId) && subtypes & (1 << CC_Secp256k1Type.typeId)) { @@ -209,7 +209,7 @@ static CC *cc_secp256k1Condition(const unsigned char *publicKey, const unsigned } -static CC *secp256k1FromJSON(const cJSON *params, unsigned char *err) { +static CC *secp256k1FromJSON(const cJSON *params, char *err) { CC *cond = 0; unsigned char *pk = 0, *sig = 0; size_t pkSize, sigSize; diff --git a/src/cryptoconditions/src/threshold.c b/src/cryptoconditions/src/threshold.c index f4684cd7b..9c1800302 100644 --- a/src/cryptoconditions/src/threshold.c +++ b/src/cryptoconditions/src/threshold.c @@ -165,7 +165,7 @@ static Fulfillment_t *thresholdToFulfillment(const CC *cond) { } -static CC *thresholdFromJSON(const cJSON *params, unsigned char *err) { +static CC *thresholdFromJSON(const cJSON *params, char *err) { cJSON *threshold_item = cJSON_GetObjectItem(params, "threshold"); if (!cJSON_IsNumber(threshold_item)) { strcpy(err, "threshold must be a number"); diff --git a/src/cryptoconditions/tests/custom-vectors/1000_test-minimal-eval.json b/src/cryptoconditions/tests/custom-vectors/1000_test-minimal-eval.json index 14ab8ca49..2b91d0b36 100644 --- a/src/cryptoconditions/tests/custom-vectors/1000_test-minimal-eval.json +++ b/src/cryptoconditions/tests/custom-vectors/1000_test-minimal-eval.json @@ -1,7 +1,6 @@ { "json": { "type": "eval-sha-256", - "method": "testEval", "params": "dGVzdEV2YWw" }, "cost": 131072, diff --git a/src/komodo_cc.cpp b/src/komodo_cc.cpp index 1ebcd7e89..cf18323cf 100644 --- a/src/komodo_cc.cpp +++ b/src/komodo_cc.cpp @@ -59,13 +59,12 @@ CC* CCNewSecp256k1(CPubKey k) } -CC* CCNewEval(std::string method, std::vector paramsBin) +CC* CCNewEval(std::vector code) { CC *cond = cc_new(CC_Eval); - strcpy(cond->method, method.data()); - cond->paramsBin = (unsigned char*) malloc(paramsBin.size()); - memcpy(cond->paramsBin, paramsBin.data(), paramsBin.size()); - cond->paramsBinLength = paramsBin.size(); + cond->code = (unsigned char*) malloc(code.size()); + memcpy(cond->code, code.data(), code.size()); + cond->codeLength = code.size(); return cond; } diff --git a/src/komodo_cc.h b/src/komodo_cc.h index af9efef1c..b85ddfc5e 100644 --- a/src/komodo_cc.h +++ b/src/komodo_cc.h @@ -37,7 +37,7 @@ bool IsSignedCryptoCondition(const CC *cond); * Construct crypto conditions */ CC* CCNewPreimage(std::vector preimage); -CC* CCNewEval(std::string method, std::vector paramsBin); +CC* CCNewEval(std::vector code); CC* CCNewSecp256k1(CPubKey k); CC* CCNewThreshold(int t, std::vector v); diff --git a/src/test-komodo/test_cryptoconditions.cpp b/src/test-komodo/test_cryptoconditions.cpp index 6f31914df..c9ffde955 100644 --- a/src/test-komodo/test_cryptoconditions.cpp +++ b/src/test-komodo/test_cryptoconditions.cpp @@ -4,6 +4,7 @@ #include "base58.h" #include "key.h" #include "komodo_cc.h" +#include "cc/eval.h" #include "primitives/transaction.h" #include "script/interpreter.h" #include "script/serverchecker.h" @@ -84,8 +85,8 @@ TEST_F(CCTest, testMayAcceptCryptoCondition) { "type": "threshold-sha-256", "threshold": 1, "subfulfillments": [ - { "type": "eval-sha-256", "method": "test", "params": "" }, - { "type": "eval-sha-256", "method": "test", "params": "" } + { "type": "eval-sha-256", "code": "" }, + { "type": "eval-sha-256", "code": "" } ] })!!"); ASSERT_FALSE(CCPubKey(cond).MayAcceptCryptoCondition()); @@ -140,9 +141,22 @@ TEST_F(CCTest, testVerifyCryptoCondition) ASSERT_FALSE(Verify(cond)); } +extern Eval* EVAL_TEST; TEST_F(CCTest, testVerifyEvalCondition) { + + class EvalMock : public Eval + { + public: + bool Dispatch(const CC *cond, const CTransaction &txTo, unsigned int nIn) + { return cond->code[0] ? Valid() : Invalid(""); } + }; + + EvalMock eval; + EVAL_TEST = &eval; + + CC *cond; ScriptError error; CMutableTransaction mtxTo; @@ -156,20 +170,11 @@ TEST_F(CCTest, testVerifyEvalCondition) }; // ok - CCFromJson(cond, R"!!({ - "type": "threshold-sha-256", - "threshold": 2, - "subfulfillments": [ - { "type": "secp256k1-sha-256", "publicKey": "AgWorQwdvFFfFJrzd5gaq1i4Nq8AjU16shvXb6+AVQtH" }, - { "type": "eval-sha-256", "method": "TestEval", "params": "" } - ]})!!"); - CC *ecCond = cond->subconditions[1]; - ecCond->paramsBin = (unsigned char*) "TestEval"; - ecCond->paramsBinLength = 8; - CCSign(mtxTo, cond); // will reorder subconditions + cond = CCNewThreshold(2, { CCNewSecp256k1(notaryKey.GetPubKey()), CCNewEval({1}) }); + CCSign(mtxTo, cond); ASSERT_TRUE(Verify(cond)); - ecCond->paramsBin = (unsigned char*) "FailEval"; + cond->subconditions[1]->code[0] = 0; ASSERT_FALSE(Verify(cond)); } diff --git a/src/test-komodo/test_eval_bet.cpp b/src/test-komodo/test_eval_bet.cpp index cff8a972c..2529b4e46 100644 --- a/src/test-komodo/test_eval_bet.cpp +++ b/src/test-komodo/test_eval_bet.cpp @@ -67,6 +67,7 @@ public: } }; +const EvalCode EVAL_DISPUTEBET = 0xf2; class EvalMock : public Eval { @@ -79,14 +80,17 @@ public: bool Dispatch(const CC *cond, const CTransaction &txTo, unsigned int nIn) { - if (strcmp(cond->method, "DisputeBet") == 0) { + EvalCode ecode = cond->code[0]; + std::vector vparams(cond->code+1, cond->code+cond->codeLength); + + if (ecode == EVAL_DISPUTEBET) { MockVM vm; - return DisputePayout(vm, cond, txTo, nIn); + return DisputePayout(vm, vparams, txTo, nIn); } - if (strcmp(cond->method, "ImportPayout") == 0) { - return ImportPayout(cond, txTo, nIn); + if (ecode == EVAL_IMPORTPAYOUT) { + return ImportPayout(vparams, txTo, nIn); } - return Invalid("invalid-method"); + return Invalid("invalid-code"); } bool GetSpendsConfirmed(uint256 hash, std::vector &spendsOut) const @@ -148,7 +152,7 @@ public: BetProtocol bet; CAmount totalPayout; - ExampleBet() : bet(BetProtocol(players, DisputeHeader(2, VCH("BetHeader", 9)))), totalPayout(100) {} + ExampleBet() : bet(BetProtocol(EVAL_DISPUTEBET, players, 2, VCH("BetHeader", 9))), totalPayout(100) {} ~ExampleBet() {}; CTransaction SessionTx() @@ -180,7 +184,7 @@ public: std::vector Payouts(int playerIdx) { - return MockVM().evaluate(bet.disputeHeader.vmParams, PlayerState(playerIdx)).second; + return MockVM().evaluate(bet.vmParams, PlayerState(playerIdx)).second; } CMutableTransaction DisputeTx(int playerIdx) @@ -280,7 +284,12 @@ TEST_F(TestBet, testMakeDisputeCond) { CC *disputeCond = ebet.DisputeCond(); EXPECT_EQ("(2 of 15,(1 of 5,5,5))", CCShowStructure(disputeCond)); - EXPECT_EQ(0, memcmp("\x2\tBetHeader", (char*) disputeCond->subconditions[0]->paramsBin, 11)); + + CC *evalCond = disputeCond->subconditions[0]; + uint8_t target[100]; + sprintf((char*)target, "%c\x02\tBetHeader", EVAL_DISPUTEBET); + EXPECT_EQ(0, memcmp(target, evalCond->code, 12)); + for (int i=0; isubconditions[1]->subconditions[i])); @@ -315,10 +324,9 @@ TEST_F(TestBet, testDispute) // Success EXPECT_TRUE(TestCC(disputeTx, 0, disputeCond)); - // Set result hash to some rubbish and check false - uint256 rubbishHash; - std::vector rubbish(rubbishHash.begin(), rubbishHash.end()); - disputeTx.vout[0].scriptPubKey = CScript() << OP_RETURN << rubbish; + // Set result hash to 0 and check false + uint256 nonsense; + disputeTx.vout[0].scriptPubKey = CScript() << OP_RETURN << E_MARSHAL(ss << nonsense); EXPECT_EQ(1, CCSign(disputeTx, 0, disputeCond, {Player2})); EXPECT_FALSE(TestCC(disputeTx, 0, disputeCond)); EXPECT_EQ("wrong-payout", eval.state.GetRejectReason()); @@ -371,21 +379,21 @@ TEST_F(TestBet, testDisputeInvalidParams) CC *evalCond = disputeCond->subconditions[0]; // too long - evalCond->paramsBin = (unsigned char*) realloc(evalCond->paramsBin, ++evalCond->paramsBinLength); + evalCond->code = (unsigned char*) realloc(evalCond->code, ++evalCond->codeLength); ASSERT_EQ(1, CCSign(disputeTx, 0, disputeCond, {Player2})); EXPECT_FALSE(TestCC(disputeTx, 0, disputeCond)); - EXPECT_EQ("invalid-dispute-header", eval.state.GetRejectReason()); + EXPECT_EQ("malformed-params", eval.state.GetRejectReason()); // too short eval.state = CValidationState(); - evalCond->paramsBinLength = 1; + evalCond->codeLength = 1; ASSERT_EQ(1, CCSign(disputeTx, 0, disputeCond, {Player2})); EXPECT_FALSE(TestCC(disputeTx, 0, disputeCond)); - EXPECT_EQ("invalid-dispute-header", eval.state.GetRejectReason()); + EXPECT_EQ("malformed-params", eval.state.GetRejectReason()); // is fine eval.state = CValidationState(); - evalCond->paramsBinLength = 11; + evalCond->codeLength = 12; ASSERT_EQ(1, CCSign(disputeTx, 0, disputeCond, {Player2})); EXPECT_TRUE(TestCC(disputeTx, 0, disputeCond)); } @@ -435,7 +443,7 @@ TEST_F(TestBet, testMakePayoutCond) { CC *payoutCond = ebet.PayoutCond(); EXPECT_EQ("(1 of (3 of 5,5,5),(2 of (1 of 5,5,5),15))", CCShowStructure(payoutCond)); - EXPECT_EQ(0, memcmp(payoutCond->subconditions[1]->subconditions[1]->paramsBin, + EXPECT_EQ(0, memcmp(payoutCond->subconditions[1]->subconditions[1]->code+1, ebet.SessionTx().GetHash().begin(), 32)); } @@ -543,13 +551,13 @@ TEST_F(TestBet, testImportPayoutMangleSessionId) CMutableTransaction importTx = ebet.ImportPayoutTx(); CC *payoutCond = ebet.PayoutCond(); - payoutCond->subconditions[1]->subconditions[1]->paramsBinLength = 31; + payoutCond->subconditions[1]->subconditions[1]->codeLength = 31; EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); ASSERT_FALSE(TestCC(importTx, 0, payoutCond)); EXPECT_EQ("malformed-params", eval.state.GetRejectReason()); payoutCond = ebet.PayoutCond(); - memset(payoutCond->subconditions[1]->subconditions[1]->paramsBin, 1, 32); + memset(payoutCond->subconditions[1]->subconditions[1]->code+1, 1, 32); EXPECT_EQ(2, CCSign(importTx, 0, payoutCond, {Player2})); ASSERT_FALSE(TestCC(importTx, 0, payoutCond)); EXPECT_EQ("wrong-session", eval.state.GetRejectReason()); diff --git a/src/test-komodo/test_eval_notarisation.cpp b/src/test-komodo/test_eval_notarisation.cpp index 7fc2f1b4d..e9cd7bea5 100644 --- a/src/test-komodo/test_eval_notarisation.cpp +++ b/src/test-komodo/test_eval_notarisation.cpp @@ -110,7 +110,7 @@ TEST(TestEvalNotarisation, testGetNotarisation) EXPECT_EQ(data.MoM.GetHex(), "88289b6566a48567f65c8e60ca65b7f3877bbdb97cfc3958da31bcf073a70b05"); MoMProof proof; - CheckDeserialize(vMomProof, proof); + E_UNMARSHAL(vMomProof, ss >> proof); EXPECT_EQ(data.MoM, proof.Exec(proofTxHash)); } From e36af93babe8fcaed62c6601fd1a74580ebe62d5 Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Sat, 7 Apr 2018 21:46:29 -0300 Subject: [PATCH 146/339] update cryptoconditions --- src/cryptoconditions/.gitmodules | 3 - src/cryptoconditions/src/anon.c | 2 +- src/cryptoconditions/src/eval.c | 5 +- src/cryptoconditions/src/internal.h | 8 ++ src/cryptoconditions/src/json_rpc.c | 37 ++++---- src/cryptoconditions/src/preimage.c | 14 +-- src/cryptoconditions/src/secp256k1.c | 8 +- src/cryptoconditions/src/utils.c | 88 ++++++++++++++++++- .../1000_test-minimal-eval.json | 13 --- src/cryptoconditions/tests/test_ed25519.py | 6 +- .../tests/test_failure_modes.py | 4 +- src/cryptoconditions/tests/test_secp256k1.py | 16 ++-- src/cryptoconditions/tests/test_vectors.py | 23 +++-- .../vectors/0000_test-minimal-preimage.json | 13 +++ .../vectors/0001_test-minimal-prefix.json | 20 +++++ .../vectors/0002_test-minimal-threshold.json | 21 +++++ .../tests/vectors/0003_test-minimal-rsa.json | 14 +++ .../vectors/0004_test-minimal-ed25519.json | 14 +++ .../vectors/0005_test-basic-preimage.json | 13 +++ .../tests/vectors/0006_test-basic-prefix.json | 21 +++++ ...007_test-basic-prefix-two-levels-deep.json | 26 ++++++ .../vectors/0008_test-basic-threshold.json | 39 ++++++++ ...-basic-threshold-same-condition-twice.json | 54 ++++++++++++ ...asic-threshold-same-fulfillment-twice.json | 48 ++++++++++ ..._test-basic-threshold-two-levels-deep.json | 50 +++++++++++ ...012_test-basic-threshold-schroedinger.json | 25 ++++++ .../tests/vectors/0013_test-basic-rsa.json | 14 +++ .../vectors/0014_test-basic-rsa4096.json | 14 +++ .../vectors/0015_test-basic-ed25519.json | 14 +++ .../0016_test-advanced-notarized-receipt.json | 33 +++++++ ...d-notarized-receipt-multiple-notaries.json | 74 ++++++++++++++++ .../tests/vectors/1000_test-minimal-eval.json | 13 +++ .../1001_test-minimal-secp256k1.json | 4 +- src/test-komodo/test_cryptoconditions.cpp | 11 +-- 34 files changed, 674 insertions(+), 88 deletions(-) delete mode 100644 src/cryptoconditions/.gitmodules delete mode 100644 src/cryptoconditions/tests/custom-vectors/1000_test-minimal-eval.json create mode 100644 src/cryptoconditions/tests/vectors/0000_test-minimal-preimage.json create mode 100644 src/cryptoconditions/tests/vectors/0001_test-minimal-prefix.json create mode 100644 src/cryptoconditions/tests/vectors/0002_test-minimal-threshold.json create mode 100644 src/cryptoconditions/tests/vectors/0003_test-minimal-rsa.json create mode 100644 src/cryptoconditions/tests/vectors/0004_test-minimal-ed25519.json create mode 100644 src/cryptoconditions/tests/vectors/0005_test-basic-preimage.json create mode 100644 src/cryptoconditions/tests/vectors/0006_test-basic-prefix.json create mode 100644 src/cryptoconditions/tests/vectors/0007_test-basic-prefix-two-levels-deep.json create mode 100644 src/cryptoconditions/tests/vectors/0008_test-basic-threshold.json create mode 100644 src/cryptoconditions/tests/vectors/0009_test-basic-threshold-same-condition-twice.json create mode 100644 src/cryptoconditions/tests/vectors/0010_test-basic-threshold-same-fulfillment-twice.json create mode 100644 src/cryptoconditions/tests/vectors/0011_test-basic-threshold-two-levels-deep.json create mode 100644 src/cryptoconditions/tests/vectors/0012_test-basic-threshold-schroedinger.json create mode 100644 src/cryptoconditions/tests/vectors/0013_test-basic-rsa.json create mode 100644 src/cryptoconditions/tests/vectors/0014_test-basic-rsa4096.json create mode 100644 src/cryptoconditions/tests/vectors/0015_test-basic-ed25519.json create mode 100644 src/cryptoconditions/tests/vectors/0016_test-advanced-notarized-receipt.json create mode 100644 src/cryptoconditions/tests/vectors/0017_test-advanced-notarized-receipt-multiple-notaries.json create mode 100644 src/cryptoconditions/tests/vectors/1000_test-minimal-eval.json rename src/cryptoconditions/tests/{custom-vectors => vectors}/1001_test-minimal-secp256k1.json (71%) diff --git a/src/cryptoconditions/.gitmodules b/src/cryptoconditions/.gitmodules deleted file mode 100644 index 635f6c43d..000000000 --- a/src/cryptoconditions/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "ext/crypto-conditions"] - path = ext/crypto-conditions - url = http://github.com/libscott/crypto-conditions.git diff --git a/src/cryptoconditions/src/anon.c b/src/cryptoconditions/src/anon.c index 80161a36a..114517074 100644 --- a/src/cryptoconditions/src/anon.c +++ b/src/cryptoconditions/src/anon.c @@ -14,7 +14,7 @@ CC *mkAnon(const Condition_t *asnCond) { CCType *realType = getTypeByAsnEnum(asnCond->present); if (!realType) { - printf("Unknown ASN type: %i", asnCond->present); + fprintf(stderr, "Unknown ASN type: %i", asnCond->present); return 0; } CC *cond = cc_new(CC_Anon); diff --git a/src/cryptoconditions/src/eval.c b/src/cryptoconditions/src/eval.c index 2c15b7c0e..4a7d13276 100644 --- a/src/cryptoconditions/src/eval.c +++ b/src/cryptoconditions/src/eval.c @@ -88,8 +88,9 @@ static uint32_t evalSubtypes(const CC *cond) { * The JSON api doesn't contain custom verifiers, so a stub method is provided suitable for testing */ int jsonVerifyEval(CC *cond, void *context) { - if (cond->codeLength == 9 && memcmp(cond->code, "TestEval", 8)) - return cond->code[8]; + if (cond->codeLength == 5 && 0 == memcmp(cond->code, "TEST", 4)) { + return cond->code[5]; + } fprintf(stderr, "Cannot verify eval; user function unknown\n"); return 0; } diff --git a/src/cryptoconditions/src/internal.h b/src/cryptoconditions/src/internal.h index 90c997dfe..76955f406 100644 --- a/src/cryptoconditions/src/internal.h +++ b/src/cryptoconditions/src/internal.h @@ -15,6 +15,8 @@ extern "C" { #define BUF_SIZE 1024 * 1024 +typedef char bool; + /* * Condition Type @@ -67,6 +69,12 @@ int checkDecodeBase64(const cJSON *value, char *key, char *err, unsigned char ** int jsonGetBase64(const cJSON *params, char *key, char *err, unsigned char **data, size_t *size); int jsonGetBase64Optional(const cJSON *params, char *key, char *err, unsigned char **data, size_t *size); void jsonAddBase64(cJSON *params, char *key, unsigned char *bin, size_t size); +char* cc_hex_encode(const uint8_t *bin, size_t len); +uint8_t* cc_hex_decode(const char* hex); +bool checkDecodeHex(const cJSON *params, char *key, char *err, uint8_t **data, size_t *size); +bool jsonGetHex(const cJSON *params, char *key, char *err, unsigned char **data, size_t *size); +void jsonAddHex(cJSON *params, char *key, uint8_t *bin, size_t size); +int jsonGetHexOptional(const cJSON *params, char *key, char *err, unsigned char **data, size_t *size); #ifdef __cplusplus diff --git a/src/cryptoconditions/src/json_rpc.c b/src/cryptoconditions/src/json_rpc.c index 13972ca35..42c13612c 100644 --- a/src/cryptoconditions/src/json_rpc.c +++ b/src/cryptoconditions/src/json_rpc.c @@ -5,31 +5,26 @@ static cJSON *jsonCondition(CC *cond) { - unsigned char buf[1000]; - size_t conditionBinLength = cc_conditionBinary(cond, buf); - cJSON *root = cJSON_CreateObject(); - unsigned char *uri = cc_conditionUri(cond); + + char *uri = cc_conditionUri(cond); cJSON_AddItemToObject(root, "uri", cJSON_CreateString(uri)); free(uri); - unsigned char *b64 = base64_encode(buf, conditionBinLength); - cJSON_AddItemToObject(root, "bin", cJSON_CreateString(b64)); - free(b64); + unsigned char buf[1000]; + size_t conditionBinLength = cc_conditionBinary(cond, buf); + jsonAddHex(root, "bin", buf, conditionBinLength); return root; } static cJSON *jsonFulfillment(CC *cond) { - unsigned char buf[1000000]; + uint8_t buf[1000000]; size_t fulfillmentBinLength = cc_fulfillmentBinary(cond, buf, 1000000); cJSON *root = cJSON_CreateObject(); - unsigned char *b64 = base64_encode(buf, fulfillmentBinLength); - cJSON_AddItemToObject(root, "fulfillment", cJSON_CreateString(b64)); - free(b64); - + jsonAddHex(root, "fulfillment", buf, fulfillmentBinLength); return root; } @@ -98,9 +93,9 @@ static cJSON *jsonVerifyFulfillment(cJSON *params, char *err) { size_t ffill_bin_len, msg_len, cond_bin_len; cJSON *out = 0; - if (!(jsonGetBase64(params, "fulfillment", err, &ffill_bin, &ffill_bin_len) && - jsonGetBase64(params, "message", err, &msg, &msg_len) && - jsonGetBase64(params, "condition", err, &cond_bin, &cond_bin_len))) + if (!(jsonGetHex(params, "fulfillment", err, &ffill_bin, &ffill_bin_len) && + jsonGetHex(params, "message", err, &msg, &msg_len) && + jsonGetHex(params, "condition", err, &cond_bin, &cond_bin_len))) goto END; CC *cond = cc_readFulfillmentBinary(ffill_bin, ffill_bin_len); @@ -124,7 +119,7 @@ END: static cJSON *jsonDecodeFulfillment(cJSON *params, char *err) { size_t ffill_bin_len; unsigned char *ffill_bin; - if (!jsonGetBase64(params, "fulfillment", err, &ffill_bin, &ffill_bin_len)) + if (!jsonGetHex(params, "fulfillment", err, &ffill_bin, &ffill_bin_len)) return NULL; CC *cond = cc_readFulfillmentBinary(ffill_bin, ffill_bin_len); @@ -142,7 +137,7 @@ static cJSON *jsonDecodeFulfillment(cJSON *params, char *err) { static cJSON *jsonDecodeCondition(cJSON *params, char *err) { size_t cond_bin_len; unsigned char *cond_bin; - if (!jsonGetBase64(params, "bin", err, &cond_bin, &cond_bin_len)) + if (!jsonGetHex(params, "bin", err, &cond_bin, &cond_bin_len)) return NULL; CC *cond = cc_readConditionBinary(cond_bin, cond_bin_len); @@ -171,7 +166,7 @@ static cJSON *jsonSignTreeEd25519(cJSON *params, char *err) { } size_t skLength; - if (!jsonGetBase64(params, "privateKey", err, &sk, &skLength)) { + if (!jsonGetHex(params, "privateKey", err, &sk, &skLength)) { goto END; } @@ -180,7 +175,7 @@ static cJSON *jsonSignTreeEd25519(cJSON *params, char *err) { } size_t msgLength; - if (!jsonGetBase64(params, "message", err, &msg, &msgLength)) { + if (!jsonGetHex(params, "message", err, &msg, &msgLength)) { goto END; } @@ -208,7 +203,7 @@ static cJSON *jsonSignTreeSecp256k1(cJSON *params, char *err) { } size_t skLength; - if (!jsonGetBase64(params, "privateKey", err, &sk, &skLength)) { + if (!jsonGetHex(params, "privateKey", err, &sk, &skLength)) { goto END; } @@ -217,7 +212,7 @@ static cJSON *jsonSignTreeSecp256k1(cJSON *params, char *err) { } size_t msgLength; - if (!jsonGetBase64(params, "message", err, &msg, &msgLength)) { + if (!jsonGetHex(params, "message", err, &msg, &msgLength)) { goto END; } diff --git a/src/cryptoconditions/src/preimage.c b/src/cryptoconditions/src/preimage.c index 049e0eecc..2e3ec7c77 100644 --- a/src/cryptoconditions/src/preimage.c +++ b/src/cryptoconditions/src/preimage.c @@ -11,23 +11,17 @@ struct CCType CC_PreimageType; static CC *preimageFromJSON(const cJSON *params, char *err) { - cJSON *preimage_item = cJSON_GetObjectItem(params, "preimage"); - if (!cJSON_IsString(preimage_item)) { - strcpy(err, "preimage must be a string"); + CC *cond = cc_new(CC_Preimage); + if (!jsonGetBase64(params, "preimage", err, &cond->preimage, &cond->preimageLength)) { + free(cond); return NULL; } - char *preimage_b64 = preimage_item->valuestring; - - CC *cond = cc_new(CC_Preimage); - cond->preimage = base64_decode(preimage_b64, &cond->preimageLength); return cond; } static void preimageToJSON(const CC *cond, cJSON *params) { - unsigned char *encoded = base64_encode(cond->preimage, cond->preimageLength); - cJSON_AddStringToObject(params, "preimage", encoded); - free(encoded); + jsonAddBase64(params, "preimage", cond->preimage, cond->preimageLength); } diff --git a/src/cryptoconditions/src/secp256k1.c b/src/cryptoconditions/src/secp256k1.c index b62b2c178..73f7a9164 100644 --- a/src/cryptoconditions/src/secp256k1.c +++ b/src/cryptoconditions/src/secp256k1.c @@ -214,9 +214,9 @@ static CC *secp256k1FromJSON(const cJSON *params, char *err) { unsigned char *pk = 0, *sig = 0; size_t pkSize, sigSize; - if (!jsonGetBase64(params, "publicKey", err, &pk, &pkSize)) goto END; + if (!jsonGetHex(params, "publicKey", err, &pk, &pkSize)) goto END; - if (!jsonGetBase64Optional(params, "signature", err, &sig, &sigSize)) goto END; + if (!jsonGetHexOptional(params, "signature", err, &sig, &sigSize)) goto END; if (sig && SECP256K1_SIG_SIZE != sigSize) { strcpy(err, "signature has incorrect length"); goto END; @@ -234,9 +234,9 @@ END: static void secp256k1ToJSON(const CC *cond, cJSON *params) { - jsonAddBase64(params, "publicKey", cond->publicKey, SECP256K1_PK_SIZE); + jsonAddHex(params, "publicKey", cond->publicKey, SECP256K1_PK_SIZE); if (cond->signature) { - jsonAddBase64(params, "signature", cond->signature, SECP256K1_SIG_SIZE); + jsonAddHex(params, "signature", cond->signature, SECP256K1_SIG_SIZE); } } diff --git a/src/cryptoconditions/src/utils.c b/src/cryptoconditions/src/utils.c index c87e8ddda..b795932b3 100644 --- a/src/cryptoconditions/src/utils.c +++ b/src/cryptoconditions/src/utils.c @@ -154,10 +154,9 @@ int checkString(const cJSON *value, char *key, char *err) { } int checkDecodeBase64(const cJSON *value, char *key, char *err, unsigned char **data, size_t *size) { - if (!checkString(value, key, err)) { - sprintf(err, "%s must be valid base64 string", key); + if (!checkString(value, key, err)) return 0; - } + *data = base64_decode(value->valuestring, size); if (!*data) { @@ -200,10 +199,91 @@ unsigned char *hashFingerprintContents(asn_TYPE_descriptor_t *asnType, void *fp) asn_enc_rval_t rc = der_encode_to_buffer(asnType, fp, buf, BUF_SIZE); ASN_STRUCT_FREE(*asnType, fp); if (rc.encoded < 1) { - printf("Encoding fingerprint failed\n"); + fprintf(stderr, "Encoding fingerprint failed\n"); return 0; } unsigned char *hash = malloc(32); sha256(buf, rc.encoded, hash); return hash; } + + +char* cc_hex_encode(const uint8_t *bin, size_t len) +{ + char* hex = malloc(len*2+1); + if (bin == NULL) return hex; + char map[16] = "0123456789ABCDEF"; + for (int i=0; i> 4]; + hex[i*2+1] = map[bin[i] & 0x0F]; + } + hex[len*2] = '\0'; + return hex; +} + + +uint8_t* cc_hex_decode(const char* hex) +{ + size_t len = strlen(hex); + + if (len % 2 == 1) return NULL; + + uint8_t* bin = calloc(1, len/2); + + for (int i=0; i 15) goto ERR; + + bin[i/2] += c << (i%2 ? 0 : 4); + } + return bin; +ERR: + free(bin); + return NULL; +} + + +bool checkDecodeHex(const cJSON *value, char *key, char *err, unsigned char **data, size_t *size) { + if (!checkString(value, key, err)) + return 0; + + *data = cc_hex_decode(value->valuestring); + if (!*data) { + sprintf(err, "%s must be valid hex string", key); + return 0; + } + *size = strlen(value->valuestring) / 2; + return 1; +} + + +bool jsonGetHex(const cJSON *params, char *key, char *err, unsigned char **data, size_t *size) +{ + cJSON *item = cJSON_GetObjectItem(params, key); + if (!item) { + sprintf(err, "%s is required", key); + return 0; + } + return checkDecodeHex(item, key, err, data, size); +} + + +void jsonAddHex(cJSON *params, char *key, unsigned char *bin, size_t size) { + unsigned char *hex = cc_hex_encode(bin, size); + cJSON_AddItemToObject(params, key, cJSON_CreateString(hex)); + free(hex); +} + + +int jsonGetHexOptional(const cJSON *params, char *key, char *err, unsigned char **data, size_t *size) { + cJSON *item = cJSON_GetObjectItem(params, key); + if (!item) { + return 1; + } + return checkDecodeHex(item, key, err, data, size); +} + + diff --git a/src/cryptoconditions/tests/custom-vectors/1000_test-minimal-eval.json b/src/cryptoconditions/tests/custom-vectors/1000_test-minimal-eval.json deleted file mode 100644 index 2b91d0b36..000000000 --- a/src/cryptoconditions/tests/custom-vectors/1000_test-minimal-eval.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "json": { - "type": "eval-sha-256", - "params": "dGVzdEV2YWw" - }, - "cost": 131072, - "subtypes": [], - "fingerprintContents": "", - "fulfillment": "AF148008746573744576616C8108746573744576616C", - "conditionBinary": "AF27802062CC11575F91E1611379B5A0B53678805FC03858544FC28E72BB66A14629C08F8103100000", - "conditionUri": "ni:///sha-256;YswRV1-R4WETebWgtTZ4gF_AOFhUT8KOcrtmoUYpwI8?fpt=eval-sha-256&cost=1048576", - "message": "" -} diff --git a/src/cryptoconditions/tests/test_ed25519.py b/src/cryptoconditions/tests/test_ed25519.py index 271b9b023..ba97bdd9d 100644 --- a/src/cryptoconditions/tests/test_ed25519.py +++ b/src/cryptoconditions/tests/test_ed25519.py @@ -9,7 +9,7 @@ def test_sign_ed25519_pass_simple(): 'type': 'ed25519-sha-256', 'publicKey': "E0x0Ws4GhWhO_zBoUyaLbuqCz6hDdq11Ft1Dgbe9y9k", }, - 'privateKey': '11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo', + 'privateKey': 'D75A980182B10AB7D54BFED3C964073A0EE172F3DAA62325AF021A68F707511A', 'message': '', }) @@ -34,7 +34,7 @@ def test_sign_ed25519_pass_prefix(): 'publicKey': "E0x0Ws4GhWhO_zBoUyaLbuqCz6hDdq11Ft1Dgbe9y9k", } }, - 'privateKey': '11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo', + 'privateKey': 'D75A980182B10AB7D54BFED3C964073A0EE172F3DAA62325AF021A68F707511A', 'message': '', }) @@ -60,7 +60,7 @@ def test_sign_ed25519_fail(): 'type': 'ed25519-sha-256', 'publicKey': "E0x0Ws4GhWhO_zBoUyaLbuqCz6hDdq11Ft1Dgbe9y9k", }, - 'privateKey': '22qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo', + 'privateKey': '225A980182B10AB7D54BFED3C964073A0EE172F3DAA62325AF021A68F707511A', 'message': '', }) diff --git a/src/cryptoconditions/tests/test_failure_modes.py b/src/cryptoconditions/tests/test_failure_modes.py index 52ab3bdb9..59b0b3f24 100644 --- a/src/cryptoconditions/tests/test_failure_modes.py +++ b/src/cryptoconditions/tests/test_failure_modes.py @@ -65,9 +65,9 @@ def test_validate_empty_sigs(): def test_non_canonical_secp256k1(): cond = { "type": "secp256k1-sha-256", - "publicKey": "AtXZaTBVNawpp3B5wR1PDdQGYc-W4E6XSl6NfjdO4iWq", + "publicKey": "02D5D969305535AC29A77079C11D4F0DD40661CF96E04E974A5E8D7E374EE225AA", # Signature is correct, but non canonical; validation should fail - "signature": "nC1v8580C7r2XohL3_rnQ2p7dWiDnFuhF_poGCRfudrDITgwKywgjm5CTdnHAnkK4QskG4nI0KBrActwgzSrbg" + "signature": "9C2D6FF39F340BBAF65E884BDFFAE7436A7B7568839C5BA117FA6818245FB9DAC32138302B2C208E6E424DD9C702790AE10B241B89C8D0A06B01CB708334AB6E" } res = jsonRPC('verifyFulfillment', { 'fulfillment': jsonRPC('encodeFulfillment', cond)['fulfillment'], diff --git a/src/cryptoconditions/tests/test_secp256k1.py b/src/cryptoconditions/tests/test_secp256k1.py index bbc9462fa..fe3c72b67 100644 --- a/src/cryptoconditions/tests/test_secp256k1.py +++ b/src/cryptoconditions/tests/test_secp256k1.py @@ -2,25 +2,25 @@ import json import base64 import hashlib import secp256k1 -from .test_vectors import jsonRPC, encode_base64, decode_base64 +from .test_vectors import jsonRPC key = secp256k1.PrivateKey() def test_sign_secp256k1_pass_simple(): - pubkey = encode_base64(key.pubkey.serialize()) + pubkey = encode_b16(key.pubkey.serialize()) msg = '' res = jsonRPC('signTreeSecp256k1', { 'condition': { 'type': 'secp256k1-sha-256', 'publicKey': pubkey, }, - 'privateKey': encode_base64(key.private_key), + 'privateKey': encode_b16(key.private_key), 'message': msg, }) - sig = encode_base64(key.ecdsa_serialize_compact(key.ecdsa_sign(msg.encode()))) + sig = encode_b16(key.ecdsa_serialize_compact(key.ecdsa_sign(msg.encode()))) assert res == { "num_signed": 1, @@ -42,14 +42,14 @@ def test_sign_secp256k1_pass_simple(): def test_sign_secp256k1_fail(): # privateKey doesnt match publicKey - pubkey = encode_base64(key.pubkey.serialize()) + pubkey = encode_b16(key.pubkey.serialize()) msg = '' res = jsonRPC('signTreeSecp256k1', { 'condition': { 'type': 'secp256k1-sha-256', 'publicKey': pubkey, }, - 'privateKey': encode_base64('0' * 32), + 'privateKey': encode_b16(b'0' * 32), 'message': msg, }) @@ -60,3 +60,7 @@ def test_sign_secp256k1_fail(): "publicKey": pubkey, } } + + +def encode_b16(s): + return base64.b16encode(s).decode() diff --git a/src/cryptoconditions/tests/test_vectors.py b/src/cryptoconditions/tests/test_vectors.py index 34ed9a7d3..884d695be 100644 --- a/src/cryptoconditions/tests/test_vectors.py +++ b/src/cryptoconditions/tests/test_vectors.py @@ -125,25 +125,24 @@ def b16_to_b64(b16): return encode_base64(base64.b16decode(b16)) +def b64_to_b16(b64): + #if type(b64) == str: + # b64 = b64.encode() + return base64.b16encode(decode_base64(b64)).decode() + + def _read_vectors(name): - paths = ['ext/crypto-conditions/test-vectors/valid/%s.json', - 'tests/custom-vectors/%s.json'] - for fmt in paths: - path = fmt % name - if os.path.isfile(path): - vectors = json.load(open(path)) - break - else: - raise IOError("Vectors file not found: %s.json" % name) - for key in ['conditionBinary', 'fulfillment', 'message']: - vectors[key] = b16_to_b64(vectors[key]) - return vectors + path = 'tests/vectors/%s.json' % name + if os.path.isfile(path): + return json.load(open(path)) + raise IOError("Vectors file not found: %s.json" % name) so = cdll.LoadLibrary('.libs/libcryptoconditions.so') so.cc_jsonRPC.restype = c_char_p + def jsonRPC(method, params): req = json.dumps({ 'method': method, diff --git a/src/cryptoconditions/tests/vectors/0000_test-minimal-preimage.json b/src/cryptoconditions/tests/vectors/0000_test-minimal-preimage.json new file mode 100644 index 000000000..a0cf7be8f --- /dev/null +++ b/src/cryptoconditions/tests/vectors/0000_test-minimal-preimage.json @@ -0,0 +1,13 @@ +{ + "json": { + "type": "preimage-sha-256", + "preimage": "" + }, + "cost": 0, + "subtypes": [], + "fingerprintContents": "", + "fulfillment": "A0028000", + "conditionBinary": "A0258020E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855810100", + "conditionUri": "ni:///sha-256;47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU?fpt=preimage-sha-256&cost=0", + "message": "" +} \ No newline at end of file diff --git a/src/cryptoconditions/tests/vectors/0001_test-minimal-prefix.json b/src/cryptoconditions/tests/vectors/0001_test-minimal-prefix.json new file mode 100644 index 000000000..e2e942e9f --- /dev/null +++ b/src/cryptoconditions/tests/vectors/0001_test-minimal-prefix.json @@ -0,0 +1,20 @@ +{ + "json": { + "type": "prefix-sha-256", + "maxMessageLength": 0, + "prefix": "", + "subfulfillment": { + "type": "preimage-sha-256", + "preimage": "" + } + }, + "cost": 1024, + "subtypes": [ + "preimage-sha-256" + ], + "fingerprintContents": "302E8000810100A227A0258020E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855810100", + "fulfillment": "A10B8000810100A204A0028000", + "conditionBinary": "A12A8020BB1AC5260C0141B7E54B26EC2330637C5597BF811951AC09E744AD20FF77E2878102040082020780", + "conditionUri": "ni:///sha-256;uxrFJgwBQbflSybsIzBjfFWXv4EZUawJ50StIP934oc?fpt=prefix-sha-256&cost=1024&subtypes=preimage-sha-256", + "message": "" +} \ No newline at end of file diff --git a/src/cryptoconditions/tests/vectors/0002_test-minimal-threshold.json b/src/cryptoconditions/tests/vectors/0002_test-minimal-threshold.json new file mode 100644 index 000000000..67d2d551e --- /dev/null +++ b/src/cryptoconditions/tests/vectors/0002_test-minimal-threshold.json @@ -0,0 +1,21 @@ +{ + "json": { + "type": "threshold-sha-256", + "threshold": 1, + "subfulfillments": [ + { + "type": "preimage-sha-256", + "preimage": "" + } + ] + }, + "cost": 1024, + "subtypes": [ + "preimage-sha-256" + ], + "fingerprintContents": "302C800101A127A0258020E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855810100", + "fulfillment": "A208A004A0028000A100", + "conditionBinary": "A22A8020B4B84136DF48A71D73F4985C04C6767A778ECB65BA7023B4506823BEEE7631B98102040082020780", + "conditionUri": "ni:///sha-256;tLhBNt9Ipx1z9JhcBMZ2eneOy2W6cCO0UGgjvu52Mbk?fpt=threshold-sha-256&cost=1024&subtypes=preimage-sha-256", + "message": "" +} \ No newline at end of file diff --git a/src/cryptoconditions/tests/vectors/0003_test-minimal-rsa.json b/src/cryptoconditions/tests/vectors/0003_test-minimal-rsa.json new file mode 100644 index 000000000..881a8c527 --- /dev/null +++ b/src/cryptoconditions/tests/vectors/0003_test-minimal-rsa.json @@ -0,0 +1,14 @@ +{ + "json": { + "type": "rsa-sha-256", + "modulus": "4e-LJNb3awnIHtd1KqJi8ETwSodNQ4CdMc6mEvmbDJeotDdBU-Pu89ZmFoQ-DkHCkyZLcbYXPbHPDWzVWMWGV3Bvzwl_cExIPlnL_f1bPue8gNdAxeDwR_PoX8DXWBV3am8_I8XcXnlxOaaILjgzakpfs2E3Yg_zZj264yhHKAGGL3Ly-HsgK5yJrdfNWwoHb3xT41A59n7RfsgV5bQwXMYxlwaNXm5Xm6beX04-V99eTgcv8s5MZutFIzlzh1J1ljnwJXv1fb1cRD-1FYzOCj02rce6AfM6C7bbsr-YnWBxEvI0TZk-d-VjwdNh3t9X2pbvLPxoXwArY4JGpbMJuQ", + "signature": "vULWVp9lma7UVflrwO0I7RSAvzbNnhRn-cb3RGHJ46dJM0svZASqX59rr-dsNH0GklCzXRyXDHkwWe5zOoGT8w-nj-x8rkWePd_XYzgF1HaUDQy1PX-zidza6vboz0jEtWNUMOTyvN_lBcLA_Be0DZPH7bfCYev0OJWnBeAkqgVJpmD3CjIVBkdSLb5rY1IEl8_4-NXXR2iifFuG5YC-P83Jbxl2KTy6DVjfxgtRi2MqbcHpUMQ-Ix_ho3mqbdzFLHDt-FHGwBI6lkJhz9s4V81s1a3DfY2izJJO2uHYTPYSRYfydMH6NpfaKQHwJp8DskPAO2FOA4Xhlh-sUAD5uw" + }, + "cost": 65536, + "subtypes": [], + "fingerprintContents": "3082010480820100E1EF8B24D6F76B09C81ED7752AA262F044F04A874D43809D31CEA612F99B0C97A8B4374153E3EEF3D66616843E0E41C293264B71B6173DB1CF0D6CD558C58657706FCF097F704C483E59CBFDFD5B3EE7BC80D740C5E0F047F3E85FC0D75815776A6F3F23C5DC5E797139A6882E38336A4A5FB36137620FF3663DBAE328472801862F72F2F87B202B9C89ADD7CD5B0A076F7C53E35039F67ED17EC815E5B4305CC63197068D5E6E579BA6DE5F4E3E57DF5E4E072FF2CE4C66EB452339738752759639F0257BF57DBD5C443FB5158CCE0A3D36ADC7BA01F33A0BB6DBB2BF989D607112F2344D993E77E563C1D361DEDF57DA96EF2CFC685F002B638246A5B309B9", + "fulfillment": "A382020880820100E1EF8B24D6F76B09C81ED7752AA262F044F04A874D43809D31CEA612F99B0C97A8B4374153E3EEF3D66616843E0E41C293264B71B6173DB1CF0D6CD558C58657706FCF097F704C483E59CBFDFD5B3EE7BC80D740C5E0F047F3E85FC0D75815776A6F3F23C5DC5E797139A6882E38336A4A5FB36137620FF3663DBAE328472801862F72F2F87B202B9C89ADD7CD5B0A076F7C53E35039F67ED17EC815E5B4305CC63197068D5E6E579BA6DE5F4E3E57DF5E4E072FF2CE4C66EB452339738752759639F0257BF57DBD5C443FB5158CCE0A3D36ADC7BA01F33A0BB6DBB2BF989D607112F2344D993E77E563C1D361DEDF57DA96EF2CFC685F002B638246A5B309B981820100BD42D6569F6599AED455F96BC0ED08ED1480BF36CD9E1467F9C6F74461C9E3A749334B2F6404AA5F9F6BAFE76C347D069250B35D1C970C793059EE733A8193F30FA78FEC7CAE459E3DDFD7633805D476940D0CB53D7FB389DCDAEAF6E8CF48C4B5635430E4F2BCDFE505C2C0FC17B40D93C7EDB7C261EBF43895A705E024AA0549A660F70A32150647522DBE6B63520497CFF8F8D5D74768A27C5B86E580BE3FCDC96F1976293CBA0D58DFC60B518B632A6DC1E950C43E231FE1A379AA6DDCC52C70EDF851C6C0123A964261CFDB3857CD6CD5ADC37D8DA2CC924EDAE1D84CF6124587F274C1FA3697DA2901F0269F03B243C03B614E0385E1961FAC5000F9BB", + "conditionBinary": "A3278020B31FA8206E4EA7E515337B3B33082B877651801085ED84FB4DAEB247BF698D7F8103010000", + "conditionUri": "ni:///sha-256;sx-oIG5Op-UVM3s7Mwgrh3ZRgBCF7YT7Ta6yR79pjX8?fpt=rsa-sha-256&cost=65536", + "message": "" +} \ No newline at end of file diff --git a/src/cryptoconditions/tests/vectors/0004_test-minimal-ed25519.json b/src/cryptoconditions/tests/vectors/0004_test-minimal-ed25519.json new file mode 100644 index 000000000..669dc6d98 --- /dev/null +++ b/src/cryptoconditions/tests/vectors/0004_test-minimal-ed25519.json @@ -0,0 +1,14 @@ +{ + "json": { + "type": "ed25519-sha-256", + "publicKey": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo", + "signature": "5VZDAMNgrHKQhuLMgG6CioSHfx645dl02HPgZSJJAVVfuIIVkKM7rMYeOXAc-bRr0lv18FlbviRlUUFDjnoQCw" + }, + "cost": 131072, + "subtypes": [], + "fingerprintContents": "30228020D75A980182B10AB7D54BFED3C964073A0EE172F3DAA62325AF021A68F707511A", + "fulfillment": "A4648020D75A980182B10AB7D54BFED3C964073A0EE172F3DAA62325AF021A68F707511A8140E5564300C360AC729086E2CC806E828A84877F1EB8E5D974D873E065224901555FB8821590A33BACC61E39701CF9B46BD25BF5F0595BBE24655141438E7A100B", + "conditionBinary": "A4278020799239ABA8FC4FF7EABFBC4C44E69E8BDFED993324E12ED64792ABE289CF1D5F8103020000", + "conditionUri": "ni:///sha-256;eZI5q6j8T_fqv7xMROaei9_tmTMk4S7WR5Kr4onPHV8?fpt=ed25519-sha-256&cost=131072", + "message": "" +} \ No newline at end of file diff --git a/src/cryptoconditions/tests/vectors/0005_test-basic-preimage.json b/src/cryptoconditions/tests/vectors/0005_test-basic-preimage.json new file mode 100644 index 000000000..585fe2e47 --- /dev/null +++ b/src/cryptoconditions/tests/vectors/0005_test-basic-preimage.json @@ -0,0 +1,13 @@ +{ + "json": { + "type": "preimage-sha-256", + "preimage": "YWFh" + }, + "cost": 3, + "subtypes": [], + "fingerprintContents": "616161", + "fulfillment": "A0058003616161", + "conditionBinary": "A02580209834876DCFB05CB167A5C24953EBA58C4AC89B1ADF57F28F2F9D09AF107EE8F0810103", + "conditionUri": "ni:///sha-256;mDSHbc-wXLFnpcJJU-uljErImxrfV_KPL50JrxB-6PA?fpt=preimage-sha-256&cost=3", + "message": "" +} \ No newline at end of file diff --git a/src/cryptoconditions/tests/vectors/0006_test-basic-prefix.json b/src/cryptoconditions/tests/vectors/0006_test-basic-prefix.json new file mode 100644 index 000000000..59cd7b361 --- /dev/null +++ b/src/cryptoconditions/tests/vectors/0006_test-basic-prefix.json @@ -0,0 +1,21 @@ +{ + "json": { + "type": "prefix-sha-256", + "maxMessageLength": 0, + "prefix": "YWFh", + "subfulfillment": { + "type": "ed25519-sha-256", + "publicKey": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo", + "signature": "UGoepoMY5i1AY12tBD4Zh-vCbltcRAb3vfhacziPv-XCRaxJ9HcOvHh3CCcKpqh2n-_okw_Q6h7mSzFAfXaVCQ" + } + }, + "cost": 132099, + "subtypes": [ + "ed25519-sha-256" + ], + "fingerprintContents": "30338003616161810100A229A4278020799239ABA8FC4FF7EABFBC4C44E69E8BDFED993324E12ED64792ABE289CF1D5F8103020000", + "fulfillment": "A1708003616161810100A266A4648020D75A980182B10AB7D54BFED3C964073A0EE172F3DAA62325AF021A68F707511A8140506A1EA68318E62D40635DAD043E1987EBC26E5B5C4406F7BDF85A73388FBFE5C245AC49F4770EBC787708270AA6A8769FEFE8930FD0EA1EE64B31407D769509", + "conditionBinary": "A12B8020451FE15F16299D495993FE692DB989E56A5230A90476F77392A3CD3213C0733F810302040382020308", + "conditionUri": "ni:///sha-256;RR_hXxYpnUlZk_5pLbmJ5WpSMKkEdvdzkqPNMhPAcz8?fpt=prefix-sha-256&cost=132099&subtypes=ed25519-sha-256", + "message": "" +} \ No newline at end of file diff --git a/src/cryptoconditions/tests/vectors/0007_test-basic-prefix-two-levels-deep.json b/src/cryptoconditions/tests/vectors/0007_test-basic-prefix-two-levels-deep.json new file mode 100644 index 000000000..93dfb249e --- /dev/null +++ b/src/cryptoconditions/tests/vectors/0007_test-basic-prefix-two-levels-deep.json @@ -0,0 +1,26 @@ +{ + "json": { + "type": "prefix-sha-256", + "maxMessageLength": 3, + "prefix": "YmJi", + "subfulfillment": { + "type": "prefix-sha-256", + "maxMessageLength": 6, + "prefix": "YWFh", + "subfulfillment": { + "type": "ed25519-sha-256", + "publicKey": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo", + "signature": "pCNg9H99uG218DfIECQiNyB9et1uPlMX4hKyB-Jb7SrLSFrQvLtXdVcmDsu71ncY1sq630W61lXRuM6EYJ6XAQ" + } + } + }, + "cost": 133135, + "subtypes": [ + "ed25519-sha-256" + ], + "fingerprintContents": "30378003626262810103A22DA12B80207F19C9BB3BC767DE39657E11D16068F8CAB00E3E3C23916DF967B584A28B26DC810302040982020308", + "fulfillment": "A17C8003626262810103A272A1708003616161810106A266A4648020D75A980182B10AB7D54BFED3C964073A0EE172F3DAA62325AF021A68F707511A8140A42360F47F7DB86DB5F037C810242237207D7ADD6E3E5317E212B207E25BED2ACB485AD0BCBB577557260ECBBBD67718D6CABADF45BAD655D1B8CE84609E9701", + "conditionBinary": "A12B8020177350AD8566C528B92D9B5382DF2C68D9BA9F9FA41D43DBDD8E40B118DD9641810302080F82020308", + "conditionUri": "ni:///sha-256;F3NQrYVmxSi5LZtTgt8saNm6n5-kHUPb3Y5AsRjdlkE?fpt=prefix-sha-256&cost=133135&subtypes=ed25519-sha-256", + "message": "7A7A7A" +} \ No newline at end of file diff --git a/src/cryptoconditions/tests/vectors/0008_test-basic-threshold.json b/src/cryptoconditions/tests/vectors/0008_test-basic-threshold.json new file mode 100644 index 000000000..56b4984d8 --- /dev/null +++ b/src/cryptoconditions/tests/vectors/0008_test-basic-threshold.json @@ -0,0 +1,39 @@ +{ + "json": { + "type": "threshold-sha-256", + "threshold": 2, + "subfulfillments": [ + { + "type": "rsa-sha-256", + "modulus": "u7ChoxT_ai_HmuBvYQ3I1EIckz7QxDVOaurZHvlH6k-PYysuL3i4oHp4wzJIlcfLCRbrM0wQCQ5e254Cle0v8d6v0fSfVEEuQ-3iywbP_DlTAzCaTOPqwjQdmvMYgzfuur09Skr49D4VfW8C-dHySkJ3cEnJMKojP-1cY7B_clzea7JEBPy_wLhyR-rLfbBEeFumbt6OeSESRwFQQB4KhHG9428tXsuWD1cboX2vOB2DeN7CHhAS5LN2yebEa7Z9aO7xK6mhWWf0hti8kbPisG-l_KabdSQmrwKcsUnqWG3thR66Fgh2rNhfBiJx-tc9FfXw8CLiYTCSJr7jVnrQUvl0bKi_rPDU9BcwCFwJegICgwHZKgxUXAOXRywu7lthIiAl1jRw7mgc4yUnR86coj8Z5m8vY4bmrRORHXrazTjOXKj_LC2Zq7D1w7qEdQlhPmYyoSzm73jaTIIOkINAUwA9EZf2pXsBAP7hUshMixszu5ZXGYh4D6-9aXz4NwqZ2o-q91aH2VHMZTPHi44c4uHVzrmhFikgGvQ3R1yUAn-lJhS0MAt33PGArEnKo0AWjzJi_R7osTgCzqNXVLQjuDP6FMXdDEdt3l1ee_c3TWHySMO6uRywVQvRy-9wUH7o2xzzmTB-Io1PRZKmbFhXPP7MY5ZoBvr4gQnMsJkj6ls", + "signature": "QSAOQpYe6kYMgnbyOatmt2-PKGnqzMX56ZRcCrxjsUMGVvPaLSF6QzJ-6M4RJ9FKhddK9BL-k3A0W6a0QAPXca7dK6D8JQYn_fYWMa_WTpvucUsbr7afkBvutvlZsWpUsyippnTIg8r8T8L3sEdtvKqNm_1H9zTjRza_ZulzsxXCq_RyewYso8QCk261CEnhgV3RYEpgTe-maM_oI7AIv4979XzrG0HlGP9TrpEe-YgFcbPRdCNB1g48sr65PrXxePjve6DG8ikLmVXYPWD5Q9ZEVx7I1fBk2V8doedZ1pINhKVMvEl4NkCnsM89Ao5ifsetJakV9tjCSy4JkVKKAsW-8BBsGLPznFmZVut6J7M3MT3Pk-dYZ2BqSsWhq2-btETcHa0fVG-u3mrpNIhASQF2kTcdUe4dZQ785YGzDGhDCH5wFBkPRGAmfYlNUlgU3aNDuaBIncCMajQzR0LOowtJJRLSlXRSF91l7P7LnKGNIS-EpQbXACbtMyiWvSSmMFoMve6d_Yq7hQf4QOuUz6jpKOaRDCdfe2jRH5ZGPBAqWWYTR4aVvHZx-ycwkTnGzS8Vyn4kBS5H9ONO-LhE7DZKhb3JvoQlz_cqd76Y2QFphqZnEJgl8e8Y4IFwqHtDaOfBQsGdrRBgXE80HVIJmHrzGrqOLklj8-B5TdEfC3I" + }, + { + "type": "prefix-sha-256", + "maxMessageLength": 0, + "prefix": "YWFh", + "subfulfillment": { + "type": "ed25519-sha-256", + "publicKey": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo", + "signature": "NEydEqAqV7Nf2WYZPO6V1du7xndVP86_QUwY2nUAKd05xuU63Yks7-RCNYMf-OXzaGiO93zPb5l_1BGmp-v5Ag" + } + }, + { + "type": "ed25519-sha-256", + "publicKey": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo", + "signature": "UGoepoMY5i1AY12tBD4Zh-vCbltcRAb3vfhacziPv-XCRaxJ9HcOvHh3CCcKpqh2n-_okw_Q6h7mSzFAfXaVCQ" + } + ] + }, + "cost": 397315, + "subtypes": [ + "ed25519-sha-256", + "prefix-sha-256", + "rsa-sha-256" + ], + "fingerprintContents": "308184800102A17FA12B8020451FE15F16299D495993FE692DB989E56A5230A90476F77392A3CD3213C0733F810302040382020308A32780204DD2EA7F85B3EACB8F19058E8360955C32E74C124392A1F44660739709C539C38103040000A4278020799239ABA8FC4FF7EABFBC4C44E69E8BDFED993324E12ED64792ABE289CF1D5F8103020000", + "fulfillment": "A2820106A081D8A1708003616161810100A266A4648020D75A980182B10AB7D54BFED3C964073A0EE172F3DAA62325AF021A68F707511A8140344C9D12A02A57B35FD966193CEE95D5DBBBC677553FCEBF414C18DA750029DD39C6E53ADD892CEFE44235831FF8E5F368688EF77CCF6F997FD411A6A7EBF902A4648020D75A980182B10AB7D54BFED3C964073A0EE172F3DAA62325AF021A68F707511A8140506A1EA68318E62D40635DAD043E1987EBC26E5B5C4406F7BDF85A73388FBFE5C245AC49F4770EBC787708270AA6A8769FEFE8930FD0EA1EE64B31407D769509A129A32780204DD2EA7F85B3EACB8F19058E8360955C32E74C124392A1F44660739709C539C38103040000", + "conditionBinary": "A22B8020B6ACF4083E438BE4356F25FF92C295E9C8E1BAB141B4607BA48511EBA35AEFCC810306100382020358", + "conditionUri": "ni:///sha-256;tqz0CD5Di-Q1byX_ksKV6cjhurFBtGB7pIUR66Na78w?fpt=threshold-sha-256&cost=397315&subtypes=prefix-sha-256,rsa-sha-256,ed25519-sha-256", + "message": "616161" +} diff --git a/src/cryptoconditions/tests/vectors/0009_test-basic-threshold-same-condition-twice.json b/src/cryptoconditions/tests/vectors/0009_test-basic-threshold-same-condition-twice.json new file mode 100644 index 000000000..a669b8d5f --- /dev/null +++ b/src/cryptoconditions/tests/vectors/0009_test-basic-threshold-same-condition-twice.json @@ -0,0 +1,54 @@ +{ + "json": { + "type": "threshold-sha-256", + "threshold": 1, + "subfulfillments": [ + { + "type": "prefix-sha-256", + "maxMessageLength": 0, + "prefix": "YWFh", + "subfulfillment": { + "type": "ed25519-sha-256", + "publicKey": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo", + "signature": "UGoepoMY5i1AY12tBD4Zh-vCbltcRAb3vfhacziPv-XCRaxJ9HcOvHh3CCcKpqh2n-_okw_Q6h7mSzFAfXaVCQ" + } + }, + { + "type": "rsa-sha-256", + "modulus": "u7ChoxT_ai_HmuBvYQ3I1EIckz7QxDVOaurZHvlH6k-PYysuL3i4oHp4wzJIlcfLCRbrM0wQCQ5e254Cle0v8d6v0fSfVEEuQ-3iywbP_DlTAzCaTOPqwjQdmvMYgzfuur09Skr49D4VfW8C-dHySkJ3cEnJMKojP-1cY7B_clzea7JEBPy_wLhyR-rLfbBEeFumbt6OeSESRwFQQB4KhHG9428tXsuWD1cboX2vOB2DeN7CHhAS5LN2yebEa7Z9aO7xK6mhWWf0hti8kbPisG-l_KabdSQmrwKcsUnqWG3thR66Fgh2rNhfBiJx-tc9FfXw8CLiYTCSJr7jVnrQUvl0bKi_rPDU9BcwCFwJegICgwHZKgxUXAOXRywu7lthIiAl1jRw7mgc4yUnR86coj8Z5m8vY4bmrRORHXrazTjOXKj_LC2Zq7D1w7qEdQlhPmYyoSzm73jaTIIOkINAUwA9EZf2pXsBAP7hUshMixszu5ZXGYh4D6-9aXz4NwqZ2o-q91aH2VHMZTPHi44c4uHVzrmhFikgGvQ3R1yUAn-lJhS0MAt33PGArEnKo0AWjzJi_R7osTgCzqNXVLQjuDP6FMXdDEdt3l1ee_c3TWHySMO6uRywVQvRy-9wUH7o2xzzmTB-Io1PRZKmbFhXPP7MY5ZoBvr4gQnMsJkj6ls", + "signature": "fss4we3Ml_SM2IUwwkbFSRKGf1EbxN3QjFc8ogg6yf2qNFwXdo2t6YNCSBjbUqNy4oD7pWgvZSFalz-3KGdJO2T4-zQVM5felzo2xzxSuR4DQBtvpWP3d4T6r4ggQFvukx6jX3qNlCUUrlhsH8yo7e-biQTRuOEcnNjdu38VG3cX4STnLVejyjP0TkrXvDvYf9wge6rqrbax8XVPx48bQmbd84bl1STBo4cGUjqoIPEYsFN3Law-SoZ700WkvDWSCe9sHIPPVDKcJUjRrwUd_tr1PoBA9_OwYThrJ7UMj98w-k_X1fPfTbB0RMW4Z9V_P9L5r0AXRyHlYEJILwy4oEx4b74N47mHskntvTC32yuSic9E0OfLLmvewIpukErdNo5AwKf5LoSGWAaLDdbF7989xvK3YBB8AfWqr6jjf3ZmKIb8XS2yXduOP9T6ixFPj-pjn0VfAugCY_a85IO6LiChBeliMO84t5OO-qUKmdnj1qMd5Piy_H28FnXN_57X6tSUmOfo1oNTvMKBCWBg5azgw5dZNCYu18OxfmpxsXPgWF8Th7omsxSFqCCOOBoFPoFdVu3Lj_2pa9pLgJF5FzWZKKNEBnwBjPf6MD_PkybcjX9atigIbUvTgEbwKVNZrgENagDTgT984cfm7baOB4eYWTuaV6ycCgpMLSgk-gA" + }, + { + "type": "prefix-sha-256", + "maxMessageLength": 0, + "prefix": "YWFh", + "subfulfillment": { + "type": "ed25519-sha-256", + "publicKey": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo", + "signature": "UGoepoMY5i1AY12tBD4Zh-vCbltcRAb3vfhacziPv-XCRaxJ9HcOvHh3CCcKpqh2n-_okw_Q6h7mSzFAfXaVCQ" + } + }, + { + "type": "rsa-sha-256", + "modulus": "u7ChoxT_ai_HmuBvYQ3I1EIckz7QxDVOaurZHvlH6k-PYysuL3i4oHp4wzJIlcfLCRbrM0wQCQ5e254Cle0v8d6v0fSfVEEuQ-3iywbP_DlTAzCaTOPqwjQdmvMYgzfuur09Skr49D4VfW8C-dHySkJ3cEnJMKojP-1cY7B_clzea7JEBPy_wLhyR-rLfbBEeFumbt6OeSESRwFQQB4KhHG9428tXsuWD1cboX2vOB2DeN7CHhAS5LN2yebEa7Z9aO7xK6mhWWf0hti8kbPisG-l_KabdSQmrwKcsUnqWG3thR66Fgh2rNhfBiJx-tc9FfXw8CLiYTCSJr7jVnrQUvl0bKi_rPDU9BcwCFwJegICgwHZKgxUXAOXRywu7lthIiAl1jRw7mgc4yUnR86coj8Z5m8vY4bmrRORHXrazTjOXKj_LC2Zq7D1w7qEdQlhPmYyoSzm73jaTIIOkINAUwA9EZf2pXsBAP7hUshMixszu5ZXGYh4D6-9aXz4NwqZ2o-q91aH2VHMZTPHi44c4uHVzrmhFikgGvQ3R1yUAn-lJhS0MAt33PGArEnKo0AWjzJi_R7osTgCzqNXVLQjuDP6FMXdDEdt3l1ee_c3TWHySMO6uRywVQvRy-9wUH7o2xzzmTB-Io1PRZKmbFhXPP7MY5ZoBvr4gQnMsJkj6ls", + "signature": "fss4we3Ml_SM2IUwwkbFSRKGf1EbxN3QjFc8ogg6yf2qNFwXdo2t6YNCSBjbUqNy4oD7pWgvZSFalz-3KGdJO2T4-zQVM5felzo2xzxSuR4DQBtvpWP3d4T6r4ggQFvukx6jX3qNlCUUrlhsH8yo7e-biQTRuOEcnNjdu38VG3cX4STnLVejyjP0TkrXvDvYf9wge6rqrbax8XVPx48bQmbd84bl1STBo4cGUjqoIPEYsFN3Law-SoZ700WkvDWSCe9sHIPPVDKcJUjRrwUd_tr1PoBA9_OwYThrJ7UMj98w-k_X1fPfTbB0RMW4Z9V_P9L5r0AXRyHlYEJILwy4oEx4b74N47mHskntvTC32yuSic9E0OfLLmvewIpukErdNo5AwKf5LoSGWAaLDdbF7989xvK3YBB8AfWqr6jjf3ZmKIb8XS2yXduOP9T6ixFPj-pjn0VfAugCY_a85IO6LiChBeliMO84t5OO-qUKmdnj1qMd5Piy_H28FnXN_57X6tSUmOfo1oNTvMKBCWBg5azgw5dZNCYu18OxfmpxsXPgWF8Th7omsxSFqCCOOBoFPoFdVu3Lj_2pa9pLgJF5FzWZKKNEBnwBjPf6MD_PkybcjX9atigIbUvTgEbwKVNZrgENagDTgT984cfm7baOB4eYWTuaV6ycCgpMLSgk-gA" + }, + { + "type": "preimage-sha-256", + "preimage": "YWFh" + } + ] + }, + "cost": 267264, + "subtypes": [ + "ed25519-sha-256", + "prefix-sha-256", + "preimage-sha-256", + "rsa-sha-256" + ], + "fingerprintContents": "3081D9800101A181D3A02580209834876DCFB05CB167A5C24953EBA58C4AC89B1ADF57F28F2F9D09AF107EE8F0810103A12B8020451FE15F16299D495993FE692DB989E56A5230A90476F77392A3CD3213C0733F810302040382020308A12B8020451FE15F16299D495993FE692DB989E56A5230A90476F77392A3CD3213C0733F810302040382020308A32780204DD2EA7F85B3EACB8F19058E8360955C32E74C124392A1F44660739709C539C38103040000A32780204DD2EA7F85B3EACB8F19058E8360955C32E74C124392A1F44660739709C539C38103040000", + "fulfillment": "A281B8A007A0058003616161A181ACA12B8020451FE15F16299D495993FE692DB989E56A5230A90476F77392A3CD3213C0733F810302040382020308A12B8020451FE15F16299D495993FE692DB989E56A5230A90476F77392A3CD3213C0733F810302040382020308A32780204DD2EA7F85B3EACB8F19058E8360955C32E74C124392A1F44660739709C539C38103040000A32780204DD2EA7F85B3EACB8F19058E8360955C32E74C124392A1F44660739709C539C38103040000", + "conditionBinary": "A22B80209A0B2C63DF80686E6020D0CA21CBFE668CCEC3D1AF82713FEAE9B8DD4A0F9BB78103041400820203D8", + "conditionUri": "ni:///sha-256;mgssY9-AaG5gINDKIcv-ZozOw9GvgnE_6um43UoPm7c?fpt=threshold-sha-256&cost=267264&subtypes=preimage-sha-256,prefix-sha-256,rsa-sha-256,ed25519-sha-256", + "message": "" +} diff --git a/src/cryptoconditions/tests/vectors/0010_test-basic-threshold-same-fulfillment-twice.json b/src/cryptoconditions/tests/vectors/0010_test-basic-threshold-same-fulfillment-twice.json new file mode 100644 index 000000000..9a1927d4b --- /dev/null +++ b/src/cryptoconditions/tests/vectors/0010_test-basic-threshold-same-fulfillment-twice.json @@ -0,0 +1,48 @@ +{ + "json": { + "type": "threshold-sha-256", + "threshold": 4, + "subfulfillments": [ + { + "type": "prefix-sha-256", + "maxMessageLength": 0, + "prefix": "YWFh", + "subfulfillment": { + "type": "ed25519-sha-256", + "publicKey": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo", + "signature": "UGoepoMY5i1AY12tBD4Zh-vCbltcRAb3vfhacziPv-XCRaxJ9HcOvHh3CCcKpqh2n-_okw_Q6h7mSzFAfXaVCQ" + } + }, + { + "type": "ed25519-sha-256", + "publicKey": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo", + "signature": "5VZDAMNgrHKQhuLMgG6CioSHfx645dl02HPgZSJJAVVfuIIVkKM7rMYeOXAc-bRr0lv18FlbviRlUUFDjnoQCw" + }, + { + "type": "prefix-sha-256", + "maxMessageLength": 0, + "prefix": "YWFh", + "subfulfillment": { + "type": "ed25519-sha-256", + "publicKey": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo", + "signature": "UGoepoMY5i1AY12tBD4Zh-vCbltcRAb3vfhacziPv-XCRaxJ9HcOvHh3CCcKpqh2n-_okw_Q6h7mSzFAfXaVCQ" + } + }, + { + "type": "ed25519-sha-256", + "publicKey": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo", + "signature": "5VZDAMNgrHKQhuLMgG6CioSHfx645dl02HPgZSJJAVVfuIIVkKM7rMYeOXAc-bRr0lv18FlbviRlUUFDjnoQCw" + } + ] + }, + "cost": 530438, + "subtypes": [ + "ed25519-sha-256", + "prefix-sha-256" + ], + "fingerprintContents": "3081B2800104A181ACA12B8020451FE15F16299D495993FE692DB989E56A5230A90476F77392A3CD3213C0733F810302040382020308A12B8020451FE15F16299D495993FE692DB989E56A5230A90476F77392A3CD3213C0733F810302040382020308A4278020799239ABA8FC4FF7EABFBC4C44E69E8BDFED993324E12ED64792ABE289CF1D5F8103020000A4278020799239ABA8FC4FF7EABFBC4C44E69E8BDFED993324E12ED64792ABE289CF1D5F8103020000", + "fulfillment": "A28201B6A08201B0A1708003616161810100A266A4648020D75A980182B10AB7D54BFED3C964073A0EE172F3DAA62325AF021A68F707511A8140506A1EA68318E62D40635DAD043E1987EBC26E5B5C4406F7BDF85A73388FBFE5C245AC49F4770EBC787708270AA6A8769FEFE8930FD0EA1EE64B31407D769509A1708003616161810100A266A4648020D75A980182B10AB7D54BFED3C964073A0EE172F3DAA62325AF021A68F707511A8140506A1EA68318E62D40635DAD043E1987EBC26E5B5C4406F7BDF85A73388FBFE5C245AC49F4770EBC787708270AA6A8769FEFE8930FD0EA1EE64B31407D769509A4648020D75A980182B10AB7D54BFED3C964073A0EE172F3DAA62325AF021A68F707511A8140E5564300C360AC729086E2CC806E828A84877F1EB8E5D974D873E065224901555FB8821590A33BACC61E39701CF9B46BD25BF5F0595BBE24655141438E7A100BA4648020D75A980182B10AB7D54BFED3C964073A0EE172F3DAA62325AF021A68F707511A8140E5564300C360AC729086E2CC806E828A84877F1EB8E5D974D873E065224901555FB8821590A33BACC61E39701CF9B46BD25BF5F0595BBE24655141438E7A100BA100", + "conditionBinary": "A22B80208E433EF5D3EAA00A2B34A05CA7C22DD392973A19F1A243268CB53111BDF1C844810308180682020348", + "conditionUri": "ni:///sha-256;jkM-9dPqoAorNKBcp8It05KXOhnxokMmjLUxEb3xyEQ?fpt=threshold-sha-256&cost=530438&subtypes=prefix-sha-256,ed25519-sha-256", + "message": "" +} diff --git a/src/cryptoconditions/tests/vectors/0011_test-basic-threshold-two-levels-deep.json b/src/cryptoconditions/tests/vectors/0011_test-basic-threshold-two-levels-deep.json new file mode 100644 index 000000000..af153f473 --- /dev/null +++ b/src/cryptoconditions/tests/vectors/0011_test-basic-threshold-two-levels-deep.json @@ -0,0 +1,50 @@ +{ + "json": { + "type": "threshold-sha-256", + "threshold": 2, + "subfulfillments": [ + { + "type": "threshold-sha-256", + "threshold": 2, + "subfulfillments": [ + { + "type": "rsa-sha-256", + "modulus": "u7ChoxT_ai_HmuBvYQ3I1EIckz7QxDVOaurZHvlH6k-PYysuL3i4oHp4wzJIlcfLCRbrM0wQCQ5e254Cle0v8d6v0fSfVEEuQ-3iywbP_DlTAzCaTOPqwjQdmvMYgzfuur09Skr49D4VfW8C-dHySkJ3cEnJMKojP-1cY7B_clzea7JEBPy_wLhyR-rLfbBEeFumbt6OeSESRwFQQB4KhHG9428tXsuWD1cboX2vOB2DeN7CHhAS5LN2yebEa7Z9aO7xK6mhWWf0hti8kbPisG-l_KabdSQmrwKcsUnqWG3thR66Fgh2rNhfBiJx-tc9FfXw8CLiYTCSJr7jVnrQUvl0bKi_rPDU9BcwCFwJegICgwHZKgxUXAOXRywu7lthIiAl1jRw7mgc4yUnR86coj8Z5m8vY4bmrRORHXrazTjOXKj_LC2Zq7D1w7qEdQlhPmYyoSzm73jaTIIOkINAUwA9EZf2pXsBAP7hUshMixszu5ZXGYh4D6-9aXz4NwqZ2o-q91aH2VHMZTPHi44c4uHVzrmhFikgGvQ3R1yUAn-lJhS0MAt33PGArEnKo0AWjzJi_R7osTgCzqNXVLQjuDP6FMXdDEdt3l1ee_c3TWHySMO6uRywVQvRy-9wUH7o2xzzmTB-Io1PRZKmbFhXPP7MY5ZoBvr4gQnMsJkj6ls", + "signature": "fss4we3Ml_SM2IUwwkbFSRKGf1EbxN3QjFc8ogg6yf2qNFwXdo2t6YNCSBjbUqNy4oD7pWgvZSFalz-3KGdJO2T4-zQVM5felzo2xzxSuR4DQBtvpWP3d4T6r4ggQFvukx6jX3qNlCUUrlhsH8yo7e-biQTRuOEcnNjdu38VG3cX4STnLVejyjP0TkrXvDvYf9wge6rqrbax8XVPx48bQmbd84bl1STBo4cGUjqoIPEYsFN3Law-SoZ700WkvDWSCe9sHIPPVDKcJUjRrwUd_tr1PoBA9_OwYThrJ7UMj98w-k_X1fPfTbB0RMW4Z9V_P9L5r0AXRyHlYEJILwy4oEx4b74N47mHskntvTC32yuSic9E0OfLLmvewIpukErdNo5AwKf5LoSGWAaLDdbF7989xvK3YBB8AfWqr6jjf3ZmKIb8XS2yXduOP9T6ixFPj-pjn0VfAugCY_a85IO6LiChBeliMO84t5OO-qUKmdnj1qMd5Piy_H28FnXN_57X6tSUmOfo1oNTvMKBCWBg5azgw5dZNCYu18OxfmpxsXPgWF8Th7omsxSFqCCOOBoFPoFdVu3Lj_2pa9pLgJF5FzWZKKNEBnwBjPf6MD_PkybcjX9atigIbUvTgEbwKVNZrgENagDTgT984cfm7baOB4eYWTuaV6ycCgpMLSgk-gA" + }, + { + "type": "prefix-sha-256", + "maxMessageLength": 0, + "prefix": "YWFh", + "subfulfillment": { + "type": "ed25519-sha-256", + "publicKey": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo", + "signature": "UGoepoMY5i1AY12tBD4Zh-vCbltcRAb3vfhacziPv-XCRaxJ9HcOvHh3CCcKpqh2n-_okw_Q6h7mSzFAfXaVCQ" + } + }, + { + "type": "ed25519-sha-256", + "publicKey": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo", + "signature": "5VZDAMNgrHKQhuLMgG6CioSHfx645dl02HPgZSJJAVVfuIIVkKM7rMYeOXAc-bRr0lv18FlbviRlUUFDjnoQCw" + } + ] + }, + { + "type": "preimage-sha-256", + "preimage": "YWFh" + } + ] + }, + "cost": 399366, + "subtypes": [ + "ed25519-sha-256", + "prefix-sha-256", + "preimage-sha-256", + "rsa-sha-256" + ], + "fingerprintContents": "3059800102A154A02580209834876DCFB05CB167A5C24953EBA58C4AC89B1ADF57F28F2F9D09AF107EE8F0810103A22B8020B6ACF4083E438BE4356F25FF92C295E9C8E1BAB141B4607BA48511EBA35AEFCC810306100382020358", + "fulfillment": "A2820117A0820111A0058003616161A2820106A081D8A1708003616161810100A266A4648020D75A980182B10AB7D54BFED3C964073A0EE172F3DAA62325AF021A68F707511A8140506A1EA68318E62D40635DAD043E1987EBC26E5B5C4406F7BDF85A73388FBFE5C245AC49F4770EBC787708270AA6A8769FEFE8930FD0EA1EE64B31407D769509A4648020D75A980182B10AB7D54BFED3C964073A0EE172F3DAA62325AF021A68F707511A8140E5564300C360AC729086E2CC806E828A84877F1EB8E5D974D873E065224901555FB8821590A33BACC61E39701CF9B46BD25BF5F0595BBE24655141438E7A100BA129A32780204DD2EA7F85B3EACB8F19058E8360955C32E74C124392A1F44660739709C539C38103040000A100", + "conditionBinary": "A22B80200C99630A201A99B0748D2BADB205E5CA939692C687D1C4A697E39BA8BA1EBE718103061806820203D8", + "conditionUri": "ni:///sha-256;DJljCiAambB0jSutsgXlypOWksaH0cSml-ObqLoevnE?fpt=threshold-sha-256&cost=399366&subtypes=preimage-sha-256,prefix-sha-256,rsa-sha-256,ed25519-sha-256", + "message": "" +} diff --git a/src/cryptoconditions/tests/vectors/0012_test-basic-threshold-schroedinger.json b/src/cryptoconditions/tests/vectors/0012_test-basic-threshold-schroedinger.json new file mode 100644 index 000000000..4285ac44d --- /dev/null +++ b/src/cryptoconditions/tests/vectors/0012_test-basic-threshold-schroedinger.json @@ -0,0 +1,25 @@ +{ + "json": { + "type": "threshold-sha-256", + "threshold": 1, + "subfulfillments": [ + { + "type": "preimage-sha-256", + "preimage": "YWFh" + }, + { + "type": "preimage-sha-256", + "preimage": "YWFh" + } + ] + }, + "cost": 2051, + "subtypes": [ + "preimage-sha-256" + ], + "fingerprintContents": "3053800101A14EA02580209834876DCFB05CB167A5C24953EBA58C4AC89B1ADF57F28F2F9D09AF107EE8F0810103A02580209834876DCFB05CB167A5C24953EBA58C4AC89B1ADF57F28F2F9D09AF107EE8F0810103", + "fulfillment": "A232A007A0058003616161A127A02580209834876DCFB05CB167A5C24953EBA58C4AC89B1ADF57F28F2F9D09AF107EE8F0810103", + "conditionBinary": "A22A8020E4FDB4652C6F17A38B2ABE9AA00640B1E184FE7A8D0C971B5D24F7EDA6FC68BF8102080382020780", + "conditionUri": "ni:///sha-256;5P20ZSxvF6OLKr6aoAZAseGE_nqNDJcbXST37ab8aL8?fpt=threshold-sha-256&cost=2051&subtypes=preimage-sha-256", + "message": "" +} \ No newline at end of file diff --git a/src/cryptoconditions/tests/vectors/0013_test-basic-rsa.json b/src/cryptoconditions/tests/vectors/0013_test-basic-rsa.json new file mode 100644 index 000000000..5681fc5c1 --- /dev/null +++ b/src/cryptoconditions/tests/vectors/0013_test-basic-rsa.json @@ -0,0 +1,14 @@ +{ + "json": { + "type": "rsa-sha-256", + "modulus": "4e-LJNb3awnIHtd1KqJi8ETwSodNQ4CdMc6mEvmbDJeotDdBU-Pu89ZmFoQ-DkHCkyZLcbYXPbHPDWzVWMWGV3Bvzwl_cExIPlnL_f1bPue8gNdAxeDwR_PoX8DXWBV3am8_I8XcXnlxOaaILjgzakpfs2E3Yg_zZj264yhHKAGGL3Ly-HsgK5yJrdfNWwoHb3xT41A59n7RfsgV5bQwXMYxlwaNXm5Xm6beX04-V99eTgcv8s5MZutFIzlzh1J1ljnwJXv1fb1cRD-1FYzOCj02rce6AfM6C7bbsr-YnWBxEvI0TZk-d-VjwdNh3t9X2pbvLPxoXwArY4JGpbMJuQ", + "signature": "SOiUXv4AdVbVv01fJJ5ICPcwfilRHTJi2u9h2ICY-apKi8BiOoyXVzj2XWv0WdVD8onXPLx69Oo6M_vz7ERARHkR1yKUCR5WGDNijkmncu1gjebERZWpHj4X1s9ew7JSjWPSrdZGOYmxLuxXffZHCWDfaDKp2Ew2DRwhetZMhiW9tZT7CtoIbN7LveWA1CS_l0bS8MMSgm27sArWi1LEy31HFWujXjqYHJc4Y3ksyA0EoYAhClJBWGW2Szphd0sdOXXXipiwgh7lXKD4YwXUJSnhDrAVzv1AL7WbKruN7uUqbyRH0ihGA9IZzU6M-c_91UmIicN4C1ndalfvfXMmIA" + }, + "cost": 65536, + "subtypes": [], + "fingerprintContents": "3082010480820100E1EF8B24D6F76B09C81ED7752AA262F044F04A874D43809D31CEA612F99B0C97A8B4374153E3EEF3D66616843E0E41C293264B71B6173DB1CF0D6CD558C58657706FCF097F704C483E59CBFDFD5B3EE7BC80D740C5E0F047F3E85FC0D75815776A6F3F23C5DC5E797139A6882E38336A4A5FB36137620FF3663DBAE328472801862F72F2F87B202B9C89ADD7CD5B0A076F7C53E35039F67ED17EC815E5B4305CC63197068D5E6E579BA6DE5F4E3E57DF5E4E072FF2CE4C66EB452339738752759639F0257BF57DBD5C443FB5158CCE0A3D36ADC7BA01F33A0BB6DBB2BF989D607112F2344D993E77E563C1D361DEDF57DA96EF2CFC685F002B638246A5B309B9", + "fulfillment": "A382020880820100E1EF8B24D6F76B09C81ED7752AA262F044F04A874D43809D31CEA612F99B0C97A8B4374153E3EEF3D66616843E0E41C293264B71B6173DB1CF0D6CD558C58657706FCF097F704C483E59CBFDFD5B3EE7BC80D740C5E0F047F3E85FC0D75815776A6F3F23C5DC5E797139A6882E38336A4A5FB36137620FF3663DBAE328472801862F72F2F87B202B9C89ADD7CD5B0A076F7C53E35039F67ED17EC815E5B4305CC63197068D5E6E579BA6DE5F4E3E57DF5E4E072FF2CE4C66EB452339738752759639F0257BF57DBD5C443FB5158CCE0A3D36ADC7BA01F33A0BB6DBB2BF989D607112F2344D993E77E563C1D361DEDF57DA96EF2CFC685F002B638246A5B309B98182010048E8945EFE007556D5BF4D5F249E4808F7307E29511D3262DAEF61D88098F9AA4A8BC0623A8C975738F65D6BF459D543F289D73CBC7AF4EA3A33FBF3EC4440447911D72294091E561833628E49A772ED608DE6C44595A91E3E17D6CF5EC3B2528D63D2ADD6463989B12EEC577DF6470960DF6832A9D84C360D1C217AD64C8625BDB594FB0ADA086CDECBBDE580D424BF9746D2F0C312826DBBB00AD68B52C4CB7D47156BA35E3A981C973863792CC80D04A180210A52415865B64B3A61774B1D3975D78A98B0821EE55CA0F86305D42529E10EB015CEFD402FB59B2ABB8DEEE52A6F2447D2284603D219CD4E8CF9CFFDD5498889C3780B59DD6A57EF7D732620", + "conditionBinary": "A3278020B31FA8206E4EA7E515337B3B33082B877651801085ED84FB4DAEB247BF698D7F8103010000", + "conditionUri": "ni:///sha-256;sx-oIG5Op-UVM3s7Mwgrh3ZRgBCF7YT7Ta6yR79pjX8?fpt=rsa-sha-256&cost=65536", + "message": "616161" +} \ No newline at end of file diff --git a/src/cryptoconditions/tests/vectors/0014_test-basic-rsa4096.json b/src/cryptoconditions/tests/vectors/0014_test-basic-rsa4096.json new file mode 100644 index 000000000..ab17137b2 --- /dev/null +++ b/src/cryptoconditions/tests/vectors/0014_test-basic-rsa4096.json @@ -0,0 +1,14 @@ +{ + "json": { + "type": "rsa-sha-256", + "modulus": "u7ChoxT_ai_HmuBvYQ3I1EIckz7QxDVOaurZHvlH6k-PYysuL3i4oHp4wzJIlcfLCRbrM0wQCQ5e254Cle0v8d6v0fSfVEEuQ-3iywbP_DlTAzCaTOPqwjQdmvMYgzfuur09Skr49D4VfW8C-dHySkJ3cEnJMKojP-1cY7B_clzea7JEBPy_wLhyR-rLfbBEeFumbt6OeSESRwFQQB4KhHG9428tXsuWD1cboX2vOB2DeN7CHhAS5LN2yebEa7Z9aO7xK6mhWWf0hti8kbPisG-l_KabdSQmrwKcsUnqWG3thR66Fgh2rNhfBiJx-tc9FfXw8CLiYTCSJr7jVnrQUvl0bKi_rPDU9BcwCFwJegICgwHZKgxUXAOXRywu7lthIiAl1jRw7mgc4yUnR86coj8Z5m8vY4bmrRORHXrazTjOXKj_LC2Zq7D1w7qEdQlhPmYyoSzm73jaTIIOkINAUwA9EZf2pXsBAP7hUshMixszu5ZXGYh4D6-9aXz4NwqZ2o-q91aH2VHMZTPHi44c4uHVzrmhFikgGvQ3R1yUAn-lJhS0MAt33PGArEnKo0AWjzJi_R7osTgCzqNXVLQjuDP6FMXdDEdt3l1ee_c3TWHySMO6uRywVQvRy-9wUH7o2xzzmTB-Io1PRZKmbFhXPP7MY5ZoBvr4gQnMsJkj6ls", + "signature": "QSAOQpYe6kYMgnbyOatmt2-PKGnqzMX56ZRcCrxjsUMGVvPaLSF6QzJ-6M4RJ9FKhddK9BL-k3A0W6a0QAPXca7dK6D8JQYn_fYWMa_WTpvucUsbr7afkBvutvlZsWpUsyippnTIg8r8T8L3sEdtvKqNm_1H9zTjRza_ZulzsxXCq_RyewYso8QCk261CEnhgV3RYEpgTe-maM_oI7AIv4979XzrG0HlGP9TrpEe-YgFcbPRdCNB1g48sr65PrXxePjve6DG8ikLmVXYPWD5Q9ZEVx7I1fBk2V8doedZ1pINhKVMvEl4NkCnsM89Ao5ifsetJakV9tjCSy4JkVKKAsW-8BBsGLPznFmZVut6J7M3MT3Pk-dYZ2BqSsWhq2-btETcHa0fVG-u3mrpNIhASQF2kTcdUe4dZQ785YGzDGhDCH5wFBkPRGAmfYlNUlgU3aNDuaBIncCMajQzR0LOowtJJRLSlXRSF91l7P7LnKGNIS-EpQbXACbtMyiWvSSmMFoMve6d_Yq7hQf4QOuUz6jpKOaRDCdfe2jRH5ZGPBAqWWYTR4aVvHZx-ycwkTnGzS8Vyn4kBS5H9ONO-LhE7DZKhb3JvoQlz_cqd76Y2QFphqZnEJgl8e8Y4IFwqHtDaOfBQsGdrRBgXE80HVIJmHrzGrqOLklj8-B5TdEfC3I" + }, + "cost": 262144, + "subtypes": [], + "fingerprintContents": "3082020480820200BBB0A1A314FF6A2FC79AE06F610DC8D4421C933ED0C4354E6AEAD91EF947EA4F8F632B2E2F78B8A07A78C3324895C7CB0916EB334C10090E5EDB9E0295ED2FF1DEAFD1F49F54412E43EDE2CB06CFFC395303309A4CE3EAC2341D9AF3188337EEBABD3D4A4AF8F43E157D6F02F9D1F24A42777049C930AA233FED5C63B07F725CDE6BB24404FCBFC0B87247EACB7DB044785BA66EDE8E792112470150401E0A8471BDE36F2D5ECB960F571BA17DAF381D8378DEC21E1012E4B376C9E6C46BB67D68EEF12BA9A15967F486D8BC91B3E2B06FA5FCA69B752426AF029CB149EA586DED851EBA160876ACD85F062271FAD73D15F5F0F022E261309226BEE3567AD052F9746CA8BFACF0D4F41730085C097A02028301D92A0C545C0397472C2EEE5B61222025D63470EE681CE3252747CE9CA23F19E66F2F6386E6AD13911D7ADACD38CE5CA8FF2C2D99ABB0F5C3BA847509613E6632A12CE6EF78DA4C820E90834053003D1197F6A57B0100FEE152C84C8B1B33BB96571988780FAFBD697CF8370A99DA8FAAF75687D951CC6533C78B8E1CE2E1D5CEB9A11629201AF437475C94027FA52614B4300B77DCF180AC49CAA340168F3262FD1EE8B13802CEA35754B423B833FA14C5DD0C476DDE5D5E7BF7374D61F248C3BAB91CB0550BD1CBEF70507EE8DB1CF399307E228D4F4592A66C58573CFECC63966806FAF88109CCB09923EA5B", + "fulfillment": "A382040880820200BBB0A1A314FF6A2FC79AE06F610DC8D4421C933ED0C4354E6AEAD91EF947EA4F8F632B2E2F78B8A07A78C3324895C7CB0916EB334C10090E5EDB9E0295ED2FF1DEAFD1F49F54412E43EDE2CB06CFFC395303309A4CE3EAC2341D9AF3188337EEBABD3D4A4AF8F43E157D6F02F9D1F24A42777049C930AA233FED5C63B07F725CDE6BB24404FCBFC0B87247EACB7DB044785BA66EDE8E792112470150401E0A8471BDE36F2D5ECB960F571BA17DAF381D8378DEC21E1012E4B376C9E6C46BB67D68EEF12BA9A15967F486D8BC91B3E2B06FA5FCA69B752426AF029CB149EA586DED851EBA160876ACD85F062271FAD73D15F5F0F022E261309226BEE3567AD052F9746CA8BFACF0D4F41730085C097A02028301D92A0C545C0397472C2EEE5B61222025D63470EE681CE3252747CE9CA23F19E66F2F6386E6AD13911D7ADACD38CE5CA8FF2C2D99ABB0F5C3BA847509613E6632A12CE6EF78DA4C820E90834053003D1197F6A57B0100FEE152C84C8B1B33BB96571988780FAFBD697CF8370A99DA8FAAF75687D951CC6533C78B8E1CE2E1D5CEB9A11629201AF437475C94027FA52614B4300B77DCF180AC49CAA340168F3262FD1EE8B13802CEA35754B423B833FA14C5DD0C476DDE5D5E7BF7374D61F248C3BAB91CB0550BD1CBEF70507EE8DB1CF399307E228D4F4592A66C58573CFECC63966806FAF88109CCB09923EA5B8182020041200E42961EEA460C8276F239AB66B76F8F2869EACCC5F9E9945C0ABC63B1430656F3DA2D217A43327EE8CE1127D14A85D74AF412FE9370345BA6B44003D771AEDD2BA0FC250627FDF61631AFD64E9BEE714B1BAFB69F901BEEB6F959B16A54B328A9A674C883CAFC4FC2F7B0476DBCAA8D9BFD47F734E34736BF66E973B315C2ABF4727B062CA3C402936EB50849E1815DD1604A604DEFA668CFE823B008BF8F7BF57CEB1B41E518FF53AE911EF9880571B3D1742341D60E3CB2BEB93EB5F178F8EF7BA0C6F2290B9955D83D60F943D644571EC8D5F064D95F1DA1E759D6920D84A54CBC49783640A7B0CF3D028E627EC7AD25A915F6D8C24B2E0991528A02C5BEF0106C18B3F39C599956EB7A27B337313DCF93E75867606A4AC5A1AB6F9BB444DC1DAD1F546FAEDE6AE934884049017691371D51EE1D650EFCE581B30C6843087E7014190F4460267D894D525814DDA343B9A0489DC08C6A34334742CEA30B492512D295745217DD65ECFECB9CA18D212F84A506D70026ED332896BD24A6305A0CBDEE9DFD8ABB8507F840EB94CFA8E928E6910C275F7B68D11F96463C102A596613478695BC7671FB27309139C6CD2F15CA7E24052E47F4E34EF8B844EC364A85BDC9BE8425CFF72A77BE98D9016986A667109825F1EF18E08170A87B4368E7C142C19DAD10605C4F341D5209987AF31ABA8E2E4963F3E0794DD11F0B72", + "conditionBinary": "A32780204DD2EA7F85B3EACB8F19058E8360955C32E74C124392A1F44660739709C539C38103040000", + "conditionUri": "ni:///sha-256;TdLqf4Wz6suPGQWOg2CVXDLnTBJDkqH0RmBzlwnFOcM?fpt=rsa-sha-256&cost=262144", + "message": "616161" +} \ No newline at end of file diff --git a/src/cryptoconditions/tests/vectors/0015_test-basic-ed25519.json b/src/cryptoconditions/tests/vectors/0015_test-basic-ed25519.json new file mode 100644 index 000000000..89247eb1b --- /dev/null +++ b/src/cryptoconditions/tests/vectors/0015_test-basic-ed25519.json @@ -0,0 +1,14 @@ +{ + "json": { + "type": "ed25519-sha-256", + "publicKey": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo", + "signature": "UGoepoMY5i1AY12tBD4Zh-vCbltcRAb3vfhacziPv-XCRaxJ9HcOvHh3CCcKpqh2n-_okw_Q6h7mSzFAfXaVCQ" + }, + "cost": 131072, + "subtypes": [], + "fingerprintContents": "30228020D75A980182B10AB7D54BFED3C964073A0EE172F3DAA62325AF021A68F707511A", + "fulfillment": "A4648020D75A980182B10AB7D54BFED3C964073A0EE172F3DAA62325AF021A68F707511A8140506A1EA68318E62D40635DAD043E1987EBC26E5B5C4406F7BDF85A73388FBFE5C245AC49F4770EBC787708270AA6A8769FEFE8930FD0EA1EE64B31407D769509", + "conditionBinary": "A4278020799239ABA8FC4FF7EABFBC4C44E69E8BDFED993324E12ED64792ABE289CF1D5F8103020000", + "conditionUri": "ni:///sha-256;eZI5q6j8T_fqv7xMROaei9_tmTMk4S7WR5Kr4onPHV8?fpt=ed25519-sha-256&cost=131072", + "message": "616161" +} \ No newline at end of file diff --git a/src/cryptoconditions/tests/vectors/0016_test-advanced-notarized-receipt.json b/src/cryptoconditions/tests/vectors/0016_test-advanced-notarized-receipt.json new file mode 100644 index 000000000..f1dc75bf8 --- /dev/null +++ b/src/cryptoconditions/tests/vectors/0016_test-advanced-notarized-receipt.json @@ -0,0 +1,33 @@ +{ + "json": { + "type": "threshold-sha-256", + "threshold": 2, + "subfulfillments": [ + { + "type": "prefix-sha-256", + "maxMessageLength": 0, + "prefix": "aHR0cHM6Ly9ub3RhcnkuZXhhbXBsZS9jYXNlcy82NTdjMTJkYS04ZGNhLTQzYjAtOTdjYS04ZWU4YzM4YWI5Zjcvc3RhdGUvZXhlY3V0ZWQ", + "subfulfillment": { + "type": "ed25519-sha-256", + "publicKey": "LlMeiL_oxBn5Ya2ckB3ivdjnoOcUhFUFnonreZhrJSQ", + "signature": "5f3bvsLo21m8tqaA5KcFb91GUAtOmaNxnyVzUDahSSg-KHzt7c2eWlDNl2q0EfhP9Wmqveb24M5qC90MSoJGCA" + } + }, + { + "type": "preimage-sha-256", + "preimage": "aHR0cHM6Ly9ub3RhcnkuZXhhbXBsZS9jYXNlcy82NTdjMTJkYS04ZGNhLTQzYjAtOTdjYS04ZWU4YzM4YWI5Zjcvc3RhdGUvZXhlY3V0ZWQ" + } + ] + }, + "cost": 134304, + "subtypes": [ + "ed25519-sha-256", + "prefix-sha-256", + "preimage-sha-256" + ], + "fingerprintContents": "3059800102A154A02580200B4AC3A1E0932CB71B74309FAD7D15DF51BD4D1359ED59FF7C917B35DF24464A810150A12B80203F94525555CF4C5234BF77CB108501D97B9D8A28D1E7A3A7FE8D3D7F031FDEBD810302045082020308", + "fulfillment": "A282011AA0820114A052805068747470733A2F2F6E6F746172792E6578616D706C652F63617365732F36353763313264612D386463612D343362302D393763612D3865653863333861623966372F73746174652F6578656375746564A181BD805068747470733A2F2F6E6F746172792E6578616D706C652F63617365732F36353763313264612D386463612D343362302D393763612D3865653863333861623966372F73746174652F6578656375746564810100A266A46480202E531E88BFE8C419F961AD9C901DE2BDD8E7A0E7148455059E89EB79986B25248140E5FDDBBEC2E8DB59BCB6A680E4A7056FDD46500B4E99A3719F25735036A149283E287CEDEDCD9E5A50CD976AB411F84FF569AABDE6F6E0CE6A0BDD0C4A824608A100", + "conditionBinary": "A22B802009E391004628725E88F8557E954FB2A0EAE2B7C151C47DF3C4AF22F8C16988F98103020CA0820203C8", + "conditionUri": "ni:///sha-256;CeORAEYocl6I-FV-lU-yoOrit8FRxH3zxK8i-MFpiPk?fpt=threshold-sha-256&cost=134304&subtypes=preimage-sha-256,prefix-sha-256,ed25519-sha-256", + "message": "" +} diff --git a/src/cryptoconditions/tests/vectors/0017_test-advanced-notarized-receipt-multiple-notaries.json b/src/cryptoconditions/tests/vectors/0017_test-advanced-notarized-receipt-multiple-notaries.json new file mode 100644 index 000000000..a8e98bc20 --- /dev/null +++ b/src/cryptoconditions/tests/vectors/0017_test-advanced-notarized-receipt-multiple-notaries.json @@ -0,0 +1,74 @@ +{ + "json": { + "type": "threshold-sha-256", + "threshold": 2, + "subfulfillments": [ + { + "type": "prefix-sha-256", + "maxMessageLength": 0, + "prefix": "Y2FzZXMvNjU3YzEyZGEtOGRjYS00M2IwLTk3Y2EtOGVlOGMzOGFiOWY3L3N0YXRlL2V4ZWN1dGVk", + "subfulfillment": { + "type": "threshold-sha-256", + "threshold": 3, + "subfulfillments": [ + { + "type": "prefix-sha-256", + "maxMessageLength": 1025, + "prefix": "aHR0cHM6Ly9ub3Rhcnk0LmV4YW1wbGUv", + "subfulfillment": { + "type": "ed25519-sha-256", + "publicKey": "Rkvo5cq-MB4FMv5iIUjPy8zxG_MXop9cyHg5xpUf6pg", + "signature": "rlayC5_mc7O1szd9hCV8kIVronrH_IYj89BwVubxNmV2CacPp9ASs8UqqLrQPtxIKp7kA-aA5IPjr1mlxK05BA" + } + }, + { + "type": "prefix-sha-256", + "maxMessageLength": 1024, + "prefix": "aHR0cHM6Ly9ub3RhcnkxLmV4YW1wbGUv", + "subfulfillment": { + "type": "ed25519-sha-256", + "publicKey": "LlMeiL_oxBn5Ya2ckB3ivdjnoOcUhFUFnonreZhrJSQ", + "signature": "hzAaGAj3PCA_DpyBBvEwcQiB2s2sgHwQ00m3mCDcs0B8d7nSPbQoJ2QL3EE4P9xOynYZwXA36HA3pcfPM4F6Dg" + } + }, + { + "type": "prefix-sha-256", + "maxMessageLength": 1024, + "prefix": "aHR0cHM6Ly9ub3RhcnkyLmV4YW1wbGUv", + "subfulfillment": { + "type": "ed25519-sha-256", + "publicKey": "WQI-doqchYdsYeuqo07BjmSFf6dmksVamWNfm4jlr5A", + "signature": "rPnug4hbpY9ixCtImejOqRWpGS90iMFZLOlZVgtS-Ho3kOA208aVS4dVQUjRMcy682nGimajE3_o-kNooWWgCg" + } + }, + { + "type": "prefix-sha-256", + "maxMessageLength": 1024, + "prefix": "aHR0cHM6Ly9ub3RhcnkzLmV4YW1wbGUv", + "subfulfillment": { + "type": "ed25519-sha-256", + "publicKey": "mpisbb_wkOluONgfBUd9-Gs7uw7_wxG8e0LNrJnWvdk", + "signature": "l6MrDGHOFRA2ytNZacn5XrVEZepdYpupZav4pqkX8Q3RSr5V0zBUQ45oyRWmtnwd34oMFtLYAfjQuoXv7pu_Dw" + } + } + ] + } + }, + { + "type": "preimage-sha-256", + "preimage": "aHR0cHM6Ly9ub3RhcnkuZXhhbXBsZS9jYXNlcy82NTdjMTJkYS04ZGNhLTQzYjAtOTdjYS04ZWU4YzM4YWI5Zjcvc3RhdGUvZXhlY3V0ZWQ" + } + ] + }, + "cost": 406738, + "subtypes": [ + "ed25519-sha-256", + "prefix-sha-256", + "preimage-sha-256" + ], + "fingerprintContents": "3059800102A154A02580200B4AC3A1E0932CB71B74309FAD7D15DF51BD4D1359ED59FF7C917B35DF24464A810150A12B8020062F2C1BDD08661FE7FEFAC20E02DA8B0184FCD36F6C6C54C53CC28D2E54DD118103062C8282020328", + "fulfillment": "A2820272A082026CA052805068747470733A2F2F6E6F746172792E6578616D706C652F63617365732F36353763313264612D386463612D343362302D393763612D3865653863333861623966372F73746174652F6578656375746564A1820214803963617365732F36353763313264612D386463612D343362302D393763612D3865653863333861623966372F73746174652F6578656375746564810100A28201D2A28201CEA082019BA18186801868747470733A2F2F6E6F74617279312E6578616D706C652F81020400A266A46480202E531E88BFE8C419F961AD9C901DE2BDD8E7A0E7148455059E89EB79986B2524814087301A1808F73C203F0E9C8106F130710881DACDAC807C10D349B79820DCB3407C77B9D23DB42827640BDC41383FDC4ECA7619C17037E87037A5C7CF33817A0EA18186801868747470733A2F2F6E6F74617279322E6578616D706C652F81020400A266A464802059023E768A9C85876C61EBAAA34EC18E64857FA76692C55A99635F9B88E5AF908140ACF9EE83885BA58F62C42B4899E8CEA915A9192F7488C1592CE959560B52F87A3790E036D3C6954B87554148D131CCBAF369C68A66A3137FE8FA4368A165A00AA18186801868747470733A2F2F6E6F74617279332E6578616D706C652F81020400A266A46480209A98AC6DBFF090E96E38D81F05477DF86B3BBB0EFFC311BC7B42CDAC99D6BDD9814097A32B0C61CE151036CAD35969C9F95EB54465EA5D629BA965ABF8A6A917F10DD14ABE55D33054438E68C915A6B67C1DDF8A0C16D2D801F8D0BA85EFEE9BBF0FA12DA12B8020EE0BC02F977C264B6C306ED1B168FEB4FD600950AD21750CE8A86ECBD4603538810302081982020308A100", + "conditionBinary": "A22B8020424A704949529267B621B3D79119D729B2382CED8B296C3C028FA97D350F6D0781030634D2820203C8", + "conditionUri": "ni:///sha-256;QkpwSUlSkme2IbPXkRnXKbI4LO2LKWw8Ao-pfTUPbQc?fpt=threshold-sha-256&cost=406738&subtypes=preimage-sha-256,prefix-sha-256,ed25519-sha-256", + "message": "" +} diff --git a/src/cryptoconditions/tests/vectors/1000_test-minimal-eval.json b/src/cryptoconditions/tests/vectors/1000_test-minimal-eval.json new file mode 100644 index 000000000..74e52beee --- /dev/null +++ b/src/cryptoconditions/tests/vectors/1000_test-minimal-eval.json @@ -0,0 +1,13 @@ +{ + "json": { + "type": "eval-sha-256", + "code": "VEVTVAE" + }, + "cost": 131072, + "subtypes": [], + "fingerprintContents": "", + "fulfillment": "AF0780055445535401", + "conditionBinary": "AF278020FD9DA5ADD8CF3164C4F46EF3B8B4925001F414718A13CEDEDD27A27CA93D5A238103100000", + "conditionUri": "ni:///sha-256;_Z2lrdjPMWTE9G7zuLSSUAH0FHGKE87e3SeifKk9WiM?fpt=eval-sha-256&cost=1048576", + "message": "" +} diff --git a/src/cryptoconditions/tests/custom-vectors/1001_test-minimal-secp256k1.json b/src/cryptoconditions/tests/vectors/1001_test-minimal-secp256k1.json similarity index 71% rename from src/cryptoconditions/tests/custom-vectors/1001_test-minimal-secp256k1.json rename to src/cryptoconditions/tests/vectors/1001_test-minimal-secp256k1.json index d34de80fa..a85b29d91 100644 --- a/src/cryptoconditions/tests/custom-vectors/1001_test-minimal-secp256k1.json +++ b/src/cryptoconditions/tests/vectors/1001_test-minimal-secp256k1.json @@ -1,8 +1,8 @@ { "json": { "type": "secp256k1-sha-256", - "publicKey": "AtXZaTBVNawpp3B5wR1PDdQGYc-W4E6XSl6NfjdO4iWq", - "signature": "nC1v8580C7r2XohL3_rnQ2p7dWiDnFuhF_poGCRfudo83sfP1NPfcZG9siY4_Ybz2aO4yyV_z5tU0JMcTQGV0w" + "publicKey": "02D5D969305535AC29A77079C11D4F0DD40661CF96E04E974A5E8D7E374EE225AA", + "signature": "9C2D6FF39F340BBAF65E884BDFFAE7436A7B7568839C5BA117FA6818245FB9DA3CDEC7CFD4D3DF7191BDB22638FD86F3D9A3B8CB257FCF9B54D0931C4D0195D3" }, "cost": 131072, "subtypes": [], diff --git a/src/test-komodo/test_cryptoconditions.cpp b/src/test-komodo/test_cryptoconditions.cpp index c9ffde955..6d7ac67c8 100644 --- a/src/test-komodo/test_cryptoconditions.cpp +++ b/src/test-komodo/test_cryptoconditions.cpp @@ -63,7 +63,7 @@ TEST_F(CCTest, testMayAcceptCryptoCondition) { "type": "threshold-sha-256", "threshold": 2, "subfulfillments": [ - { "type": "secp256k1-sha-256", "publicKey": "AgWorQwdvFFfFJrzd5gaq1i4Nq8AjU16shvXb6+AVQtH" } + { "type": "secp256k1-sha-256", "publicKey": "0205a8ad0c1dbc515f149af377981aab58b836af008d4d7ab21bd76faf80550b47" } ] })!!"); ASSERT_TRUE(CCPubKey(cond).MayAcceptCryptoCondition()); @@ -75,7 +75,7 @@ TEST_F(CCTest, testMayAcceptCryptoCondition) "prefix": "abc", "maxMessageLength": 10, "subfulfillment": - { "type": "secp256k1-sha-256", "publicKey": "AgWorQwdvFFfFJrzd5gaq1i4Nq8AjU16shvXb6+AVQtH" } + { "type": "secp256k1-sha-256", "publicKey": "0205a8ad0c1dbc515f149af377981aab58b836af008d4d7ab21bd76faf80550b47" } })!!"); ASSERT_FALSE(CCPubKey(cond).MayAcceptCryptoCondition()); @@ -108,9 +108,10 @@ TEST_F(CCTest, testVerifyCryptoCondition) }; // ok + cond = CCNewSecp256k1(notaryKey.GetPubKey()); CCFromJson(cond, R"!!({ "type": "secp256k1-sha-256", - "publicKey": "AgWorQwdvFFfFJrzd5gaq1i4Nq8AjU16shvXb6+AVQtH" + "publicKey": "0205a8ad0c1dbc515f149af377981aab58b836af008d4d7ab21bd76faf80550b47" })!!"); CCSign(mtxTo, cond); ASSERT_TRUE(Verify(cond)); @@ -122,7 +123,7 @@ TEST_F(CCTest, testVerifyCryptoCondition) "threshold": 1, "subfulfillments": [ { "type": "preimage-sha-256", "preimage": "" }, - { "type": "secp256k1-sha-256", "publicKey": "AgWorQwdvFFfFJrzd5gaq1i4Nq8AjU16shvXb6+AVQtH" } + { "type": "secp256k1-sha-256", "publicKey": "0205a8ad0c1dbc515f149af377981aab58b836af008d4d7ab21bd76faf80550b47" } ] })!!"); cond->threshold = 2; @@ -196,7 +197,7 @@ TEST_F(CCTest, testCryptoConditionsDisabled) // ok CCFromJson(cond, R"!!({ "type": "secp256k1-sha-256", - "publicKey": "AgWorQwdvFFfFJrzd5gaq1i4Nq8AjU16shvXb6+AVQtH" + "publicKey": "0205a8ad0c1dbc515f149af377981aab58b836af008d4d7ab21bd76faf80550b47" })!!"); CCSign(mtxTo, cond); ASSERT_TRUE(Verify(cond)); From 7214ca0730df0a4854dc6620497c83ecb38ed532 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 8 Apr 2018 13:39:53 +0300 Subject: [PATCH 147/339] Test --- src/komodo_events.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_events.h b/src/komodo_events.h index 315a78686..7e9dfa2df 100644 --- a/src/komodo_events.h +++ b/src/komodo_events.h @@ -40,7 +40,7 @@ struct komodo_event *komodo_eventadd(struct komodo_state *sp,int32_t height,char void komodo_eventadd_notarized(struct komodo_state *sp,char *symbol,int32_t height,char *dest,uint256 notarized_hash,uint256 notarized_desttxid,int32_t notarizedheight,uint256 MoM,int32_t MoMdepth) { struct komodo_event_notarized N; - if ( komodo_verifynotarization(symbol,dest,height,notarizedheight,notarized_hash,notarized_desttxid) != 0 ) + if ( 0 && komodo_verifynotarization(symbol,dest,height,notarizedheight,notarized_hash,notarized_desttxid) != 0 ) { if ( height > 50000 || ASSETCHAINS_SYMBOL[0] != 0 ) printf("[%s] error validating notarization ht.%d notarized_height.%d, if on a pruned %s node this can be ignored\n",ASSETCHAINS_SYMBOL,height,notarizedheight,dest); From 9caa00ee19efbfcd6626d63167cdcc228de7515a Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 8 Apr 2018 13:48:29 +0300 Subject: [PATCH 148/339] Test --- src/fiat/bntn | 0 src/komodo_events.h | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) mode change 100644 => 100755 src/fiat/bntn diff --git a/src/fiat/bntn b/src/fiat/bntn old mode 100644 new mode 100755 diff --git a/src/komodo_events.h b/src/komodo_events.h index 7e9dfa2df..897f3b7bd 100644 --- a/src/komodo_events.h +++ b/src/komodo_events.h @@ -40,12 +40,12 @@ struct komodo_event *komodo_eventadd(struct komodo_state *sp,int32_t height,char void komodo_eventadd_notarized(struct komodo_state *sp,char *symbol,int32_t height,char *dest,uint256 notarized_hash,uint256 notarized_desttxid,int32_t notarizedheight,uint256 MoM,int32_t MoMdepth) { struct komodo_event_notarized N; - if ( 0 && komodo_verifynotarization(symbol,dest,height,notarizedheight,notarized_hash,notarized_desttxid) != 0 ) + /*if ( komodo_verifynotarization(symbol,dest,height,notarizedheight,notarized_hash,notarized_desttxid) != 0 ) { if ( height > 50000 || ASSETCHAINS_SYMBOL[0] != 0 ) printf("[%s] error validating notarization ht.%d notarized_height.%d, if on a pruned %s node this can be ignored\n",ASSETCHAINS_SYMBOL,height,notarizedheight,dest); } - else + else*/ { if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 ) fprintf(stderr,"validated [%s] ht.%d notarized %d\n",ASSETCHAINS_SYMBOL,height,notarizedheight); From 605e77944e7542ae3780cafe6cc89939fcf6c211 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 8 Apr 2018 14:04:11 +0300 Subject: [PATCH 149/339] Test --- src/komodo_events.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_events.h b/src/komodo_events.h index 897f3b7bd..9b44cdd3e 100644 --- a/src/komodo_events.h +++ b/src/komodo_events.h @@ -40,12 +40,12 @@ struct komodo_event *komodo_eventadd(struct komodo_state *sp,int32_t height,char void komodo_eventadd_notarized(struct komodo_state *sp,char *symbol,int32_t height,char *dest,uint256 notarized_hash,uint256 notarized_desttxid,int32_t notarizedheight,uint256 MoM,int32_t MoMdepth) { struct komodo_event_notarized N; - /*if ( komodo_verifynotarization(symbol,dest,height,notarizedheight,notarized_hash,notarized_desttxid) != 0 ) + if ( NOTARY_PUBKEY33[0] == 0 || komodo_verifynotarization(symbol,dest,height,notarizedheight,notarized_hash,notarized_desttxid) != 0 ) { if ( height > 50000 || ASSETCHAINS_SYMBOL[0] != 0 ) printf("[%s] error validating notarization ht.%d notarized_height.%d, if on a pruned %s node this can be ignored\n",ASSETCHAINS_SYMBOL,height,notarizedheight,dest); } - else*/ + else { if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 ) fprintf(stderr,"validated [%s] ht.%d notarized %d\n",ASSETCHAINS_SYMBOL,height,notarizedheight); From 6a933d59d80282fed84a2545e757c7b87392d53e Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 8 Apr 2018 18:53:33 +0300 Subject: [PATCH 150/339] Test --- src/komodo.h | 23 ++++++++++++----------- src/komodo_events.h | 2 +- src/main.cpp | 2 +- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/komodo.h b/src/komodo.h index c387198f8..0ff04b529 100644 --- a/src/komodo.h +++ b/src/komodo.h @@ -508,7 +508,7 @@ void komodo_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numnotar int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scriptbuf,int32_t scriptlen,int32_t height,uint256 txhash,int32_t i,int32_t j,uint64_t *voutmaskp,int32_t *specialtxp,int32_t *notarizedheightp,uint64_t value,int32_t notarized,uint64_t signedmask,uint32_t timestamp) { static uint256 zero; static FILE *signedfp; - int32_t opretlen,nid,k,len = 0; uint256 kmdtxid,desttxid; uint8_t crypto777[33]; struct komodo_state *sp; char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; + int32_t opretlen,nid,k,len = 0; uint256 srchash,desttxid; uint8_t crypto777[33]; struct komodo_state *sp; char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; if ( (sp= komodo_stateptr(symbol,dest)) == 0 ) return(-1); if ( scriptlen == 35 && scriptbuf[0] == 33 && scriptbuf[34] == 0xac ) @@ -566,23 +566,24 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr printf("[%s] notarized.%d notarizedht.%d sp.Nht %d sp.ht %d opretlen.%d (%c %c %c)\n",ASSETCHAINS_SYMBOL,notarized,*notarizedheightp,sp->NOTARIZED_HEIGHT,sp->CURRENT_HEIGHT,opretlen,scriptbuf[len+32*2+4],scriptbuf[len+32*2+4+1],scriptbuf[len+32*2+4+2]); if ( j == 1 && opretlen >= 32*2+4 && strcmp(ASSETCHAINS_SYMBOL[0]==0?"KMD":ASSETCHAINS_SYMBOL,(char *)&scriptbuf[len+32*2+4]) == 0 ) { - len += iguana_rwbignum(0,&scriptbuf[len],32,(uint8_t *)&kmdtxid); + len += iguana_rwbignum(0,&scriptbuf[len],32,(uint8_t *)&srchash); len += iguana_rwnum(0,&scriptbuf[len],sizeof(*notarizedheightp),(uint8_t *)notarizedheightp); len += iguana_rwbignum(0,&scriptbuf[len],32,(uint8_t *)&desttxid); if ( strcmp("PIZZA",ASSETCHAINS_SYMBOL) == 0 && opretlen == 110 ) { notarized = 1; } - int32_t validated = 1; - /*if ( ASSETCHAINS_SYMBOL[0] != 0 ) - validated = 1; - else if ( height < sp->CURRENT_HEIGHT-64 || komodo_verifynotarization((char *)"KMD",(char *)"BTC",height,*notarizedheightp,kmdtxid,desttxid) == 0 ) - validated = 1;*/ + int32_t validated = 0; + CBlockIndex *pindex; + if ( (pindex= mapBlockIndex[srchash]) == 0 || pindex->nHeight != *notarizedheightp ) + { + fprintf(stderr,"FORK detected. notarized.%d %s no in this chain! REWIND to %d\n",*notarizedheightp,srchash.ToString().c_str(),sp->NOTARIZED_HEIGHT); + } else validated = 1; if ( notarized != 0 && *notarizedheightp > sp->NOTARIZED_HEIGHT && *notarizedheightp < height && validated != 0 ) { int32_t nameoffset = (int32_t)strlen(ASSETCHAINS_SYMBOL) + 1; sp->NOTARIZED_HEIGHT = *notarizedheightp; - sp->NOTARIZED_HASH = kmdtxid; + sp->NOTARIZED_HASH = srchash; sp->NOTARIZED_DESTTXID = desttxid; memset(&sp->MoM,0,sizeof(sp->MoM)); sp->MoMdepth = 0; @@ -603,7 +604,7 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr komodo_stateupdate(height,0,0,0,zero,0,0,0,0,0,0,0,0,0,0,sp->MoM,sp->MoMdepth); len += nameoffset; if ( ASSETCHAINS_SYMBOL[0] != 0 ) - printf("[%s] ht.%d NOTARIZED.%d %s.%s %sTXID.%s lens.(%d %d) MoM.%s %d\n",ASSETCHAINS_SYMBOL,height,*notarizedheightp,ASSETCHAINS_SYMBOL[0]==0?"KMD":ASSETCHAINS_SYMBOL,kmdtxid.ToString().c_str(),ASSETCHAINS_SYMBOL[0]==0?"BTC":"KMD",desttxid.ToString().c_str(),opretlen,len,sp->MoM.ToString().c_str(),sp->MoMdepth); + printf("[%s] ht.%d NOTARIZED.%d %s.%s %sTXID.%s lens.(%d %d) MoM.%s %d\n",ASSETCHAINS_SYMBOL,height,*notarizedheightp,ASSETCHAINS_SYMBOL[0]==0?"KMD":ASSETCHAINS_SYMBOL,srchash.ToString().c_str(),ASSETCHAINS_SYMBOL[0]==0?"BTC":"KMD",desttxid.ToString().c_str(),opretlen,len,sp->MoM.ToString().c_str(),sp->MoMdepth); if ( ASSETCHAINS_SYMBOL[0] == 0 ) { if ( signedfp == 0 ) @@ -629,7 +630,7 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr } } } else //if ( height >= sp->CURRENT_HEIGHT-64 )//KOMODO_MAINNET_START ) - printf("validated.%d notarized.%d %llx reject ht.%d NOTARIZED.%d prev.%d %s.%s DESTTXID.%s (%s) len.%d opretlen.%d\n",validated,notarized,(long long)signedmask,height,*notarizedheightp,sp->NOTARIZED_HEIGHT,ASSETCHAINS_SYMBOL[0]==0?"KMD":ASSETCHAINS_SYMBOL,kmdtxid.ToString().c_str(),desttxid.ToString().c_str(),(char *)&scriptbuf[len],len,opretlen); + printf("validated.%d notarized.%d %llx reject ht.%d NOTARIZED.%d prev.%d %s.%s DESTTXID.%s (%s) len.%d opretlen.%d\n",validated,notarized,(long long)signedmask,height,*notarizedheightp,sp->NOTARIZED_HEIGHT,ASSETCHAINS_SYMBOL[0]==0?"KMD":ASSETCHAINS_SYMBOL,srchash.ToString().c_str(),desttxid.ToString().c_str(),(char *)&scriptbuf[len],len,opretlen); } else if ( i == 0 && j == 1 && opretlen == 149 ) { @@ -693,7 +694,7 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block) { static int32_t hwmheight; uint64_t signedmask,voutmask; char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; struct komodo_state *sp; - uint8_t scriptbuf[10001],pubkeys[64][33],rmd160[20],scriptPubKey[35]; uint256 kmdtxid,zero,btctxid,txhash; + uint8_t scriptbuf[10001],pubkeys[64][33],rmd160[20],scriptPubKey[35]; uint256 zero,btctxid,txhash; int32_t i,j,k,numnotaries,notarized,scriptlen,isratification,nid,numvalid,specialtx,notarizedheight,notaryid,len,numvouts,numvins,height,txn_count; memset(&zero,0,sizeof(zero)); komodo_init(pindex->nHeight); diff --git a/src/komodo_events.h b/src/komodo_events.h index 9b44cdd3e..4d9ff87dc 100644 --- a/src/komodo_events.h +++ b/src/komodo_events.h @@ -40,7 +40,7 @@ struct komodo_event *komodo_eventadd(struct komodo_state *sp,int32_t height,char void komodo_eventadd_notarized(struct komodo_state *sp,char *symbol,int32_t height,char *dest,uint256 notarized_hash,uint256 notarized_desttxid,int32_t notarizedheight,uint256 MoM,int32_t MoMdepth) { struct komodo_event_notarized N; - if ( NOTARY_PUBKEY33[0] == 0 || komodo_verifynotarization(symbol,dest,height,notarizedheight,notarized_hash,notarized_desttxid) != 0 ) + if ( NOTARY_PUBKEY33[0] != 0 && komodo_verifynotarization(symbol,dest,height,notarizedheight,notarized_hash,notarized_desttxid) != 0 ) { if ( height > 50000 || ASSETCHAINS_SYMBOL[0] != 0 ) printf("[%s] error validating notarization ht.%d notarized_height.%d, if on a pruned %s node this can be ignored\n",ASSETCHAINS_SYMBOL,height,notarizedheight,dest); diff --git a/src/main.cpp b/src/main.cpp index 929589df9..4bfa9f122 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3089,7 +3089,7 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo } } fprintf(stderr,"reached rewind.%d, best to do: ./komodo-cli stop\n",KOMODO_REWIND); - sleep(60); + sleep(300); KOMODO_REWIND = 0; return(true); } From dbbdf7de87a1e5d1a9e7a3c76df9d0e0f317300a Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 8 Apr 2018 18:57:56 +0300 Subject: [PATCH 151/339] Test --- src/komodo.h | 2 ++ src/main.cpp | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/komodo.h b/src/komodo.h index 0ff04b529..c9ee4142c 100644 --- a/src/komodo.h +++ b/src/komodo.h @@ -578,6 +578,8 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr if ( (pindex= mapBlockIndex[srchash]) == 0 || pindex->nHeight != *notarizedheightp ) { fprintf(stderr,"FORK detected. notarized.%d %s no in this chain! REWIND to %d\n",*notarizedheightp,srchash.ToString().c_str(),sp->NOTARIZED_HEIGHT); + if ( sp->NOTARIZED_HEIGHT > 0 ) + KOMODO_REWIND = sp->NOTARIZED_HEIGHT - 1; } else validated = 1; if ( notarized != 0 && *notarizedheightp > sp->NOTARIZED_HEIGHT && *notarizedheightp < height && validated != 0 ) { diff --git a/src/main.cpp b/src/main.cpp index 4bfa9f122..4482cf4c6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3079,9 +3079,10 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo } if ( KOMODO_REWIND != 0 ) { - fprintf(stderr,"rewind start ht.%d\n",chainActive.Tip()->nHeight); + fprintf(stderr,">>>>>>>>>>> rewind start ht.%d\n",chainActive.Tip()->nHeight); while ( KOMODO_REWIND > 0 && chainActive.Tip()->nHeight > KOMODO_REWIND ) { + fprintf(stderr,"%d ",(int32_t)chainActive.Tip()->nHeight); if ( !DisconnectTip(state) ) { InvalidateBlock(state,chainActive.Tip()); @@ -3089,7 +3090,7 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo } } fprintf(stderr,"reached rewind.%d, best to do: ./komodo-cli stop\n",KOMODO_REWIND); - sleep(300); + sleep(60); KOMODO_REWIND = 0; return(true); } From 91165f19e604d537712061b81aade2b742485bfc Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 8 Apr 2018 19:01:04 +0300 Subject: [PATCH 152/339] Test --- src/main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 4482cf4c6..9b736d3dd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3079,7 +3079,7 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo } if ( KOMODO_REWIND != 0 ) { - fprintf(stderr,">>>>>>>>>>> rewind start ht.%d\n",chainActive.Tip()->nHeight); + fprintf(stderr,">>>>>>>>>>> rewind start ht.%d -> KOMODO_REWIND.%d\n",chainActive.Tip()->nHeight,KOMODO_REWIND); while ( KOMODO_REWIND > 0 && chainActive.Tip()->nHeight > KOMODO_REWIND ) { fprintf(stderr,"%d ",(int32_t)chainActive.Tip()->nHeight); @@ -3091,6 +3091,7 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo } fprintf(stderr,"reached rewind.%d, best to do: ./komodo-cli stop\n",KOMODO_REWIND); sleep(60); + fprintf(stderr,"resuming normal operations\n"); KOMODO_REWIND = 0; return(true); } From c5803d26ecb02d8a27b17c1dbe531af54b3896f7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 8 Apr 2018 19:11:10 +0300 Subject: [PATCH 153/339] Rewind to min ht --- src/komodo.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/komodo.h b/src/komodo.h index c9ee4142c..2d510acae 100644 --- a/src/komodo.h +++ b/src/komodo.h @@ -578,8 +578,10 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr if ( (pindex= mapBlockIndex[srchash]) == 0 || pindex->nHeight != *notarizedheightp ) { fprintf(stderr,"FORK detected. notarized.%d %s no in this chain! REWIND to %d\n",*notarizedheightp,srchash.ToString().c_str(),sp->NOTARIZED_HEIGHT); - if ( sp->NOTARIZED_HEIGHT > 0 ) + if ( sp->NOTARIZED_HEIGHT > 0 && sp->NOTARIZED_HEIGHT < *notarized_heightp ) KOMODO_REWIND = sp->NOTARIZED_HEIGHT - 1; + else if ( *notarized_heightp > 101 ) + KOMODO_REWIND = *notarized_heightp - 101; } else validated = 1; if ( notarized != 0 && *notarizedheightp > sp->NOTARIZED_HEIGHT && *notarizedheightp < height && validated != 0 ) { From 986ec226cd7f1df14313a0afdb1795a5243229e4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 8 Apr 2018 19:22:47 +0300 Subject: [PATCH 154/339] Print --- src/komodo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo.h b/src/komodo.h index 2d510acae..efded0840 100644 --- a/src/komodo.h +++ b/src/komodo.h @@ -577,7 +577,7 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr CBlockIndex *pindex; if ( (pindex= mapBlockIndex[srchash]) == 0 || pindex->nHeight != *notarizedheightp ) { - fprintf(stderr,"FORK detected. notarized.%d %s no in this chain! REWIND to %d\n",*notarizedheightp,srchash.ToString().c_str(),sp->NOTARIZED_HEIGHT); + fprintf(stderr,"FORK detected. notarized.%d %s not in this chain! REWIND to %d\n",*notarizedheightp,srchash.ToString().c_str(),sp->NOTARIZED_HEIGHT); if ( sp->NOTARIZED_HEIGHT > 0 && sp->NOTARIZED_HEIGHT < *notarized_heightp ) KOMODO_REWIND = sp->NOTARIZED_HEIGHT - 1; else if ( *notarized_heightp > 101 ) From 6c93ad75b277bd504a027917ba59038a63a9feb9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 8 Apr 2018 19:40:37 +0300 Subject: [PATCH 155/339] Test --- src/komodo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo.h b/src/komodo.h index efded0840..985e28a21 100644 --- a/src/komodo.h +++ b/src/komodo.h @@ -578,7 +578,7 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr if ( (pindex= mapBlockIndex[srchash]) == 0 || pindex->nHeight != *notarizedheightp ) { fprintf(stderr,"FORK detected. notarized.%d %s not in this chain! REWIND to %d\n",*notarizedheightp,srchash.ToString().c_str(),sp->NOTARIZED_HEIGHT); - if ( sp->NOTARIZED_HEIGHT > 0 && sp->NOTARIZED_HEIGHT < *notarized_heightp ) + if ( sp->NOTARIZED_HEIGHT > 0 && sp->NOTARIZED_HEIGHT < *notarizedheightp ) KOMODO_REWIND = sp->NOTARIZED_HEIGHT - 1; else if ( *notarized_heightp > 101 ) KOMODO_REWIND = *notarized_heightp - 101; From 83de8f955e0cdbc6aadb0805497a37dd72db43e3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 8 Apr 2018 19:41:18 +0300 Subject: [PATCH 156/339] Test --- src/komodo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo.h b/src/komodo.h index 985e28a21..092c572ac 100644 --- a/src/komodo.h +++ b/src/komodo.h @@ -580,7 +580,7 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr fprintf(stderr,"FORK detected. notarized.%d %s not in this chain! REWIND to %d\n",*notarizedheightp,srchash.ToString().c_str(),sp->NOTARIZED_HEIGHT); if ( sp->NOTARIZED_HEIGHT > 0 && sp->NOTARIZED_HEIGHT < *notarizedheightp ) KOMODO_REWIND = sp->NOTARIZED_HEIGHT - 1; - else if ( *notarized_heightp > 101 ) + else if ( *notarizedheightp > 101 ) KOMODO_REWIND = *notarized_heightp - 101; } else validated = 1; if ( notarized != 0 && *notarizedheightp > sp->NOTARIZED_HEIGHT && *notarizedheightp < height && validated != 0 ) From 34dd6cc4fdd7d0398e49fce65b3ca9df2762796d Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 8 Apr 2018 19:41:51 +0300 Subject: [PATCH 157/339] Test --- src/komodo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo.h b/src/komodo.h index 092c572ac..99bd008d8 100644 --- a/src/komodo.h +++ b/src/komodo.h @@ -581,7 +581,7 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr if ( sp->NOTARIZED_HEIGHT > 0 && sp->NOTARIZED_HEIGHT < *notarizedheightp ) KOMODO_REWIND = sp->NOTARIZED_HEIGHT - 1; else if ( *notarizedheightp > 101 ) - KOMODO_REWIND = *notarized_heightp - 101; + KOMODO_REWIND = *notarizedheightp - 101; } else validated = 1; if ( notarized != 0 && *notarizedheightp > sp->NOTARIZED_HEIGHT && *notarizedheightp < height && validated != 0 ) { From 935e05222a7e5d3dab01cb58de6d365343450c0d Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 8 Apr 2018 19:48:35 +0300 Subject: [PATCH 158/339] Test --- src/komodo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo.h b/src/komodo.h index 99bd008d8..2979a49b1 100644 --- a/src/komodo.h +++ b/src/komodo.h @@ -575,7 +575,7 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr } int32_t validated = 0; CBlockIndex *pindex; - if ( (pindex= mapBlockIndex[srchash]) == 0 || pindex->nHeight != *notarizedheightp ) + if ( IsInitialBlockDownload() == 0 && (pindex= mapBlockIndex[srchash]) == 0 || pindex->nHeight != *notarizedheightp ) { fprintf(stderr,"FORK detected. notarized.%d %s not in this chain! REWIND to %d\n",*notarizedheightp,srchash.ToString().c_str(),sp->NOTARIZED_HEIGHT); if ( sp->NOTARIZED_HEIGHT > 0 && sp->NOTARIZED_HEIGHT < *notarizedheightp ) From fd836de79b15c53064e543073e92049525c3399f Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 8 Apr 2018 19:59:29 +0300 Subject: [PATCH 159/339] Test --- src/komodo.h | 4 ++-- src/main.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/komodo.h b/src/komodo.h index 2979a49b1..8f24032d7 100644 --- a/src/komodo.h +++ b/src/komodo.h @@ -578,10 +578,10 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr if ( IsInitialBlockDownload() == 0 && (pindex= mapBlockIndex[srchash]) == 0 || pindex->nHeight != *notarizedheightp ) { fprintf(stderr,"FORK detected. notarized.%d %s not in this chain! REWIND to %d\n",*notarizedheightp,srchash.ToString().c_str(),sp->NOTARIZED_HEIGHT); - if ( sp->NOTARIZED_HEIGHT > 0 && sp->NOTARIZED_HEIGHT < *notarizedheightp ) + /*if ( sp->NOTARIZED_HEIGHT > 0 && sp->NOTARIZED_HEIGHT < *notarizedheightp ) KOMODO_REWIND = sp->NOTARIZED_HEIGHT - 1; else if ( *notarizedheightp > 101 ) - KOMODO_REWIND = *notarizedheightp - 101; + KOMODO_REWIND = *notarizedheightp - 101;*/ } else validated = 1; if ( notarized != 0 && *notarizedheightp > sp->NOTARIZED_HEIGHT && *notarizedheightp < height && validated != 0 ) { diff --git a/src/main.cpp b/src/main.cpp index 9b736d3dd..f69adbd50 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3089,7 +3089,7 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo break; } } - fprintf(stderr,"reached rewind.%d, best to do: ./komodo-cli stop\n",KOMODO_REWIND); + fprintf(stderr,"reached rewind.%d, best to do: ./komodo-cli -ac_name=%s stop\n",KOMODO_REWIND,ASSETCHAINS_SYMBOL); sleep(60); fprintf(stderr,"resuming normal operations\n"); KOMODO_REWIND = 0; From f4e0076aa0914ab6c83ca5ea1f7a6cd8be55aec9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 8 Apr 2018 20:07:56 +0300 Subject: [PATCH 160/339] Test --- src/komodo.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/komodo.h b/src/komodo.h index 8f24032d7..95b4a8478 100644 --- a/src/komodo.h +++ b/src/komodo.h @@ -575,13 +575,13 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr } int32_t validated = 0; CBlockIndex *pindex; - if ( IsInitialBlockDownload() == 0 && (pindex= mapBlockIndex[srchash]) == 0 || pindex->nHeight != *notarizedheightp ) + if ( IsInitialBlockDownload() == 0 && ((pindex= mapBlockIndex[srchash]) == 0 || pindex->nHeight != *notarizedheightp) ) { fprintf(stderr,"FORK detected. notarized.%d %s not in this chain! REWIND to %d\n",*notarizedheightp,srchash.ToString().c_str(),sp->NOTARIZED_HEIGHT); - /*if ( sp->NOTARIZED_HEIGHT > 0 && sp->NOTARIZED_HEIGHT < *notarizedheightp ) + if ( sp->NOTARIZED_HEIGHT > 0 && sp->NOTARIZED_HEIGHT < *notarizedheightp ) KOMODO_REWIND = sp->NOTARIZED_HEIGHT - 1; else if ( *notarizedheightp > 101 ) - KOMODO_REWIND = *notarizedheightp - 101;*/ + KOMODO_REWIND = *notarizedheightp - 101; } else validated = 1; if ( notarized != 0 && *notarizedheightp > sp->NOTARIZED_HEIGHT && *notarizedheightp < height && validated != 0 ) { From 11ed15a670c46c87bbd6eb3710b80b6be4388898 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 8 Apr 2018 21:34:49 +0300 Subject: [PATCH 161/339] Test --- src/komodo.h | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/komodo.h b/src/komodo.h index 95b4a8478..d0e1075be 100644 --- a/src/komodo.h +++ b/src/komodo.h @@ -577,11 +577,18 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr CBlockIndex *pindex; if ( IsInitialBlockDownload() == 0 && ((pindex= mapBlockIndex[srchash]) == 0 || pindex->nHeight != *notarizedheightp) ) { - fprintf(stderr,"FORK detected. notarized.%d %s not in this chain! REWIND to %d\n",*notarizedheightp,srchash.ToString().c_str(),sp->NOTARIZED_HEIGHT); + static int32_t last_rewind; int32_t rewindtarget; if ( sp->NOTARIZED_HEIGHT > 0 && sp->NOTARIZED_HEIGHT < *notarizedheightp ) - KOMODO_REWIND = sp->NOTARIZED_HEIGHT - 1; + rewindtarget = sp->NOTARIZED_HEIGHT - 1; else if ( *notarizedheightp > 101 ) - KOMODO_REWIND = *notarizedheightp - 101; + rewindtarget = *notarizedheightp - 101; + else rewindtarget = 0; + if ( rewindtarget != 0 && rewindtarget > KOMODO_REWIND && rewindtarget > last_rewind ) + { + last_rewind = rewindtarget; + KOMODO_REWIND = rewindtarget; + fprintf(stderr,"FORK detected. notarized.%d %s not in this chain! last notarization %d -> rewindtarget.%d\n",*notarizedheightp,srchash.ToString().c_str(),sp->NOTARIZED_HEIGHT,rewindtarget); + } } else validated = 1; if ( notarized != 0 && *notarizedheightp > sp->NOTARIZED_HEIGHT && *notarizedheightp < height && validated != 0 ) { From 8d787d2580a72813ab6d8fdef38e6ee35aee277b Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 8 Apr 2018 21:55:19 +0300 Subject: [PATCH 162/339] Test --- src/komodo.h | 2 +- src/main.cpp | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/komodo.h b/src/komodo.h index d0e1075be..95691f33d 100644 --- a/src/komodo.h +++ b/src/komodo.h @@ -640,7 +640,7 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr komodo_stateupdate(height,0,0,0,txhash,0,0,0,0,0,0,value,&scriptbuf[len],opretlen-len+4+3+(scriptbuf[1] == 0x4d),j,zero,0); } } - } else //if ( height >= sp->CURRENT_HEIGHT-64 )//KOMODO_MAINNET_START ) + } else if ( *notarizedheightp != sp->NOTARIZED_HEIGHT ) printf("validated.%d notarized.%d %llx reject ht.%d NOTARIZED.%d prev.%d %s.%s DESTTXID.%s (%s) len.%d opretlen.%d\n",validated,notarized,(long long)signedmask,height,*notarizedheightp,sp->NOTARIZED_HEIGHT,ASSETCHAINS_SYMBOL[0]==0?"KMD":ASSETCHAINS_SYMBOL,srchash.ToString().c_str(),desttxid.ToString().c_str(),(char *)&scriptbuf[len],len,opretlen); } else if ( i == 0 && j == 1 && opretlen == 149 ) diff --git a/src/main.cpp b/src/main.cpp index f69adbd50..6f4dd89fa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3610,8 +3610,14 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta { // Check that the block chain matches the known block chain up to a checkpoint if (!Checkpoints::CheckBlock(chainParams.Checkpoints(), nHeight, hash)) - return state.DoS(100, error("%s: rejected by checkpoint lock-in at %d", __func__, nHeight),REJECT_CHECKPOINT, "checkpoint mismatch"); - + { + CBlockIndex *heightblock = chainActive[nHeight]; + if ( heightblock != 0 && heightblock->GetBlockHash() == hash ) + { + //fprintf(stderr,"got a pre notarization block that matches height.%d\n",(int32_t)nHeight); + return true; + } return state.DoS(100, error("%s: rejected by checkpoint lock-in at %d", __func__, nHeight),REJECT_CHECKPOINT, "checkpoint mismatch"); + } // Don't accept any forks from the main chain prior to last checkpoint CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(chainParams.Checkpoints()); int32_t notarized_height; From 576f0b157f0350631b68fe1a9163b21a76d6066f Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 8 Apr 2018 21:56:37 +0300 Subject: [PATCH 163/339] Test --- src/komodo.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo.h b/src/komodo.h index 95691f33d..dbad75aa7 100644 --- a/src/komodo.h +++ b/src/komodo.h @@ -574,8 +574,8 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr notarized = 1; } int32_t validated = 0; - CBlockIndex *pindex; - if ( IsInitialBlockDownload() == 0 && ((pindex= mapBlockIndex[srchash]) == 0 || pindex->nHeight != *notarizedheightp) ) + CBlockIndex *pindex;//IsInitialBlockDownload() == 0 && + if ( ((pindex= mapBlockIndex[srchash]) == 0 || pindex->nHeight != *notarizedheightp) ) { static int32_t last_rewind; int32_t rewindtarget; if ( sp->NOTARIZED_HEIGHT > 0 && sp->NOTARIZED_HEIGHT < *notarizedheightp ) From 899aa3878532f56a6e3f8ff33cc5a3743ca5358a Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 8 Apr 2018 22:06:26 +0300 Subject: [PATCH 164/339] Test --- src/komodo.h | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/komodo.h b/src/komodo.h index dbad75aa7..aa358ab4e 100644 --- a/src/komodo.h +++ b/src/komodo.h @@ -573,11 +573,11 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr { notarized = 1; } - int32_t validated = 0; + static int32_t last_rewind; + int32_t rewindtarget,validated = 0; CBlockIndex *pindex;//IsInitialBlockDownload() == 0 && if ( ((pindex= mapBlockIndex[srchash]) == 0 || pindex->nHeight != *notarizedheightp) ) { - static int32_t last_rewind; int32_t rewindtarget; if ( sp->NOTARIZED_HEIGHT > 0 && sp->NOTARIZED_HEIGHT < *notarizedheightp ) rewindtarget = sp->NOTARIZED_HEIGHT - 1; else if ( *notarizedheightp > 101 ) @@ -585,11 +585,19 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr else rewindtarget = 0; if ( rewindtarget != 0 && rewindtarget > KOMODO_REWIND && rewindtarget > last_rewind ) { + if ( last_rewind != 0 ) + { + KOMODO_REWIND = rewindtarget; + fprintf(stderr,"%s FORK detected. notarized.%d %s not in this chain! last notarization %d -> rewindtarget.%d\n",ASSETCHAINS_SYMBOL,*notarizedheightp,srchash.ToString().c_str(),sp->NOTARIZED_HEIGHT,rewindtarget); + } last_rewind = rewindtarget; - KOMODO_REWIND = rewindtarget; - fprintf(stderr,"FORK detected. notarized.%d %s not in this chain! last notarization %d -> rewindtarget.%d\n",*notarizedheightp,srchash.ToString().c_str(),sp->NOTARIZED_HEIGHT,rewindtarget); } - } else validated = 1; + } + else + { + last_rewind = 0; + validated = 1; + } if ( notarized != 0 && *notarizedheightp > sp->NOTARIZED_HEIGHT && *notarizedheightp < height && validated != 0 ) { int32_t nameoffset = (int32_t)strlen(ASSETCHAINS_SYMBOL) + 1; From 79d54107a1caa69dfb6ceefb322664b3b7f685d9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 8 Apr 2018 22:12:14 +0300 Subject: [PATCH 165/339] Test --- src/komodo.h | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/komodo.h b/src/komodo.h index aa358ab4e..6a27ffb62 100644 --- a/src/komodo.h +++ b/src/komodo.h @@ -592,12 +592,7 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr } last_rewind = rewindtarget; } - } - else - { - last_rewind = 0; - validated = 1; - } + } else validated = 1; if ( notarized != 0 && *notarizedheightp > sp->NOTARIZED_HEIGHT && *notarizedheightp < height && validated != 0 ) { int32_t nameoffset = (int32_t)strlen(ASSETCHAINS_SYMBOL) + 1; From 6a11ba537be4dc6464b38d9a9e75e24de9a00f5b Mon Sep 17 00:00:00 2001 From: jl777 Date: Sun, 8 Apr 2018 22:25:29 +0300 Subject: [PATCH 166/339] Test --- src/komodo.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo.h b/src/komodo.h index 6a27ffb62..32fcce047 100644 --- a/src/komodo.h +++ b/src/komodo.h @@ -575,8 +575,8 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr } static int32_t last_rewind; int32_t rewindtarget,validated = 0; - CBlockIndex *pindex;//IsInitialBlockDownload() == 0 && - if ( ((pindex= mapBlockIndex[srchash]) == 0 || pindex->nHeight != *notarizedheightp) ) + CBlockIndex *pindex;// + if ( IsInitialBlockDownload() == 0 && ((pindex= mapBlockIndex[srchash]) == 0 || pindex->nHeight != *notarizedheightp) ) { if ( sp->NOTARIZED_HEIGHT > 0 && sp->NOTARIZED_HEIGHT < *notarizedheightp ) rewindtarget = sp->NOTARIZED_HEIGHT - 1; From 21965c3f7af9b75e340d804ef9cbeb665fae62e7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 14:26:07 +0300 Subject: [PATCH 167/339] Test --- src/wallet/rpcwallet.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 09b403f7f..c350e0e28 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2695,7 +2695,7 @@ int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex); int32_t komodo_staked(uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) { - set setAddress; int32_t nMinDepth = 1,nMaxDepth = 9999999; vector vecOutputs; + set setAddress; int32_t i,siglen=0,nMinDepth = 1,nMaxDepth = 9999999; vector vecOutputs; assert(pwalletMain != NULL); LOCK2(cs_main, pwalletMain->cs_wallet); *utxovaluep = 0; @@ -2754,8 +2754,21 @@ int32_t komodo_staked(uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,ui } fprintf(stderr,"(%s) %s/v%d nValue %.8f locktime.%u txheight.%d pindexht.%d\n",CBitcoinAddress(address).ToString().c_str(),out.tx->GetHash().GetHex().c_str(),out.i,(double)nValue/COIN,locktime,txheight,pindex->nHeight); } + bool signSuccess; SignatureData sigdata; uint8_t *ptr; + auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); + CTransaction txNewConst(txNew); + signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, 0, nValue, SIGHASH_ALL), out.tx->vout[out.i].scriptPubKey, sigdata, consensusBranchId); + if (!signSuccess) + fprintf(stderr,"failed to create signature\n"); + else + { + ptr = (uint8_t *)sigdata.data(); + siglen = sigdata.size(); + for (i=0; i Date: Mon, 9 Apr 2018 14:35:50 +0300 Subject: [PATCH 168/339] Test --- src/wallet/rpcwallet.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index c350e0e28..ef0088330 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2691,6 +2691,7 @@ UniValue listunspent(const UniValue& params, bool fHelp) return results; } +#include "script/sign.h" int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex); int32_t komodo_staked(uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) @@ -2754,8 +2755,18 @@ int32_t komodo_staked(uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,ui } fprintf(stderr,"(%s) %s/v%d nValue %.8f locktime.%u txheight.%d pindexht.%d\n",CBitcoinAddress(address).ToString().c_str(),out.tx->GetHash().GetHex().c_str(),out.i,(double)nValue/COIN,locktime,txheight,pindex->nHeight); } - bool signSuccess; SignatureData sigdata; uint8_t *ptr; + bool signSuccess; SignatureData sigdata; uint8_t *ptr; uint256 revtxid,utxotxid; auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); + CMutableTransaction txNew = CreateNewContextualCMutableTransaction(Params().GetConsensus(), chainActive.Height() + 1); + txNew.vin.resize(1); + txNew.vout.resize(1); + for (i=0; i<32; i++) + ((uint8_t *)&revtxid)[i] = ((uint8_t *)utxotxidp)[31 - i]; + txNew.vin[0].prevout.hash = revtxid; + txNew.vin[0].prevout.n = *utxovoutp; + txNew.vout[0].scriptPubKey = CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG; + txNew.vout[0].nValue = nValue - txfees; + txNew.nLockTime = (uint32_t)chainActive.Tip()->nTime + chainparams.GetConsensus().nPowTargetSpacing; // set to a time close to now CTransaction txNewConst(txNew); signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, 0, nValue, SIGHASH_ALL), out.tx->vout[out.i].scriptPubKey, sigdata, consensusBranchId); if (!signSuccess) From 969322e04240990be02ddabf710fd516bd56de19 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 14:36:59 +0300 Subject: [PATCH 169/339] Test --- src/wallet/rpcwallet.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index ef0088330..c9e9d0009 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2776,7 +2776,8 @@ int32_t komodo_staked(uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,ui ptr = (uint8_t *)sigdata.data(); siglen = sigdata.size(); for (i=0; i Date: Mon, 9 Apr 2018 14:37:43 +0300 Subject: [PATCH 170/339] Test --- src/wallet/rpcwallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index c9e9d0009..085d39fd0 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2773,7 +2773,7 @@ int32_t komodo_staked(uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,ui fprintf(stderr,"failed to create signature\n"); else { - ptr = (uint8_t *)sigdata.data(); + ptr = (uint8_t *)sigdata.scriptSig.data(); siglen = sigdata.size(); for (i=0; i Date: Mon, 9 Apr 2018 14:42:07 +0300 Subject: [PATCH 171/339] Test --- src/miner.cpp | 2 +- src/wallet/rpcwallet.cpp | 188 ++++++++++++++++++++------------------- 2 files changed, 97 insertions(+), 93 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 6f59771bf..bba4e62d3 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -405,7 +405,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) txStaked.vout[0].scriptPubKey = CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG; txStaked.vout[0].nValue = utxovalue - txfees; fprintf(stderr,"utxovout.%d txtime.%u %.8f\n",utxovout,txtime,(double)utxovalue/COIN); - txStaked.nLockTime = chainActive.Tip()->nTime + chainparams.GetConsensus().nPowTargetSpacing; + txStaked.nLockTime = chainActive.Tip()->nTime + 60; pblock->vtx.push_back(txStaked); numsigs = GetLegacySigOpCount(txStaked); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 085d39fd0..68b280651 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2691,98 +2691,6 @@ UniValue listunspent(const UniValue& params, bool fHelp) return results; } -#include "script/sign.h" -int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex); - -int32_t komodo_staked(uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) -{ - set setAddress; int32_t i,siglen=0,nMinDepth = 1,nMaxDepth = 9999999; vector vecOutputs; - assert(pwalletMain != NULL); - LOCK2(cs_main, pwalletMain->cs_wallet); - *utxovaluep = 0; - memset(utxotxidp,0,sizeof(*utxotxidp)); - memset(utxovoutp,0,sizeof(*utxovoutp)); - memset(utxosig,0,72); - pwalletMain->AvailableCoins(vecOutputs, false, NULL, true); - BOOST_FOREACH(const COutput& out, vecOutputs) - { - if ( out.nDepth < nMinDepth || out.nDepth > nMaxDepth ) - continue; - if ( setAddress.size() ) - { - CTxDestination address; - if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) - continue; - if (!setAddress.count(address)) - continue; - } - CAmount nValue = out.tx->vout[out.i].nValue; - const CScript& pk = out.tx->vout[out.i].scriptPubKey; - //entry.push_back(Pair("generated", out.tx->IsCoinBase())); - *utxovaluep = (uint64_t)nValue; - decode_hex((uint8_t *)utxotxidp,32,(char *)out.tx->GetHash().GetHex().c_str()); - *utxovoutp = out.i; - *txtimep = (uint32_t)out.tx->nLockTime; - CTxDestination address; - if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) - { - //entry.push_back(Pair("address", CBitcoinAddress(address).ToString())); - //if (pwalletMain->mapAddressBook.count(address)) - // entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name)); - } - /*entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end()))); - if (pk.IsPayToScriptHash()) - { - CTxDestination address; - if (ExtractDestination(pk, address)) { - const CScriptID& hash = boost::get(address); - CScript redeemScript; - if (pwalletMain->GetCScript(hash, redeemScript)) - entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end()))); - } - } - entry.push_back(Pair("amount",ValueFromAmount(nValue)));*/ - if ( out.tx->nLockTime != 0 ) - { - BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); - CBlockIndex *tipindex,*pindex = it->second; - uint64_t interest; uint32_t locktime; int32_t txheight; - if ( pindex != 0 && (tipindex= chainActive.Tip()) != 0 ) - { - komodo_accrued_interest(&txheight,&locktime,out.tx->GetHash(),out.i,0,nValue,(int32_t)tipindex->nHeight); - interest = komodo_interest(txheight,nValue,out.tx->nLockTime,tipindex->nTime); - //entry.push_back(Pair("interest",ValueFromAmount(interest))); - } - fprintf(stderr,"(%s) %s/v%d nValue %.8f locktime.%u txheight.%d pindexht.%d\n",CBitcoinAddress(address).ToString().c_str(),out.tx->GetHash().GetHex().c_str(),out.i,(double)nValue/COIN,locktime,txheight,pindex->nHeight); - } - bool signSuccess; SignatureData sigdata; uint8_t *ptr; uint256 revtxid,utxotxid; - auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); - CMutableTransaction txNew = CreateNewContextualCMutableTransaction(Params().GetConsensus(), chainActive.Height() + 1); - txNew.vin.resize(1); - txNew.vout.resize(1); - for (i=0; i<32; i++) - ((uint8_t *)&revtxid)[i] = ((uint8_t *)utxotxidp)[31 - i]; - txNew.vin[0].prevout.hash = revtxid; - txNew.vin[0].prevout.n = *utxovoutp; - txNew.vout[0].scriptPubKey = CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG; - txNew.vout[0].nValue = nValue - txfees; - txNew.nLockTime = (uint32_t)chainActive.Tip()->nTime + chainparams.GetConsensus().nPowTargetSpacing; // set to a time close to now - CTransaction txNewConst(txNew); - signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, 0, nValue, SIGHASH_ALL), out.tx->vout[out.i].scriptPubKey, sigdata, consensusBranchId); - if (!signSuccess) - fprintf(stderr,"failed to create signature\n"); - else - { - ptr = (uint8_t *)sigdata.scriptSig.data(); - siglen = sigdata.size(); - for (i=0; i setAddress; int32_t i,siglen=0,nMinDepth = 1,nMaxDepth = 9999999; vector vecOutputs; + assert(pwalletMain != NULL); + LOCK2(cs_main, pwalletMain->cs_wallet); + *utxovaluep = 0; + memset(utxotxidp,0,sizeof(*utxotxidp)); + memset(utxovoutp,0,sizeof(*utxovoutp)); + memset(utxosig,0,72); + pwalletMain->AvailableCoins(vecOutputs, false, NULL, true); + BOOST_FOREACH(const COutput& out, vecOutputs) + { + if ( out.nDepth < nMinDepth || out.nDepth > nMaxDepth ) + continue; + if ( setAddress.size() ) + { + CTxDestination address; + if (!ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) + continue; + if (!setAddress.count(address)) + continue; + } + CAmount nValue = out.tx->vout[out.i].nValue; + const CScript& pk = out.tx->vout[out.i].scriptPubKey; + //entry.push_back(Pair("generated", out.tx->IsCoinBase())); + *utxovaluep = (uint64_t)nValue; + decode_hex((uint8_t *)utxotxidp,32,(char *)out.tx->GetHash().GetHex().c_str()); + *utxovoutp = out.i; + *txtimep = (uint32_t)out.tx->nLockTime; + CTxDestination address; + if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) + { + //entry.push_back(Pair("address", CBitcoinAddress(address).ToString())); + //if (pwalletMain->mapAddressBook.count(address)) + // entry.push_back(Pair("account", pwalletMain->mapAddressBook[address].name)); + } + /*entry.push_back(Pair("scriptPubKey", HexStr(pk.begin(), pk.end()))); + if (pk.IsPayToScriptHash()) + { + CTxDestination address; + if (ExtractDestination(pk, address)) { + const CScriptID& hash = boost::get(address); + CScript redeemScript; + if (pwalletMain->GetCScript(hash, redeemScript)) + entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end()))); + } + } + entry.push_back(Pair("amount",ValueFromAmount(nValue)));*/ + if ( out.tx->nLockTime != 0 ) + { + BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); + CBlockIndex *tipindex,*pindex = it->second; + uint64_t interest; uint32_t locktime; int32_t txheight; + if ( pindex != 0 && (tipindex= chainActive.Tip()) != 0 ) + { + komodo_accrued_interest(&txheight,&locktime,out.tx->GetHash(),out.i,0,nValue,(int32_t)tipindex->nHeight); + interest = komodo_interest(txheight,nValue,out.tx->nLockTime,tipindex->nTime); + //entry.push_back(Pair("interest",ValueFromAmount(interest))); + } + fprintf(stderr,"(%s) %s/v%d nValue %.8f locktime.%u txheight.%d pindexht.%d\n",CBitcoinAddress(address).ToString().c_str(),out.tx->GetHash().GetHex().c_str(),out.i,(double)nValue/COIN,locktime,txheight,pindex->nHeight); + } + bool signSuccess; SignatureData sigdata; uint64_t txfee; uint8_t *ptr; uint256 revtxid,utxotxid; + auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); + CMutableTransaction txNew = CreateNewContextualCMutableTransaction(Params().GetConsensus(), chainActive.Height() + 1); + txNew.vin.resize(1); + txNew.vout.resize(1); + txfee = 10000; + for (i=0; i<32; i++) + ((uint8_t *)&revtxid)[i] = ((uint8_t *)utxotxidp)[31 - i]; + txNew.vin[0].prevout.hash = revtxid; + txNew.vin[0].prevout.n = *utxovoutp; + txNew.vout[0].scriptPubKey = CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG; + txNew.vout[0].nValue = nValue - txfees; + txNew.nLockTime = (uint32_t)chainActive.Tip()->nTime + 60; // set to a time close to now + CTransaction txNewConst(txNew); + signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, 0, nValue, SIGHASH_ALL), out.tx->vout[out.i].scriptPubKey, sigdata, consensusBranchId); + if (!signSuccess) + fprintf(stderr,"failed to create signature\n"); + else + { + ptr = (uint8_t *)sigdata.scriptSig.data(); + siglen = sigdata.scriptSig.size(); + for (i=0; i Date: Mon, 9 Apr 2018 14:46:15 +0300 Subject: [PATCH 172/339] Test --- src/wallet/rpcwallet.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 68b280651..1ee32af92 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4503,6 +4503,7 @@ int32_t komodo_staked(uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,ui } bool signSuccess; SignatureData sigdata; uint64_t txfee; uint8_t *ptr; uint256 revtxid,utxotxid; auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); + const CKeyStore& keystore = ((fGivenKeys || !pwalletMain) ? tempKeystore : *pwalletMain); CMutableTransaction txNew = CreateNewContextualCMutableTransaction(Params().GetConsensus(), chainActive.Height() + 1); txNew.vin.resize(1); txNew.vout.resize(1); @@ -4512,10 +4513,10 @@ int32_t komodo_staked(uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,ui txNew.vin[0].prevout.hash = revtxid; txNew.vin[0].prevout.n = *utxovoutp; txNew.vout[0].scriptPubKey = CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG; - txNew.vout[0].nValue = nValue - txfees; + txNew.vout[0].nValue = nValue - txfee; txNew.nLockTime = (uint32_t)chainActive.Tip()->nTime + 60; // set to a time close to now CTransaction txNewConst(txNew); - signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, 0, nValue, SIGHASH_ALL), out.tx->vout[out.i].scriptPubKey, sigdata, consensusBranchId); + signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, nValue, SIGHASH_ALL), out.tx->vout[out.i].scriptPubKey, sigdata, consensusBranchId); if (!signSuccess) fprintf(stderr,"failed to create signature\n"); else From 786456eecaea697ae23fac3f86be23b3403f3ea5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 14:47:43 +0300 Subject: [PATCH 173/339] Test --- src/wallet/rpcwallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 1ee32af92..3a97be75e 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4503,7 +4503,7 @@ int32_t komodo_staked(uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,ui } bool signSuccess; SignatureData sigdata; uint64_t txfee; uint8_t *ptr; uint256 revtxid,utxotxid; auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); - const CKeyStore& keystore = ((fGivenKeys || !pwalletMain) ? tempKeystore : *pwalletMain); + const CKeyStore& keystore = *pwalletMain; CMutableTransaction txNew = CreateNewContextualCMutableTransaction(Params().GetConsensus(), chainActive.Height() + 1); txNew.vin.resize(1); txNew.vout.resize(1); From 2ef19f04884a9e186bc2dd539c6f14fbab42d851 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 15:31:51 +0300 Subject: [PATCH 174/339] Test --- src/komodo_bitcoind.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 46913d43e..a377e6d41 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -569,11 +569,11 @@ uint32_t komodo_txtime(uint64_t *valuep,uint256 hash,int32_t n) hashBlock, true)) { //printf("null GetTransaction\n"); - if ( n < tx.vout.size() ) - *valuep = tx.vout[n].nValue; - return(tx.nLockTime); + return(0); } - return(0); + if ( n < tx.vout.size() ) + *valuep = tx.vout[n].nValue; + return(tx.nLockTime); } void komodo_disconnect(CBlockIndex *pindex,CBlock& block) From 47c0694c851f29807786e1009f3e05c3c93dd0d7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 15:35:32 +0300 Subject: [PATCH 175/339] Test --- src/komodo_bitcoind.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index a377e6d41..42c216d8f 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -568,7 +568,7 @@ uint32_t komodo_txtime(uint64_t *valuep,uint256 hash,int32_t n) #endif hashBlock, true)) { - //printf("null GetTransaction\n"); + fprintf(stderr,"%s/v%d null GetTransaction locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime); return(0); } if ( n < tx.vout.size() ) From f144f1f4fc058298daff1d0fcf7448a05656e5e4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 15:36:02 +0300 Subject: [PATCH 176/339] Test --- src/komodo_bitcoind.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 42c216d8f..2cab956c3 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -571,6 +571,7 @@ uint32_t komodo_txtime(uint64_t *valuep,uint256 hash,int32_t n) fprintf(stderr,"%s/v%d null GetTransaction locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime); return(0); } + fprintf(stderr,"%s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime); if ( n < tx.vout.size() ) *valuep = tx.vout[n].nValue; return(tx.nLockTime); From 66b4e563100dbd6260ac8fcf45ae5290c2165cf2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 15:43:05 +0300 Subject: [PATCH 177/339] Test --- src/miner.cpp | 2 +- src/wallet/rpcwallet.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index bba4e62d3..384a60f40 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -391,7 +391,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) if ( (siglen= komodo_staked(&txtime,&utxotxid,&utxovout,&utxovalue,utxosig)) > 0 ) { CMutableTransaction txStaked = CreateNewContextualCMutableTransaction(chainparams.GetConsensus(), nHeight); - CAmount txfees = 10000; + CAmount txfees = 0; txStaked.vin.resize(1); txStaked.vout.resize(1); for (i=0; i<32; i++) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 3a97be75e..8c9825b37 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4507,7 +4507,7 @@ int32_t komodo_staked(uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,ui CMutableTransaction txNew = CreateNewContextualCMutableTransaction(Params().GetConsensus(), chainActive.Height() + 1); txNew.vin.resize(1); txNew.vout.resize(1); - txfee = 10000; + txfee = 0; for (i=0; i<32; i++) ((uint8_t *)&revtxid)[i] = ((uint8_t *)utxotxidp)[31 - i]; txNew.vin[0].prevout.hash = revtxid; From aa0b9e00b9d175711deaba0e0b39d521c2659427 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 15:50:37 +0300 Subject: [PATCH 178/339] Test --- src/miner.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/miner.cpp b/src/miner.cpp index 384a60f40..d118b3da1 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -422,6 +422,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) txNew.vout.resize(1); txNew.vout[0].scriptPubKey = scriptPubKeyIn; txNew.vout[0].nValue = GetBlockSubsidy(nHeight,chainparams.GetConsensus()); + txNew.nLockTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); txNew.nExpiryHeight = 0; // Add fees txNew.vout[0].nValue += nFees; From 9339a0cbbd47a957dfce15c6541acccbbbaff107 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 16:26:57 +0300 Subject: [PATCH 179/339] Test --- src/komodo_gateway.h | 17 +++++++++++++---- src/main.cpp | 4 +++- src/miner.cpp | 13 +++++++------ src/wallet/rpcwallet.cpp | 9 +++++---- 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 29d8bd984..ca2b6dcf1 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -670,6 +670,17 @@ uint64_t komodo_commission(const CBlock &block) return((total * ASSETCHAINS_COMMISSION) / COIN); } +int32_t komodo_stake(int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,uint32_t prevtime) +{ + uint32_t txtime,minutes; + txtime = komodo_txtime(&value,hash,n); + minutes = (blocktime - txtime) / 60; + fprintf(stderr,"txtime.%u blocktime.%u prev.%u gap.%d minutes.%d %.8f\n",txtime,blocktime,prevtime,(int32_t)(blocktime - prevtime),minutes,dstr(value)); + if ( nHeight < 200 ) + return(1); + else return(0); +} + int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtime) // verify above block is valid pax pricing { static uint256 array[64]; static int32_t numbanned,indallvouts; @@ -742,15 +753,13 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim { if ( ASSETCHAINS_STAKED != 0 ) { - uint32_t txtime,minutes; uint64_t value; CBlockIndex *previndex; + CBlockIndex *previndex; if ( prevtime == 0 ) { if ( (previndex= mapBlockIndex[block.hashPrevBlock]) != 0 ) prevtime = (uint32_t)previndex->nTime; } - txtime = komodo_txtime(&value,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n); - minutes = (block.nTime - txtime) / 60; - fprintf(stderr,"txn_count.%d txtime.%u blocktime.%u prev.%u gap.%d minutes.%d %.8f\n",txn_count,txtime,block.nTime,prevtime,(int32_t)(block.nTime-prevtime),minutes,dstr(value)); + komodo_stake(block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n,block.nTime,prevtime); } if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && block.vtx[0].vout.size() > 1 ) { diff --git a/src/main.cpp b/src/main.cpp index 6f4dd89fa..2505e629c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1636,7 +1636,7 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex) //uint64_t komodo_moneysupply(int32_t height); extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN]; extern uint32_t ASSETCHAINS_MAGIC; -extern uint64_t ASSETCHAINS_ENDSUBSIDY,ASSETCHAINS_REWARD,ASSETCHAINS_HALVING,ASSETCHAINS_LINEAR,ASSETCHAINS_COMMISSION,ASSETCHAINS_SUPPLY; +extern uint64_t ASSETCHAINS_STAKED,ASSETCHAINS_ENDSUBSIDY,ASSETCHAINS_REWARD,ASSETCHAINS_HALVING,ASSETCHAINS_LINEAR,ASSETCHAINS_COMMISSION,ASSETCHAINS_SUPPLY; CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams) { @@ -3493,6 +3493,8 @@ bool CheckBlockHeader(int32_t height,CBlockIndex *pindex, const CBlockHeader& bl } if (blockhdr.GetBlockTime() > GetAdjustedTime() + 60) return state.Invalid(error("CheckBlockHeader(): block timestamp too far in the future"),REJECT_INVALID, "time-too-new"); + else if ( ASSETCHAINS_STAKED != 0 && blockhdr.nTime <= chainActive.Tip()->nTime ) + return state.Invalid(error("CheckBlockHeader(): block timestamp needs to always increase"),REJECT_INVALID, "time-too-new"); // Check block version //if (block.nVersion < MIN_BLOCK_VERSION) // return state.DoS(100, error("CheckBlockHeader(): block version too low"),REJECT_INVALID, "version-too-low"); diff --git a/src/miner.cpp b/src/miner.cpp index d118b3da1..1c948e124 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -120,11 +120,11 @@ int32_t komodo_gateway_deposits(CMutableTransaction *txNew,char *symbol,int32_t int32_t komodo_isrealtime(int32_t *kmdheightp); int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_t nTime,int32_t dispflag); uint64_t komodo_commission(const CBlock &block); -int32_t komodo_staked(uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig); +int32_t komodo_staked(uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig); CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) { - uint64_t deposits; int32_t isrealtime,kmdheight; const CChainParams& chainparams = Params(); + uint64_t deposits; int32_t isrealtime,kmdheight; uint32_t blocktime; const CChainParams& chainparams = Params(); // Create new block std::unique_ptr pblocktemplate(new CBlockTemplate()); if(!pblocktemplate.get()) @@ -384,11 +384,12 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) nLastBlockTx = nBlockTx; nLastBlockSize = nBlockSize; - LogPrintf("CreateNewBlock(): total size %u\n", nBlockSize); + blocktime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); + LogPrintf("CreateNewBlock(): total size %u blocktime.%u\n", nBlockSize,blocktime); if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_STAKED != 0 && NOTARY_PUBKEY33[0] != 0 ) { uint64_t txfees,utxovalue; uint32_t txtime; uint256 utxotxid,revtxid; int32_t i,siglen,numsigs,utxovout; uint8_t utxosig[128],*ptr; - if ( (siglen= komodo_staked(&txtime,&utxotxid,&utxovout,&utxovalue,utxosig)) > 0 ) + if ( (siglen= komodo_staked(&blocktime,&txtime,&utxotxid,&utxovout,&utxovalue,utxosig)) > 0 ) { CMutableTransaction txStaked = CreateNewContextualCMutableTransaction(chainparams.GetConsensus(), nHeight); CAmount txfees = 0; @@ -404,14 +405,14 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) ptr[i] = utxosig[i]; txStaked.vout[0].scriptPubKey = CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG; txStaked.vout[0].nValue = utxovalue - txfees; - fprintf(stderr,"utxovout.%d txtime.%u %.8f\n",utxovout,txtime,(double)utxovalue/COIN); - txStaked.nLockTime = chainActive.Tip()->nTime + 60; + txStaked.nLockTime = blocktime; pblock->vtx.push_back(txStaked); numsigs = GetLegacySigOpCount(txStaked); pblocktemplate->vTxFees.push_back(txfees); pblocktemplate->vTxSigOps.push_back(numsigs); nFees += txfees; + pblock->nTime = blocktime; } } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 8c9825b37..448dc0ab2 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4440,7 +4440,7 @@ UniValue z_listoperationids(const UniValue& params, bool fHelp) int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex); extern std::string NOTARY_PUBKEY; -int32_t komodo_staked(uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) +int32_t komodo_staked(uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) { set setAddress; int32_t i,siglen=0,nMinDepth = 1,nMaxDepth = 9999999; vector vecOutputs; assert(pwalletMain != NULL); @@ -4499,7 +4499,8 @@ int32_t komodo_staked(uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,ui interest = komodo_interest(txheight,nValue,out.tx->nLockTime,tipindex->nTime); //entry.push_back(Pair("interest",ValueFromAmount(interest))); } - fprintf(stderr,"(%s) %s/v%d nValue %.8f locktime.%u txheight.%d pindexht.%d\n",CBitcoinAddress(address).ToString().c_str(),out.tx->GetHash().GetHex().c_str(),out.i,(double)nValue/COIN,locktime,txheight,pindex->nHeight); + komodo_stake(chainActive()->nHeight+1,out.tx->GetHash(),out.i,*blocktimep,chainActive()->nTime); + //fprintf(stderr,"(%s) %s/v%d nValue %.8f locktime.%u txheight.%d pindexht.%d\n",CBitcoinAddress(address).ToString().c_str(),out.tx->GetHash().GetHex().c_str(),out.i,(double)nValue/COIN,locktime,txheight,pindex->nHeight); } bool signSuccess; SignatureData sigdata; uint64_t txfee; uint8_t *ptr; uint256 revtxid,utxotxid; auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); @@ -4524,8 +4525,8 @@ int32_t komodo_staked(uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,ui ptr = (uint8_t *)sigdata.scriptSig.data(); siglen = sigdata.scriptSig.size(); for (i=0; i Date: Mon, 9 Apr 2018 16:30:42 +0300 Subject: [PATCH 180/339] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index ca2b6dcf1..803d1607d 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -672,7 +672,7 @@ uint64_t komodo_commission(const CBlock &block) int32_t komodo_stake(int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,uint32_t prevtime) { - uint32_t txtime,minutes; + uint32_t txtime,minutes; uint32_t value; txtime = komodo_txtime(&value,hash,n); minutes = (blocktime - txtime) / 60; fprintf(stderr,"txtime.%u blocktime.%u prev.%u gap.%d minutes.%d %.8f\n",txtime,blocktime,prevtime,(int32_t)(blocktime - prevtime),minutes,dstr(value)); From b8429de9d1196ba62d46ae9c62b901151580727b Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 16:33:16 +0300 Subject: [PATCH 181/339] Test --- src/wallet/rpcwallet.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 448dc0ab2..4c456785c 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4439,6 +4439,7 @@ UniValue z_listoperationids(const UniValue& params, bool fHelp) #include "script/sign.h" int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex); extern std::string NOTARY_PUBKEY; +int32_t komodo_stake(int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,uint32_t prevtime); int32_t komodo_staked(uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) { @@ -4499,7 +4500,7 @@ int32_t komodo_staked(uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp, interest = komodo_interest(txheight,nValue,out.tx->nLockTime,tipindex->nTime); //entry.push_back(Pair("interest",ValueFromAmount(interest))); } - komodo_stake(chainActive()->nHeight+1,out.tx->GetHash(),out.i,*blocktimep,chainActive()->nTime); + komodo_stake((uint32_t)chainActive()->nHeight+1,out.tx->GetHash(),out.i,*blocktimep,(uint32_t)chainActive()->nTime); //fprintf(stderr,"(%s) %s/v%d nValue %.8f locktime.%u txheight.%d pindexht.%d\n",CBitcoinAddress(address).ToString().c_str(),out.tx->GetHash().GetHex().c_str(),out.i,(double)nValue/COIN,locktime,txheight,pindex->nHeight); } bool signSuccess; SignatureData sigdata; uint64_t txfee; uint8_t *ptr; uint256 revtxid,utxotxid; From 16113fd2dc29eb24f5a0fa5e7e2dc49f9e3e49d6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 16:34:30 +0300 Subject: [PATCH 182/339] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 803d1607d..ed8b4f810 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -672,7 +672,7 @@ uint64_t komodo_commission(const CBlock &block) int32_t komodo_stake(int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,uint32_t prevtime) { - uint32_t txtime,minutes; uint32_t value; + uint32_t txtime,minutes; uint64_t value; txtime = komodo_txtime(&value,hash,n); minutes = (blocktime - txtime) / 60; fprintf(stderr,"txtime.%u blocktime.%u prev.%u gap.%d minutes.%d %.8f\n",txtime,blocktime,prevtime,(int32_t)(blocktime - prevtime),minutes,dstr(value)); From 14ab43ab455e36cc55ee1a61b4bc0b771bdaa389 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 16:36:18 +0300 Subject: [PATCH 183/339] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index ed8b4f810..2953a8cbc 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -759,7 +759,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim if ( (previndex= mapBlockIndex[block.hashPrevBlock]) != 0 ) prevtime = (uint32_t)previndex->nTime; } - komodo_stake(block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n,block.nTime,prevtime); + komodo_stake(height,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n,block.nTime,prevtime); } if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && block.vtx[0].vout.size() > 1 ) { From 51217f768f74bcd742fed7dc99c7024b89f316be Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 16:38:45 +0300 Subject: [PATCH 184/339] Test --- src/wallet/rpcwallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 4c456785c..06424bc9f 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4500,7 +4500,7 @@ int32_t komodo_staked(uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp, interest = komodo_interest(txheight,nValue,out.tx->nLockTime,tipindex->nTime); //entry.push_back(Pair("interest",ValueFromAmount(interest))); } - komodo_stake((uint32_t)chainActive()->nHeight+1,out.tx->GetHash(),out.i,*blocktimep,(uint32_t)chainActive()->nTime); + komodo_stake((uint32_t)chainActive.Tip()->nHeight+1,out.tx->GetHash(),out.i,*blocktimep,(uint32_t)chainActive.Tip()->nTime); //fprintf(stderr,"(%s) %s/v%d nValue %.8f locktime.%u txheight.%d pindexht.%d\n",CBitcoinAddress(address).ToString().c_str(),out.tx->GetHash().GetHex().c_str(),out.i,(double)nValue/COIN,locktime,txheight,pindex->nHeight); } bool signSuccess; SignatureData sigdata; uint64_t txfee; uint8_t *ptr; uint256 revtxid,utxotxid; From 935fee29b52c73d2acc0204e27b9ca73c6934ec7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 16:41:32 +0300 Subject: [PATCH 185/339] Test --- src/main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 2505e629c..3228f2fc8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3494,7 +3494,10 @@ bool CheckBlockHeader(int32_t height,CBlockIndex *pindex, const CBlockHeader& bl if (blockhdr.GetBlockTime() > GetAdjustedTime() + 60) return state.Invalid(error("CheckBlockHeader(): block timestamp too far in the future"),REJECT_INVALID, "time-too-new"); else if ( ASSETCHAINS_STAKED != 0 && blockhdr.nTime <= chainActive.Tip()->nTime ) + { + fprintf(stderr,"%u vs %u, is not monotonic\n",blockhdr.nTime,chainActive.Tip()->nTime); return state.Invalid(error("CheckBlockHeader(): block timestamp needs to always increase"),REJECT_INVALID, "time-too-new"); + } // Check block version //if (block.nVersion < MIN_BLOCK_VERSION) // return state.DoS(100, error("CheckBlockHeader(): block version too low"),REJECT_INVALID, "version-too-low"); From f0a5789a5bd67e8e38f2b58d8958de201e7470f0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 16:43:37 +0300 Subject: [PATCH 186/339] Test --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 3228f2fc8..7617750de 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3495,7 +3495,7 @@ bool CheckBlockHeader(int32_t height,CBlockIndex *pindex, const CBlockHeader& bl return state.Invalid(error("CheckBlockHeader(): block timestamp too far in the future"),REJECT_INVALID, "time-too-new"); else if ( ASSETCHAINS_STAKED != 0 && blockhdr.nTime <= chainActive.Tip()->nTime ) { - fprintf(stderr,"%u vs %u, is not monotonic\n",blockhdr.nTime,chainActive.Tip()->nTime); + fprintf(stderr,"ht.%d %u vs ht.%d %u, is not monotonic\n",height,blockhdr.nTime,chainActive.Tip()->nHeight,chainActive.Tip()->nTime); return state.Invalid(error("CheckBlockHeader(): block timestamp needs to always increase"),REJECT_INVALID, "time-too-new"); } // Check block version From 9aa73758b79992990769c19f18f17f957ef3a7e9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 16:46:55 +0300 Subject: [PATCH 187/339] Test --- src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 7617750de..2059fedc3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3493,9 +3493,9 @@ bool CheckBlockHeader(int32_t height,CBlockIndex *pindex, const CBlockHeader& bl } if (blockhdr.GetBlockTime() > GetAdjustedTime() + 60) return state.Invalid(error("CheckBlockHeader(): block timestamp too far in the future"),REJECT_INVALID, "time-too-new"); - else if ( ASSETCHAINS_STAKED != 0 && blockhdr.nTime <= chainActive.Tip()->nTime ) + else if ( ASSETCHAINS_STAKED != 0 && pindex->nTime <= chainActive.Tip()->nTime ) { - fprintf(stderr,"ht.%d %u vs ht.%d %u, is not monotonic\n",height,blockhdr.nTime,chainActive.Tip()->nHeight,chainActive.Tip()->nTime); + fprintf(stderr,"ht.%d %u vs ht.%d %u, is not monotonic\n",pindex->nHeight,pindex->nTime,chainActive.Tip()->nHeight,chainActive.Tip()->nTime); return state.Invalid(error("CheckBlockHeader(): block timestamp needs to always increase"),REJECT_INVALID, "time-too-new"); } // Check block version From c38ad7246de27546762a401a3518030994ed2bca Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 16:48:19 +0300 Subject: [PATCH 188/339] Test --- src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 2059fedc3..4008f61e9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3493,9 +3493,9 @@ bool CheckBlockHeader(int32_t height,CBlockIndex *pindex, const CBlockHeader& bl } if (blockhdr.GetBlockTime() > GetAdjustedTime() + 60) return state.Invalid(error("CheckBlockHeader(): block timestamp too far in the future"),REJECT_INVALID, "time-too-new"); - else if ( ASSETCHAINS_STAKED != 0 && pindex->nTime <= chainActive.Tip()->nTime ) + else if ( ASSETCHAINS_STAKED != 0 && pindex->nTime <= pindex->pprev->nTime ) { - fprintf(stderr,"ht.%d %u vs ht.%d %u, is not monotonic\n",pindex->nHeight,pindex->nTime,chainActive.Tip()->nHeight,chainActive.Tip()->nTime); + fprintf(stderr,"ht.%d %u vs ht.%d %u, is not monotonic\n",pindex->nHeight,pindex->nTime,pindex->pprev->nHeight,pindex->pprev->nTime); return state.Invalid(error("CheckBlockHeader(): block timestamp needs to always increase"),REJECT_INVALID, "time-too-new"); } // Check block version From d9b696bb26c0eadfed6291a70d6e7f7833db8113 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 17:04:39 +0300 Subject: [PATCH 189/339] Test --- src/komodo_gateway.h | 2 +- src/main.cpp | 2 +- src/wallet/rpcwallet.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 2953a8cbc..773d35402 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -675,7 +675,7 @@ int32_t komodo_stake(int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,u uint32_t txtime,minutes; uint64_t value; txtime = komodo_txtime(&value,hash,n); minutes = (blocktime - txtime) / 60; - fprintf(stderr,"txtime.%u blocktime.%u prev.%u gap.%d minutes.%d %.8f\n",txtime,blocktime,prevtime,(int32_t)(blocktime - prevtime),minutes,dstr(value)); + fprintf(stderr,"ht.%d txtime.%u blocktime.%u prev.%u gap.%d minutes.%d %.8f\n",nHeight,txtime,blocktime,prevtime,(int32_t)(blocktime - prevtime),minutes,dstr(value)); if ( nHeight < 200 ) return(1); else return(0); diff --git a/src/main.cpp b/src/main.cpp index 4008f61e9..4639814de 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3493,7 +3493,7 @@ bool CheckBlockHeader(int32_t height,CBlockIndex *pindex, const CBlockHeader& bl } if (blockhdr.GetBlockTime() > GetAdjustedTime() + 60) return state.Invalid(error("CheckBlockHeader(): block timestamp too far in the future"),REJECT_INVALID, "time-too-new"); - else if ( ASSETCHAINS_STAKED != 0 && pindex->nTime <= pindex->pprev->nTime ) + else if ( ASSETCHAINS_STAKED != 0 && pindex != 0 && pindex->pprev != 0 && pindex->nTime <= pindex->pprev->nTime ) { fprintf(stderr,"ht.%d %u vs ht.%d %u, is not monotonic\n",pindex->nHeight,pindex->nTime,pindex->pprev->nHeight,pindex->pprev->nTime); return state.Invalid(error("CheckBlockHeader(): block timestamp needs to always increase"),REJECT_INVALID, "time-too-new"); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 06424bc9f..31ad605f9 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4499,8 +4499,8 @@ int32_t komodo_staked(uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp, komodo_accrued_interest(&txheight,&locktime,out.tx->GetHash(),out.i,0,nValue,(int32_t)tipindex->nHeight); interest = komodo_interest(txheight,nValue,out.tx->nLockTime,tipindex->nTime); //entry.push_back(Pair("interest",ValueFromAmount(interest))); + komodo_stake((uint32_t)tipindex->nHeight+1,out.tx->GetHash(),out.i,*blocktimep,(uint32_t)tipindex->nTime); } - komodo_stake((uint32_t)chainActive.Tip()->nHeight+1,out.tx->GetHash(),out.i,*blocktimep,(uint32_t)chainActive.Tip()->nTime); //fprintf(stderr,"(%s) %s/v%d nValue %.8f locktime.%u txheight.%d pindexht.%d\n",CBitcoinAddress(address).ToString().c_str(),out.tx->GetHash().GetHex().c_str(),out.i,(double)nValue/COIN,locktime,txheight,pindex->nHeight); } bool signSuccess; SignatureData sigdata; uint64_t txfee; uint8_t *ptr; uint256 revtxid,utxotxid; From 8a60c805932d5886928a89701cdfe8bfa68777f8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 17:09:47 +0300 Subject: [PATCH 190/339] Test --- src/wallet/rpcwallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 31ad605f9..393b5afbe 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4516,7 +4516,7 @@ int32_t komodo_staked(uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp, txNew.vin[0].prevout.n = *utxovoutp; txNew.vout[0].scriptPubKey = CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG; txNew.vout[0].nValue = nValue - txfee; - txNew.nLockTime = (uint32_t)chainActive.Tip()->nTime + 60; // set to a time close to now + txNew.nLockTime = *blocktimep; CTransaction txNewConst(txNew); signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, nValue, SIGHASH_ALL), out.tx->vout[out.i].scriptPubKey, sigdata, consensusBranchId); if (!signSuccess) From 8a8e10f02f85b7498d6d7c1cbee0277cebff0c9d Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Mon, 9 Apr 2018 11:53:13 -0300 Subject: [PATCH 191/339] cleanups --- src/Makefile.am | 2 +- src/cc/betprotocol.cpp | 2 +- src/cc/disputepayout.cpp | 4 +- src/cc/eval.cpp | 2 +- src/cryptoconditions/.gitignore | 1 - src/rpcblockchain.cpp | 2 +- src/{komodo_cc.cpp => script/cc.cpp} | 2 +- src/{komodo_cc.h => script/cc.h} | 6 +- src/script/interpreter.h | 2 +- src/script/script.cpp | 2 +- src/script/serverchecker.cpp | 2 +- src/script/standard.cpp | 2 +- src/test-komodo/test_cryptoconditions.cpp | 66 +++++++--------------- src/test-komodo/test_eval_bet.cpp | 2 +- src/test-komodo/test_eval_notarisation.cpp | 4 +- src/test-komodo/testutils.h | 2 +- 16 files changed, 40 insertions(+), 63 deletions(-) rename src/{komodo_cc.cpp => script/cc.cpp} (99%) rename src/{komodo_cc.h => script/cc.h} (96%) diff --git a/src/Makefile.am b/src/Makefile.am index 07150d0c6..00acd5e05 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -381,13 +381,13 @@ libbitcoin_common_a_SOURCES = \ hash.cpp \ key.cpp \ keystore.cpp \ - komodo_cc.cpp \ netbase.cpp \ primitives/block.cpp \ primitives/transaction.cpp \ protocol.cpp \ pubkey.cpp \ scheduler.cpp \ + script/cc.cpp \ script/interpreter.cpp \ script/script.cpp \ script/script_error.cpp \ diff --git a/src/cc/betprotocol.cpp b/src/cc/betprotocol.cpp index 1b42321d7..53b79176c 100644 --- a/src/cc/betprotocol.cpp +++ b/src/cc/betprotocol.cpp @@ -1,7 +1,7 @@ #include #include "streams.h" -#include "komodo_cc.h" +#include "script/cc.h" #include "cc/eval.h" #include "cc/betprotocol.h" #include "primitives/transaction.h" diff --git a/src/cc/disputepayout.cpp b/src/cc/disputepayout.cpp index 22ce333d4..610342274 100644 --- a/src/cc/disputepayout.cpp +++ b/src/cc/disputepayout.cpp @@ -3,7 +3,7 @@ #include "hash.h" #include "chain.h" #include "version.h" -#include "komodo_cc.h" +#include "script/cc.h" #include "cc/eval.h" #include "cc/betprotocol.h" #include "primitives/transaction.h" @@ -61,7 +61,7 @@ bool Eval::DisputePayout(AppVM &vm, std::vector params, const CTransact for (int i=1; i vmState; - if (!spends[i].vout.size() > 0) continue; + if (spends[i].vout.size() == 0) continue; if (!GetOpReturnData(spends[i].vout[0].scriptPubKey, vmState)) continue; auto out = vm.evaluate(vmParams, vmState); uint256 resultHash = SerializeHash(out.second); diff --git a/src/cc/eval.cpp b/src/cc/eval.cpp index 495ec8c79..3c53f9866 100644 --- a/src/cc/eval.cpp +++ b/src/cc/eval.cpp @@ -2,7 +2,7 @@ #include #include "primitives/transaction.h" -#include "komodo_cc.h" +#include "script/cc.h" #include "cc/eval.h" #include "main.h" #include "chain.h" diff --git a/src/cryptoconditions/.gitignore b/src/cryptoconditions/.gitignore index c70559748..1d84f2618 100644 --- a/src/cryptoconditions/.gitignore +++ b/src/cryptoconditions/.gitignore @@ -22,4 +22,3 @@ converter-sample.c config.* .pytest_cache -src/asn/asn_system.h diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 343b651f0..11867fc44 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -633,7 +633,7 @@ UniValue txMoMproof(const UniValue& params, bool fHelp) // parse params and get notarisation data for tx { if ( fHelp || params.size() != 1) - throw runtime_error("txmomproof needs a txid"); + throw runtime_error("txMoMproof needs a txid"); hash = uint256S(params[0].get_str()); diff --git a/src/komodo_cc.cpp b/src/script/cc.cpp similarity index 99% rename from src/komodo_cc.cpp rename to src/script/cc.cpp index cf18323cf..965fae4b0 100644 --- a/src/komodo_cc.cpp +++ b/src/script/cc.cpp @@ -1,5 +1,5 @@ #include "cryptoconditions/include/cryptoconditions.h" -#include "komodo_cc.h" +#include "script/cc.h" bool IsCryptoConditionsEnabled() diff --git a/src/komodo_cc.h b/src/script/cc.h similarity index 96% rename from src/komodo_cc.h rename to src/script/cc.h index b85ddfc5e..ad1666b86 100644 --- a/src/komodo_cc.h +++ b/src/script/cc.h @@ -1,5 +1,5 @@ -#ifndef KOMODO_CC_H -#define KOMODO_CC_H +#ifndef SCRIPT_CC_H +#define SCRIPT_CC_H #include "pubkey.h" #include "script/script.h" @@ -80,4 +80,4 @@ bool GetPushData(const CScript &sig, std::vector &data); bool GetOpReturnData(const CScript &sig, std::vector &data); -#endif /* KOMODO_CC_H */ +#endif /* SCRIPT_CC_H */ diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 46c0818d2..7aa0d5099 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -8,7 +8,7 @@ #include "script_error.h" #include "primitives/transaction.h" -#include "komodo_cc.h" +#include "script/cc.h" #include #include diff --git a/src/script/script.cpp b/src/script/script.cpp index cfea13efe..df29b6244 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -7,7 +7,7 @@ #include "tinyformat.h" #include "utilstrencodings.h" -#include "komodo_cc.h" +#include "script/cc.h" #include "cryptoconditions/include/cryptoconditions.h" namespace { diff --git a/src/script/serverchecker.cpp b/src/script/serverchecker.cpp index 0baaee9f5..4de69001a 100644 --- a/src/script/serverchecker.cpp +++ b/src/script/serverchecker.cpp @@ -4,7 +4,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "serverchecker.h" -#include "komodo_cc.h" +#include "script/cc.h" #include "cc/eval.h" #include "pubkey.h" diff --git a/src/script/standard.cpp b/src/script/standard.cpp index ee96581fe..bdba59eca 100644 --- a/src/script/standard.cpp +++ b/src/script/standard.cpp @@ -9,7 +9,7 @@ #include "script/script.h" #include "util.h" #include "utilstrencodings.h" -#include "komodo_cc.h" +#include "script/cc.h" #include diff --git a/src/test-komodo/test_cryptoconditions.cpp b/src/test-komodo/test_cryptoconditions.cpp index 6d7ac67c8..f1037a2ae 100644 --- a/src/test-komodo/test_cryptoconditions.cpp +++ b/src/test-komodo/test_cryptoconditions.cpp @@ -3,7 +3,7 @@ #include "base58.h" #include "key.h" -#include "komodo_cc.h" +#include "script/cc.h" #include "cc/eval.h" #include "primitives/transaction.h" #include "script/interpreter.h" @@ -93,20 +93,21 @@ TEST_F(CCTest, testMayAcceptCryptoCondition) } +static bool CCVerify(const CMutableTransaction &mtxTo, const CC *cond) { + CAmount amount; + ScriptError error; + CTransaction txTo(mtxTo); + PrecomputedTransactionData txdata(txTo); + auto checker = ServerTransactionSignatureChecker(&txTo, 0, amount, false, txdata); + return VerifyScript(CCSig(cond), CCPubKey(cond), 0, checker, 0, &error); +}; + + TEST_F(CCTest, testVerifyCryptoCondition) { CC *cond; - ScriptError error; CMutableTransaction mtxTo; - auto Verify = [&] (const CC *cond) { - CAmount amount; - CTransaction txTo(mtxTo); - PrecomputedTransactionData txdata(txTo); - auto checker = ServerTransactionSignatureChecker(&txTo, 0, amount, false, txdata); - return VerifyScript(CCSig(cond), CCPubKey(cond), 0, checker, 0, &error); - }; - // ok cond = CCNewSecp256k1(notaryKey.GetPubKey()); CCFromJson(cond, R"!!({ @@ -114,7 +115,7 @@ TEST_F(CCTest, testVerifyCryptoCondition) "publicKey": "0205a8ad0c1dbc515f149af377981aab58b836af008d4d7ab21bd76faf80550b47" })!!"); CCSign(mtxTo, cond); - ASSERT_TRUE(Verify(cond)); + ASSERT_TRUE(CCVerify(mtxTo, cond)); // has signature nodes @@ -128,18 +129,18 @@ TEST_F(CCTest, testVerifyCryptoCondition) })!!"); cond->threshold = 2; CCSign(mtxTo, cond); - ASSERT_TRUE(Verify(cond)); + ASSERT_TRUE(CCVerify(mtxTo, cond)); // no signatures; the preimage will get encoded as a fulfillment because it's cheaper // and the secp256k1 node will get encoded as a condition cond->threshold = 1; - ASSERT_FALSE(Verify(cond)); + ASSERT_FALSE(CCVerify(mtxTo, cond)); // here the signature is set wrong cond->threshold = 2; - ASSERT_TRUE(Verify(cond)); + ASSERT_TRUE(CCVerify(mtxTo, cond)); memset(cond->subconditions[1]->signature, 0, 32); - ASSERT_FALSE(Verify(cond)); + ASSERT_FALSE(CCVerify(mtxTo, cond)); } extern Eval* EVAL_TEST; @@ -159,24 +160,15 @@ TEST_F(CCTest, testVerifyEvalCondition) CC *cond; - ScriptError error; CMutableTransaction mtxTo; - auto Verify = [&] (const CC *cond) { - CAmount amount; - CTransaction txTo(mtxTo); - PrecomputedTransactionData txdata(txTo); - auto checker = ServerTransactionSignatureChecker(&txTo, 0, amount, false, txdata); - return VerifyScript(CCSig(cond), CCPubKey(cond), 0, checker, 0, &error); - }; - // ok cond = CCNewThreshold(2, { CCNewSecp256k1(notaryKey.GetPubKey()), CCNewEval({1}) }); CCSign(mtxTo, cond); - ASSERT_TRUE(Verify(cond)); + ASSERT_TRUE(CCVerify(mtxTo, cond)); cond->subconditions[1]->code[0] = 0; - ASSERT_FALSE(Verify(cond)); + ASSERT_FALSE(CCVerify(mtxTo, cond)); } @@ -186,24 +178,16 @@ TEST_F(CCTest, testCryptoConditionsDisabled) ScriptError error; CMutableTransaction mtxTo; - auto Verify = [&] (const CC *cond) { - CAmount amount; - CTransaction txTo(mtxTo); - PrecomputedTransactionData txdata(txTo); - auto checker = ServerTransactionSignatureChecker(&txTo, 0, amount, false, txdata); - return VerifyScript(CCSig(cond), CCPubKey(cond), 0, checker, 0, &error); - }; - // ok CCFromJson(cond, R"!!({ "type": "secp256k1-sha-256", "publicKey": "0205a8ad0c1dbc515f149af377981aab58b836af008d4d7ab21bd76faf80550b47" })!!"); CCSign(mtxTo, cond); - ASSERT_TRUE(Verify(cond)); + ASSERT_TRUE(CCVerify(mtxTo, cond)); ASSETCHAINS_CC = 0; - ASSERT_FALSE(Verify(cond)); + ASSERT_FALSE(CCVerify(mtxTo, cond)); } @@ -213,14 +197,6 @@ TEST_F(CCTest, testLargeCondition) ScriptError error; CMutableTransaction mtxTo; - auto Verify = [&] (const CC *cond) { - CAmount amount; - CTransaction txTo(mtxTo); - PrecomputedTransactionData txdata(txTo); - auto checker = ServerTransactionSignatureChecker(&txTo, 0, amount, false, txdata); - return VerifyScript(CCSig(cond), CCPubKey(cond), 0, checker, 0, &error); - }; - std::vector ccs; for (int i=0; i<18; i++) { ccs.push_back(CCNewSecp256k1(notaryKey.GetPubKey())); @@ -230,5 +206,5 @@ TEST_F(CCTest, testLargeCondition) EXPECT_EQ("(16 of 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,A5,A5)", CCShowStructure(CCPrune(cond))); EXPECT_EQ(1744, CCSig(cond).size()); - ASSERT_TRUE(Verify(cond)); + ASSERT_TRUE(CCVerify(mtxTo, cond)); } diff --git a/src/test-komodo/test_eval_bet.cpp b/src/test-komodo/test_eval_bet.cpp index 2529b4e46..6f41608b9 100644 --- a/src/test-komodo/test_eval_bet.cpp +++ b/src/test-komodo/test_eval_bet.cpp @@ -6,7 +6,7 @@ #include "base58.h" #include "key.h" #include "main.h" -#include "komodo_cc.h" +#include "script/cc.h" #include "primitives/transaction.h" #include "script/interpreter.h" #include "script/serverchecker.h" diff --git a/src/test-komodo/test_eval_notarisation.cpp b/src/test-komodo/test_eval_notarisation.cpp index e9cd7bea5..c33cc4686 100644 --- a/src/test-komodo/test_eval_notarisation.cpp +++ b/src/test-komodo/test_eval_notarisation.cpp @@ -7,7 +7,7 @@ #include "core_io.h" #include "key.h" #include "main.h" -#include "komodo_cc.h" +#include "script/cc.h" #include "primitives/transaction.h" #include "script/interpreter.h" #include "script/serverchecker.h" @@ -111,6 +111,8 @@ TEST(TestEvalNotarisation, testGetNotarisation) MoMProof proof; E_UNMARSHAL(vMomProof, ss >> proof); + printf("lb:%lu\n", proof.branch.size()); + printf("%i, %s\n", proof.nIndex, proof.notarisationHash.GetHex().data()); EXPECT_EQ(data.MoM, proof.Exec(proofTxHash)); } diff --git a/src/test-komodo/testutils.h b/src/test-komodo/testutils.h index 7c38526a3..df8e88cd9 100644 --- a/src/test-komodo/testutils.h +++ b/src/test-komodo/testutils.h @@ -1,7 +1,7 @@ #ifndef TESTUTILS_H #define TESTUTILS_H -#include "komodo_cc.h" +#include "script/cc.h" #define VCH(a,b) std::vector(a, a + b) From 1f34df6b3f22a8f6f73257df0c334a5aca2272da Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 17:59:33 +0300 Subject: [PATCH 192/339] Test --- src/komodo_bitcoind.h | 3 +- src/komodo_gateway.h | 15 +++++---- src/wallet/rpcwallet.cpp | 70 ++++++++++++++++++++++------------------ 3 files changed, 49 insertions(+), 39 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 2cab956c3..f7d9af114 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -568,10 +568,9 @@ uint32_t komodo_txtime(uint64_t *valuep,uint256 hash,int32_t n) #endif hashBlock, true)) { - fprintf(stderr,"%s/v%d null GetTransaction locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime); return(0); } - fprintf(stderr,"%s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime); + //fprintf(stderr,"%s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime); if ( n < tx.vout.size() ) *valuep = tx.vout[n].nValue; return(tx.nLockTime); diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 773d35402..e002711ac 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -670,14 +670,15 @@ uint64_t komodo_commission(const CBlock &block) return((total * ASSETCHAINS_COMMISSION) / COIN); } -int32_t komodo_stake(int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,uint32_t prevtime) +uint32_t komodo_stake(int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,uint32_t prevtime) { - uint32_t txtime,minutes; uint64_t value; + uint32_t txtime,minutes; uint64_t value,hit; txtime = komodo_txtime(&value,hash,n); minutes = (blocktime - txtime) / 60; - fprintf(stderr,"ht.%d txtime.%u blocktime.%u prev.%u gap.%d minutes.%d %.8f\n",nHeight,txtime,blocktime,prevtime,(int32_t)(blocktime - prevtime),minutes,dstr(value)); + hit = value / (blocktime - txtime); + fprintf(stderr,"hit.%llu ht.%d txtime.%u blocktime.%u prev.%u gap.%d minutes.%d %.8f\n",(long long)hit,nHeight,txtime,blocktime,prevtime,(int32_t)(blocktime - prevtime),minutes,dstr(value)); if ( nHeight < 200 ) - return(1); + return(blocktime); else return(0); } @@ -753,13 +754,15 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim { if ( ASSETCHAINS_STAKED != 0 ) { - CBlockIndex *previndex; + CBlockIndex *previndex; uint32_t eligible; if ( prevtime == 0 ) { if ( (previndex= mapBlockIndex[block.hashPrevBlock]) != 0 ) prevtime = (uint32_t)previndex->nTime; } - komodo_stake(height,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n,block.nTime,prevtime); + eligible = komodo_stake(height,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n,block.nTime,prevtime); + if ( eligible > block.nTime ) + fprintf(stderr,"eligible.%u vs blocktime.%u, lag.%d\n",eligible,(uint32_t)block.nTime,(int32_t)(eligible - block.nTime)); } if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && block.vtx[0].vout.size() > 1 ) { diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 393b5afbe..60c1aa7be 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4439,11 +4439,11 @@ UniValue z_listoperationids(const UniValue& params, bool fHelp) #include "script/sign.h" int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex); extern std::string NOTARY_PUBKEY; -int32_t komodo_stake(int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,uint32_t prevtime); +uint32_t komodo_stake(int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,uint32_t prevtime); int32_t komodo_staked(uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) { - set setAddress; int32_t i,siglen=0,nMinDepth = 1,nMaxDepth = 9999999; vector vecOutputs; + set setAddress; int32_t i,siglen=0,nMinDepth = 1,nMaxDepth = 9999999; vector vecOutputs; const COutput& best; uint32_t earliest = 0; assert(pwalletMain != NULL); LOCK2(cs_main, pwalletMain->cs_wallet); *utxovaluep = 0; @@ -4466,10 +4466,6 @@ int32_t komodo_staked(uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp, CAmount nValue = out.tx->vout[out.i].nValue; const CScript& pk = out.tx->vout[out.i].scriptPubKey; //entry.push_back(Pair("generated", out.tx->IsCoinBase())); - *utxovaluep = (uint64_t)nValue; - decode_hex((uint8_t *)utxotxidp,32,(char *)out.tx->GetHash().GetHex().c_str()); - *utxovoutp = out.i; - *txtimep = (uint32_t)out.tx->nLockTime; CTxDestination address; if (ExtractDestination(out.tx->vout[out.i].scriptPubKey, address)) { @@ -4499,35 +4495,47 @@ int32_t komodo_staked(uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp, komodo_accrued_interest(&txheight,&locktime,out.tx->GetHash(),out.i,0,nValue,(int32_t)tipindex->nHeight); interest = komodo_interest(txheight,nValue,out.tx->nLockTime,tipindex->nTime); //entry.push_back(Pair("interest",ValueFromAmount(interest))); - komodo_stake((uint32_t)tipindex->nHeight+1,out.tx->GetHash(),out.i,*blocktimep,(uint32_t)tipindex->nTime); + eligible = komodo_stake((uint32_t)tipindex->nHeight+1,out.tx->GetHash(),out.i,*blocktimep,(uint32_t)tipindex->nTime); + if ( eligible > 0 && eligible < earliest ) + { + earliest = eligible; + best = out; + *utxovaluep = (uint64_t)nValue; + decode_hex((uint8_t *)utxotxidp,32,(char *)out.tx->GetHash().GetHex().c_str()); + *utxovoutp = out.i; + *txtimep = (uint32_t)out.tx->nLockTime; + } } //fprintf(stderr,"(%s) %s/v%d nValue %.8f locktime.%u txheight.%d pindexht.%d\n",CBitcoinAddress(address).ToString().c_str(),out.tx->GetHash().GetHex().c_str(),out.i,(double)nValue/COIN,locktime,txheight,pindex->nHeight); } - bool signSuccess; SignatureData sigdata; uint64_t txfee; uint8_t *ptr; uint256 revtxid,utxotxid; - auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); - const CKeyStore& keystore = *pwalletMain; - CMutableTransaction txNew = CreateNewContextualCMutableTransaction(Params().GetConsensus(), chainActive.Height() + 1); - txNew.vin.resize(1); - txNew.vout.resize(1); - txfee = 0; - for (i=0; i<32; i++) - ((uint8_t *)&revtxid)[i] = ((uint8_t *)utxotxidp)[31 - i]; - txNew.vin[0].prevout.hash = revtxid; - txNew.vin[0].prevout.n = *utxovoutp; - txNew.vout[0].scriptPubKey = CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG; - txNew.vout[0].nValue = nValue - txfee; - txNew.nLockTime = *blocktimep; - CTransaction txNewConst(txNew); - signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, nValue, SIGHASH_ALL), out.tx->vout[out.i].scriptPubKey, sigdata, consensusBranchId); - if (!signSuccess) - fprintf(stderr,"failed to create signature\n"); - else + if ( earliest != 0 ) { - ptr = (uint8_t *)sigdata.scriptSig.data(); - siglen = sigdata.scriptSig.size(); - for (i=0; ivout[best.i].scriptPubKey, sigdata, consensusBranchId); + if (!signSuccess) + fprintf(stderr,"failed to create signature\n"); + else + { + ptr = (uint8_t *)sigdata.scriptSig.data(); + siglen = sigdata.scriptSig.size(); + for (i=0; i Date: Mon, 9 Apr 2018 18:02:28 +0300 Subject: [PATCH 193/339] Test --- src/wallet/rpcwallet.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 60c1aa7be..88454da8d 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4443,10 +4443,11 @@ uint32_t komodo_stake(int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime, int32_t komodo_staked(uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) { - set setAddress; int32_t i,siglen=0,nMinDepth = 1,nMaxDepth = 9999999; vector vecOutputs; const COutput& best; uint32_t earliest = 0; + set setAddress; int32_t i,siglen=0,nMinDepth = 1,nMaxDepth = 9999999; vector vecOutputs; const COutpu best; uint32_t eligible,earliest = 0; assert(pwalletMain != NULL); LOCK2(cs_main, pwalletMain->cs_wallet); *utxovaluep = 0; + memset(&best,0,sizeof(best)); memset(utxotxidp,0,sizeof(*utxotxidp)); memset(utxovoutp,0,sizeof(*utxovoutp)); memset(utxosig,0,72); @@ -4492,9 +4493,6 @@ int32_t komodo_staked(uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp, uint64_t interest; uint32_t locktime; int32_t txheight; if ( pindex != 0 && (tipindex= chainActive.Tip()) != 0 ) { - komodo_accrued_interest(&txheight,&locktime,out.tx->GetHash(),out.i,0,nValue,(int32_t)tipindex->nHeight); - interest = komodo_interest(txheight,nValue,out.tx->nLockTime,tipindex->nTime); - //entry.push_back(Pair("interest",ValueFromAmount(interest))); eligible = komodo_stake((uint32_t)tipindex->nHeight+1,out.tx->GetHash(),out.i,*blocktimep,(uint32_t)tipindex->nTime); if ( eligible > 0 && eligible < earliest ) { From ebcb53068f0c88b536012281d100ee8834d2e904 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 18:03:28 +0300 Subject: [PATCH 194/339] Test --- src/wallet/rpcwallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 88454da8d..b8a0a87de 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4443,7 +4443,7 @@ uint32_t komodo_stake(int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime, int32_t komodo_staked(uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) { - set setAddress; int32_t i,siglen=0,nMinDepth = 1,nMaxDepth = 9999999; vector vecOutputs; const COutpu best; uint32_t eligible,earliest = 0; + set setAddress; int32_t i,siglen=0,nMinDepth = 1,nMaxDepth = 9999999; vector vecOutputs; COutput best; uint32_t eligible,earliest = 0; assert(pwalletMain != NULL); LOCK2(cs_main, pwalletMain->cs_wallet); *utxovaluep = 0; From df643d5cd7d11ce2fda8090ea64b81e54668b462 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 18:06:37 +0300 Subject: [PATCH 195/339] Test --- src/wallet/rpcwallet.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index b8a0a87de..5d3feeeb0 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4443,11 +4443,10 @@ uint32_t komodo_stake(int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime, int32_t komodo_staked(uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) { - set setAddress; int32_t i,siglen=0,nMinDepth = 1,nMaxDepth = 9999999; vector vecOutputs; COutput best; uint32_t eligible,earliest = 0; + set setAddress; int32_t i,siglen=0,nMinDepth = 1,nMaxDepth = 9999999; vector vecOutputs; uint32_t eligible,earliest = 0; CScript best_scriptPubkey; assert(pwalletMain != NULL); LOCK2(cs_main, pwalletMain->cs_wallet); *utxovaluep = 0; - memset(&best,0,sizeof(best)); memset(utxotxidp,0,sizeof(*utxotxidp)); memset(utxovoutp,0,sizeof(*utxovoutp)); memset(utxosig,0,72); @@ -4497,7 +4496,7 @@ int32_t komodo_staked(uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp, if ( eligible > 0 && eligible < earliest ) { earliest = eligible; - best = out; + best_scriptPubkey = out.tx->vout[out.i].scriptPubKey; *utxovaluep = (uint64_t)nValue; decode_hex((uint8_t *)utxotxidp,32,(char *)out.tx->GetHash().GetHex().c_str()); *utxovoutp = out.i; @@ -4523,7 +4522,7 @@ int32_t komodo_staked(uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp, txNew.vout[0].nValue = nValue - txfee; txNew.nLockTime = *blocktimep; CTransaction txNewConst(txNew); - signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, nValue, SIGHASH_ALL), best.tx->vout[best.i].scriptPubKey, sigdata, consensusBranchId); + signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, nValue, SIGHASH_ALL), best_scriptPubKey, sigdata, consensusBranchId); if (!signSuccess) fprintf(stderr,"failed to create signature\n"); else From 9159a0408bfbc53b994caaa1cdcce1872bd4fc80 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 18:07:58 +0300 Subject: [PATCH 196/339] Test --- src/wallet/rpcwallet.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 5d3feeeb0..f208635ff 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4443,7 +4443,7 @@ uint32_t komodo_stake(int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime, int32_t komodo_staked(uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) { - set setAddress; int32_t i,siglen=0,nMinDepth = 1,nMaxDepth = 9999999; vector vecOutputs; uint32_t eligible,earliest = 0; CScript best_scriptPubkey; + set setAddress; int32_t i,siglen=0,nMinDepth = 1,nMaxDepth = 9999999; vector vecOutputs; uint32_t eligible,earliest = 0; CScript best_scriptPubKey; assert(pwalletMain != NULL); LOCK2(cs_main, pwalletMain->cs_wallet); *utxovaluep = 0; @@ -4496,7 +4496,7 @@ int32_t komodo_staked(uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp, if ( eligible > 0 && eligible < earliest ) { earliest = eligible; - best_scriptPubkey = out.tx->vout[out.i].scriptPubKey; + best_scriptPubKey = out.tx->vout[out.i].scriptPubKey; *utxovaluep = (uint64_t)nValue; decode_hex((uint8_t *)utxotxidp,32,(char *)out.tx->GetHash().GetHex().c_str()); *utxovoutp = out.i; From 39e050579014fa89308de9b72269b39545b23544 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 18:24:11 +0300 Subject: [PATCH 197/339] Test --- src/komodo_gateway.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index e002711ac..232a78eb1 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -672,11 +672,11 @@ uint64_t komodo_commission(const CBlock &block) uint32_t komodo_stake(int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,uint32_t prevtime) { - uint32_t txtime,minutes; uint64_t value,hit; + uint32_t txtime,minutes; uint64_t value,coinage; txtime = komodo_txtime(&value,hash,n); minutes = (blocktime - txtime) / 60; - hit = value / (blocktime - txtime); - fprintf(stderr,"hit.%llu ht.%d txtime.%u blocktime.%u prev.%u gap.%d minutes.%d %.8f\n",(long long)hit,nHeight,txtime,blocktime,prevtime,(int32_t)(blocktime - prevtime),minutes,dstr(value)); + coinage = value * (blocktime - txtime); + fprintf(stderr,"coinage.%llu ht.%d txtime.%u blocktime.%u prev.%u gap.%d minutes.%d %.8f\n",(long long)coinage,nHeight,txtime,blocktime,prevtime,(int32_t)(blocktime - prevtime),minutes,dstr(value)); if ( nHeight < 200 ) return(blocktime); else return(0); From 8a29624f4ce98d017449b8a694e21563686e454c Mon Sep 17 00:00:00 2001 From: Scott Sadler Date: Mon, 9 Apr 2018 12:36:43 -0300 Subject: [PATCH 198/339] remove stray printf --- src/test-komodo/test_eval_notarisation.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/test-komodo/test_eval_notarisation.cpp b/src/test-komodo/test_eval_notarisation.cpp index c33cc4686..86d5f58c4 100644 --- a/src/test-komodo/test_eval_notarisation.cpp +++ b/src/test-komodo/test_eval_notarisation.cpp @@ -111,8 +111,6 @@ TEST(TestEvalNotarisation, testGetNotarisation) MoMProof proof; E_UNMARSHAL(vMomProof, ss >> proof); - printf("lb:%lu\n", proof.branch.size()); - printf("%i, %s\n", proof.nIndex, proof.notarisationHash.GetHex().data()); EXPECT_EQ(data.MoM, proof.Exec(proofTxHash)); } From add7f889fd862c0825afde268778e401f6ff53ca Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 18:38:38 +0300 Subject: [PATCH 199/339] Test --- src/komodo_gateway.h | 2 ++ src/wallet/rpcwallet.cpp | 27 ++++++++++++--------------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 232a78eb1..e1c8ec4fd 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -675,6 +675,8 @@ uint32_t komodo_stake(int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime, uint32_t txtime,minutes; uint64_t value,coinage; txtime = komodo_txtime(&value,hash,n); minutes = (blocktime - txtime) / 60; + if ( txtime == 0 ) + txtime = prevtime; coinage = value * (blocktime - txtime); fprintf(stderr,"coinage.%llu ht.%d txtime.%u blocktime.%u prev.%u gap.%d minutes.%d %.8f\n",(long long)coinage,nHeight,txtime,blocktime,prevtime,(int32_t)(blocktime - prevtime),minutes,dstr(value)); if ( nHeight < 200 ) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index f208635ff..9954456fd 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4485,23 +4485,20 @@ int32_t komodo_staked(uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp, } } entry.push_back(Pair("amount",ValueFromAmount(nValue)));*/ - if ( out.tx->nLockTime != 0 ) + BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); + CBlockIndex *tipindex,*pindex = it->second; + uint64_t interest; uint32_t locktime; int32_t txheight; + if ( pindex != 0 && (tipindex= chainActive.Tip()) != 0 ) { - BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); - CBlockIndex *tipindex,*pindex = it->second; - uint64_t interest; uint32_t locktime; int32_t txheight; - if ( pindex != 0 && (tipindex= chainActive.Tip()) != 0 ) + eligible = komodo_stake((uint32_t)tipindex->nHeight+1,out.tx->GetHash(),out.i,*blocktimep,(uint32_t)tipindex->nTime); + if ( eligible > 0 && eligible < earliest ) { - eligible = komodo_stake((uint32_t)tipindex->nHeight+1,out.tx->GetHash(),out.i,*blocktimep,(uint32_t)tipindex->nTime); - if ( eligible > 0 && eligible < earliest ) - { - earliest = eligible; - best_scriptPubKey = out.tx->vout[out.i].scriptPubKey; - *utxovaluep = (uint64_t)nValue; - decode_hex((uint8_t *)utxotxidp,32,(char *)out.tx->GetHash().GetHex().c_str()); - *utxovoutp = out.i; - *txtimep = (uint32_t)out.tx->nLockTime; - } + earliest = eligible; + best_scriptPubKey = out.tx->vout[out.i].scriptPubKey; + *utxovaluep = (uint64_t)nValue; + decode_hex((uint8_t *)utxotxidp,32,(char *)out.tx->GetHash().GetHex().c_str()); + *utxovoutp = out.i; + *txtimep = (uint32_t)out.tx->nLockTime; } //fprintf(stderr,"(%s) %s/v%d nValue %.8f locktime.%u txheight.%d pindexht.%d\n",CBitcoinAddress(address).ToString().c_str(),out.tx->GetHash().GetHex().c_str(),out.i,(double)nValue/COIN,locktime,txheight,pindex->nHeight); } From a2cc707b5433bbe343fc0330bd53d8a8d7d83001 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 18:44:52 +0300 Subject: [PATCH 200/339] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index e1c8ec4fd..901fb6487 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -678,7 +678,7 @@ uint32_t komodo_stake(int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime, if ( txtime == 0 ) txtime = prevtime; coinage = value * (blocktime - txtime); - fprintf(stderr,"coinage.%llu ht.%d txtime.%u blocktime.%u prev.%u gap.%d minutes.%d %.8f\n",(long long)coinage,nHeight,txtime,blocktime,prevtime,(int32_t)(blocktime - prevtime),minutes,dstr(value)); + fprintf(stderr,"coinage.%llu %d ht.%d txtime.%u blocktime.%u prev.%u gap.%d minutes.%d %.8f\n",(long long)coinage,(int32_t)(blocktime - txtime),nHeight,txtime,blocktime,prevtime,(int32_t)(blocktime - prevtime),minutes,dstr(value)); if ( nHeight < 200 ) return(blocktime); else return(0); From f65cd56ff25f590939b8da748a90c7fa146413da Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 18:49:38 +0300 Subject: [PATCH 201/339] Test --- src/komodo_gateway.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 901fb6487..99657dfec 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -672,13 +672,13 @@ uint64_t komodo_commission(const CBlock &block) uint32_t komodo_stake(int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,uint32_t prevtime) { - uint32_t txtime,minutes; uint64_t value,coinage; + uint32_t txtime,minutes; uint64_t value,coinage,supply = ASSETCHAINS_SUPPLY*SATOSHIDEN + nHeight*ASSETCHAINS_REWARD; txtime = komodo_txtime(&value,hash,n); minutes = (blocktime - txtime) / 60; if ( txtime == 0 ) txtime = prevtime; - coinage = value * (blocktime - txtime); - fprintf(stderr,"coinage.%llu %d ht.%d txtime.%u blocktime.%u prev.%u gap.%d minutes.%d %.8f\n",(long long)coinage,(int32_t)(blocktime - txtime),nHeight,txtime,blocktime,prevtime,(int32_t)(blocktime - prevtime),minutes,dstr(value)); + coinage = value * (blocktime - txtime) * value / supply; + fprintf(stderr,"coinage.%llu %d ht.%d txtime.%u blocktime.%u prev.%u gap.%d minutes.%d %.8f.%.8f\n",(long long)coinage,(int32_t)(blocktime - txtime),nHeight,txtime,blocktime,prevtime,(int32_t)(blocktime - prevtime),minutes,dstr(value),dstr(supply)); if ( nHeight < 200 ) return(blocktime); else return(0); From 97dfa23436a2450d09687b90beddc5cf55192022 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 18:52:59 +0300 Subject: [PATCH 202/339] Test --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 99657dfec..c5f5b0f5c 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -672,12 +672,12 @@ uint64_t komodo_commission(const CBlock &block) uint32_t komodo_stake(int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,uint32_t prevtime) { - uint32_t txtime,minutes; uint64_t value,coinage,supply = ASSETCHAINS_SUPPLY*SATOSHIDEN + nHeight*ASSETCHAINS_REWARD; + uint32_t txtime,minutes; uint64_t value,coinage,supply = ASSETCHAINS_SUPPLY + nHeight*ASSETCHAINS_REWARD/SATOSHIDEN; txtime = komodo_txtime(&value,hash,n); minutes = (blocktime - txtime) / 60; if ( txtime == 0 ) txtime = prevtime; - coinage = value * (blocktime - txtime) * value / supply; + coinage = value * (blocktime - txtime) / supply; fprintf(stderr,"coinage.%llu %d ht.%d txtime.%u blocktime.%u prev.%u gap.%d minutes.%d %.8f.%.8f\n",(long long)coinage,(int32_t)(blocktime - txtime),nHeight,txtime,blocktime,prevtime,(int32_t)(blocktime - prevtime),minutes,dstr(value),dstr(supply)); if ( nHeight < 200 ) return(blocktime); From d16afe20169cc87c5fa4eadfbe1ca34e859e8361 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 18:57:37 +0300 Subject: [PATCH 203/339] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index c5f5b0f5c..8a026e239 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -678,7 +678,7 @@ uint32_t komodo_stake(int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime, if ( txtime == 0 ) txtime = prevtime; coinage = value * (blocktime - txtime) / supply; - fprintf(stderr,"coinage.%llu %d ht.%d txtime.%u blocktime.%u prev.%u gap.%d minutes.%d %.8f.%.8f\n",(long long)coinage,(int32_t)(blocktime - txtime),nHeight,txtime,blocktime,prevtime,(int32_t)(blocktime - prevtime),minutes,dstr(value),dstr(supply)); + fprintf(stderr,"coinage.%llu %d ht.%d txtime.%u blocktime.%u prev.%u gap.%d minutes.%d %.8f/%llu\n",(long long)coinage,(int32_t)(blocktime - txtime),nHeight,txtime,blocktime,prevtime,(int32_t)(blocktime - prevtime),minutes,dstr(value),(long long)supply); if ( nHeight < 200 ) return(blocktime); else return(0); From 357e4ca5f0ea40e93912b90e6c3b5ae90b6738a6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 19:33:50 +0300 Subject: [PATCH 204/339] Test --- src/komodo_gateway.h | 32 +++++++++++++++++++++++--------- src/miner.cpp | 11 +++++++---- src/wallet/rpcwallet.cpp | 9 +++++---- 3 files changed, 35 insertions(+), 17 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 8a026e239..3a6f97af6 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -670,18 +670,31 @@ uint64_t komodo_commission(const CBlock &block) return((total * ASSETCHAINS_COMMISSION) / COIN); } -uint32_t komodo_stake(int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,uint32_t prevtime) +uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,uint32_t prevtime) { - uint32_t txtime,minutes; uint64_t value,coinage,supply = ASSETCHAINS_SUPPLY + nHeight*ASSETCHAINS_REWARD/SATOSHIDEN; + CBlockIndex *pindex; arith_uint256 hashval; uint256 hash; int32_t i; uint32_t txtime,minutes,winner = 0; uint64_t value,coinage,supply = ASSETCHAINS_SUPPLY + nHeight*ASSETCHAINS_REWARD/SATOSHIDEN; + if ( nHeight < 200 ) + return(blocktime); txtime = komodo_txtime(&value,hash,n); minutes = (blocktime - txtime) / 60; if ( txtime == 0 ) txtime = prevtime; - coinage = value * (blocktime - txtime) / supply; - fprintf(stderr,"coinage.%llu %d ht.%d txtime.%u blocktime.%u prev.%u gap.%d minutes.%d %.8f/%llu\n",(long long)coinage,(int32_t)(blocktime - txtime),nHeight,txtime,blocktime,prevtime,(int32_t)(blocktime - prevtime),minutes,dstr(value),(long long)supply); - if ( nHeight < 200 ) - return(blocktime); - else return(0); + if ( (pindex= komodo_chainactive(nHeight-200)) != 0 ) + { + coinage = value * (blocktime - txtime) / supply; + hash = pindex->GetBlockHash(); // hash pubkey + hashval = UintToArith256(hash); + hashval = (hashval / arith_uint256(coinage+1)); + if ( hashval <= bnTarget ) + winner = 1; + for (i=31; i>=0; i--) + printf("%02x",((uint8_t *)&hashval)[i]); + printf(" vs "); + for (i=31; i>=0; i--) + printf("%02x",((uint8_t *)&bnTarget)[i]); + fprintf(stderr," winner.%d %s coinage.%llu %d ht.%d gap.%d minutes.%d %.8f/%llu\n",winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,(int32_t)(blocktime - prevtime),minutes,dstr(value),(long long)supply); + } + return(0); } int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtime) // verify above block is valid pax pricing @@ -756,13 +769,14 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim { if ( ASSETCHAINS_STAKED != 0 ) { - CBlockIndex *previndex; uint32_t eligible; + arith_uint256 bnTarget; bool fNegative,fOverflow; CBlockIndex *previndex; uint32_t eligible; if ( prevtime == 0 ) { if ( (previndex= mapBlockIndex[block.hashPrevBlock]) != 0 ) prevtime = (uint32_t)previndex->nTime; } - eligible = komodo_stake(height,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n,block.nTime,prevtime); + bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow); + eligible = komodo_stake(height,bnTarget,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n,block.nTime,prevtime); if ( eligible > block.nTime ) fprintf(stderr,"eligible.%u vs blocktime.%u, lag.%d\n",eligible,(uint32_t)block.nTime,(int32_t)(eligible - block.nTime)); } diff --git a/src/miner.cpp b/src/miner.cpp index 1c948e124..adc562bdf 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -120,7 +120,7 @@ int32_t komodo_gateway_deposits(CMutableTransaction *txNew,char *symbol,int32_t int32_t komodo_isrealtime(int32_t *kmdheightp); int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_t nTime,int32_t dispflag); uint64_t komodo_commission(const CBlock &block); -int32_t komodo_staked(uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig); +int32_t komodo_staked(uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig); CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) { @@ -385,7 +385,9 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) nLastBlockTx = nBlockTx; nLastBlockSize = nBlockSize; blocktime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); - LogPrintf("CreateNewBlock(): total size %u blocktime.%u\n", nBlockSize,blocktime); + pblock->nTime = blocktime; + pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus()); + LogPrintf("CreateNewBlock(): total size %u blocktime.%u nBits.%08x\n", nBlockSize,blocktime,pblock->nBits); if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_STAKED != 0 && NOTARY_PUBKEY33[0] != 0 ) { uint64_t txfees,utxovalue; uint32_t txtime; uint256 utxotxid,revtxid; int32_t i,siglen,numsigs,utxovout; uint8_t utxosig[128],*ptr; @@ -480,7 +482,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) pblock->hashPrevBlock = pindexPrev->GetBlockHash(); pblock->hashReserved = uint256(); //UpdateTime(pblock, Params().GetConsensus(), pindexPrev); - pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus()); + //pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus()); pblock->nSolution.clear(); pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]); @@ -1033,7 +1035,8 @@ void static BitcoinMiner() // Update nNonce and nTime pblock->nNonce = ArithToUint256(UintToArith256(pblock->nNonce) + 1); pblock->nBits = savebits; - UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); + if ( ASSETCHAINS_STAKED == 0 ) + UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); if (chainparams.GetConsensus().fPowAllowMinDifficultyBlocks) { // Changing pblock->nTime can change work required on testnet: diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 9954456fd..53e3fdeff 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4439,11 +4439,12 @@ UniValue z_listoperationids(const UniValue& params, bool fHelp) #include "script/sign.h" int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex); extern std::string NOTARY_PUBKEY; -uint32_t komodo_stake(int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,uint32_t prevtime); +uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,uint32_t prevtime); -int32_t komodo_staked(uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) +int32_t komodo_staked(uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) { - set setAddress; int32_t i,siglen=0,nMinDepth = 1,nMaxDepth = 9999999; vector vecOutputs; uint32_t eligible,earliest = 0; CScript best_scriptPubKey; + set setAddress; int32_t i,siglen=0,nMinDepth = 1,nMaxDepth = 9999999; vector vecOutputs; uint32_t eligible,earliest = 0; CScript best_scriptPubKey; arith_uint256 bnTarget; bool fNegative,fOverflow; + bnTarget.SetCompact(nBits, &fNegative, &fOverflow); assert(pwalletMain != NULL); LOCK2(cs_main, pwalletMain->cs_wallet); *utxovaluep = 0; @@ -4490,7 +4491,7 @@ int32_t komodo_staked(uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp, uint64_t interest; uint32_t locktime; int32_t txheight; if ( pindex != 0 && (tipindex= chainActive.Tip()) != 0 ) { - eligible = komodo_stake((uint32_t)tipindex->nHeight+1,out.tx->GetHash(),out.i,*blocktimep,(uint32_t)tipindex->nTime); + eligible = komodo_stake(bnTarget,(uint32_t)tipindex->nHeight+1,out.tx->GetHash(),out.i,*blocktimep,(uint32_t)tipindex->nTime); if ( eligible > 0 && eligible < earliest ) { earliest = eligible; From 42673bc0722b84ec03c270b68952cf28679a7625 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 19:34:56 +0300 Subject: [PATCH 205/339] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 3a6f97af6..44abafa92 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -776,7 +776,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim prevtime = (uint32_t)previndex->nTime; } bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow); - eligible = komodo_stake(height,bnTarget,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n,block.nTime,prevtime); + eligible = komodo_stake(bnTarget,height,bnTarget,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n,block.nTime,prevtime); if ( eligible > block.nTime ) fprintf(stderr,"eligible.%u vs blocktime.%u, lag.%d\n",eligible,(uint32_t)block.nTime,(int32_t)(eligible - block.nTime)); } From 66b30bbc39c4bf0b847e986c742c7d42b44b3cf1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 19:35:48 +0300 Subject: [PATCH 206/339] Test --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 44abafa92..9541f1949 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -670,12 +670,12 @@ uint64_t komodo_commission(const CBlock &block) return((total * ASSETCHAINS_COMMISSION) / COIN); } -uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,uint32_t prevtime) +uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_t vout,uint32_t blocktime,uint32_t prevtime) { CBlockIndex *pindex; arith_uint256 hashval; uint256 hash; int32_t i; uint32_t txtime,minutes,winner = 0; uint64_t value,coinage,supply = ASSETCHAINS_SUPPLY + nHeight*ASSETCHAINS_REWARD/SATOSHIDEN; if ( nHeight < 200 ) return(blocktime); - txtime = komodo_txtime(&value,hash,n); + txtime = komodo_txtime(&value,txid,vout); minutes = (blocktime - txtime) / 60; if ( txtime == 0 ) txtime = prevtime; From c59bdf3a8152f2d2dda593bdc0501cf3dd5b1ce1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 19:37:00 +0300 Subject: [PATCH 207/339] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 9541f1949..dc4a021f0 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -692,7 +692,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ printf(" vs "); for (i=31; i>=0; i--) printf("%02x",((uint8_t *)&bnTarget)[i]); - fprintf(stderr," winner.%d %s coinage.%llu %d ht.%d gap.%d minutes.%d %.8f/%llu\n",winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,(int32_t)(blocktime - prevtime),minutes,dstr(value),(long long)supply); + fprintf(stderr," winner.%d coinage.%llu %d ht.%d gap.%d minutes.%d %.8f/%llu\n",winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,(int32_t)(blocktime - prevtime),minutes,dstr(value),(long long)supply); } return(0); } From fd573503ba10d577bc165dac6f9f7dfadc53ed9d Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 19:40:22 +0300 Subject: [PATCH 208/339] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index dc4a021f0..3bfd0b58a 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -776,7 +776,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim prevtime = (uint32_t)previndex->nTime; } bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow); - eligible = komodo_stake(bnTarget,height,bnTarget,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n,block.nTime,prevtime); + eligible = komodo_stake(bnTarget,height,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n,block.nTime,prevtime); if ( eligible > block.nTime ) fprintf(stderr,"eligible.%u vs blocktime.%u, lag.%d\n",eligible,(uint32_t)block.nTime,(int32_t)(eligible - block.nTime)); } From acb3822ea063ff2317c6eadc07d1ccb56b66e7e5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 19:42:12 +0300 Subject: [PATCH 209/339] Test --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index adc562bdf..5acd8da34 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -391,7 +391,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_STAKED != 0 && NOTARY_PUBKEY33[0] != 0 ) { uint64_t txfees,utxovalue; uint32_t txtime; uint256 utxotxid,revtxid; int32_t i,siglen,numsigs,utxovout; uint8_t utxosig[128],*ptr; - if ( (siglen= komodo_staked(&blocktime,&txtime,&utxotxid,&utxovout,&utxovalue,utxosig)) > 0 ) + if ( (siglen= komodo_staked(pblock->nBits,&blocktime,&txtime,&utxotxid,&utxovout,&utxovalue,utxosig)) > 0 ) { CMutableTransaction txStaked = CreateNewContextualCMutableTransaction(chainparams.GetConsensus(), nHeight); CAmount txfees = 0; From aa789b4f24f1c102573c5eac54bd9f4d629ceae0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 19:46:18 +0300 Subject: [PATCH 210/339] Test --- src/komodo_gateway.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 3bfd0b58a..e52c27ac4 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -688,10 +688,10 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ if ( hashval <= bnTarget ) winner = 1; for (i=31; i>=0; i--) - printf("%02x",((uint8_t *)&hashval)[i]); - printf(" vs "); + fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]); + fprintf(stderr," vs "); for (i=31; i>=0; i--) - printf("%02x",((uint8_t *)&bnTarget)[i]); + fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); fprintf(stderr," winner.%d coinage.%llu %d ht.%d gap.%d minutes.%d %.8f/%llu\n",winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,(int32_t)(blocktime - prevtime),minutes,dstr(value),(long long)supply); } return(0); From 6eb0958c4d03eae1f2705f667d9cf947f7a5c4af Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 19:57:32 +0300 Subject: [PATCH 211/339] Test --- src/komodo_gateway.h | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index e52c27ac4..4e0257fff 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -672,21 +672,30 @@ uint64_t komodo_commission(const CBlock &block) uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_t vout,uint32_t blocktime,uint32_t prevtime) { - CBlockIndex *pindex; arith_uint256 hashval; uint256 hash; int32_t i; uint32_t txtime,minutes,winner = 0; uint64_t value,coinage,supply = ASSETCHAINS_SUPPLY + nHeight*ASSETCHAINS_REWARD/SATOSHIDEN; + CBlockIndex *pindex; arith_uint256 hashval; uint256 hash; int32_t i; uint32_t txtime,minutes,winner = 0; uint64_t diff,value,coinage,supply = ASSETCHAINS_SUPPLY + nHeight*ASSETCHAINS_REWARD/SATOSHIDEN; if ( nHeight < 200 ) return(blocktime); txtime = komodo_txtime(&value,txid,vout); minutes = (blocktime - txtime) / 60; if ( txtime == 0 ) txtime = prevtime; - if ( (pindex= komodo_chainactive(nHeight-200)) != 0 ) + if ( blocktime > txtime && (pindex= komodo_chainactive(nHeight-200)) != 0 ) { - coinage = value * (blocktime - txtime) / supply; + diff = (blocktime - txtime); + coinage = value * diff / supply; hash = pindex->GetBlockHash(); // hash pubkey hashval = UintToArith256(hash); hashval = (hashval / arith_uint256(coinage+1)); if ( hashval <= bnTarget ) winner = 1; + else + { + arith_uint256 val; + val = bnTarget * arith_uint256(value*diff/supply) / UintToArith256(hash) + for (i=31; i>=0; i--) + fprintf(stderr,"%02x",((uint8_t *)&val)[i]); + printf(" adjust val\n"); + } for (i=31; i>=0; i--) fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]); fprintf(stderr," vs "); From dd5541420a60692d48d5fcd8d78e15a4b834110a Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 19:58:41 +0300 Subject: [PATCH 212/339] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 4e0257fff..17a62d990 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -691,7 +691,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ else { arith_uint256 val; - val = bnTarget * arith_uint256(value*diff/supply) / UintToArith256(hash) + val = bnTarget * arith_uint256(value*diff/supply) / UintToArith256(hash); for (i=31; i>=0; i--) fprintf(stderr,"%02x",((uint8_t *)&val)[i]); printf(" adjust val\n"); From 8e9ef91cf4b37998b77f8cb343d40dd9bc4ae276 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 20:06:19 +0300 Subject: [PATCH 213/339] Test --- src/miner.cpp | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 5acd8da34..69a7d240c 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -752,7 +752,7 @@ void static BitcoinMiner() Mining_height = pindexPrev->nHeight+1; Mining_start = (uint32_t)time(NULL); } - if ( ASSETCHAINS_SYMBOL[0] != 0 ) + if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_STAKED == 0 ) { //fprintf(stderr,"%s create new block ht.%d\n",ASSETCHAINS_SYMBOL,Mining_height); sleep(3); @@ -900,17 +900,26 @@ void static BitcoinMiner() // fprintf(stderr," missed target\n"); return false; } - if ( /*ASSETCHAINS_SYMBOL[0] == 0 &&*/ Mining_start != 0 && time(NULL) < Mining_start+roundrobin_delay ) + if ( ASSETCHAINS_STAKED == 0 ) { - //printf("Round robin diff sleep %d\n",(int32_t)(Mining_start+roundrobin_delay-time(NULL))); - int32_t nseconds = Mining_start+roundrobin_delay-time(NULL); - if ( nseconds > 0 ) - sleep(nseconds); - MilliSleep((rand() % 1700) + 1); + if ( Mining_start != 0 && time(NULL) < Mining_start+roundrobin_delay ) + { + //printf("Round robin diff sleep %d\n",(int32_t)(Mining_start+roundrobin_delay-time(NULL))); + int32_t nseconds = Mining_start+roundrobin_delay-time(NULL); + if ( nseconds > 0 ) + sleep(nseconds); + MilliSleep((rand() % 1700) + 1); + } + else if ( ASSETCHAINS_SYMBOL[0] != 0 ) + { + sleep(rand() % 30); + } } - else if ( ASSETCHAINS_SYMBOL[0] != 0 ) + else { - sleep(rand() % 30); + printf("need to wait %d seconds to submit\n",(int32_t)(pblock->nTime - GetAdjustedTime())); + while ( GetAdjustedTime() < pblock->nTime ) + sleep(1); } KOMODO_CHOSEN_ONE = 1; // Found a solution From ee2d6a73da2ad82348b0073077783b316eb9ade8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 20:07:45 +0300 Subject: [PATCH 214/339] Test --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 17a62d990..353f8f72f 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -703,7 +703,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); fprintf(stderr," winner.%d coinage.%llu %d ht.%d gap.%d minutes.%d %.8f/%llu\n",winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,(int32_t)(blocktime - prevtime),minutes,dstr(value),(long long)supply); } - return(0); + return(blocktime * winner); } int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtime) // verify above block is valid pax pricing @@ -786,7 +786,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim } bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow); eligible = komodo_stake(bnTarget,height,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n,block.nTime,prevtime); - if ( eligible > block.nTime ) + if ( eligible == 0 || eligible > block.nTime ) fprintf(stderr,"eligible.%u vs blocktime.%u, lag.%d\n",eligible,(uint32_t)block.nTime,(int32_t)(eligible - block.nTime)); } if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && block.vtx[0].vout.size() > 1 ) From 274f9fb365400f89dd81963f033892cfea941f02 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 20:14:41 +0300 Subject: [PATCH 215/339] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 353f8f72f..9b16c846e 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -682,7 +682,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ if ( blocktime > txtime && (pindex= komodo_chainactive(nHeight-200)) != 0 ) { diff = (blocktime - txtime); - coinage = value * diff / supply; + coinage = value * diff;// / supply; hash = pindex->GetBlockHash(); // hash pubkey hashval = UintToArith256(hash); hashval = (hashval / arith_uint256(coinage+1)); From 64eb9cb21d37cc983ae6b882d7039fb0e99aebc3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 20:21:15 +0300 Subject: [PATCH 216/339] Test --- src/komodo_gateway.h | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 9b16c846e..10edb63db 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -672,7 +672,7 @@ uint64_t komodo_commission(const CBlock &block) uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_t vout,uint32_t blocktime,uint32_t prevtime) { - CBlockIndex *pindex; arith_uint256 hashval; uint256 hash; int32_t i; uint32_t txtime,minutes,winner = 0; uint64_t diff,value,coinage,supply = ASSETCHAINS_SUPPLY + nHeight*ASSETCHAINS_REWARD/SATOSHIDEN; + CBlockIndex *pindex; arith_uint256 hashval; uint256 hash; int32_t i,j; uint32_t txtime,minutes,winner = 0; uint64_t diff,value,coinage,supply = ASSETCHAINS_SUPPLY + nHeight*ASSETCHAINS_REWARD/SATOSHIDEN; if ( nHeight < 200 ) return(blocktime); txtime = komodo_txtime(&value,txid,vout); @@ -681,11 +681,10 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ txtime = prevtime; if ( blocktime > txtime && (pindex= komodo_chainactive(nHeight-200)) != 0 ) { - diff = (blocktime - txtime); - coinage = value * diff;// / supply; hash = pindex->GetBlockHash(); // hash pubkey - hashval = UintToArith256(hash); - hashval = (hashval / arith_uint256(coinage+1)); + diff = (blocktime - txtime); + coinage = value * diff / supply; + hashval = (UintToArith256(hash) / arith_uint256(coinage+1)); if ( hashval <= bnTarget ) winner = 1; else @@ -694,7 +693,19 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ val = bnTarget * arith_uint256(value*diff/supply) / UintToArith256(hash); for (i=31; i>=0; i--) fprintf(stderr,"%02x",((uint8_t *)&val)[i]); - printf(" adjust val\n"); + fprintf(stderr," adjust val\n"); + for (i=1; i<3600; i++) + { + diff = (i + blocktime - txtime); + coinage = value * diff / supply; + hashval = (UintToArith256(hash) / arith_uint256(coinage+1)); + if ( hashval <= bnTarget ) + { + winner = 1; + break; + } + } + fprintf(stderr,"iterated until i.%d winner.%d\n",i,winner); } for (i=31; i>=0; i--) fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]); From 41ed65c8381b7634d495175058ffd585f1c91d48 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 20:25:20 +0300 Subject: [PATCH 217/339] Test --- src/komodo_gateway.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 10edb63db..bf172052c 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -676,6 +676,8 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ if ( nHeight < 200 ) return(blocktime); txtime = komodo_txtime(&value,txid,vout); + if ( value == 0 ) + return(0); minutes = (blocktime - txtime) / 60; if ( txtime == 0 ) txtime = prevtime; @@ -684,7 +686,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ hash = pindex->GetBlockHash(); // hash pubkey diff = (blocktime - txtime); coinage = value * diff / supply; - hashval = (UintToArith256(hash) / arith_uint256(coinage+1)); + hashval = arith_uint256(1000000) * (UintToArith256(hash) / arith_uint256(coinage+1)); if ( hashval <= bnTarget ) winner = 1; else @@ -698,7 +700,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ { diff = (i + blocktime - txtime); coinage = value * diff / supply; - hashval = (UintToArith256(hash) / arith_uint256(coinage+1)); + hashval = arith_uint256(1000000) * (UintToArith256(hash) / arith_uint256(coinage+1)); if ( hashval <= bnTarget ) { winner = 1; From cb6b9bd10dec6f820a2c2361f721b24124f78d79 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 20:33:08 +0300 Subject: [PATCH 218/339] Test --- src/komodo_gateway.h | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index bf172052c..5008c1753 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -685,25 +685,21 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ { hash = pindex->GetBlockHash(); // hash pubkey diff = (blocktime - txtime); - coinage = value * diff / supply; + coinage = (value * diff * diff) / supply; hashval = arith_uint256(1000000) * (UintToArith256(hash) / arith_uint256(coinage+1)); if ( hashval <= bnTarget ) winner = 1; else { - arith_uint256 val; - val = bnTarget * arith_uint256(value*diff/supply) / UintToArith256(hash); - for (i=31; i>=0; i--) - fprintf(stderr,"%02x",((uint8_t *)&val)[i]); - fprintf(stderr," adjust val\n"); - for (i=1; i<3600; i++) + for (i=1; i<3600*8; i++) { diff = (i + blocktime - txtime); - coinage = value * diff / supply; + coinage = (value * diff * diff) / supply; hashval = arith_uint256(1000000) * (UintToArith256(hash) / arith_uint256(coinage+1)); if ( hashval <= bnTarget ) { winner = 1; + blocktime += i; break; } } From 7591c6aa4751baab61fd36726b1e66c7b63e045f Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 20:35:59 +0300 Subject: [PATCH 219/339] Test --- src/komodo_gateway.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 5008c1753..fdb30bb73 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -686,7 +686,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ hash = pindex->GetBlockHash(); // hash pubkey diff = (blocktime - txtime); coinage = (value * diff * diff) / supply; - hashval = arith_uint256(1000000) * (UintToArith256(hash) / arith_uint256(coinage+1)); + hashval = arith_uint256(100000000000) * (UintToArith256(hash) / arith_uint256(coinage+1)); if ( hashval <= bnTarget ) winner = 1; else @@ -695,7 +695,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ { diff = (i + blocktime - txtime); coinage = (value * diff * diff) / supply; - hashval = arith_uint256(1000000) * (UintToArith256(hash) / arith_uint256(coinage+1)); + hashval = arith_uint256(100000000000) * (UintToArith256(hash) / arith_uint256(coinage+1)); if ( hashval <= bnTarget ) { winner = 1; @@ -796,7 +796,9 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow); eligible = komodo_stake(bnTarget,height,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n,block.nTime,prevtime); if ( eligible == 0 || eligible > block.nTime ) + { fprintf(stderr,"eligible.%u vs blocktime.%u, lag.%d\n",eligible,(uint32_t)block.nTime,(int32_t)(eligible - block.nTime)); + } } if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && block.vtx[0].vout.size() > 1 ) { From 1ac4a10dbe986114695af9b5bb257649b6a942a1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 20:38:18 +0300 Subject: [PATCH 220/339] Test --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index fdb30bb73..8238130ee 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -685,7 +685,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ { hash = pindex->GetBlockHash(); // hash pubkey diff = (blocktime - txtime); - coinage = (value * diff * diff) / supply; + coinage = (((value * diff) / supply) * diff) / supply; hashval = arith_uint256(100000000000) * (UintToArith256(hash) / arith_uint256(coinage+1)); if ( hashval <= bnTarget ) winner = 1; @@ -694,7 +694,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ for (i=1; i<3600*8; i++) { diff = (i + blocktime - txtime); - coinage = (value * diff * diff) / supply; + coinage = (((value * diff) / supply) * diff) / supply; hashval = arith_uint256(100000000000) * (UintToArith256(hash) / arith_uint256(coinage+1)); if ( hashval <= bnTarget ) { From e1a17ed172f47f65cc253f6775ccdc70daf8649c Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 20:47:37 +0300 Subject: [PATCH 221/339] Test --- src/komodo_gateway.h | 19 +++++++++---------- src/wallet/rpcwallet.cpp | 1 + 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 8238130ee..3ed0c607f 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -672,13 +672,12 @@ uint64_t komodo_commission(const CBlock &block) uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_t vout,uint32_t blocktime,uint32_t prevtime) { - CBlockIndex *pindex; arith_uint256 hashval; uint256 hash; int32_t i,j; uint32_t txtime,minutes,winner = 0; uint64_t diff,value,coinage,supply = ASSETCHAINS_SUPPLY + nHeight*ASSETCHAINS_REWARD/SATOSHIDEN; + CBlockIndex *pindex; arith_uint256 hashval; uint256 hash; int32_t i,iter=0; uint32_t txtime,winner = 0; uint64_t diff,value,coinage,supply = ASSETCHAINS_SUPPLY + nHeight*ASSETCHAINS_REWARD/SATOSHIDEN; if ( nHeight < 200 ) return(blocktime); txtime = komodo_txtime(&value,txid,vout); if ( value == 0 ) return(0); - minutes = (blocktime - txtime) / 60; if ( txtime == 0 ) txtime = prevtime; if ( blocktime > txtime && (pindex= komodo_chainactive(nHeight-200)) != 0 ) @@ -691,26 +690,26 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ winner = 1; else { - for (i=1; i<3600*8; i++) + for (iter=1; iter<3600*8; iter++) { - diff = (i + blocktime - txtime); + diff = (iter + blocktime - txtime); coinage = (((value * diff) / supply) * diff) / supply; hashval = arith_uint256(100000000000) * (UintToArith256(hash) / arith_uint256(coinage+1)); if ( hashval <= bnTarget ) { winner = 1; - blocktime += i; + blocktime += iter; break; } } - fprintf(stderr,"iterated until i.%d winner.%d\n",i,winner); + //fprintf(stderr,"iterated until i.%d winner.%d\n",i,winner); } for (i=31; i>=0; i--) fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]); - fprintf(stderr," vs "); - for (i=31; i>=0; i--) - fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); - fprintf(stderr," winner.%d coinage.%llu %d ht.%d gap.%d minutes.%d %.8f/%llu\n",winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,(int32_t)(blocktime - prevtime),minutes,dstr(value),(long long)supply); + //fprintf(stderr," vs "); + //for (i=31; i>=0; i--) + // fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); + fprintf(stderr," iter.%d winner.%d coinage.%llu %d ht.%d gap.%d %.8f/%llu\n",iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,(int32_t)(blocktime - prevtime),dstr(value),(long long)supply); } return(blocktime * winner); } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 53e3fdeff..a9e64158c 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4530,6 +4530,7 @@ int32_t komodo_staked(uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint for (i=0; i Date: Mon, 9 Apr 2018 20:51:52 +0300 Subject: [PATCH 222/339] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 3ed0c607f..11ce8f359 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -680,7 +680,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ return(0); if ( txtime == 0 ) txtime = prevtime; - if ( blocktime > txtime && (pindex= komodo_chainactive(nHeight-200)) != 0 ) + if ( blocktime > txtime+6000 && (pindex= komodo_chainactive(nHeight-200)) != 0 ) { hash = pindex->GetBlockHash(); // hash pubkey diff = (blocktime - txtime); From d5d586e078189a8485d3a6a99ad980bb55edb08f Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 20:59:16 +0300 Subject: [PATCH 223/339] Test --- src/komodo_gateway.h | 4 ++-- src/wallet/rpcwallet.cpp | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 11ce8f359..605225eed 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -685,7 +685,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ hash = pindex->GetBlockHash(); // hash pubkey diff = (blocktime - txtime); coinage = (((value * diff) / supply) * diff) / supply; - hashval = arith_uint256(100000000000) * (UintToArith256(hash) / arith_uint256(coinage+1)); + hashval = arith_uint256(1000000) * (UintToArith256(hash) / arith_uint256(coinage+1)); if ( hashval <= bnTarget ) winner = 1; else @@ -694,7 +694,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ { diff = (iter + blocktime - txtime); coinage = (((value * diff) / supply) * diff) / supply; - hashval = arith_uint256(100000000000) * (UintToArith256(hash) / arith_uint256(coinage+1)); + hashval = arith_uint256(1000000) * (UintToArith256(hash) / arith_uint256(coinage+1)); if ( hashval <= bnTarget ) { winner = 1; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index a9e64158c..3d36e43ac 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4530,6 +4530,7 @@ int32_t komodo_staked(uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint for (i=0; i Date: Mon, 9 Apr 2018 21:03:02 +0300 Subject: [PATCH 224/339] Test --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 605225eed..a9cf3edfc 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -684,7 +684,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ { hash = pindex->GetBlockHash(); // hash pubkey diff = (blocktime - txtime); - coinage = (((value * diff) / supply) * diff) / supply; + coinage = (((value * diff) / supply) * diff); hashval = arith_uint256(1000000) * (UintToArith256(hash) / arith_uint256(coinage+1)); if ( hashval <= bnTarget ) winner = 1; @@ -693,7 +693,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ for (iter=1; iter<3600*8; iter++) { diff = (iter + blocktime - txtime); - coinage = (((value * diff) / supply) * diff) / supply; + coinage = (((value * diff) / supply) * diff); hashval = arith_uint256(1000000) * (UintToArith256(hash) / arith_uint256(coinage+1)); if ( hashval <= bnTarget ) { From 14a53f21a1e9e69e226ca150f4d0aad2ecde95ef Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 21:08:46 +0300 Subject: [PATCH 225/339] Test --- src/wallet/rpcwallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 3d36e43ac..a52d7ab46 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4492,7 +4492,7 @@ int32_t komodo_staked(uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint if ( pindex != 0 && (tipindex= chainActive.Tip()) != 0 ) { eligible = komodo_stake(bnTarget,(uint32_t)tipindex->nHeight+1,out.tx->GetHash(),out.i,*blocktimep,(uint32_t)tipindex->nTime); - if ( eligible > 0 && eligible < earliest ) + if ( (eligible > 0 && eligible < earliest) || (eligible == earliest && (*utxovaluep == 0 || nValue < *utxovaluep)) ) { earliest = eligible; best_scriptPubKey = out.tx->vout[out.i].scriptPubKey; From e005f57633c3f198c821b5726b4ad3c60cd71d89 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 21:12:25 +0300 Subject: [PATCH 226/339] Test --- src/komodo_gateway.h | 8 ++++---- src/wallet/rpcwallet.cpp | 17 ++++++++++------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index a9cf3edfc..367393fde 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -704,11 +704,11 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ } //fprintf(stderr,"iterated until i.%d winner.%d\n",i,winner); } - for (i=31; i>=0; i--) + for (i=31; i>=24; i--) fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]); - //fprintf(stderr," vs "); - //for (i=31; i>=0; i--) - // fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); + fprintf(stderr," vs "); + for (i=31; i>=24; i--) + fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); fprintf(stderr," iter.%d winner.%d coinage.%llu %d ht.%d gap.%d %.8f/%llu\n",iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,(int32_t)(blocktime - prevtime),dstr(value),(long long)supply); } return(blocktime * winner); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index a52d7ab46..b31948013 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4492,14 +4492,17 @@ int32_t komodo_staked(uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint if ( pindex != 0 && (tipindex= chainActive.Tip()) != 0 ) { eligible = komodo_stake(bnTarget,(uint32_t)tipindex->nHeight+1,out.tx->GetHash(),out.i,*blocktimep,(uint32_t)tipindex->nTime); - if ( (eligible > 0 && eligible < earliest) || (eligible == earliest && (*utxovaluep == 0 || nValue < *utxovaluep)) ) + if ( eligible > 0 ) { - earliest = eligible; - best_scriptPubKey = out.tx->vout[out.i].scriptPubKey; - *utxovaluep = (uint64_t)nValue; - decode_hex((uint8_t *)utxotxidp,32,(char *)out.tx->GetHash().GetHex().c_str()); - *utxovoutp = out.i; - *txtimep = (uint32_t)out.tx->nLockTime; + if ( earliest == 0 || eligible < earliest || (eligible == earliest && (*utxovaluep == 0 || nValue < *utxovaluep)) ) + { + earliest = eligible; + best_scriptPubKey = out.tx->vout[out.i].scriptPubKey; + *utxovaluep = (uint64_t)nValue; + decode_hex((uint8_t *)utxotxidp,32,(char *)out.tx->GetHash().GetHex().c_str()); + *utxovoutp = out.i; + *txtimep = (uint32_t)out.tx->nLockTime; + } } //fprintf(stderr,"(%s) %s/v%d nValue %.8f locktime.%u txheight.%d pindexht.%d\n",CBitcoinAddress(address).ToString().c_str(),out.tx->GetHash().GetHex().c_str(),out.i,(double)nValue/COIN,locktime,txheight,pindex->nHeight); } From fd098285ce5619a15e6fddc2b1e968a23d59008b Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 21:12:49 +0300 Subject: [PATCH 227/339] Test --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 367393fde..a2c726007 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -685,7 +685,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ hash = pindex->GetBlockHash(); // hash pubkey diff = (blocktime - txtime); coinage = (((value * diff) / supply) * diff); - hashval = arith_uint256(1000000) * (UintToArith256(hash) / arith_uint256(coinage+1)); + hashval = arith_uint256(supply) * (UintToArith256(hash) / arith_uint256(coinage+1)); if ( hashval <= bnTarget ) winner = 1; else @@ -694,7 +694,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ { diff = (iter + blocktime - txtime); coinage = (((value * diff) / supply) * diff); - hashval = arith_uint256(1000000) * (UintToArith256(hash) / arith_uint256(coinage+1)); + hashval = arith_uint256(supply) * (UintToArith256(hash) / arith_uint256(coinage+1)); if ( hashval <= bnTarget ) { winner = 1; From 8c218b4887a14409ea07442cbbfb9d300a2cbb56 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 21:18:40 +0300 Subject: [PATCH 228/339] Test --- src/miner.cpp | 4 ++- src/wallet/rpcwallet.cpp | 58 ++++++++++++++++++++-------------------- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 69a7d240c..6102451d8 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -384,7 +384,9 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) nLastBlockTx = nBlockTx; nLastBlockSize = nBlockSize; - blocktime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); + if ( ASSETCHAINS_STAKED != 0 ) + blocktime = pindexPrev->GetMedianTimePast()+1; + else blocktime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); pblock->nTime = blocktime; pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus()); LogPrintf("CreateNewBlock(): total size %u blocktime.%u nBits.%08x\n", nBlockSize,blocktime,pblock->nBits); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index b31948013..6d04ccd6a 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4506,36 +4506,36 @@ int32_t komodo_staked(uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint } //fprintf(stderr,"(%s) %s/v%d nValue %.8f locktime.%u txheight.%d pindexht.%d\n",CBitcoinAddress(address).ToString().c_str(),out.tx->GetHash().GetHex().c_str(),out.i,(double)nValue/COIN,locktime,txheight,pindex->nHeight); } - if ( earliest != 0 ) + } + if ( earliest != 0 ) + { + bool signSuccess; SignatureData sigdata; uint64_t txfee; uint8_t *ptr; uint256 revtxid,utxotxid; + auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); + const CKeyStore& keystore = *pwalletMain; + CMutableTransaction txNew = CreateNewContextualCMutableTransaction(Params().GetConsensus(), chainActive.Height() + 1); + txNew.vin.resize(1); + txNew.vout.resize(1); + txfee = 0; + for (i=0; i<32; i++) + ((uint8_t *)&revtxid)[i] = ((uint8_t *)utxotxidp)[31 - i]; + txNew.vin[0].prevout.hash = revtxid; + txNew.vin[0].prevout.n = *utxovoutp; + txNew.vout[0].scriptPubKey = CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG; + txNew.vout[0].nValue = nValue - txfee; + txNew.nLockTime = *blocktimep; + CTransaction txNewConst(txNew); + signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, nValue, SIGHASH_ALL), best_scriptPubKey, sigdata, consensusBranchId); + if (!signSuccess) + fprintf(stderr,"failed to create signature\n"); + else { - bool signSuccess; SignatureData sigdata; uint64_t txfee; uint8_t *ptr; uint256 revtxid,utxotxid; - auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); - const CKeyStore& keystore = *pwalletMain; - CMutableTransaction txNew = CreateNewContextualCMutableTransaction(Params().GetConsensus(), chainActive.Height() + 1); - txNew.vin.resize(1); - txNew.vout.resize(1); - txfee = 0; - for (i=0; i<32; i++) - ((uint8_t *)&revtxid)[i] = ((uint8_t *)utxotxidp)[31 - i]; - txNew.vin[0].prevout.hash = revtxid; - txNew.vin[0].prevout.n = *utxovoutp; - txNew.vout[0].scriptPubKey = CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG; - txNew.vout[0].nValue = nValue - txfee; - txNew.nLockTime = *blocktimep; - CTransaction txNewConst(txNew); - signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, nValue, SIGHASH_ALL), best_scriptPubKey, sigdata, consensusBranchId); - if (!signSuccess) - fprintf(stderr,"failed to create signature\n"); - else - { - ptr = (uint8_t *)sigdata.scriptSig.data(); - siglen = sigdata.scriptSig.size(); - for (i=0; i Date: Mon, 9 Apr 2018 21:20:28 +0300 Subject: [PATCH 229/339] Test --- src/wallet/rpcwallet.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 6d04ccd6a..ca3fde8d0 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4521,10 +4521,10 @@ int32_t komodo_staked(uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint txNew.vin[0].prevout.hash = revtxid; txNew.vin[0].prevout.n = *utxovoutp; txNew.vout[0].scriptPubKey = CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG; - txNew.vout[0].nValue = nValue - txfee; + txNew.vout[0].nValue = *utxovaluep - txfee; txNew.nLockTime = *blocktimep; CTransaction txNewConst(txNew); - signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, nValue, SIGHASH_ALL), best_scriptPubKey, sigdata, consensusBranchId); + signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, *utxovaluep, SIGHASH_ALL), best_scriptPubKey, sigdata, consensusBranchId); if (!signSuccess) fprintf(stderr,"failed to create signature\n"); else From 6d649e094ef0e4ca97ce333107fcb4518f80b73b Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 21:24:23 +0300 Subject: [PATCH 230/339] Test --- src/komodo_gateway.h | 1 + src/pow.cpp | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index a2c726007..645ef6145 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -797,6 +797,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim if ( eligible == 0 || eligible > block.nTime ) { fprintf(stderr,"eligible.%u vs blocktime.%u, lag.%d\n",eligible,(uint32_t)block.nTime,(int32_t)(eligible - block.nTime)); + return(-1); } } if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && block.vtx[0].vout.size() > 1 ) diff --git a/src/pow.cpp b/src/pow.cpp index 63806033d..23f1cf67b 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -122,6 +122,7 @@ int32_t komodo_currentheight(); CBlockIndex *komodo_chainactive(int32_t height); void komodo_index2pubkey33(uint8_t *pubkey33,CBlockIndex *pindex,int32_t height); extern int32_t KOMODO_CHOSEN_ONE; +extern uint64_t ASSETCHAINS_STAKED; extern char ASSETCHAINS_SYMBOL[]; #define KOMODO_ELECTION_GAP 2000 @@ -141,7 +142,9 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned in height = komodo_currentheight() + 1; special = komodo_chosennotary(¬aryid,height,pubkey33,timestamp); flag = komodo_eligiblenotary(pubkeys,mids,&nonzpkeys,height); - if ( height > 34000 && ASSETCHAINS_SYMBOL[0] == 0 ) // 0 -> non-special notary + if ( ASSETCHAINS_STAKED != 0 ) + bnTarget.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow); + else if ( height > 34000 && ASSETCHAINS_SYMBOL[0] == 0 ) // 0 -> non-special notary { for (i=0; i<33; i++) { From e12ea51956ec3e70911b50b5090e93ae5f77e75c Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 21:24:42 +0300 Subject: [PATCH 231/339] Test --- src/miner.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 6102451d8..69a7d240c 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -384,9 +384,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) nLastBlockTx = nBlockTx; nLastBlockSize = nBlockSize; - if ( ASSETCHAINS_STAKED != 0 ) - blocktime = pindexPrev->GetMedianTimePast()+1; - else blocktime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); + blocktime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); pblock->nTime = blocktime; pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus()); LogPrintf("CreateNewBlock(): total size %u blocktime.%u nBits.%08x\n", nBlockSize,blocktime,pblock->nBits); From d3b5a9083eacd23dbfbcc73d31fdab82ce8de82e Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 21:52:41 +0300 Subject: [PATCH 232/339] Test --- src/komodo_gateway.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 645ef6145..7760d907c 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -672,15 +672,17 @@ uint64_t komodo_commission(const CBlock &block) uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_t vout,uint32_t blocktime,uint32_t prevtime) { - CBlockIndex *pindex; arith_uint256 hashval; uint256 hash; int32_t i,iter=0; uint32_t txtime,winner = 0; uint64_t diff,value,coinage,supply = ASSETCHAINS_SUPPLY + nHeight*ASSETCHAINS_REWARD/SATOSHIDEN; - if ( nHeight < 200 ) + CBlockIndex *pindex; arith_uint256 hashval; uint256 hash; int32_t minage,i,iter=0; uint32_t txtime,winner = 0; uint64_t diff,value,coinage,supply = ASSETCHAINS_SUPPLY + nHeight*ASSETCHAINS_REWARD/SATOSHIDEN; + if ( nHeight < 30 ) return(blocktime); txtime = komodo_txtime(&value,txid,vout); if ( value == 0 ) return(0); if ( txtime == 0 ) txtime = prevtime; - if ( blocktime > txtime+6000 && (pindex= komodo_chainactive(nHeight-200)) != 0 ) + if ( (minage= nHeight*30) > 6000 ) + minage = 6000; + if ( blocktime > txtime+minage && (pindex= komodo_chainactive(nHeight>200?nHeight-200:1)) != 0 ) { hash = pindex->GetBlockHash(); // hash pubkey diff = (blocktime - txtime); @@ -794,7 +796,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim } bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow); eligible = komodo_stake(bnTarget,height,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n,block.nTime,prevtime); - if ( eligible == 0 || eligible > block.nTime ) + if ( height > 100 && (eligible == 0 || eligible > block.nTime) ) { fprintf(stderr,"eligible.%u vs blocktime.%u, lag.%d\n",eligible,(uint32_t)block.nTime,(int32_t)(eligible - block.nTime)); return(-1); From d3aea61d5629add32ef0fa5246687d0d5c6b7b35 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 21:55:36 +0300 Subject: [PATCH 233/339] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 7760d907c..ae07d92bc 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -680,7 +680,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ return(0); if ( txtime == 0 ) txtime = prevtime; - if ( (minage= nHeight*30) > 6000 ) + if ( (minage= nHeight*3) > 6000 ) minage = 6000; if ( blocktime > txtime+minage && (pindex= komodo_chainactive(nHeight>200?nHeight-200:1)) != 0 ) { From 36067f15e97747f962276c72a7a9ffe5b1092a07 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 21:58:28 +0300 Subject: [PATCH 234/339] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index ae07d92bc..6231c458c 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -796,7 +796,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim } bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow); eligible = komodo_stake(bnTarget,height,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n,block.nTime,prevtime); - if ( height > 100 && (eligible == 0 || eligible > block.nTime) ) + if ( height >= 30 && (eligible == 0 || eligible > block.nTime) ) { fprintf(stderr,"eligible.%u vs blocktime.%u, lag.%d\n",eligible,(uint32_t)block.nTime,(int32_t)(eligible - block.nTime)); return(-1); From 6d94e8a836f4349ed71263dec604598987544606 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 22:13:18 +0300 Subject: [PATCH 235/339] Test --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 6231c458c..23d95ff0b 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -676,8 +676,8 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ if ( nHeight < 30 ) return(blocktime); txtime = komodo_txtime(&value,txid,vout); - if ( value == 0 ) - return(0); + //if ( value == 0 ) + // return(0); if ( txtime == 0 ) txtime = prevtime; if ( (minage= nHeight*3) > 6000 ) From d354a959cdba222a738be1f110608171d66da397 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 22:15:42 +0300 Subject: [PATCH 236/339] Test --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 23d95ff0b..5e792a707 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -673,8 +673,6 @@ uint64_t komodo_commission(const CBlock &block) uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_t vout,uint32_t blocktime,uint32_t prevtime) { CBlockIndex *pindex; arith_uint256 hashval; uint256 hash; int32_t minage,i,iter=0; uint32_t txtime,winner = 0; uint64_t diff,value,coinage,supply = ASSETCHAINS_SUPPLY + nHeight*ASSETCHAINS_REWARD/SATOSHIDEN; - if ( nHeight < 30 ) - return(blocktime); txtime = komodo_txtime(&value,txid,vout); //if ( value == 0 ) // return(0); @@ -713,6 +711,8 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); fprintf(stderr," iter.%d winner.%d coinage.%llu %d ht.%d gap.%d %.8f/%llu\n",iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,(int32_t)(blocktime - prevtime),dstr(value),(long long)supply); } + if ( nHeight < 30 ) + return(blocktime); return(blocktime * winner); } From c4cd1663968c3399fead6a6bb6656e7f98ff2438 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 22:19:21 +0300 Subject: [PATCH 237/339] Test --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 5e792a707..02aacbe86 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -685,7 +685,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ hash = pindex->GetBlockHash(); // hash pubkey diff = (blocktime - txtime); coinage = (((value * diff) / supply) * diff); - hashval = arith_uint256(supply) * (UintToArith256(hash) / arith_uint256(coinage+1)); + hashval = (UintToArith256(hash) / arith_uint256(coinage+1)); if ( hashval <= bnTarget ) winner = 1; else @@ -694,7 +694,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ { diff = (iter + blocktime - txtime); coinage = (((value * diff) / supply) * diff); - hashval = arith_uint256(supply) * (UintToArith256(hash) / arith_uint256(coinage+1)); + hashval = (UintToArith256(hash) / arith_uint256(coinage+1)); if ( hashval <= bnTarget ) { winner = 1; From 28d89a8620fbcb6bc2f15bd263f74e992ab4b6b9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 22:22:12 +0300 Subject: [PATCH 238/339] Test --- src/komodo_bitcoind.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index f7d9af114..0495d12c8 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -568,9 +568,10 @@ uint32_t komodo_txtime(uint64_t *valuep,uint256 hash,int32_t n) #endif hashBlock, true)) { + fprintf(stderr,"ERROR: %s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime); return(0); } - //fprintf(stderr,"%s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime); + fprintf(stderr,"%s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime); if ( n < tx.vout.size() ) *valuep = tx.vout[n].nValue; return(tx.nLockTime); From e6eb32402005a0de39d16dcd20652a44ac90472b Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 22:27:24 +0300 Subject: [PATCH 239/339] Test --- src/wallet/rpcwallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index ca3fde8d0..54a9350b6 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4504,7 +4504,7 @@ int32_t komodo_staked(uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint *txtimep = (uint32_t)out.tx->nLockTime; } } - //fprintf(stderr,"(%s) %s/v%d nValue %.8f locktime.%u txheight.%d pindexht.%d\n",CBitcoinAddress(address).ToString().c_str(),out.tx->GetHash().GetHex().c_str(),out.i,(double)nValue/COIN,locktime,txheight,pindex->nHeight); + fprintf(stderr,"(%s) %s/v%d nValue %.8f locktime.%u txheight.%d pindexht.%d\n",CBitcoinAddress(address).ToString().c_str(),out.tx->GetHash().GetHex().c_str(),out.i,(double)nValue/COIN,locktime,txheight,pindex->nHeight); } } if ( earliest != 0 ) From fd331cdc33b951640c78b5a84353a0b5d0fd9a75 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 22:30:25 +0300 Subject: [PATCH 240/339] Test --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 02aacbe86..2a2f1f190 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -711,7 +711,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); fprintf(stderr," iter.%d winner.%d coinage.%llu %d ht.%d gap.%d %.8f/%llu\n",iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,(int32_t)(blocktime - prevtime),dstr(value),(long long)supply); } - if ( nHeight < 30 ) + if ( nHeight < 2 ) return(blocktime); return(blocktime * winner); } @@ -796,7 +796,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim } bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow); eligible = komodo_stake(bnTarget,height,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n,block.nTime,prevtime); - if ( height >= 30 && (eligible == 0 || eligible > block.nTime) ) + if ( height >= 2 && (eligible == 0 || eligible > block.nTime) ) { fprintf(stderr,"eligible.%u vs blocktime.%u, lag.%d\n",eligible,(uint32_t)block.nTime,(int32_t)(eligible - block.nTime)); return(-1); From 9dd28ae0a3866ef149ea036c8f21f968c003abb0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 22:41:04 +0300 Subject: [PATCH 241/339] Test --- src/komodo_gateway.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 2a2f1f190..acd0efed7 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -786,7 +786,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim } else { - if ( ASSETCHAINS_STAKED != 0 ) + if ( ASSETCHAINS_STAKED != 0 && height >= 2 ) { arith_uint256 bnTarget; bool fNegative,fOverflow; CBlockIndex *previndex; uint32_t eligible; if ( prevtime == 0 ) @@ -795,8 +795,10 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim prevtime = (uint32_t)previndex->nTime; } bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow); - eligible = komodo_stake(bnTarget,height,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n,block.nTime,prevtime); - if ( height >= 2 && (eligible == 0 || eligible > block.nTime) ) + if ( txn_count == 1 ) + eligible = komodo_stake(bnTarget,height,block.vtx[0].vout[0].hash,0,block.nTime,prevtime); + else eligible = komodo_stake(bnTarget,height,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n,block.nTime,prevtime); + if ( eligible == 0 || eligible > block.nTime ) { fprintf(stderr,"eligible.%u vs blocktime.%u, lag.%d\n",eligible,(uint32_t)block.nTime,(int32_t)(eligible - block.nTime)); return(-1); From 34f8b3543763bceaf8b21dcd2fdb3b8ccac0faf4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 22:44:23 +0300 Subject: [PATCH 242/339] Test --- src/komodo_gateway.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index acd0efed7..25d494043 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -786,7 +786,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim } else { - if ( ASSETCHAINS_STAKED != 0 && height >= 2 ) + if ( ASSETCHAINS_STAKED != 0 && height >= 2 && txn_count > 1 ) { arith_uint256 bnTarget; bool fNegative,fOverflow; CBlockIndex *previndex; uint32_t eligible; if ( prevtime == 0 ) @@ -795,9 +795,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim prevtime = (uint32_t)previndex->nTime; } bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow); - if ( txn_count == 1 ) - eligible = komodo_stake(bnTarget,height,block.vtx[0].vout[0].hash,0,block.nTime,prevtime); - else eligible = komodo_stake(bnTarget,height,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n,block.nTime,prevtime); + eligible = komodo_stake(bnTarget,height,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n,block.nTime,prevtime); if ( eligible == 0 || eligible > block.nTime ) { fprintf(stderr,"eligible.%u vs blocktime.%u, lag.%d\n",eligible,(uint32_t)block.nTime,(int32_t)(eligible - block.nTime)); From 37af9d4af9a2adf404cc0fb0e6bd77245faeb5d5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 22:48:28 +0300 Subject: [PATCH 243/339] Test --- src/komodo_gateway.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 25d494043..60281aabb 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -674,6 +674,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ { CBlockIndex *pindex; arith_uint256 hashval; uint256 hash; int32_t minage,i,iter=0; uint32_t txtime,winner = 0; uint64_t diff,value,coinage,supply = ASSETCHAINS_SUPPLY + nHeight*ASSETCHAINS_REWARD/SATOSHIDEN; txtime = komodo_txtime(&value,txid,vout); + fprintf(stderr,"%s/v%d %.8f txtime.%u\n",txid.ToString().c_str(),vout,dstr(value),txtime); //if ( value == 0 ) // return(0); if ( txtime == 0 ) From a030053610246158540e5c8476fd8ba8adf5811d Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 22:55:21 +0300 Subject: [PATCH 244/339] Test --- src/miner.cpp | 2 +- src/wallet/rpcwallet.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 69a7d240c..4817da0ba 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -415,7 +415,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) pblocktemplate->vTxSigOps.push_back(numsigs); nFees += txfees; pblock->nTime = blocktime; - } + } else fprintf(stderr,"no utxos eligible for staking\n"); } // Create coinbase tx diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 54a9350b6..71c2025ed 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4487,9 +4487,9 @@ int32_t komodo_staked(uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint } entry.push_back(Pair("amount",ValueFromAmount(nValue)));*/ BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); - CBlockIndex *tipindex,*pindex = it->second; + CBlockIndex *tipindex; uint64_t interest; uint32_t locktime; int32_t txheight; - if ( pindex != 0 && (tipindex= chainActive.Tip()) != 0 ) + if ( (tipindex= chainActive.Tip()) != 0 ) { eligible = komodo_stake(bnTarget,(uint32_t)tipindex->nHeight+1,out.tx->GetHash(),out.i,*blocktimep,(uint32_t)tipindex->nTime); if ( eligible > 0 ) @@ -4504,7 +4504,7 @@ int32_t komodo_staked(uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint *txtimep = (uint32_t)out.tx->nLockTime; } } - fprintf(stderr,"(%s) %s/v%d nValue %.8f locktime.%u txheight.%d pindexht.%d\n",CBitcoinAddress(address).ToString().c_str(),out.tx->GetHash().GetHex().c_str(),out.i,(double)nValue/COIN,locktime,txheight,pindex->nHeight); + fprintf(stderr,"(%s) %s/v%d nValue %.8f locktime.%u txheight.%d\n",CBitcoinAddress(address).ToString().c_str(),out.tx->GetHash().GetHex().c_str(),out.i,(double)nValue/COIN,locktime,txheight); } } if ( earliest != 0 ) From d10b3e3c62b21601e7eccbb4ffb2f6ccdc5b6ad7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 23:01:54 +0300 Subject: [PATCH 245/339] Test --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 60281aabb..474184e5c 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -686,7 +686,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ hash = pindex->GetBlockHash(); // hash pubkey diff = (blocktime - txtime); coinage = (((value * diff) / supply) * diff); - hashval = (UintToArith256(hash) / arith_uint256(coinage+1)); + hashval = arith_uint256(supply) * (UintToArith256(hash) / arith_uint256(coinage+1)); if ( hashval <= bnTarget ) winner = 1; else @@ -695,7 +695,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ { diff = (iter + blocktime - txtime); coinage = (((value * diff) / supply) * diff); - hashval = (UintToArith256(hash) / arith_uint256(coinage+1)); + hashval = arith_uint256(supply) * (UintToArith256(hash) / arith_uint256(coinage+1)); if ( hashval <= bnTarget ) { winner = 1; From d231a6a77519acb836cfbd6eda74601791022a7c Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 23:17:34 +0300 Subject: [PATCH 246/339] Test --- src/komodo_gateway.h | 6 +++--- src/miner.cpp | 12 ++++++------ src/wallet/rpcwallet.cpp | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 474184e5c..292302a55 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -674,9 +674,9 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ { CBlockIndex *pindex; arith_uint256 hashval; uint256 hash; int32_t minage,i,iter=0; uint32_t txtime,winner = 0; uint64_t diff,value,coinage,supply = ASSETCHAINS_SUPPLY + nHeight*ASSETCHAINS_REWARD/SATOSHIDEN; txtime = komodo_txtime(&value,txid,vout); - fprintf(stderr,"%s/v%d %.8f txtime.%u\n",txid.ToString().c_str(),vout,dstr(value),txtime); - //if ( value == 0 ) - // return(0); + //fprintf(stderr,"%s/v%d %.8f txtime.%u\n",txid.ToString().c_str(),vout,dstr(value),txtime); + if ( value == 0 ) + return(0); if ( txtime == 0 ) txtime = prevtime; if ( (minage= nHeight*3) > 6000 ) diff --git a/src/miner.cpp b/src/miner.cpp index 4817da0ba..2b658d5ee 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -120,7 +120,7 @@ int32_t komodo_gateway_deposits(CMutableTransaction *txNew,char *symbol,int32_t int32_t komodo_isrealtime(int32_t *kmdheightp); int32_t komodo_validate_interest(const CTransaction &tx,int32_t txheight,uint32_t nTime,int32_t dispflag); uint64_t komodo_commission(const CBlock &block); -int32_t komodo_staked(uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig); +int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig); CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) { @@ -391,10 +391,11 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_STAKED != 0 && NOTARY_PUBKEY33[0] != 0 ) { uint64_t txfees,utxovalue; uint32_t txtime; uint256 utxotxid,revtxid; int32_t i,siglen,numsigs,utxovout; uint8_t utxosig[128],*ptr; - if ( (siglen= komodo_staked(pblock->nBits,&blocktime,&txtime,&utxotxid,&utxovout,&utxovalue,utxosig)) > 0 ) + CMutableTransaction txStaked = CreateNewContextualCMutableTransaction(Params().GetConsensus(), chainActive.Height() + 1); + if ( (siglen= komodo_staked(txStaked,pblock->nBits,&blocktime,&txtime,&utxotxid,&utxovout,&utxovalue,utxosig)) > 0 ) { - CMutableTransaction txStaked = CreateNewContextualCMutableTransaction(chainparams.GetConsensus(), nHeight); CAmount txfees = 0; + /*CMutableTransaction txStaked = CreateNewContextualCMutableTransaction(chainparams.GetConsensus(), nHeight); txStaked.vin.resize(1); txStaked.vout.resize(1); for (i=0; i<32; i++) @@ -407,12 +408,11 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) ptr[i] = utxosig[i]; txStaked.vout[0].scriptPubKey = CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG; txStaked.vout[0].nValue = utxovalue - txfees; - txStaked.nLockTime = blocktime; + txStaked.nLockTime = blocktime;*/ pblock->vtx.push_back(txStaked); - numsigs = GetLegacySigOpCount(txStaked); pblocktemplate->vTxFees.push_back(txfees); - pblocktemplate->vTxSigOps.push_back(numsigs); + pblocktemplate->vTxSigOps.push_back(GetLegacySigOpCount(txStaked)); nFees += txfees; pblock->nTime = blocktime; } else fprintf(stderr,"no utxos eligible for staking\n"); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 71c2025ed..5a56a16f4 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4441,7 +4441,7 @@ int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex); extern std::string NOTARY_PUBKEY; uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,uint32_t prevtime); -int32_t komodo_staked(uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) +int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) { set setAddress; int32_t i,siglen=0,nMinDepth = 1,nMaxDepth = 9999999; vector vecOutputs; uint32_t eligible,earliest = 0; CScript best_scriptPubKey; arith_uint256 bnTarget; bool fNegative,fOverflow; bnTarget.SetCompact(nBits, &fNegative, &fOverflow); @@ -4504,7 +4504,7 @@ int32_t komodo_staked(uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint *txtimep = (uint32_t)out.tx->nLockTime; } } - fprintf(stderr,"(%s) %s/v%d nValue %.8f locktime.%u txheight.%d\n",CBitcoinAddress(address).ToString().c_str(),out.tx->GetHash().GetHex().c_str(),out.i,(double)nValue/COIN,locktime,txheight); + //fprintf(stderr,"(%s) %s/v%d nValue %.8f locktime.%u txheight.%d\n",CBitcoinAddress(address).ToString().c_str(),out.tx->GetHash().GetHex().c_str(),out.i,(double)nValue/COIN,locktime,txheight); } } if ( earliest != 0 ) @@ -4512,7 +4512,6 @@ int32_t komodo_staked(uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint bool signSuccess; SignatureData sigdata; uint64_t txfee; uint8_t *ptr; uint256 revtxid,utxotxid; auto consensusBranchId = CurrentEpochBranchId(chainActive.Height() + 1, Params().GetConsensus()); const CKeyStore& keystore = *pwalletMain; - CMutableTransaction txNew = CreateNewContextualCMutableTransaction(Params().GetConsensus(), chainActive.Height() + 1); txNew.vin.resize(1); txNew.vout.resize(1); txfee = 0; @@ -4529,6 +4528,7 @@ int32_t komodo_staked(uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint fprintf(stderr,"failed to create signature\n"); else { + UpdateTransaction(txNew,0,sigdata); ptr = (uint8_t *)sigdata.scriptSig.data(); siglen = sigdata.scriptSig.size(); for (i=0; i Date: Mon, 9 Apr 2018 23:27:19 +0300 Subject: [PATCH 247/339] Test --- src/komodo_bitcoind.h | 2 +- src/wallet/rpcwallet.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 0495d12c8..ca9157adc 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -571,7 +571,7 @@ uint32_t komodo_txtime(uint64_t *valuep,uint256 hash,int32_t n) fprintf(stderr,"ERROR: %s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime); return(0); } - fprintf(stderr,"%s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime); + //fprintf(stderr,"%s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime); if ( n < tx.vout.size() ) *valuep = tx.vout[n].nValue; return(tx.nLockTime); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 5a56a16f4..0a9524d88 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4502,9 +4502,9 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt decode_hex((uint8_t *)utxotxidp,32,(char *)out.tx->GetHash().GetHex().c_str()); *utxovoutp = out.i; *txtimep = (uint32_t)out.tx->nLockTime; + fprintf(stderr,"earliest.%u [%d] (%s) nValue %.8f locktime.%u txheight.%d\n",earliest,(int32_t)(earliest- *blocktimep)CBitcoinAddress(address).ToString().c_str(),(double)nValue/COIN,locktime,txheight); } } - //fprintf(stderr,"(%s) %s/v%d nValue %.8f locktime.%u txheight.%d\n",CBitcoinAddress(address).ToString().c_str(),out.tx->GetHash().GetHex().c_str(),out.i,(double)nValue/COIN,locktime,txheight); } } if ( earliest != 0 ) From 3f26119e04eed251f79e2099d62df24a67921248 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 23:29:03 +0300 Subject: [PATCH 248/339] Test --- src/wallet/rpcwallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 0a9524d88..637edbbd8 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4502,7 +4502,7 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt decode_hex((uint8_t *)utxotxidp,32,(char *)out.tx->GetHash().GetHex().c_str()); *utxovoutp = out.i; *txtimep = (uint32_t)out.tx->nLockTime; - fprintf(stderr,"earliest.%u [%d] (%s) nValue %.8f locktime.%u txheight.%d\n",earliest,(int32_t)(earliest- *blocktimep)CBitcoinAddress(address).ToString().c_str(),(double)nValue/COIN,locktime,txheight); + fprintf(stderr,"earliest.%u [%d] (%s) nValue %.8f locktime.%u txheight.%d\n",earliest,(int32_t)(earliest- *blocktimep),CBitcoinAddress(address).ToString().c_str(),(double)nValue/COIN,locktime,txheight); } } } From 09cde8ab10f7866f8d262abf811344f1ba16d77a Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 23:34:24 +0300 Subject: [PATCH 249/339] Test --- src/wallet/rpcwallet.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 637edbbd8..98e2cd0f6 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4521,7 +4521,7 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt txNew.vin[0].prevout.n = *utxovoutp; txNew.vout[0].scriptPubKey = CScript() << ParseHex(NOTARY_PUBKEY) << OP_CHECKSIG; txNew.vout[0].nValue = *utxovaluep - txfee; - txNew.nLockTime = *blocktimep; + txNew.nLockTime = earliest; CTransaction txNewConst(txNew); signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, *utxovaluep, SIGHASH_ALL), best_scriptPubKey, sigdata, consensusBranchId); if (!signSuccess) @@ -4534,8 +4534,8 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt for (i=0; i Date: Mon, 9 Apr 2018 23:45:45 +0300 Subject: [PATCH 250/339] Test --- src/komodo_gateway.h | 4 ++-- src/miner.cpp | 26 +++++++++++--------------- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 292302a55..34f1b0161 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -686,7 +686,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ hash = pindex->GetBlockHash(); // hash pubkey diff = (blocktime - txtime); coinage = (((value * diff) / supply) * diff); - hashval = arith_uint256(supply) * (UintToArith256(hash) / arith_uint256(coinage+1)); + hashval = arith_uint256(supply * 64) * (UintToArith256(hash) / arith_uint256(coinage+1)); if ( hashval <= bnTarget ) winner = 1; else @@ -695,7 +695,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ { diff = (iter + blocktime - txtime); coinage = (((value * diff) / supply) * diff); - hashval = arith_uint256(supply) * (UintToArith256(hash) / arith_uint256(coinage+1)); + hashval = arith_uint256(supply * 64) * (UintToArith256(hash) / arith_uint256(coinage+1)); if ( hashval <= bnTarget ) { winner = 1; diff --git a/src/miner.cpp b/src/miner.cpp index 2b658d5ee..67e8e9cb3 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -395,26 +395,22 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) if ( (siglen= komodo_staked(txStaked,pblock->nBits,&blocktime,&txtime,&utxotxid,&utxovout,&utxovalue,utxosig)) > 0 ) { CAmount txfees = 0; - /*CMutableTransaction txStaked = CreateNewContextualCMutableTransaction(chainparams.GetConsensus(), nHeight); - txStaked.vin.resize(1); - txStaked.vout.resize(1); - for (i=0; i<32; i++) - ((uint8_t *)&revtxid)[i] = ((uint8_t *)&utxotxid)[31 - i]; - txStaked.vin[0].prevout.hash = revtxid; - txStaked.vin[0].prevout.n = utxovout; - txStaked.vin[0].scriptSig.resize(siglen); - ptr = (uint8_t *)txStaked.vin[0].scriptSig.data(); - for (i=0; ivtx.push_back(txStaked); pblocktemplate->vTxFees.push_back(txfees); pblocktemplate->vTxSigOps.push_back(GetLegacySigOpCount(txStaked)); nFees += txfees; pblock->nTime = blocktime; + if ( GetAdjustedTime()+30 < pblock->nTime ) + { + printf("need to wait %d seconds to submit: ",(int32_t)(pblock->nTime - GetAdjustedTime())); + while ( GetAdjustedTime()+30 < pblock->nTime ) + { + sleep(1); + fprintf(stderr,"%d ",pblock->nTime - GetAdjustedTime()); + } + fprintf(stderr,"finished waiting\n"); + } + } else fprintf(stderr,"no utxos eligible for staking\n"); } From 1599d4c8efc1a917cdb935dcfd27cfec16046265 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 23:48:34 +0300 Subject: [PATCH 251/339] Test --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index 67e8e9cb3..edbc3ae24 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -406,7 +406,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) while ( GetAdjustedTime()+30 < pblock->nTime ) { sleep(1); - fprintf(stderr,"%d ",pblock->nTime - GetAdjustedTime()); + fprintf(stderr,"%d ",(int32_t)(pblock->nTime - GetAdjustedTime())); } fprintf(stderr,"finished waiting\n"); } From 9465da966b7c9102daca7a75ee763b7b2287bc24 Mon Sep 17 00:00:00 2001 From: jl777 Date: Mon, 9 Apr 2018 23:59:13 +0300 Subject: [PATCH 252/339] Test --- src/komodo_gateway.h | 15 +++++++++------ src/miner.cpp | 11 ++++++----- src/wallet/rpcwallet.cpp | 5 ++--- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 34f1b0161..56165d598 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -705,12 +705,15 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ } //fprintf(stderr,"iterated until i.%d winner.%d\n",i,winner); } - for (i=31; i>=24; i--) - fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]); - fprintf(stderr," vs "); - for (i=31; i>=24; i--) - fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); - fprintf(stderr," iter.%d winner.%d coinage.%llu %d ht.%d gap.%d %.8f/%llu\n",iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,(int32_t)(blocktime - prevtime),dstr(value),(long long)supply); + if ( 0 ) + { + for (i=31; i>=24; i--) + fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]); + fprintf(stderr," vs "); + for (i=31; i>=24; i--) + fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); + fprintf(stderr," iter.%d winner.%d coinage.%llu %d ht.%d gap.%d %.8f/%llu\n",iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,(int32_t)(blocktime - prevtime),dstr(value),(long long)supply); + } } if ( nHeight < 2 ) return(blocktime); diff --git a/src/miner.cpp b/src/miner.cpp index edbc3ae24..853cda770 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -402,13 +402,14 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) pblock->nTime = blocktime; if ( GetAdjustedTime()+30 < pblock->nTime ) { - printf("need to wait %d seconds to submit: ",(int32_t)(pblock->nTime - GetAdjustedTime())); - while ( GetAdjustedTime()+30 < pblock->nTime ) + //printf("need to wait %d seconds to submit: ",(int32_t)(pblock->nTime - GetAdjustedTime())); + /*while ( GetAdjustedTime()+30 < pblock->nTime ) { - sleep(1); + sleep(30); fprintf(stderr,"%d ",(int32_t)(pblock->nTime - GetAdjustedTime())); - } - fprintf(stderr,"finished waiting\n"); + }*/ + //fprintf(stderr,"finished waiting\n"); + sleep(30); } } else fprintf(stderr,"no utxos eligible for staking\n"); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 98e2cd0f6..9169f1079 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4486,9 +4486,8 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt } } entry.push_back(Pair("amount",ValueFromAmount(nValue)));*/ - BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); + //BlockMap::iterator it = mapBlockIndex.find(pcoinsTip->GetBestBlock()); CBlockIndex *tipindex; - uint64_t interest; uint32_t locktime; int32_t txheight; if ( (tipindex= chainActive.Tip()) != 0 ) { eligible = komodo_stake(bnTarget,(uint32_t)tipindex->nHeight+1,out.tx->GetHash(),out.i,*blocktimep,(uint32_t)tipindex->nTime); @@ -4502,7 +4501,7 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt decode_hex((uint8_t *)utxotxidp,32,(char *)out.tx->GetHash().GetHex().c_str()); *utxovoutp = out.i; *txtimep = (uint32_t)out.tx->nLockTime; - fprintf(stderr,"earliest.%u [%d] (%s) nValue %.8f locktime.%u txheight.%d\n",earliest,(int32_t)(earliest- *blocktimep),CBitcoinAddress(address).ToString().c_str(),(double)nValue/COIN,locktime,txheight); + fprintf(stderr,"earliest.%u [%d] (%s) nValue %.8f locktime.%u\n",earliest,(int32_t)(earliest- *blocktimep),CBitcoinAddress(address).ToString().c_str(),(double)nValue/COIN,*txtimep); } } } From 8d584a9c9142ca7ddc3c927ef3e4dc9a6684c052 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 00:09:41 +0300 Subject: [PATCH 253/339] Test --- src/komodo_bitcoind.h | 10 +++++++--- src/komodo_gateway.h | 10 +++++----- src/wallet/rpcwallet.cpp | 2 +- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index ca9157adc..0f44119cb 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -557,11 +557,11 @@ uint64_t komodo_seed(int32_t height) return(seed); } -uint32_t komodo_txtime(uint64_t *valuep,uint256 hash,int32_t n) +uint32_t komodo_txtime(uint64_t *valuep,uint256 hash,int32_t n,char *address) { - CTransaction tx; - uint256 hashBlock; + CTxDestination address; CTransaction tx; uint256 hashBlock; *valuep = 0; + address[0] = 0; if (!GetTransaction(hash, tx, #ifndef KOMODO_ZCASH Params().GetConsensus(), @@ -573,7 +573,11 @@ uint32_t komodo_txtime(uint64_t *valuep,uint256 hash,int32_t n) } //fprintf(stderr,"%s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime); if ( n < tx.vout.size() ) + { *valuep = tx.vout[n].nValue; + if (ExtractDestination(tx.scriptPubKey, address)) + strcpy(address,CBitcoinAddress(address).ToString().c_str()); + } return(tx.nLockTime); } diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 56165d598..fba23a4bc 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -670,11 +670,11 @@ uint64_t komodo_commission(const CBlock &block) return((total * ASSETCHAINS_COMMISSION) / COIN); } -uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_t vout,uint32_t blocktime,uint32_t prevtime) +uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_t vout,uint32_t blocktime,uint32_t prevtime,char *destaddr) { - CBlockIndex *pindex; arith_uint256 hashval; uint256 hash; int32_t minage,i,iter=0; uint32_t txtime,winner = 0; uint64_t diff,value,coinage,supply = ASSETCHAINS_SUPPLY + nHeight*ASSETCHAINS_REWARD/SATOSHIDEN; - txtime = komodo_txtime(&value,txid,vout); - //fprintf(stderr,"%s/v%d %.8f txtime.%u\n",txid.ToString().c_str(),vout,dstr(value),txtime); + CBlockIndex *pindex; char address[64]; arith_uint256 hashval; uint256 hash; int32_t minage,i,iter=0; uint32_t txtime,winner = 0; uint64_t diff,value,coinage,supply = ASSETCHAINS_SUPPLY + nHeight*ASSETCHAINS_REWARD/SATOSHIDEN; + txtime = komodo_txtime(&value,txid,vout,address); + fprintf(stderr,"(%s) vs. (%s) %s/v%d %.8f txtime.%u\n",address,destaddr,txid.ToString().c_str(),vout,dstr(value),txtime); if ( value == 0 ) return(0); if ( txtime == 0 ) @@ -799,7 +799,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim prevtime = (uint32_t)previndex->nTime; } bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow); - eligible = komodo_stake(bnTarget,height,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n,block.nTime,prevtime); + eligible = komodo_stake(bnTarget,height,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n,block.nTime,prevtime,""); if ( eligible == 0 || eligible > block.nTime ) { fprintf(stderr,"eligible.%u vs blocktime.%u, lag.%d\n",eligible,(uint32_t)block.nTime,(int32_t)(eligible - block.nTime)); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 9169f1079..3dcd63951 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4490,7 +4490,7 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt CBlockIndex *tipindex; if ( (tipindex= chainActive.Tip()) != 0 ) { - eligible = komodo_stake(bnTarget,(uint32_t)tipindex->nHeight+1,out.tx->GetHash(),out.i,*blocktimep,(uint32_t)tipindex->nTime); + eligible = komodo_stake(bnTarget,(uint32_t)tipindex->nHeight+1,out.tx->GetHash(),out.i,*blocktimep,(uint32_t)tipindex->nTime,CBitcoinAddress(address).ToString().c_str()); if ( eligible > 0 ) { if ( earliest == 0 || eligible < earliest || (eligible == earliest && (*utxovaluep == 0 || nValue < *utxovaluep)) ) From af79cd4cfc468aafb20ae792897720c487d815fa Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 00:14:42 +0300 Subject: [PATCH 254/339] Test --- src/komodo_gateway.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index fba23a4bc..839e96304 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -672,9 +672,8 @@ uint64_t komodo_commission(const CBlock &block) uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_t vout,uint32_t blocktime,uint32_t prevtime,char *destaddr) { - CBlockIndex *pindex; char address[64]; arith_uint256 hashval; uint256 hash; int32_t minage,i,iter=0; uint32_t txtime,winner = 0; uint64_t diff,value,coinage,supply = ASSETCHAINS_SUPPLY + nHeight*ASSETCHAINS_REWARD/SATOSHIDEN; + CBlockIndex *pindex; uint8_t hashbuf[128]; char address[64]; arith_uint256 hashval; uint256 hash,addrhash,pasthash; int32_t minage,i,iter=0; uint32_t txtime,winner = 0; uint64_t diff,value,coinage,supply = ASSETCHAINS_SUPPLY + nHeight*ASSETCHAINS_REWARD/SATOSHIDEN; txtime = komodo_txtime(&value,txid,vout,address); - fprintf(stderr,"(%s) vs. (%s) %s/v%d %.8f txtime.%u\n",address,destaddr,txid.ToString().c_str(),vout,dstr(value),txtime); if ( value == 0 ) return(0); if ( txtime == 0 ) @@ -683,7 +682,10 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ minage = 6000; if ( blocktime > txtime+minage && (pindex= komodo_chainactive(nHeight>200?nHeight-200:1)) != 0 ) { - hash = pindex->GetBlockHash(); // hash pubkey + vcalc_sha256(0,(uint8_t *)&addrhash,(int32_t)strlen(address)); + pasthash = pindex->GetBlockHash(); + hash = (pasthash ^ addrhash); + fprintf(stderr,"(%s) vs. (%s) %s %.8f txtime.%u\n",address,destaddr,hash.ToString().c_str(),dstr(value),txtime); diff = (blocktime - txtime); coinage = (((value * diff) / supply) * diff); hashval = arith_uint256(supply * 64) * (UintToArith256(hash) / arith_uint256(coinage+1)); @@ -799,7 +801,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim prevtime = (uint32_t)previndex->nTime; } bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow); - eligible = komodo_stake(bnTarget,height,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n,block.nTime,prevtime,""); + eligible = komodo_stake(bnTarget,height,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n,block.nTime,prevtime,(char *)""); if ( eligible == 0 || eligible > block.nTime ) { fprintf(stderr,"eligible.%u vs blocktime.%u, lag.%d\n",eligible,(uint32_t)block.nTime,(int32_t)(eligible - block.nTime)); From 4da475be2fff2c2302f872fdc2da2a26e09b3078 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 00:18:22 +0300 Subject: [PATCH 255/339] Test --- src/komodo_gateway.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 839e96304..dd7e041de 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -682,9 +682,11 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ minage = 6000; if ( blocktime > txtime+minage && (pindex= komodo_chainactive(nHeight>200?nHeight-200:1)) != 0 ) { - vcalc_sha256(0,(uint8_t *)&addrhash,(int32_t)strlen(address)); + vcalc_sha256(0,(uint8_t *)&addrhash,address,(int32_t)strlen(address)); pasthash = pindex->GetBlockHash(); - hash = (pasthash ^ addrhash); + memcpy(hashbuf,&pasthash,sizeof(pasthash)); + memcpy(&hashbuf[sizeof(pasthash)],&addrhash,sizeof(addrhash)); + vcalc_sha256(0,(uint8_t *)&hash,hashbuf,(int32_t)sizeof(uint256)*2); fprintf(stderr,"(%s) vs. (%s) %s %.8f txtime.%u\n",address,destaddr,hash.ToString().c_str(),dstr(value),txtime); diff = (blocktime - txtime); coinage = (((value * diff) / supply) * diff); From fa4d9e24afe2d1e43953156a54187a9ccfa6e10e Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 00:26:00 +0300 Subject: [PATCH 256/339] Test --- src/komodo_bitcoind.h | 7 +++---- src/komodo_gateway.h | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 0f44119cb..6ffa4022c 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -557,11 +557,10 @@ uint64_t komodo_seed(int32_t height) return(seed); } -uint32_t komodo_txtime(uint64_t *valuep,uint256 hash,int32_t n,char *address) +uint32_t komodo_txtime(uint64_t *valuep,uint256 hash,int32_t n,char *destaddr) { CTxDestination address; CTransaction tx; uint256 hashBlock; *valuep = 0; - address[0] = 0; if (!GetTransaction(hash, tx, #ifndef KOMODO_ZCASH Params().GetConsensus(), @@ -575,8 +574,8 @@ uint32_t komodo_txtime(uint64_t *valuep,uint256 hash,int32_t n,char *address) if ( n < tx.vout.size() ) { *valuep = tx.vout[n].nValue; - if (ExtractDestination(tx.scriptPubKey, address)) - strcpy(address,CBitcoinAddress(address).ToString().c_str()); + if (ExtractDestination(tx.vout[n].scriptPubKey, address)) + strcpy(destaddr,CBitcoinAddress(address).ToString().c_str()); } return(tx.nLockTime); } diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index dd7e041de..e77e8bcb3 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -682,7 +682,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ minage = 6000; if ( blocktime > txtime+minage && (pindex= komodo_chainactive(nHeight>200?nHeight-200:1)) != 0 ) { - vcalc_sha256(0,(uint8_t *)&addrhash,address,(int32_t)strlen(address)); + vcalc_sha256(0,(uint8_t *)&addrhash,(uint8_t *)address,(int32_t)strlen(address)); pasthash = pindex->GetBlockHash(); memcpy(hashbuf,&pasthash,sizeof(pasthash)); memcpy(&hashbuf[sizeof(pasthash)],&addrhash,sizeof(addrhash)); From 1a2b98fab06458bd858444e1cdaae7d330c11186 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 00:28:19 +0300 Subject: [PATCH 257/339] Test --- src/wallet/rpcwallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 3dcd63951..8f9234c1b 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4439,7 +4439,7 @@ UniValue z_listoperationids(const UniValue& params, bool fHelp) #include "script/sign.h" int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex); extern std::string NOTARY_PUBKEY; -uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,uint32_t prevtime); +uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,uint32_t prevtime,char *destaddr); int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) { From e07cf6b5f9330a2801b1002d425afcda770f6060 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 00:28:51 +0300 Subject: [PATCH 258/339] Test --- src/wallet/rpcwallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 8f9234c1b..ed318819a 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4490,7 +4490,7 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt CBlockIndex *tipindex; if ( (tipindex= chainActive.Tip()) != 0 ) { - eligible = komodo_stake(bnTarget,(uint32_t)tipindex->nHeight+1,out.tx->GetHash(),out.i,*blocktimep,(uint32_t)tipindex->nTime,CBitcoinAddress(address).ToString().c_str()); + eligible = komodo_stake(bnTarget,(uint32_t)tipindex->nHeight+1,out.tx->GetHash(),out.i,*blocktimep,(uint32_t)tipindex->nTime,(char *)CBitcoinAddress(address).ToString().c_str()); if ( eligible > 0 ) { if ( earliest == 0 || eligible < earliest || (eligible == earliest && (*utxovaluep == 0 || nValue < *utxovaluep)) ) From 2e90eb0c2a0fa1788bcc218765bf645215f3e132 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 00:37:13 +0300 Subject: [PATCH 259/339] Test --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index e77e8bcb3..7b417c040 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -687,7 +687,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ memcpy(hashbuf,&pasthash,sizeof(pasthash)); memcpy(&hashbuf[sizeof(pasthash)],&addrhash,sizeof(addrhash)); vcalc_sha256(0,(uint8_t *)&hash,hashbuf,(int32_t)sizeof(uint256)*2); - fprintf(stderr,"(%s) vs. (%s) %s %.8f txtime.%u\n",address,destaddr,hash.ToString().c_str(),dstr(value),txtime); + //fprintf(stderr,"(%s) vs. (%s) %s %.8f txtime.%u\n",address,destaddr,hash.ToString().c_str(),dstr(value),txtime); diff = (blocktime - txtime); coinage = (((value * diff) / supply) * diff); hashval = arith_uint256(supply * 64) * (UintToArith256(hash) / arith_uint256(coinage+1)); @@ -709,7 +709,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ } //fprintf(stderr,"iterated until i.%d winner.%d\n",i,winner); } - if ( 0 ) + if ( 1 ) { for (i=31; i>=24; i--) fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]); From 22439b80345a3dfff11ddb3b0705e687cc2069ca Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 00:43:42 +0300 Subject: [PATCH 260/339] Test --- src/komodo_gateway.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 7b417c040..c4bbcd92a 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -672,7 +672,7 @@ uint64_t komodo_commission(const CBlock &block) uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_t vout,uint32_t blocktime,uint32_t prevtime,char *destaddr) { - CBlockIndex *pindex; uint8_t hashbuf[128]; char address[64]; arith_uint256 hashval; uint256 hash,addrhash,pasthash; int32_t minage,i,iter=0; uint32_t txtime,winner = 0; uint64_t diff,value,coinage,supply = ASSETCHAINS_SUPPLY + nHeight*ASSETCHAINS_REWARD/SATOSHIDEN; + CBlockIndex *pindex; uint8_t hashbuf[128]; char address[64]; bits256 addrhash; arith_uint256 hashval; uint256 hash,pasthash; int32_t segid,minage,i,iter=0; uint32_t txtime,winner = 0; uint64_t diff,value,coinage,supply = ASSETCHAINS_SUPPLY + nHeight*ASSETCHAINS_REWARD/SATOSHIDEN; txtime = komodo_txtime(&value,txid,vout,address); if ( value == 0 ) return(0); @@ -683,6 +683,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ if ( blocktime > txtime+minage && (pindex= komodo_chainactive(nHeight>200?nHeight-200:1)) != 0 ) { vcalc_sha256(0,(uint8_t *)&addrhash,(uint8_t *)address,(int32_t)strlen(address)); + segid = ((nHeight + addrhash.uints[0]) & 0x3f); pasthash = pindex->GetBlockHash(); memcpy(hashbuf,&pasthash,sizeof(pasthash)); memcpy(&hashbuf[sizeof(pasthash)],&addrhash,sizeof(addrhash)); @@ -704,6 +705,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ { winner = 1; blocktime += iter; + blocktime += segid; break; } } @@ -716,7 +718,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ fprintf(stderr," vs "); for (i=31; i>=24; i--) fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); - fprintf(stderr," iter.%d winner.%d coinage.%llu %d ht.%d gap.%d %.8f/%llu\n",iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,(int32_t)(blocktime - prevtime),dstr(value),(long long)supply); + fprintf(stderr," segid.%d iter.%d winner.%d coinage.%llu %d ht.%d gap.%d %.8f/%llu\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,(int32_t)(blocktime - prevtime),dstr(value),(long long)supply); } } if ( nHeight < 2 ) From 1dd815ba0bcf7e7dca15381d950d3628ba716c68 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 00:49:11 +0300 Subject: [PATCH 261/339] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index c4bbcd92a..c90e1dd80 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -711,7 +711,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ } //fprintf(stderr,"iterated until i.%d winner.%d\n",i,winner); } - if ( 1 ) + if ( 0 ) { for (i=31; i>=24; i--) fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]); From 8b6faa2e8438e1fec3cfd282917737870c7bafb6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 01:09:27 +0300 Subject: [PATCH 262/339] Test --- src/pow.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pow.cpp b/src/pow.cpp index 23f1cf67b..93ef9ab11 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -142,9 +142,10 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned in height = komodo_currentheight() + 1; special = komodo_chosennotary(¬aryid,height,pubkey33,timestamp); flag = komodo_eligiblenotary(pubkeys,mids,&nonzpkeys,height); - if ( ASSETCHAINS_STAKED != 0 ) + /*if ( ASSETCHAINS_STAKED != 0 ) bnTarget.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow); - else if ( height > 34000 && ASSETCHAINS_SYMBOL[0] == 0 ) // 0 -> non-special notary + else*/ + if ( height > 34000 && ASSETCHAINS_SYMBOL[0] == 0 ) // 0 -> non-special notary { for (i=0; i<33; i++) { From 5bb3d0fe9f55683827d7ed9bbc0acdb117a7bf38 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 01:19:49 +0300 Subject: [PATCH 263/339] Test --- src/main.cpp | 2 +- src/miner.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 4639814de..fc5d4873c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3579,7 +3579,7 @@ bool CheckBlock(int32_t height,CBlockIndex *pindex,const CBlock& block, CValidat if ( komodo_check_deposit(ASSETCHAINS_SYMBOL[0] == 0 ? height : pindex != 0 ? (int32_t)pindex->nHeight : chainActive.Tip()->nHeight+1,block,pindex==0||pindex->pprev==0?0:pindex->pprev->nTime) < 0 ) { static uint32_t counter; - if ( counter++ < 100 ) + if ( counter++ < 100 && ASSETCHAINS_STAKED == 0 ) fprintf(stderr,"check deposit rejection\n"); return(false); } diff --git a/src/miner.cpp b/src/miner.cpp index 853cda770..d249dcce1 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -487,7 +487,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) if ( !TestBlockValidity(state, *pblock, pindexPrev, false, false)) { static uint32_t counter; - if ( counter++ < 100 ) + if ( counter++ < 100 && ASSETCHAINS_STAKED == 0 ) fprintf(stderr,"warning: testblockvalidity failed\n"); return(0); } @@ -762,7 +762,7 @@ void static BitcoinMiner() if ( ptr == 0 ) { static uint32_t counter; - if ( counter++ < 100 ) + if ( counter++ < 100 && ASSETCHAINS_STAKED == 0 ) fprintf(stderr,"created illegal block, retry\n"); continue; } From f08e247d5729c8acfded39c831ada4eea76c95a9 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Duke\" Leto" Date: Tue, 10 Apr 2018 00:33:49 -0700 Subject: [PATCH 264/339] jl777 rebased so now we have viewing keys --- contrib/komodo-cli.bash-completion | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/contrib/komodo-cli.bash-completion b/contrib/komodo-cli.bash-completion index c1a9930ef..1efc05d46 100644 --- a/contrib/komodo-cli.bash-completion +++ b/contrib/komodo-cli.bash-completion @@ -86,11 +86,10 @@ _komodo_cli() { COMPREPLY=( $( compgen -W "true false" -- "$cur" ) ) return 0 ;; -# KMD does not have viewing keys, yet -# z_importkey|z_importviewingkey) -# COMPREPLY=( $( compgen -W "yes no whenkeyisnew" -- "$cur" ) ) -# return 0 -# ;; + z_importkey|z_importviewingkey) + COMPREPLY=( $( compgen -W "yes no whenkeyisnew" -- "$cur" ) ) + return 0 + ;; move|setaccount) _komodo_accounts return 0 From 67b849d7d464b08b393f818bbbf6dafedd3cf36d Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 3 Apr 2018 02:43:52 +0100 Subject: [PATCH 265/339] Fix z_importviewingkey startHeight parameter Closes #2937. --- qa/rpc-tests/wallet_nullifiers.py | 2 +- src/wallet/rpcdump.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/qa/rpc-tests/wallet_nullifiers.py b/qa/rpc-tests/wallet_nullifiers.py index 743af7c92..207631efb 100755 --- a/qa/rpc-tests/wallet_nullifiers.py +++ b/qa/rpc-tests/wallet_nullifiers.py @@ -182,7 +182,7 @@ class WalletNullifiersTest (BitcoinTestFramework): # add node 1 address and node 2 viewing key to node 3 myzvkey = self.nodes[2].z_exportviewingkey(myzaddr) self.nodes[3].importaddress(mytaddr1) - self.nodes[3].z_importviewingkey(myzvkey) + self.nodes[3].z_importviewingkey(myzvkey, 'whenkeyisnew', 1) # Check the address has been imported assert_equal(myzaddr in self.nodes[3].z_listaddresses(), False) diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index bb42ffa1d..33dc90bb3 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -653,7 +653,7 @@ UniValue z_importviewingkey(const UniValue& params, bool fHelp) if (!EnsureWalletIsAvailable(fHelp)) return NullUniValue; - if (fHelp || params.size() < 1 || params.size() > 2) + if (fHelp || params.size() < 1 || params.size() > 3) throw runtime_error( "z_importviewingkey \"vkey\" ( rescan startHeight )\n" "\nAdds a viewing key (as returned by z_exportviewingkey) to your wallet.\n" From 70420ff34f02aed28d9bc9995a46020d5bdf2d53 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Tue, 6 Mar 2018 15:45:25 +0100 Subject: [PATCH 266/339] Test calling z_mergetoaddress to merge notes while a note merge is ongoing --- qa/rpc-tests/wallet_mergetoaddress.py | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/qa/rpc-tests/wallet_mergetoaddress.py b/qa/rpc-tests/wallet_mergetoaddress.py index ff3534e9b..d8531319c 100755 --- a/qa/rpc-tests/wallet_mergetoaddress.py +++ b/qa/rpc-tests/wallet_mergetoaddress.py @@ -324,13 +324,25 @@ class WalletMergeToAddressTest (BitcoinTestFramework): self.sync_all() # Verify maximum number of notes which node 0 can shield can be set by the limit parameter - result = self.nodes[0].z_mergetoaddress([myzaddr], myzaddr, 0, 50, 2) - assert_equal(result["mergingUTXOs"], Decimal('0')) + # Also check that we can set off a second merge before the first one is complete + result1 = self.nodes[0].z_mergetoaddress([myzaddr], myzaddr, 0, 50, 2) + result2 = self.nodes[0].z_mergetoaddress([myzaddr], myzaddr, 0, 50, 2) + + # First merge should select from all notes + assert_equal(result1["mergingUTXOs"], Decimal('0')) # Remaining UTXOs are only counted if we are trying to merge any UTXOs - assert_equal(result["remainingUTXOs"], Decimal('0')) - assert_equal(result["mergingNotes"], Decimal('2')) - assert_equal(result["remainingNotes"], Decimal('3')) - wait_and_assert_operationid_status(self.nodes[0], result['opid']) + assert_equal(result1["remainingUTXOs"], Decimal('0')) + assert_equal(result1["mergingNotes"], Decimal('2')) + assert_equal(result1["remainingNotes"], Decimal('3')) + + # Second merge should ignore locked notes + assert_equal(result2["mergingUTXOs"], Decimal('0')) + assert_equal(result2["remainingUTXOs"], Decimal('0')) + assert_equal(result2["mergingNotes"], Decimal('2')) + assert_equal(result2["remainingNotes"], Decimal('1')) + + wait_and_assert_operationid_status(self.nodes[0], result1['opid']) + wait_and_assert_operationid_status(self.nodes[0], result2['opid']) self.sync_all() self.nodes[1].generate(1) self.sync_all() @@ -340,7 +352,7 @@ class WalletMergeToAddressTest (BitcoinTestFramework): assert_equal(result["mergingUTXOs"], Decimal('10')) assert_equal(result["remainingUTXOs"], Decimal('7')) assert_equal(result["mergingNotes"], Decimal('2')) - assert_equal(result["remainingNotes"], Decimal('2')) + assert_equal(result["remainingNotes"], Decimal('1')) wait_and_assert_operationid_status(self.nodes[0], result['opid']) # Don't sync node 2 which rejects the tx due to its mempooltxinputlimit sync_blocks(self.nodes[:2]) From 98a4f6a6569d57e6792c9b814a480aec4e6d0b42 Mon Sep 17 00:00:00 2001 From: Brad Miller Date: Thu, 15 Mar 2018 15:58:31 -0600 Subject: [PATCH 267/339] Implement note locking for z_mergetoaddress Co-authored-by: Eirik Ogilvie-Wigley --- qa/rpc-tests/wallet_mergetoaddress.py | 8 ++-- .../asyncrpcoperation_mergetoaddress.cpp | 24 +++++++++++ src/wallet/asyncrpcoperation_mergetoaddress.h | 4 ++ src/wallet/gtest/test_wallet.cpp | 33 +++++++++++++++ src/wallet/wallet.cpp | 41 +++++++++++++++++++ src/wallet/wallet.h | 9 ++++ 6 files changed, 116 insertions(+), 3 deletions(-) diff --git a/qa/rpc-tests/wallet_mergetoaddress.py b/qa/rpc-tests/wallet_mergetoaddress.py index d8531319c..e5d5089a4 100755 --- a/qa/rpc-tests/wallet_mergetoaddress.py +++ b/qa/rpc-tests/wallet_mergetoaddress.py @@ -325,8 +325,10 @@ class WalletMergeToAddressTest (BitcoinTestFramework): # Verify maximum number of notes which node 0 can shield can be set by the limit parameter # Also check that we can set off a second merge before the first one is complete - result1 = self.nodes[0].z_mergetoaddress([myzaddr], myzaddr, 0, 50, 2) - result2 = self.nodes[0].z_mergetoaddress([myzaddr], myzaddr, 0, 50, 2) + + # myzaddr has 5 notes at this point + result1 = self.nodes[0].z_mergetoaddress([myzaddr], myzaddr, 0.0001, 50, 2) + result2 = self.nodes[0].z_mergetoaddress([myzaddr], myzaddr, 0.0001, 50, 2) # First merge should select from all notes assert_equal(result1["mergingUTXOs"], Decimal('0')) @@ -340,9 +342,9 @@ class WalletMergeToAddressTest (BitcoinTestFramework): assert_equal(result2["remainingUTXOs"], Decimal('0')) assert_equal(result2["mergingNotes"], Decimal('2')) assert_equal(result2["remainingNotes"], Decimal('1')) - wait_and_assert_operationid_status(self.nodes[0], result1['opid']) wait_and_assert_operationid_status(self.nodes[0], result2['opid']) + self.sync_all() self.nodes[1].generate(1) self.sync_all() diff --git a/src/wallet/asyncrpcoperation_mergetoaddress.cpp b/src/wallet/asyncrpcoperation_mergetoaddress.cpp index 30ef560df..fa823f50a 100644 --- a/src/wallet/asyncrpcoperation_mergetoaddress.cpp +++ b/src/wallet/asyncrpcoperation_mergetoaddress.cpp @@ -98,6 +98,7 @@ AsyncRPCOperation_mergetoaddress::AsyncRPCOperation_mergetoaddress( // Lock UTXOs lock_utxos(); + lock_notes(); // Enable payment disclosure if requested paymentDisclosureMode = fExperimentalMode && GetBoolArg("-paymentdisclosure", false); @@ -111,6 +112,7 @@ void AsyncRPCOperation_mergetoaddress::main() { if (isCancelled()) { unlock_utxos(); // clean up + unlock_notes(); return; } @@ -173,6 +175,7 @@ void AsyncRPCOperation_mergetoaddress::main() LogPrintf("%s", s); unlock_utxos(); // clean up + unlock_notes(); // clean up // !!! Payment disclosure START if (success && paymentDisclosureMode && paymentDisclosureData_.size() > 0) { @@ -921,3 +924,24 @@ void AsyncRPCOperation_mergetoaddress::unlock_utxos() { pwalletMain->UnlockCoin(std::get<0>(utxo)); } } + + +/** + * Lock input notes + */ + void AsyncRPCOperation_mergetoaddress::lock_notes() { + LOCK2(cs_main, pwalletMain->cs_wallet); + for (auto note : noteInputs_) { + pwalletMain->LockNote(std::get<0>(note)); + } +} + +/** + * Unlock input notes + */ +void AsyncRPCOperation_mergetoaddress::unlock_notes() { + LOCK2(cs_main, pwalletMain->cs_wallet); + for (auto note : noteInputs_) { + pwalletMain->UnlockNote(std::get<0>(note)); + } +} diff --git a/src/wallet/asyncrpcoperation_mergetoaddress.h b/src/wallet/asyncrpcoperation_mergetoaddress.h index 1619b5c97..34548a5ba 100644 --- a/src/wallet/asyncrpcoperation_mergetoaddress.h +++ b/src/wallet/asyncrpcoperation_mergetoaddress.h @@ -121,6 +121,10 @@ private: void unlock_utxos(); + void lock_notes(); + + void unlock_notes(); + // payment disclosure! std::vector paymentDisclosureData_; }; diff --git a/src/wallet/gtest/test_wallet.cpp b/src/wallet/gtest/test_wallet.cpp index 4aeaf00df..e976e4ae4 100644 --- a/src/wallet/gtest/test_wallet.cpp +++ b/src/wallet/gtest/test_wallet.cpp @@ -1046,3 +1046,36 @@ TEST(wallet_tests, MarkAffectedTransactionsDirty) { wallet.MarkAffectedTransactionsDirty(wtx2); EXPECT_FALSE(wallet.mapWallet[hash].fDebitCached); } + +TEST(wallet_tests, NoteLocking) { + TestWallet wallet; + + auto sk = libzcash::SpendingKey::random(); + wallet.AddSpendingKey(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.hash, jsoutpt.js, jsoutpt.n)); + EXPECT_FALSE(wallet.IsLockedNote(jsoutpt2.hash, jsoutpt2.js, jsoutpt2.n)); + + // Test selective unlocking + wallet.UnlockNote(jsoutpt); + EXPECT_FALSE(wallet.IsLockedNote(jsoutpt.hash, jsoutpt.js, jsoutpt.n)); + + // Test multiple locking + wallet.LockNote(jsoutpt); + wallet.LockNote(jsoutpt2); + EXPECT_TRUE(wallet.IsLockedNote(jsoutpt.hash, jsoutpt.js, jsoutpt.n)); + EXPECT_TRUE(wallet.IsLockedNote(jsoutpt2.hash, jsoutpt2.js, jsoutpt2.n)); + + // Test unlock all + wallet.UnlockAllNotes(); + EXPECT_FALSE(wallet.IsLockedNote(jsoutpt.hash, jsoutpt.js, jsoutpt.n)); + EXPECT_FALSE(wallet.IsLockedNote(jsoutpt2.hash, jsoutpt2.js, jsoutpt2.n)); +} diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 8172c00e3..eadf7f36d 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -3535,6 +3535,42 @@ void CWallet::ListLockedCoins(std::vector& vOutpts) } } + +// Note Locking Operations + +void CWallet::LockNote(JSOutPoint& output) +{ + AssertLockHeld(cs_wallet); // setLockedNotes + setLockedNotes.insert(output); +} + +void CWallet::UnlockNote(JSOutPoint& output) +{ + AssertLockHeld(cs_wallet); // setLockedNotes + setLockedNotes.erase(output); +} + +void CWallet::UnlockAllNotes() +{ + AssertLockHeld(cs_wallet); // setLockedNotes + setLockedNotes.clear(); +} + +bool CWallet::IsLockedNote(uint256 hash, size_t js, uint8_t n) const +{ + AssertLockHeld(cs_wallet); // setLockedNotes + JSOutPoint outpt(hash, js, n); + + return (setLockedNotes.count(outpt) > 0); +} + +std::vector CWallet::ListLockedNotes() +{ + AssertLockHeld(cs_wallet); // setLockedNotes + std::vector vOutpts(setLockedNotes.begin(), setLockedNotes.end()); + return vOutpts; +} + /** @} */ // end of Actions class CAffectedKeysVisitor : public boost::static_visitor { @@ -3825,6 +3861,11 @@ void CWallet::GetFilteredNotes( if (ignoreUnspendable && !HaveSpendingKey(pa)) { continue; } + + // skip locked notes + if (IsLockedNote(jsop.hash, jsop.js, jsop.n)) { + continue; + } int i = jsop.js; // Index into CTransaction.vjoinsplit int j = jsop.n; // Index into JSDescription.ciphertexts diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 0f9e6c5da..f77a55a04 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -882,6 +882,7 @@ public: CPubKey vchDefaultKey; std::set setLockedCoins; + std::set setLockedNotes; int64_t nTimeFirstKey; @@ -902,6 +903,14 @@ public: void UnlockAllCoins(); void ListLockedCoins(std::vector& vOutpts); + + bool IsLockedNote(uint256 hash, size_t js, uint8_t n) const; + void LockNote(JSOutPoint& output); + void UnlockNote(JSOutPoint& output); + void UnlockAllNotes(); + std::vector ListLockedNotes(); + + /** * keystore implementation * Generate a new key From 6ff482a5099e754a05d81bc505917c43329d3241 Mon Sep 17 00:00:00 2001 From: Mihail Fedorov Date: Tue, 10 Apr 2018 15:36:01 +0300 Subject: [PATCH 268/339] BNTN, CHAIN, PRLPAY --- src/assetchains | 2 ++ src/assetchains.old | 2 ++ src/dpowassets | 5 +++-- src/fiat-cli | 2 ++ src/fiat/bntn | 0 src/fiat/chain | 2 ++ src/fiat/prlpay | 2 ++ 7 files changed, 13 insertions(+), 2 deletions(-) mode change 100644 => 100755 src/fiat/bntn create mode 100755 src/fiat/chain create mode 100755 src/fiat/prlpay diff --git a/src/assetchains b/src/assetchains index c3e161142..517687097 100755 --- a/src/assetchains +++ b/src/assetchains @@ -53,3 +53,5 @@ komodo_asset BEER 100000000 komodo_asset NINJA 100000000 komodo_asset OOT 216000000 komodo_asset BNTN 500000000 +komodo_asset CHAIN 999999 +komodo_asset PRLPAY 500000000 diff --git a/src/assetchains.old b/src/assetchains.old index 6bb60d95a..c025e0430 100755 --- a/src/assetchains.old +++ b/src/assetchains.old @@ -30,6 +30,8 @@ echo $pubkey ./komodod -pubkey=$pubkey -ac_name=NINJA -ac_supply=100000000 -addnode=78.47.196.146 & ./komodod -pubkey=$pubkey -ac_name=OOT -ac_supply=216000000 -addnode=174.138.107.226 & ./komodod -pubkey=$pubkey -ac_name=BNTN -ac_supply=500000000 -addnode=94.130.169.205 & +./komodod -pubkey=$pubkey -ac_name=CHAIN -ac_supply=999999 -addnode=78.47.146.222 & +./komodod -pubkey=$pubkey -ac_name=PRLPAY -ac_supply=500000000 -addnode=13.250.226.125 & #sleep $delay #./komodod -pubkey=$pubkey -ac_name=USD -addnode=78.47.196.146 $1 & diff --git a/src/dpowassets b/src/dpowassets index bd970c357..cd68083ae 100755 --- a/src/dpowassets +++ b/src/dpowassets @@ -26,11 +26,12 @@ curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dp curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"AXO\",\"pubkey\":\"$pubkey\"}" curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"ETOMIC\",\"pubkey\":\"$pubkey\"}" curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"BTCH\",\"pubkey\":\"$pubkey\"}" -#curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"CHAIN\",\"pubkey\":\"$pubkey\"}" +curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"CHAIN\",\"pubkey\":\"$pubkey\"}" curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"VOTE2018\",\"pubkey\":\"$pubkey\"}" curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"NINJA\",\"pubkey\":\"$pubkey\"}" curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"OOT\",\"pubkey\":\"$pubkey\"}" -#curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"BNTN\",\"pubkey\":\"$pubkey\"}" +curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"BNTN\",\"pubkey\":\"$pubkey\"}" +curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"PRLPAY\",\"pubkey\":\"$pubkey\"}" #curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"USD\",\"pubkey\":\"$pubkey\"}" #curl --url "http://127.0.0.1:7776" --data "{\"agent\":\"iguana\",\"method\":\"dpow\",\"symbol\":\"EUR\",\"pubkey\":\"$pubkey\"}" diff --git a/src/fiat-cli b/src/fiat-cli index a7ee8c62e..f170d4c1c 100755 --- a/src/fiat-cli +++ b/src/fiat-cli @@ -26,3 +26,5 @@ echo vote2018; fiat/vote2018 $1 $2 $3 $4 echo ninja; fiat/ninja $1 $2 $3 $4 echo oot; fiat/oot $1 $2 $3 $4 echo bntn: fiat/bntn $1 $2 $3 $4 +echo chain: fiat/chain $1 $2 $3 $4 +echo prlpay: fiat/prlpay $1 $2 $3 $4 diff --git a/src/fiat/bntn b/src/fiat/bntn old mode 100644 new mode 100755 diff --git a/src/fiat/chain b/src/fiat/chain new file mode 100755 index 000000000..c55d30fbd --- /dev/null +++ b/src/fiat/chain @@ -0,0 +1,2 @@ +#!/bin/bash +./komodo-cli -ac_name=CHAIN $1 $2 $3 $4 $5 $6 diff --git a/src/fiat/prlpay b/src/fiat/prlpay new file mode 100755 index 000000000..7ae6f4e8d --- /dev/null +++ b/src/fiat/prlpay @@ -0,0 +1,2 @@ +#!/bin/bash +./komodo-cli -ac_name=BNTN $1 $2 $3 $4 $5 $6 From 4786d20c0b2f813c5a209817469cdcf3bc514bcc Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 16:40:59 +0300 Subject: [PATCH 269/339] PoW targeting in -ac_staking=perc mode --- src/komodo_gateway.h | 105 ++++++++++++++++++++++++++++++++++++++----- src/komodo_utils.h | 5 ++- src/main.cpp | 2 +- 3 files changed, 98 insertions(+), 14 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index c90e1dd80..94a68fb4b 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -726,6 +726,66 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ return(blocktime * winner); } +#define KOMODO_POWMINMULT 16 +arith_uint256 komodo_PoWtarget(int32_t *PoSpercp,arith_uint256 target,int32_t height,int32_t goalperc) +{ + CBlockIndex *pindex; arith_uint256 bnTarget,hashval,sum,ave; bool fNegative,fOverflow; int32_t i,n,ht,percPoS,i,diff; + *percPoSp = percPoS = 0; + sum = arith_uint256(0); + ave = sum; + for (i=n=0; i<100; i++) + { + ht = height - 100 + i; + if ( (pindex= komodo_chainactive(ht)) != 0 ) + { + bnTarget.SetCompact(pindex->nBits,&fNegative,&fOverflow); + bnTarget = (bnTarget / arith_uint256(KOMODO_POWMINMULT)); + hashval = UintToArith256(pindex->GetBlockHash()); + if ( hashval <= bnTarget ) // PoW is never as easy as PoS/64, some PoS will be counted as PoW + { + sum += hashval; + n++; + } else percPoS++; + } + } + *percPoSp = percPoS; + target = (target / arith_uint256(KOMODO_POWMINMULT)); + if ( n > 0 ) + { + ave = (sum / arith_uint256(n)); + if ( ave > target ) + ave = target; + } else return(target); + if ( percPoS < goalperc ) // increase PoW diff -> lower bnTarget + { + bnTarget = (ave * arith_uint256(goalperc)) / arith_uint256(percPoS + goalperc); + for (i=31; i>=24; i--) + fprintf(stderr,"%02x",((uint8_t *)&ave)[i]); + fprintf(stderr," increase diff -> ") + for (i=31; i>=24; i--) + fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); + fprintf(stderr," floor diff ") + for (i=31; i>=24; i--) + fprintf(stderr,"%02x",((uint8_t *)&target)[i]); + fprintf(stderr," ht.%d percPoS.%d vs goal.%d -> diff %d\n",height,percPoS,goalperc,goalperc - percPoS); + } + else if ( percPoS > goalperc ) // decrease PoW diff -> raise bnTarget + { + bnTarget = ((ave * arith_uint256(goalperc)) + (target * arith_uint256(percPoS))) / arith_uint256(percPoS + goalperc); + for (i=31; i>=24; i--) + fprintf(stderr,"%02x",((uint8_t *)&ave)[i]); + fprintf(stderr," decrease diff -> ") + for (i=31; i>=24; i--) + fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); + fprintf(stderr," floor diff ") + for (i=31; i>=24; i--) + fprintf(stderr,"%02x",((uint8_t *)&target)[i]); + fprintf(stderr," ht.%d percPoS.%d vs goal.%d -> diff %d\n",height,percPoS,goalperc,goalperc - percPoS); + } + else bnTarget = ave; // recent ave is perfect + return(bnTarget); +} + int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtime) // verify above block is valid pax pricing { static uint256 array[64]; static int32_t numbanned,indallvouts; @@ -796,20 +856,43 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim } else { - if ( ASSETCHAINS_STAKED != 0 && height >= 2 && txn_count > 1 ) + if ( ASSETCHAINS_STAKED != 0 && height >= 2 ) { - arith_uint256 bnTarget; bool fNegative,fOverflow; CBlockIndex *previndex; uint32_t eligible; - if ( prevtime == 0 ) - { - if ( (previndex= mapBlockIndex[block.hashPrevBlock]) != 0 ) - prevtime = (uint32_t)previndex->nTime; - } + arith_uint256 bnTarget,hashval; int32_t PoSperc; bool fNegative,fOverflow; CBlockIndex *previndex; uint32_t eligible,isPoS = 0; bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow); - eligible = komodo_stake(bnTarget,height,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n,block.nTime,prevtime,(char *)""); - if ( eligible == 0 || eligible > block.nTime ) + if ( txn_count > 1 ) { - fprintf(stderr,"eligible.%u vs blocktime.%u, lag.%d\n",eligible,(uint32_t)block.nTime,(int32_t)(eligible - block.nTime)); - return(-1); + if ( prevtime == 0 ) + { + if ( (previndex= mapBlockIndex[block.hashPrevBlock]) != 0 ) + prevtime = (uint32_t)previndex->nTime; + } + eligible = komodo_stake(bnTarget,height,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n,block.nTime,prevtime,(char *)""); + if ( eligible == 0 || eligible > block.nTime ) + { + fprintf(stderr,"PoS failute ht.%d eligible.%u vs blocktime.%u, lag.%d\n",height,eligible,(uint32_t)block.nTime,(int32_t)(eligible - block.nTime)); + } else isPoS = 1; + } + if ( isPoS == 0 && height > 100 ) + { + if ( ASSETCHAINS_STAKED == 100 ) + { + fprintf(stderr,"ht.%d 100% PoS after height 100 rule violated for -ac_staking=100\n",height); + return(-1); + } + // check PoW + bnTarget = komodo_PoWtarget(&PoSperc,bnTarget,height,ASSETCHAINS_STAKED); + hashval = UintToArith256(block.GetBlockHash()); + if ( hashval > bnTarget ) + { + for (i=31; i>=0; i--) + fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]); + fprintf(stderr," > "); + for (i=31; i>=0; i--) + fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); + fprintf(stderr," ht.%d PoW diff violation PoSperc.%d vs goalperc.%d\n",height,PoSperc,(int32_t)ASSETCHAINS_STAKED); + return(-1); + } } } if ( ASSETCHAINS_OVERRIDE_PUBKEY33[0] != 0 && ASSETCHAINS_COMMISSION != 0 && block.vtx[0].vout.size() > 1 ) diff --git a/src/komodo_utils.h b/src/komodo_utils.h index c38df1411..3059ebf64 100644 --- a/src/komodo_utils.h +++ b/src/komodo_utils.h @@ -1542,7 +1542,8 @@ void komodo_args(char *argv0) ASSETCHAINS_DECAY = GetArg("-ac_decay",0); ASSETCHAINS_COMMISSION = GetArg("-ac_perc",0); ASSETCHAINS_OVERRIDE_PUBKEY = GetArg("-ac_pubkey",""); - ASSETCHAINS_STAKED = GetArg("-ac_staked",0); + if ( (ASSETCHAINS_STAKED= GetArg("-ac_staked",0)) > 100 ) + ASSETCHAINS_STAKED = 100; if ( ASSETCHAINS_HALVING != 0 && ASSETCHAINS_HALVING < 1440 ) { ASSETCHAINS_HALVING = 1440; @@ -1574,7 +1575,7 @@ void komodo_args(char *argv0) extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_REWARD),(void *)&ASSETCHAINS_REWARD); extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_HALVING),(void *)&ASSETCHAINS_HALVING); extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_DECAY),(void *)&ASSETCHAINS_DECAY); - val = ASSETCHAINS_COMMISSION | ((ASSETCHAINS_STAKED & 0xffff) << 32); + val = ASSETCHAINS_COMMISSION | ((ASSETCHAINS_STAKED & 0xff) << 32); extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(val),(void *)&val); } addn = GetArg("-seednode",""); diff --git a/src/main.cpp b/src/main.cpp index fc5d4873c..94c536c2f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3626,7 +3626,7 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta // Don't accept any forks from the main chain prior to last checkpoint CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(chainParams.Checkpoints()); int32_t notarized_height; - if (pcheckpoint && (nHeight < pcheckpoint->nHeight || nHeight == 1 && chainActive.Tip() != 0 && chainActive.Tip()->nHeight > 1) ) + if (pcheckpoint && nHeight > 1 && nHeight < pcheckpoint->nHeight ) return state.DoS(100, error("%s: forked chain older than last checkpoint (height %d) vs %d", __func__, nHeight,pcheckpoint->nHeight)); else if ( komodo_checkpoint(¬arized_height,nHeight,hash) < 0 ) { From 2d9c76280a19f9c2d1a673a48614ecd3706763ba Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 16:49:15 +0300 Subject: [PATCH 270/339] Test --- src/komodo_gateway.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 94a68fb4b..a87c1deb8 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -727,9 +727,9 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ } #define KOMODO_POWMINMULT 16 -arith_uint256 komodo_PoWtarget(int32_t *PoSpercp,arith_uint256 target,int32_t height,int32_t goalperc) +arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t height,int32_t goalperc) { - CBlockIndex *pindex; arith_uint256 bnTarget,hashval,sum,ave; bool fNegative,fOverflow; int32_t i,n,ht,percPoS,i,diff; + CBlockIndex *pindex; arith_uint256 bnTarget,hashval,sum,ave; bool fNegative,fOverflow; int32_t i,n,ht,percPoS,diff; *percPoSp = percPoS = 0; sum = arith_uint256(0); ave = sum; @@ -877,12 +877,12 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim { if ( ASSETCHAINS_STAKED == 100 ) { - fprintf(stderr,"ht.%d 100% PoS after height 100 rule violated for -ac_staking=100\n",height); + fprintf(stderr,"ht.%d 100%% PoS after height 100 rule violated for -ac_staking=100\n",height); return(-1); } // check PoW bnTarget = komodo_PoWtarget(&PoSperc,bnTarget,height,ASSETCHAINS_STAKED); - hashval = UintToArith256(block.GetBlockHash()); + hashval = UintToArith256(block.GetHash()); if ( hashval > bnTarget ) { for (i=31; i>=0; i--) From 8706c053521e8ffcdacbdd26afae674c3e4cd124 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 16:50:39 +0300 Subject: [PATCH 271/339] Test --- src/komodo_gateway.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index a87c1deb8..89e4b6080 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -761,10 +761,10 @@ arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t he bnTarget = (ave * arith_uint256(goalperc)) / arith_uint256(percPoS + goalperc); for (i=31; i>=24; i--) fprintf(stderr,"%02x",((uint8_t *)&ave)[i]); - fprintf(stderr," increase diff -> ") + fprintf(stderr," increase diff -> "); for (i=31; i>=24; i--) fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); - fprintf(stderr," floor diff ") + fprintf(stderr," floor diff "); for (i=31; i>=24; i--) fprintf(stderr,"%02x",((uint8_t *)&target)[i]); fprintf(stderr," ht.%d percPoS.%d vs goal.%d -> diff %d\n",height,percPoS,goalperc,goalperc - percPoS); @@ -774,10 +774,10 @@ arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t he bnTarget = ((ave * arith_uint256(goalperc)) + (target * arith_uint256(percPoS))) / arith_uint256(percPoS + goalperc); for (i=31; i>=24; i--) fprintf(stderr,"%02x",((uint8_t *)&ave)[i]); - fprintf(stderr," decrease diff -> ") + fprintf(stderr," decrease diff -> "); for (i=31; i>=24; i--) fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); - fprintf(stderr," floor diff ") + fprintf(stderr," floor diff "); for (i=31; i>=24; i--) fprintf(stderr,"%02x",((uint8_t *)&target)[i]); fprintf(stderr," ht.%d percPoS.%d vs goal.%d -> diff %d\n",height,percPoS,goalperc,goalperc - percPoS); From deba7f205242c6b980df9bea40bd9e0389bcfdd9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 17:05:51 +0300 Subject: [PATCH 272/339] Mine PoW for ac_staking --- src/miner.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index d249dcce1..e29ec3e08 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -855,6 +855,14 @@ void static BitcoinMiner() } //else fprintf(stderr,"duplicate at j.%d\n",j); } else Mining_start = 0; } else Mining_start = 0; + if ( ASSETCHAINS_STAKED != 0 && NOTARY_PUBKEY33[0] == 0 ) + { + int32_t percPoS,z; + haskTarget = komodo_PoWtarget(&percPoS,haskTarget,pblock->nHeight,ASSETCHAINS_STAKED); + for (z=31; z>=0; z--) + fprintf(stderr,"%02x",((uint8_t *)&hashTarget)[z]); + fprintf(stderr," PoW for staked coin\n"); + } while (true) { /*if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 && pblock->vtx[0].vout.size() == 1 && Mining_height > ASSETCHAINS_MINHEIGHT ) // skips when it shouldnt @@ -914,9 +922,12 @@ void static BitcoinMiner() } else { - printf("need to wait %d seconds to submit\n",(int32_t)(pblock->nTime - GetAdjustedTime())); - while ( GetAdjustedTime() < pblock->nTime ) - sleep(1); + if ( NOTARY_PUBKEY33[0] != 0 ) + { + printf("need to wait %d seconds to submit\n",(int32_t)(pblock->nTime - GetAdjustedTime())); + while ( GetAdjustedTime() < pblock->nTime ) + sleep(1); + } } KOMODO_CHOSEN_ONE = 1; // Found a solution From a8e51a65048be2b04c9e9831066d4fe1d502f778 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 17:09:15 +0300 Subject: [PATCH 273/339] Test --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index e29ec3e08..e4991515e 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -858,7 +858,7 @@ void static BitcoinMiner() if ( ASSETCHAINS_STAKED != 0 && NOTARY_PUBKEY33[0] == 0 ) { int32_t percPoS,z; - haskTarget = komodo_PoWtarget(&percPoS,haskTarget,pblock->nHeight,ASSETCHAINS_STAKED); + hashTarget = komodo_PoWtarget(&percPoS,haskTarget,Mining_height,ASSETCHAINS_STAKED); for (z=31; z>=0; z--) fprintf(stderr,"%02x",((uint8_t *)&hashTarget)[z]); fprintf(stderr," PoW for staked coin\n"); From 898a4b9b6847ba4d52820de6e51eb7ce6a9898e8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 17:09:50 +0300 Subject: [PATCH 274/339] Test --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index e4991515e..78dcbea9d 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -858,7 +858,7 @@ void static BitcoinMiner() if ( ASSETCHAINS_STAKED != 0 && NOTARY_PUBKEY33[0] == 0 ) { int32_t percPoS,z; - hashTarget = komodo_PoWtarget(&percPoS,haskTarget,Mining_height,ASSETCHAINS_STAKED); + hashTarget = komodo_PoWtarget(&percPoS,hashTarget,Mining_height,ASSETCHAINS_STAKED); for (z=31; z>=0; z--) fprintf(stderr,"%02x",((uint8_t *)&hashTarget)[z]); fprintf(stderr," PoW for staked coin\n"); From 13691369bf9993e120183ad0dd561ef2a2f0c8f5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 17:10:41 +0300 Subject: [PATCH 275/339] Test --- src/miner.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/miner.cpp b/src/miner.cpp index 78dcbea9d..b02a62513 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -654,6 +654,7 @@ static bool ProcessBlockFound(CBlock* pblock) int32_t komodo_baseid(char *origbase); int32_t komodo_eligiblenotary(uint8_t pubkeys[66][33],int32_t *mids,int32_t *nonzpkeysp,int32_t height); +arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t height,int32_t goalperc); int32_t FOUND_BLOCK,KOMODO_MAYBEMINED; extern int32_t KOMODO_LASTMINED; int32_t roundrobin_delay; From 7dbeae5dc35def1354d346c688757074a7c73984 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 17:21:31 +0300 Subject: [PATCH 276/339] Test --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index b02a62513..27ac64234 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -387,7 +387,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) blocktime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); pblock->nTime = blocktime; pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus()); - LogPrintf("CreateNewBlock(): total size %u blocktime.%u nBits.%08x\n", nBlockSize,blocktime,pblock->nBits); + //LogPrintf("CreateNewBlock(): total size %u blocktime.%u nBits.%08x\n", nBlockSize,blocktime,pblock->nBits); if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_STAKED != 0 && NOTARY_PUBKEY33[0] != 0 ) { uint64_t txfees,utxovalue; uint32_t txtime; uint256 utxotxid,revtxid; int32_t i,siglen,numsigs,utxovout; uint8_t utxosig[128],*ptr; From 0d8ffadc4a924f25d40ce7ffb99e362cee170ef6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 17:29:21 +0300 Subject: [PATCH 277/339] Test --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index 27ac64234..17ab7353e 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -1053,7 +1053,7 @@ void static BitcoinMiner() // Update nNonce and nTime pblock->nNonce = ArithToUint256(UintToArith256(pblock->nNonce) + 1); pblock->nBits = savebits; - if ( ASSETCHAINS_STAKED == 0 ) + if ( ASSETCHAINS_STAKED == 0 || NOTARY_PUBKEY33[0] == 0 ) UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev); if (chainparams.GetConsensus().fPowAllowMinDifficultyBlocks) { From 4972b74b60027f75534811b6e63bf027171a15e6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 17:49:11 +0300 Subject: [PATCH 278/339] Test --- src/komodo_gateway.h | 42 ++++++++++++++++++++++++------------------ src/miner.cpp | 6 +++--- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 89e4b6080..1363a6c84 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -759,28 +759,34 @@ arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t he if ( percPoS < goalperc ) // increase PoW diff -> lower bnTarget { bnTarget = (ave * arith_uint256(goalperc)) / arith_uint256(percPoS + goalperc); - for (i=31; i>=24; i--) - fprintf(stderr,"%02x",((uint8_t *)&ave)[i]); - fprintf(stderr," increase diff -> "); - for (i=31; i>=24; i--) - fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); - fprintf(stderr," floor diff "); - for (i=31; i>=24; i--) - fprintf(stderr,"%02x",((uint8_t *)&target)[i]); - fprintf(stderr," ht.%d percPoS.%d vs goal.%d -> diff %d\n",height,percPoS,goalperc,goalperc - percPoS); + if ( 0 ) + { + for (i=31; i>=24; i--) + fprintf(stderr,"%02x",((uint8_t *)&ave)[i]); + fprintf(stderr," increase diff -> "); + for (i=31; i>=24; i--) + fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); + fprintf(stderr," floor diff "); + for (i=31; i>=24; i--) + fprintf(stderr,"%02x",((uint8_t *)&target)[i]); + fprintf(stderr," ht.%d percPoS.%d vs goal.%d -> diff %d\n",height,percPoS,goalperc,goalperc - percPoS); + } } else if ( percPoS > goalperc ) // decrease PoW diff -> raise bnTarget { bnTarget = ((ave * arith_uint256(goalperc)) + (target * arith_uint256(percPoS))) / arith_uint256(percPoS + goalperc); - for (i=31; i>=24; i--) - fprintf(stderr,"%02x",((uint8_t *)&ave)[i]); - fprintf(stderr," decrease diff -> "); - for (i=31; i>=24; i--) - fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); - fprintf(stderr," floor diff "); - for (i=31; i>=24; i--) - fprintf(stderr,"%02x",((uint8_t *)&target)[i]); - fprintf(stderr," ht.%d percPoS.%d vs goal.%d -> diff %d\n",height,percPoS,goalperc,goalperc - percPoS); + if ( 0 ) + { + for (i=31; i>=24; i--) + fprintf(stderr,"%02x",((uint8_t *)&ave)[i]); + fprintf(stderr," decrease diff -> "); + for (i=31; i>=24; i--) + fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); + fprintf(stderr," floor diff "); + for (i=31; i>=24; i--) + fprintf(stderr,"%02x",((uint8_t *)&target)[i]); + fprintf(stderr," ht.%d percPoS.%d vs goal.%d -> diff %d\n",height,percPoS,goalperc,goalperc - percPoS); + } } else bnTarget = ave; // recent ave is perfect return(bnTarget); diff --git a/src/miner.cpp b/src/miner.cpp index 17ab7353e..79cd2588e 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -100,7 +100,7 @@ public: void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev) { - pblock->nTime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); + pblock->nTime = 1 + std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); } #include "komodo_defs.h" @@ -902,8 +902,8 @@ void static BitcoinMiner() solutionTargetChecks.increment(); if ( UintToArith256(pblock->GetHash()) > hashTarget ) { - //if ( 0 && ASSETCHAINS_SYMBOL[0] != 0 ) - // fprintf(stderr," missed target\n"); + if ( ASSETCHAINS_SYMBOL[0] != 0 ) + fprintf(stderr," missed target\n"); return false; } if ( ASSETCHAINS_STAKED == 0 ) From 68d0354d9de9c556cbce49ff9270462c37eba6b9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 17:58:38 +0300 Subject: [PATCH 279/339] Test --- src/miner.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/miner.cpp b/src/miner.cpp index 79cd2588e..21e0a8fdd 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -929,6 +929,15 @@ void static BitcoinMiner() while ( GetAdjustedTime() < pblock->nTime ) sleep(1); } + else + { + CValidationState state; + if ( !TestBlockValidity(state, *pblock, pindexPrev, false, false)) + { + fprintf(stderr,"Invalid block mined, try again\n"); + return(false); + } + } } KOMODO_CHOSEN_ONE = 1; // Found a solution From 25d977f73d321acf9c1d3909ed36b2fcf1741c21 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 17:58:56 +0300 Subject: [PATCH 280/339] Test --- src/miner.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index 21e0a8fdd..1a0a5c6f7 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -902,8 +902,8 @@ void static BitcoinMiner() solutionTargetChecks.increment(); if ( UintToArith256(pblock->GetHash()) > hashTarget ) { - if ( ASSETCHAINS_SYMBOL[0] != 0 ) - fprintf(stderr," missed target\n"); + //if ( ASSETCHAINS_SYMBOL[0] != 0 ) + // fprintf(stderr," missed target\n"); return false; } if ( ASSETCHAINS_STAKED == 0 ) From 14bbc7eb1d4bc42352e7a89b0ebaffd70837f7f1 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 18:01:04 +0300 Subject: [PATCH 281/339] Test --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index 1a0a5c6f7..9fbe1adb0 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -932,7 +932,7 @@ void static BitcoinMiner() else { CValidationState state; - if ( !TestBlockValidity(state, *pblock, pindexPrev, false, false)) + if ( !TestBlockValidity(state, *pblock, chainActive.Tip(), false, false)) { fprintf(stderr,"Invalid block mined, try again\n"); return(false); From b1e74295fd6f3ee91dfeb4eb713374051f5d80d0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 18:19:27 +0300 Subject: [PATCH 282/339] Test --- src/main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 94c536c2f..1aafc6c26 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3576,7 +3576,8 @@ bool CheckBlock(int32_t height,CBlockIndex *pindex,const CBlock& block, CValidat if (nSigOps > MAX_BLOCK_SIGOPS) return state.DoS(100, error("CheckBlock(): out-of-bounds SigOpCount"), REJECT_INVALID, "bad-blk-sigops", true); - if ( komodo_check_deposit(ASSETCHAINS_SYMBOL[0] == 0 ? height : pindex != 0 ? (int32_t)pindex->nHeight : chainActive.Tip()->nHeight+1,block,pindex==0||pindex->pprev==0?0:pindex->pprev->nTime) < 0 ) + if ( komodo_check_deposit(height,block,(pindex==0||pindex->pprev==0)?0:pindex->pprev->nTime) < 0 ) + //if ( komodo_check_deposit(ASSETCHAINS_SYMBOL[0] == 0 ? height : pindex != 0 ? (int32_t)pindex->nHeight : chainActive.Tip()->nHeight+1,block,pindex==0||pindex->pprev==0?0:pindex->pprev->nTime) < 0 ) { static uint32_t counter; if ( counter++ < 100 && ASSETCHAINS_STAKED == 0 ) From 294925c70ab56c5d52d09889f3ea131d5f348a74 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 18:22:32 +0300 Subject: [PATCH 283/339] Test --- src/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index 1aafc6c26..2895e888e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4534,6 +4534,8 @@ bool InitBlockIndex() { if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart())) return error("LoadBlockIndex(): writing genesis block to disk failed"); CBlockIndex *pindex = AddToBlockIndex(block); + if ( pindex == 0 ) + return error("LoadBlockIndex(): couldnt add to block index"); if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) return error("LoadBlockIndex(): genesis block not accepted"); if (!ActivateBestChain(state, &block)) From b7aaca4be3ce163c523911f2a2a11e8f212e9e8d Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 19:03:31 +0300 Subject: [PATCH 284/339] Test --- src/miner.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/miner.cpp b/src/miner.cpp index 9fbe1adb0..9e705a40f 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -937,6 +937,10 @@ void static BitcoinMiner() fprintf(stderr,"Invalid block mined, try again\n"); return(false); } + arith_uint256 tmp = pblock->GetHash(); + int32_t z; for (z=31; z>=0; z--) + fprintf(stderr,"%02x",((uint8_t *)&tmp)[z]); + fprintf(stderr," mined block!\n"); } } KOMODO_CHOSEN_ONE = 1; From e4821a8282527c676f6026e3a58b9b059b59b511 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 19:06:11 +0300 Subject: [PATCH 285/339] Test --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index 9e705a40f..c444f0423 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -937,7 +937,7 @@ void static BitcoinMiner() fprintf(stderr,"Invalid block mined, try again\n"); return(false); } - arith_uint256 tmp = pblock->GetHash(); + uint256 tmp = pblock->GetHash(); int32_t z; for (z=31; z>=0; z--) fprintf(stderr,"%02x",((uint8_t *)&tmp)[z]); fprintf(stderr," mined block!\n"); From dc60244b09ccbcdaf514133ad5a80e32ae69a2df Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 19:08:25 +0300 Subject: [PATCH 286/339] Test --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 1363a6c84..a5654363d 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -891,12 +891,12 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim hashval = UintToArith256(block.GetHash()); if ( hashval > bnTarget ) { - for (i=31; i>=0; i--) + /*for (i=31; i>=0; i--) fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]); fprintf(stderr," > "); for (i=31; i>=0; i--) fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); - fprintf(stderr," ht.%d PoW diff violation PoSperc.%d vs goalperc.%d\n",height,PoSperc,(int32_t)ASSETCHAINS_STAKED); + fprintf(stderr," ht.%d PoW diff violation PoSperc.%d vs goalperc.%d\n",height,PoSperc,(int32_t)ASSETCHAINS_STAKED);*/ return(-1); } } From 88287857643acde870e749da79b4a59551327df9 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 19:10:18 +0300 Subject: [PATCH 287/339] Test --- src/miner.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index c444f0423..d8211a869 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -658,6 +658,7 @@ arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t he int32_t FOUND_BLOCK,KOMODO_MAYBEMINED; extern int32_t KOMODO_LASTMINED; int32_t roundrobin_delay; +arith_uint256 HASHTarget; #ifdef ENABLE_WALLET void static BitcoinMiner(CWallet *pwallet) @@ -800,7 +801,7 @@ void static BitcoinMiner() // uint8_t pubkeys[66][33]; int mids[256],gpucount,nonzpkeys,i,j,externalflag; uint32_t savebits; int64_t nStart = GetTime(); savebits = pblock->nBits; - arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits); + HASHTarget = arith_uint256().SetCompact(pblock->nBits); roundrobin_delay = ROUNDROBIN_DELAY; if ( ASSETCHAINS_SYMBOL[0] == 0 && notaryid >= 0 ) { @@ -851,7 +852,7 @@ void static BitcoinMiner() } else fprintf(stderr,"no nonz pubkeys\n"); if ( (Mining_height >= 235300 && Mining_height < 236000) || (j == 65 && Mining_height > KOMODO_MAYBEMINED+1 && Mining_height > KOMODO_LASTMINED+64) ) { - hashTarget = arith_uint256().SetCompact(KOMODO_MINDIFF_NBITS); + HASHTarget = arith_uint256().SetCompact(KOMODO_MINDIFF_NBITS); fprintf(stderr,"I am the chosen one for %s ht.%d\n",ASSETCHAINS_SYMBOL,pindexPrev->nHeight+1); } //else fprintf(stderr,"duplicate at j.%d\n",j); } else Mining_start = 0; @@ -859,9 +860,9 @@ void static BitcoinMiner() if ( ASSETCHAINS_STAKED != 0 && NOTARY_PUBKEY33[0] == 0 ) { int32_t percPoS,z; - hashTarget = komodo_PoWtarget(&percPoS,hashTarget,Mining_height,ASSETCHAINS_STAKED); + HASHTarget = komodo_PoWtarget(&percPoS,HASHTarget,Mining_height,ASSETCHAINS_STAKED); for (z=31; z>=0; z--) - fprintf(stderr,"%02x",((uint8_t *)&hashTarget)[z]); + fprintf(stderr,"%02x",((uint8_t *)&HASHTarget)[z]); fprintf(stderr," PoW for staked coin\n"); } while (true) @@ -891,16 +892,16 @@ void static BitcoinMiner() //fprintf(stderr,"running solver\n"); std::function)> validBlock = #ifdef ENABLE_WALLET - [&pblock, &hashTarget, &pwallet, &reservekey, &m_cs, &cancelSolver, &chainparams] + [&pblock, &HASHTarget, &pwallet, &reservekey, &m_cs, &cancelSolver, &chainparams] #else - [&pblock, &hashTarget, &m_cs, &cancelSolver, &chainparams] + [&pblock, &HASHTarget, &m_cs, &cancelSolver, &chainparams] #endif (std::vector soln) { // Write the solution to the hash and compute the result. LogPrint("pow", "- Checking solution against target\n"); pblock->nSolution = soln; solutionTargetChecks.increment(); - if ( UintToArith256(pblock->GetHash()) > hashTarget ) + if ( UintToArith256(pblock->GetHash()) > HASHTarget ) { //if ( ASSETCHAINS_SYMBOL[0] != 0 ) // fprintf(stderr," missed target\n"); @@ -934,7 +935,7 @@ void static BitcoinMiner() CValidationState state; if ( !TestBlockValidity(state, *pblock, chainActive.Tip(), false, false)) { - fprintf(stderr,"Invalid block mined, try again\n"); + //fprintf(stderr,"Invalid block mined, try again\n"); return(false); } uint256 tmp = pblock->GetHash(); @@ -947,7 +948,7 @@ void static BitcoinMiner() // Found a solution SetThreadPriority(THREAD_PRIORITY_NORMAL); LogPrintf("KomodoMiner:\n"); - LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", pblock->GetHash().GetHex(), hashTarget.GetHex()); + LogPrintf("proof-of-work found \n hash: %s \ntarget: %s\n", pblock->GetHash().GetHex(), HASHTarget.GetHex()); #ifdef ENABLE_WALLET if (ProcessBlockFound(pblock, *pwallet, reservekey)) { #else @@ -1071,7 +1072,7 @@ void static BitcoinMiner() if (chainparams.GetConsensus().fPowAllowMinDifficultyBlocks) { // Changing pblock->nTime can change work required on testnet: - hashTarget.SetCompact(pblock->nBits); + HASHTarget.SetCompact(pblock->nBits); } } } From 7da8410746ded9c6daff43dc22fc7d777240fddc Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 19:11:57 +0300 Subject: [PATCH 288/339] Test --- src/miner.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/miner.cpp b/src/miner.cpp index d8211a869..e45b9e59b 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -889,12 +889,13 @@ void static BitcoinMiner() crypto_generichash_blake2b_update(&curr_state,pblock->nNonce.begin(),pblock->nNonce.size()); // (x_1, x_2, ...) = A(I, V, n, k) LogPrint("pow", "Running Equihash solver \"%s\" with nNonce = %s\n",solver, pblock->nNonce.ToString()); + arith_uint256 hashTarget = HASHTarget; //fprintf(stderr,"running solver\n"); std::function)> validBlock = #ifdef ENABLE_WALLET - [&pblock, &HASHTarget, &pwallet, &reservekey, &m_cs, &cancelSolver, &chainparams] + [&pblock, &hashTarget, &pwallet, &reservekey, &m_cs, &cancelSolver, &chainparams] #else - [&pblock, &HASHTarget, &m_cs, &cancelSolver, &chainparams] + [&pblock, &hashTarget, &m_cs, &cancelSolver, &chainparams] #endif (std::vector soln) { // Write the solution to the hash and compute the result. From 053fef7cfd9904cc251c3186f5c21561d6d4c32f Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 19:18:32 +0300 Subject: [PATCH 289/339] Test --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index a5654363d..0ebccabcf 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -759,7 +759,7 @@ arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t he if ( percPoS < goalperc ) // increase PoW diff -> lower bnTarget { bnTarget = (ave * arith_uint256(goalperc)) / arith_uint256(percPoS + goalperc); - if ( 0 ) + if ( 1 ) { for (i=31; i>=24; i--) fprintf(stderr,"%02x",((uint8_t *)&ave)[i]); @@ -775,7 +775,7 @@ arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t he else if ( percPoS > goalperc ) // decrease PoW diff -> raise bnTarget { bnTarget = ((ave * arith_uint256(goalperc)) + (target * arith_uint256(percPoS))) / arith_uint256(percPoS + goalperc); - if ( 0 ) + if ( 1 ) { for (i=31; i>=24; i--) fprintf(stderr,"%02x",((uint8_t *)&ave)[i]); From 49c374d7ad712d50f2d7ff4b2aafc3cc14271908 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 19:34:22 +0300 Subject: [PATCH 290/339] Test --- src/komodo_gateway.h | 2 +- src/miner.cpp | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 0ebccabcf..b4ff7affd 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -876,7 +876,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim eligible = komodo_stake(bnTarget,height,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n,block.nTime,prevtime,(char *)""); if ( eligible == 0 || eligible > block.nTime ) { - fprintf(stderr,"PoS failute ht.%d eligible.%u vs blocktime.%u, lag.%d\n",height,eligible,(uint32_t)block.nTime,(int32_t)(eligible - block.nTime)); + fprintf(stderr,"PoS failure ht.%d eligible.%u vs blocktime.%u, lag.%d\n",height,eligible,(uint32_t)block.nTime,(int32_t)(eligible - block.nTime)); } else isPoS = 1; } if ( isPoS == 0 && height > 100 ) diff --git a/src/miner.cpp b/src/miner.cpp index e45b9e59b..be2c5a0aa 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -925,6 +925,12 @@ void static BitcoinMiner() } else { + CValidationState state; + if ( !TestBlockValidity(state, *pblock, chainActive.Tip(), false, false)) + { + //fprintf(stderr,"Invalid block mined, try again\n"); + return(false); + } if ( NOTARY_PUBKEY33[0] != 0 ) { printf("need to wait %d seconds to submit\n",(int32_t)(pblock->nTime - GetAdjustedTime())); @@ -933,12 +939,6 @@ void static BitcoinMiner() } else { - CValidationState state; - if ( !TestBlockValidity(state, *pblock, chainActive.Tip(), false, false)) - { - //fprintf(stderr,"Invalid block mined, try again\n"); - return(false); - } uint256 tmp = pblock->GetHash(); int32_t z; for (z=31; z>=0; z--) fprintf(stderr,"%02x",((uint8_t *)&tmp)[z]); From 409c28a2e2c43d21ecca6f9687c70581c6eb4590 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 19:46:33 +0300 Subject: [PATCH 291/339] Test --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 2895e888e..fb833bff5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -562,7 +562,7 @@ CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& loc CBlockIndex* pindex = (*mi).second; if (pindex != 0 && chain.Contains(pindex)) return pindex; - if (pindex->GetAncestor(chain.Height()) == chain.Tip()) { + if (pindex != 0 && pindex->GetAncestor(chain.Height()) == chain.Tip()) { return chain.Tip(); } } From 007aca381b562e2c2e32ee8dc89cf00efc0c92f7 Mon Sep 17 00:00:00 2001 From: jl777 Date: Tue, 10 Apr 2018 20:38:12 +0300 Subject: [PATCH 292/339] Test --- src/arith_uint256.cpp | 2 +- src/komodo_gateway.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/arith_uint256.cpp b/src/arith_uint256.cpp index a1865b649..c9074fe91 100644 --- a/src/arith_uint256.cpp +++ b/src/arith_uint256.cpp @@ -111,7 +111,7 @@ int base_uint::CompareTo(const base_uint& b) const { if ( (uint64_t)pn < 0x1000 || (uint64_t)b.pn <= 0x1000 ) { - fprintf(stderr,"CompareTo null %p or %p\n",pn,b.pn); + //fprintf(stderr,"CompareTo null %p or %p\n",pn,b.pn); return(0); } for (int i = WIDTH - 1; i >= 0; i--) { diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index b4ff7affd..e85252367 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -876,7 +876,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim eligible = komodo_stake(bnTarget,height,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n,block.nTime,prevtime,(char *)""); if ( eligible == 0 || eligible > block.nTime ) { - fprintf(stderr,"PoS failure ht.%d eligible.%u vs blocktime.%u, lag.%d\n",height,eligible,(uint32_t)block.nTime,(int32_t)(eligible - block.nTime)); + fprintf(stderr,"PoS failure ht.%d eligible.%u vs blocktime.%u, lag.%d -> check to see if it is PoW block\n",height,eligible,(uint32_t)block.nTime,(int32_t)(eligible - block.nTime)); } else isPoS = 1; } if ( isPoS == 0 && height > 100 ) From a6cb17f049780374d0bf2f143cdc5b9494f9ec1d Mon Sep 17 00:00:00 2001 From: Mihail Fedorov Date: Tue, 10 Apr 2018 21:25:36 +0300 Subject: [PATCH 293/339] fat finger typo --- src/fiat-cli | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/fiat-cli b/src/fiat-cli index f170d4c1c..ce2e7a51d 100755 --- a/src/fiat-cli +++ b/src/fiat-cli @@ -25,6 +25,6 @@ echo beer; fiat/beer $1 $2 $3 $4 echo vote2018; fiat/vote2018 $1 $2 $3 $4 echo ninja; fiat/ninja $1 $2 $3 $4 echo oot; fiat/oot $1 $2 $3 $4 -echo bntn: fiat/bntn $1 $2 $3 $4 -echo chain: fiat/chain $1 $2 $3 $4 -echo prlpay: fiat/prlpay $1 $2 $3 $4 +echo bntn; fiat/bntn $1 $2 $3 $4 +echo chain; fiat/chain $1 $2 $3 $4 +echo prlpay; fiat/prlpay $1 $2 $3 $4 From 234c0ac057d67d348addfd74ac69d6a16dfcf304 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 11 Apr 2018 04:07:06 +0300 Subject: [PATCH 294/339] Skew nBits PoS diff to 1 --- src/miner.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/miner.cpp b/src/miner.cpp index be2c5a0aa..692db8ce6 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -392,6 +392,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) { uint64_t txfees,utxovalue; uint32_t txtime; uint256 utxotxid,revtxid; int32_t i,siglen,numsigs,utxovout; uint8_t utxosig[128],*ptr; CMutableTransaction txStaked = CreateNewContextualCMutableTransaction(Params().GetConsensus(), chainActive.Height() + 1); + blocktime += 2; if ( (siglen= komodo_staked(txStaked,pblock->nBits,&blocktime,&txtime,&utxotxid,&utxovout,&utxovalue,utxosig)) > 0 ) { CAmount txfees = 0; From 3815678c0dc3bc293d069f73f01a788328fbba70 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 11 Apr 2018 04:21:48 +0300 Subject: [PATCH 295/339] Add segid even if winning block --- src/komodo_gateway.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index e85252367..4a92b6e5a 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -693,7 +693,10 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ coinage = (((value * diff) / supply) * diff); hashval = arith_uint256(supply * 64) * (UintToArith256(hash) / arith_uint256(coinage+1)); if ( hashval <= bnTarget ) + { winner = 1; + blocktime += segid; + } else { for (iter=1; iter<3600*8; iter++) From 8373141bb7b8fdaadbfd125358d89d986024ff3e Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 11 Apr 2018 04:43:43 +0300 Subject: [PATCH 296/339] Test --- src/komodo_gateway.h | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 4a92b6e5a..026969dac 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -689,9 +689,13 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ memcpy(&hashbuf[sizeof(pasthash)],&addrhash,sizeof(addrhash)); vcalc_sha256(0,(uint8_t *)&hash,hashbuf,(int32_t)sizeof(uint256)*2); //fprintf(stderr,"(%s) vs. (%s) %s %.8f txtime.%u\n",address,destaddr,hash.ToString().c_str(),dstr(value),txtime); - diff = (blocktime - txtime); - coinage = (((value * diff) / supply) * diff); - hashval = arith_uint256(supply * 64) * (UintToArith256(hash) / arith_uint256(coinage+1)); + diff = (blocktime - txtime - minage); + //if ( diff > 3600 ) + // diff = 3600; + //coinage = (((value * diff) / supply) * diff); + coinage = (value * diff); + //hashval = arith_uint256(supply * 64) * (UintToArith256(hash) / arith_uint256(coinage+1)); + hashval = (UintToArith256(hash) / arith_uint256(coinage+1)); if ( hashval <= bnTarget ) { winner = 1; @@ -699,9 +703,11 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ } else { - for (iter=1; iter<3600*8; iter++) + for (iter=1; iter<3600; iter++) { - diff = (iter + blocktime - txtime); + diff = (iter + blocktime - txtime - minage); + //if ( diff > 3600 ) + // break; coinage = (((value * diff) / supply) * diff); hashval = arith_uint256(supply * 64) * (UintToArith256(hash) / arith_uint256(coinage+1)); if ( hashval <= bnTarget ) From 188e19a735d6e7c42a1f97a86dfbe73ae5f3ed44 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 11 Apr 2018 04:45:45 +0300 Subject: [PATCH 297/339] Test --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 026969dac..d89936c37 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -693,7 +693,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ //if ( diff > 3600 ) // diff = 3600; //coinage = (((value * diff) / supply) * diff); - coinage = (value * diff); + coinage = (value * diff) * ((diff >> 16) + 1); //hashval = arith_uint256(supply * 64) * (UintToArith256(hash) / arith_uint256(coinage+1)); hashval = (UintToArith256(hash) / arith_uint256(coinage+1)); if ( hashval <= bnTarget ) @@ -720,7 +720,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ } //fprintf(stderr,"iterated until i.%d winner.%d\n",i,winner); } - if ( 0 ) + if ( 1 ) { for (i=31; i>=24; i--) fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]); From c09e3fa1a7873504b2bcc561733e41fcc30b7115 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 11 Apr 2018 04:48:32 +0300 Subject: [PATCH 298/339] Test --- src/komodo_gateway.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index d89936c37..778be3eca 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -690,8 +690,8 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ vcalc_sha256(0,(uint8_t *)&hash,hashbuf,(int32_t)sizeof(uint256)*2); //fprintf(stderr,"(%s) vs. (%s) %s %.8f txtime.%u\n",address,destaddr,hash.ToString().c_str(),dstr(value),txtime); diff = (blocktime - txtime - minage); - //if ( diff > 3600 ) - // diff = 3600; + if ( diff > 3600*24 ) + diff = 3600*24; //coinage = (((value * diff) / supply) * diff); coinage = (value * diff) * ((diff >> 16) + 1); //hashval = arith_uint256(supply * 64) * (UintToArith256(hash) / arith_uint256(coinage+1)); @@ -706,8 +706,8 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ for (iter=1; iter<3600; iter++) { diff = (iter + blocktime - txtime - minage); - //if ( diff > 3600 ) - // break; + if ( diff > 3600*24 ) + break; coinage = (((value * diff) / supply) * diff); hashval = arith_uint256(supply * 64) * (UintToArith256(hash) / arith_uint256(coinage+1)); if ( hashval <= bnTarget ) From 52955b6feca259312188859a43860703564c3299 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 11 Apr 2018 04:53:05 +0300 Subject: [PATCH 299/339] Test --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 778be3eca..d29e70261 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -694,8 +694,8 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ diff = 3600*24; //coinage = (((value * diff) / supply) * diff); coinage = (value * diff) * ((diff >> 16) + 1); - //hashval = arith_uint256(supply * 64) * (UintToArith256(hash) / arith_uint256(coinage+1)); - hashval = (UintToArith256(hash) / arith_uint256(coinage+1)); + hashval = arith_uint256(supply * 64) * (UintToArith256(hash) / arith_uint256(coinage+1)); + //hashval = (UintToArith256(hash) / arith_uint256(coinage+1)); if ( hashval <= bnTarget ) { winner = 1; From f21f0d70412eb8b072342534f9af2833a4c938b3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 11 Apr 2018 04:59:39 +0300 Subject: [PATCH 300/339] Test --- src/miner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/miner.cpp b/src/miner.cpp index 692db8ce6..b5187a615 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -385,7 +385,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) nLastBlockTx = nBlockTx; nLastBlockSize = nBlockSize; blocktime = std::max(pindexPrev->GetMedianTimePast()+1, GetAdjustedTime()); - pblock->nTime = blocktime; + pblock->nTime = blocktime + 1; pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, Params().GetConsensus()); //LogPrintf("CreateNewBlock(): total size %u blocktime.%u nBits.%08x\n", nBlockSize,blocktime,pblock->nBits); if ( ASSETCHAINS_SYMBOL[0] != 0 && ASSETCHAINS_STAKED != 0 && NOTARY_PUBKEY33[0] != 0 ) From a0845beaadafa072fcf111a1ffbaf2def86cd1f8 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 11 Apr 2018 05:15:04 +0300 Subject: [PATCH 301/339] Test --- src/komodo_gateway.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index d29e70261..c6d736686 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -720,7 +720,7 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ } //fprintf(stderr,"iterated until i.%d winner.%d\n",i,winner); } - if ( 1 ) + if ( 0 ) { for (i=31; i>=24; i--) fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]); From c966741fb69aabc9a80be17beb9973c29232ece6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 11 Apr 2018 05:16:30 +0300 Subject: [PATCH 302/339] Test --- src/miner.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/miner.cpp b/src/miner.cpp index b5187a615..f95933117 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -861,6 +861,11 @@ void static BitcoinMiner() if ( ASSETCHAINS_STAKED != 0 && NOTARY_PUBKEY33[0] == 0 ) { int32_t percPoS,z; + if ( Mining_height <= 100 ) + { + sleep(60); + continue; + } HASHTarget = komodo_PoWtarget(&percPoS,HASHTarget,Mining_height,ASSETCHAINS_STAKED); for (z=31; z>=0; z--) fprintf(stderr,"%02x",((uint8_t *)&HASHTarget)[z]); From 21d3884815f0880fece09875fb511e70f49fbbf2 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 11 Apr 2018 05:24:20 +0300 Subject: [PATCH 303/339] Test --- src/komodo_gateway.h | 39 ++++++++++++--------------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index c6d736686..39e3d4d21 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -689,37 +689,22 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ memcpy(&hashbuf[sizeof(pasthash)],&addrhash,sizeof(addrhash)); vcalc_sha256(0,(uint8_t *)&hash,hashbuf,(int32_t)sizeof(uint256)*2); //fprintf(stderr,"(%s) vs. (%s) %s %.8f txtime.%u\n",address,destaddr,hash.ToString().c_str(),dstr(value),txtime); - diff = (blocktime - txtime - minage); - if ( diff > 3600*24 ) - diff = 3600*24; - //coinage = (((value * diff) / supply) * diff); - coinage = (value * diff) * ((diff >> 16) + 1); - hashval = arith_uint256(supply * 64) * (UintToArith256(hash) / arith_uint256(coinage+1)); - //hashval = (UintToArith256(hash) / arith_uint256(coinage+1)); - if ( hashval <= bnTarget ) + for (iter=0; iter<3600; iter++) { - winner = 1; - blocktime += segid; - } - else - { - for (iter=1; iter<3600; iter++) + diff = (iter + blocktime - txtime - minage); + if ( diff > 3600*24 ) + break; + coinage = (value * diff) * ((diff >> 16) + 1); + hashval = arith_uint256(supply * 64) * (UintToArith256(hash) / arith_uint256(coinage+1)); + if ( hashval <= bnTarget ) { - diff = (iter + blocktime - txtime - minage); - if ( diff > 3600*24 ) - break; - coinage = (((value * diff) / supply) * diff); - hashval = arith_uint256(supply * 64) * (UintToArith256(hash) / arith_uint256(coinage+1)); - if ( hashval <= bnTarget ) - { - winner = 1; - blocktime += iter; - blocktime += segid; - break; - } + winner = 1; + blocktime += iter; + blocktime += segid; + break; } - //fprintf(stderr,"iterated until i.%d winner.%d\n",i,winner); } + //fprintf(stderr,"iterated until i.%d winner.%d\n",i,winner); if ( 0 ) { for (i=31; i>=24; i--) From a7fc955463118f9a5a3ac35baf0c51de5ea595bd Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 11 Apr 2018 05:30:00 +0300 Subject: [PATCH 304/339] Test --- src/komodo_gateway.h | 13 +++++++++---- src/wallet/rpcwallet.cpp | 4 ++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 39e3d4d21..f39441a5c 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -670,7 +670,7 @@ uint64_t komodo_commission(const CBlock &block) return((total * ASSETCHAINS_COMMISSION) / COIN); } -uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_t vout,uint32_t blocktime,uint32_t prevtime,char *destaddr) +uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_t vout,uint32_t blocktime,uint32_t prevtime,char *destaddr) { CBlockIndex *pindex; uint8_t hashbuf[128]; char address[64]; bits256 addrhash; arith_uint256 hashval; uint256 hash,pasthash; int32_t segid,minage,i,iter=0; uint32_t txtime,winner = 0; uint64_t diff,value,coinage,supply = ASSETCHAINS_SUPPLY + nHeight*ASSETCHAINS_REWARD/SATOSHIDEN; txtime = komodo_txtime(&value,txid,vout,address); @@ -699,10 +699,15 @@ uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_ if ( hashval <= bnTarget ) { winner = 1; - blocktime += iter; - blocktime += segid; + if ( validateflag == 0 ) + { + blocktime += iter; + blocktime += segid; + } break; } + if ( validateflag != 0 ) + break; } //fprintf(stderr,"iterated until i.%d winner.%d\n",i,winner); if ( 0 ) @@ -867,7 +872,7 @@ int32_t komodo_check_deposit(int32_t height,const CBlock& block,uint32_t prevtim if ( (previndex= mapBlockIndex[block.hashPrevBlock]) != 0 ) prevtime = (uint32_t)previndex->nTime; } - eligible = komodo_stake(bnTarget,height,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n,block.nTime,prevtime,(char *)""); + eligible = komodo_stake(1,bnTarget,height,block.vtx[txn_count-1].vin[0].prevout.hash,block.vtx[txn_count-1].vin[0].prevout.n,block.nTime,prevtime,(char *)""); if ( eligible == 0 || eligible > block.nTime ) { fprintf(stderr,"PoS failure ht.%d eligible.%u vs blocktime.%u, lag.%d -> check to see if it is PoW block\n",height,eligible,(uint32_t)block.nTime,(int32_t)(eligible - block.nTime)); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index ed318819a..c349a3e38 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4439,7 +4439,7 @@ UniValue z_listoperationids(const UniValue& params, bool fHelp) #include "script/sign.h" int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex); extern std::string NOTARY_PUBKEY; -uint32_t komodo_stake(arith_uint256 bnTarget,int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,uint32_t prevtime,char *destaddr); +uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeight,uint256 hash,int32_t n,uint32_t blocktime,uint32_t prevtime,char *destaddr); int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) { @@ -4490,7 +4490,7 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt CBlockIndex *tipindex; if ( (tipindex= chainActive.Tip()) != 0 ) { - eligible = komodo_stake(bnTarget,(uint32_t)tipindex->nHeight+1,out.tx->GetHash(),out.i,*blocktimep,(uint32_t)tipindex->nTime,(char *)CBitcoinAddress(address).ToString().c_str()); + eligible = komodo_stake(0,bnTarget,(uint32_t)tipindex->nHeight+1,out.tx->GetHash(),out.i,*blocktimep,(uint32_t)tipindex->nTime,(char *)CBitcoinAddress(address).ToString().c_str()); if ( eligible > 0 ) { if ( earliest == 0 || eligible < earliest || (eligible == earliest && (*utxovaluep == 0 || nValue < *utxovaluep)) ) From 84ec4ab355d5c73730cf3210778c111c7348487b Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 11 Apr 2018 05:42:24 +0300 Subject: [PATCH 305/339] Test --- src/komodo_gateway.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index f39441a5c..a5438ab3e 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -707,7 +707,15 @@ uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeigh break; } if ( validateflag != 0 ) + { + for (i=31; i>=24; i--) + fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]); + fprintf(stderr," vs target "); + for (i=31; i>=24; i--) + fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); + fprintf(stderr," segid.%d iter.%d winner.%d coinage.%llu %d ht.%d gap.%d %.8f/%llu\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,(int32_t)(blocktime - prevtime),dstr(value),(long long)supply); break; + } } //fprintf(stderr,"iterated until i.%d winner.%d\n",i,winner); if ( 0 ) From 8a183a994049e80c47b1082e932da43180ad72cd Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 11 Apr 2018 14:08:14 +0300 Subject: [PATCH 306/339] Revert segid for initial hit --- src/komodo_gateway.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index a5438ab3e..2cb6ab49e 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -702,7 +702,8 @@ uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeigh if ( validateflag == 0 ) { blocktime += iter; - blocktime += segid; + if ( iter > 0 ) + blocktime += segid; } break; } From bbe4341700742db4e5d15b09f81038d8388cf3c3 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 11 Apr 2018 14:12:58 +0300 Subject: [PATCH 307/339] Test --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 2cb6ab49e..9c8b73c00 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -719,14 +719,14 @@ uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeigh } } //fprintf(stderr,"iterated until i.%d winner.%d\n",i,winner); - if ( 0 ) + if ( 1 ) { for (i=31; i>=24; i--) fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]); fprintf(stderr," vs "); for (i=31; i>=24; i--) fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); - fprintf(stderr," segid.%d iter.%d winner.%d coinage.%llu %d ht.%d gap.%d %.8f/%llu\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,(int32_t)(blocktime - prevtime),dstr(value),(long long)supply); + fprintf(stderr," segid.%d iter.%d winner.%d coinage.%llu %d ht.%d t.%u %.8f/%llu\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,blocktime,dstr(value),(long long)supply); } } if ( nHeight < 2 ) From 8d7a7f1fefffaf8408923b6e7a62b125a8c32bc6 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 11 Apr 2018 14:29:01 +0300 Subject: [PATCH 308/339] Test --- src/komodo_gateway.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 9c8b73c00..490f5d8c6 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -672,12 +672,10 @@ uint64_t komodo_commission(const CBlock &block) uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_t vout,uint32_t blocktime,uint32_t prevtime,char *destaddr) { - CBlockIndex *pindex; uint8_t hashbuf[128]; char address[64]; bits256 addrhash; arith_uint256 hashval; uint256 hash,pasthash; int32_t segid,minage,i,iter=0; uint32_t txtime,winner = 0; uint64_t diff,value,coinage,supply = ASSETCHAINS_SUPPLY + nHeight*ASSETCHAINS_REWARD/SATOSHIDEN; + CBlockIndex *pindex; uint8_t hashbuf[128]; char address[64]; bits256 addrhash; arith_uint256 hashval; uint256 hash,pasthash; int32_t segid,minage,i,iter=0; uint32_t txtime,winner = 0; uint64_t diff=0,value,coinage,supply = ASSETCHAINS_SUPPLY + nHeight*ASSETCHAINS_REWARD/SATOSHIDEN; txtime = komodo_txtime(&value,txid,vout,address); - if ( value == 0 ) + if ( value == 0 || txtime == 0 ) return(0); - if ( txtime == 0 ) - txtime = prevtime; if ( (minage= nHeight*3) > 6000 ) minage = 6000; if ( blocktime > txtime+minage && (pindex= komodo_chainactive(nHeight>200?nHeight-200:1)) != 0 ) @@ -714,7 +712,7 @@ uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeigh fprintf(stderr," vs target "); for (i=31; i>=24; i--) fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); - fprintf(stderr," segid.%d iter.%d winner.%d coinage.%llu %d ht.%d gap.%d %.8f/%llu\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,(int32_t)(blocktime - prevtime),dstr(value),(long long)supply); + fprintf(stderr," segid.%d iter.%d winner.%d coinage.%llu %d ht.%d gap.%d %.8f diff.%d\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,(int32_t)(blocktime - prevtime),dstr(value),diff); break; } } @@ -726,7 +724,7 @@ uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeigh fprintf(stderr," vs "); for (i=31; i>=24; i--) fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); - fprintf(stderr," segid.%d iter.%d winner.%d coinage.%llu %d ht.%d t.%u %.8f/%llu\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,blocktime,dstr(value),(long long)supply); + fprintf(stderr," segid.%d iter.%d winner.%d coinage.%llu %d ht.%d t.%u %.8f diff.%d\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,blocktime,dstr(value),diff); } } if ( nHeight < 2 ) From 55004a5e0bd0b478116a532dbedac362b0467024 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 11 Apr 2018 14:36:16 +0300 Subject: [PATCH 309/339] Test --- src/komodo_gateway.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 490f5d8c6..ee18d23ba 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -672,7 +672,7 @@ uint64_t komodo_commission(const CBlock &block) uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeight,uint256 txid,int32_t vout,uint32_t blocktime,uint32_t prevtime,char *destaddr) { - CBlockIndex *pindex; uint8_t hashbuf[128]; char address[64]; bits256 addrhash; arith_uint256 hashval; uint256 hash,pasthash; int32_t segid,minage,i,iter=0; uint32_t txtime,winner = 0; uint64_t diff=0,value,coinage,supply = ASSETCHAINS_SUPPLY + nHeight*ASSETCHAINS_REWARD/SATOSHIDEN; + CBlockIndex *pindex; uint8_t hashbuf[128]; char address[64]; bits256 addrhash; arith_uint256 hashval; uint256 hash,pasthash; int64_t diff=0; int32_t segid,minage,i,iter=0; uint32_t txtime,winner = 0; uint64_t value,coinage,supply = ASSETCHAINS_SUPPLY + nHeight*ASSETCHAINS_REWARD/SATOSHIDEN; txtime = komodo_txtime(&value,txid,vout,address); if ( value == 0 || txtime == 0 ) return(0); @@ -712,7 +712,7 @@ uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeigh fprintf(stderr," vs target "); for (i=31; i>=24; i--) fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); - fprintf(stderr," segid.%d iter.%d winner.%d coinage.%llu %d ht.%d gap.%d %.8f diff.%d\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,(int32_t)(blocktime - prevtime),dstr(value),diff); + fprintf(stderr," segid.%d iter.%d winner.%d coinage.%llu %d ht.%d gap.%d %.8f diff.%d\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,(int32_t)(blocktime - prevtime),dstr(value),(int32_t)diff); break; } } @@ -724,7 +724,7 @@ uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeigh fprintf(stderr," vs "); for (i=31; i>=24; i--) fprintf(stderr,"%02x",((uint8_t *)&bnTarget)[i]); - fprintf(stderr," segid.%d iter.%d winner.%d coinage.%llu %d ht.%d t.%u %.8f diff.%d\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,blocktime,dstr(value),diff); + fprintf(stderr," segid.%d iter.%d winner.%d coinage.%llu %d ht.%d t.%u %.8f diff.%d\n",segid,iter,winner,(long long)coinage,(int32_t)(blocktime - txtime),nHeight,blocktime,dstr(value),(int32_t)diff); } } if ( nHeight < 2 ) From b0e712e72d571bbb0b06827813aa8def5b36411c Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 11 Apr 2018 14:52:09 +0300 Subject: [PATCH 310/339] Test --- src/wallet/rpcwallet.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index c349a3e38..407514eb5 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4493,7 +4493,9 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt eligible = komodo_stake(0,bnTarget,(uint32_t)tipindex->nHeight+1,out.tx->GetHash(),out.i,*blocktimep,(uint32_t)tipindex->nTime,(char *)CBitcoinAddress(address).ToString().c_str()); if ( eligible > 0 ) { - if ( earliest == 0 || eligible < earliest || (eligible == earliest && (*utxovaluep == 0 || nValue < *utxovaluep)) ) + if ( eligible != komodo_stake(1,bnTarget,(uint32_t)tipindex->nHeight+1,out.tx->GetHash(),out.i,*blocktimep,(uint32_t)tipindex->nTime,(char *)CBitcoinAddress(address).ToString().c_str()) ) + fprintf(stderr,"validation of winning blocktime failed\n"); + else if ( earliest == 0 || eligible < earliest || (eligible == earliest && (*utxovaluep == 0 || nValue < *utxovaluep)) ) { earliest = eligible; best_scriptPubKey = out.tx->vout[out.i].scriptPubKey; From 15da4215d3ee81dbdcfd4933c85bbf11c66678d5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 11 Apr 2018 14:56:09 +0300 Subject: [PATCH 311/339] Test --- src/wallet/rpcwallet.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 407514eb5..7f64ece38 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4493,8 +4493,8 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt eligible = komodo_stake(0,bnTarget,(uint32_t)tipindex->nHeight+1,out.tx->GetHash(),out.i,*blocktimep,(uint32_t)tipindex->nTime,(char *)CBitcoinAddress(address).ToString().c_str()); if ( eligible > 0 ) { - if ( eligible != komodo_stake(1,bnTarget,(uint32_t)tipindex->nHeight+1,out.tx->GetHash(),out.i,*blocktimep,(uint32_t)tipindex->nTime,(char *)CBitcoinAddress(address).ToString().c_str()) ) - fprintf(stderr,"validation of winning blocktime failed\n"); + if ( eligible != komodo_stake(1,bnTarget,(uint32_t)tipindex->nHeight+1,out.tx->GetHash(),out.i,eligible,(uint32_t)tipindex->nTime,(char *)CBitcoinAddress(address).ToString().c_str()) ) + fprintf(stderr,"validation of winning blocktime failed eligible.%u\n",*blocktimep,eligible); else if ( earliest == 0 || eligible < earliest || (eligible == earliest && (*utxovaluep == 0 || nValue < *utxovaluep)) ) { earliest = eligible; From 2a3bc0f1e5f6c37fc38cf6ac67d6369af17d1225 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 11 Apr 2018 14:57:42 +0300 Subject: [PATCH 312/339] Test --- src/wallet/rpcwallet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 7f64ece38..347c15f2d 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4494,7 +4494,7 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt if ( eligible > 0 ) { if ( eligible != komodo_stake(1,bnTarget,(uint32_t)tipindex->nHeight+1,out.tx->GetHash(),out.i,eligible,(uint32_t)tipindex->nTime,(char *)CBitcoinAddress(address).ToString().c_str()) ) - fprintf(stderr,"validation of winning blocktime failed eligible.%u\n",*blocktimep,eligible); + fprintf(stderr,"validation of winning blocktime failed %u -> eligible.%u\n",*blocktimep,eligible); else if ( earliest == 0 || eligible < earliest || (eligible == earliest && (*utxovaluep == 0 || nValue < *utxovaluep)) ) { earliest = eligible; From 90af749c8fa555c8466db07bddf0a4438846242e Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 11 Apr 2018 15:22:38 +0300 Subject: [PATCH 313/339] Test --- src/komodo_gateway.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index ee18d23ba..72f36a21c 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -700,8 +700,7 @@ uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeigh if ( validateflag == 0 ) { blocktime += iter; - if ( iter > 0 ) - blocktime += segid; + blocktime += segid * 2; } break; } @@ -717,7 +716,7 @@ uint32_t komodo_stake(int32_t validateflag,arith_uint256 bnTarget,int32_t nHeigh } } //fprintf(stderr,"iterated until i.%d winner.%d\n",i,winner); - if ( 1 ) + if ( 0 ) { for (i=31; i>=24; i--) fprintf(stderr,"%02x",((uint8_t *)&hashval)[i]); From 22fd8aaf5cb1c7762aca0154420985a297e5761d Mon Sep 17 00:00:00 2001 From: Mihail Fedorov Date: Thu, 12 Apr 2018 13:09:20 +0300 Subject: [PATCH 314/339] prlpay fix --- src/fiat/prlpay | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fiat/prlpay b/src/fiat/prlpay index 7ae6f4e8d..3d1063d13 100755 --- a/src/fiat/prlpay +++ b/src/fiat/prlpay @@ -1,2 +1,2 @@ #!/bin/bash -./komodo-cli -ac_name=BNTN $1 $2 $3 $4 $5 $6 +./komodo-cli -ac_name=PRLPAY $1 $2 $3 $4 $5 $6 From 52e780cc101f5c91ad619bdd2df8feaa52652e46 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 13 Apr 2018 11:59:10 +0300 Subject: [PATCH 315/339] Test --- src/komodo_bitcoind.h | 6 +++--- src/komodo_notary.h | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 6ffa4022c..901325324 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -857,13 +857,13 @@ int32_t komodo_is_special(int32_t height,uint8_t pubkey33[33],uint32_t timestamp komodo_chosennotary(&nid,height-i,pubkey33,timestamp); if ( nid == notaryid ) { - if ( (0) && notaryid > 0 ) - fprintf(stderr,"ht.%d notaryid.%d already mined -i.%d nid.%d\n",height,notaryid,i,nid); + //if ( (0) && notaryid > 0 ) + fprintf(stderr,"komodo_is_special: ht.%d notaryid.%d already mined -i.%d nid.%d\n",height,notaryid,i,nid); if ( height > 225000 ) return(-1); } } - //fprintf(stderr,"special notaryid.%d ht.%d limit.%d\n",notaryid,height,limit); + fprintf(stderr,"special notaryid.%d ht.%d limit.%d\n",notaryid,height,limit); return(1); } return(0); diff --git a/src/komodo_notary.h b/src/komodo_notary.h index f46681718..85bbb021a 100644 --- a/src/komodo_notary.h +++ b/src/komodo_notary.h @@ -203,6 +203,8 @@ int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestam int32_t i,htind,n; uint64_t mask = 0; struct knotary_entry *kp,*tmp; if ( timestamp == 0 && ASSETCHAINS_SYMBOL[0] != 0 ) timestamp = komodo_heightstamp(height); + else if ( ASSETCHAINS_SYMBOL[0] == 0 ) + timestamp = 0; if ( height >= KOMODO_NOTARIES_HARDCODED || ASSETCHAINS_SYMBOL[0] != 0 ) { if ( (timestamp != 0 && timestamp <= KOMODO_NOTARIES_TIMESTAMP1) || (ASSETCHAINS_SYMBOL[0] == 0 && height <= KOMODO_NOTARIES_HEIGHT1) ) From c54cb7d57bd31c937d99ec79883e5a6e01e4c8a4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 13 Apr 2018 14:18:51 +0300 Subject: [PATCH 316/339] Patch 790833 bug --- src/komodo_bitcoind.h | 54 +++++++++++++++++++++++++------------ src/pow.cpp | 63 ++++++++++++++++++------------------------- 2 files changed, 63 insertions(+), 54 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 901325324..958578b63 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -840,31 +840,51 @@ int32_t komodo_minerids(uint8_t *minerids,int32_t height,int32_t width) // depre return(-1); } -int32_t komodo_is_special(int32_t height,uint8_t pubkey33[33],uint32_t timestamp) +int32_t komodo_is_special(uint8_t pubkeys[66][33],int32_t mids[66],int32_t height,uint8_t pubkey33[33],uint32_t timestamp) { int32_t i,notaryid=0,minerid,limit,nid; //uint8_t _pubkey33[33]; if ( height >= 225000 ) - komodo_chosennotary(¬aryid,height,pubkey33,timestamp); - if ( height >= 34000 && notaryid >= 0 ) { - if ( height < 79693 ) - limit = 64; - else if ( height < 82000 ) - limit = 8; - else limit = 66; - for (i=1; i= 0 ) { - komodo_chosennotary(&nid,height-i,pubkey33,timestamp); - if ( nid == notaryid ) + for (i=1; i<66; i++) { - //if ( (0) && notaryid > 0 ) - fprintf(stderr,"komodo_is_special: ht.%d notaryid.%d already mined -i.%d nid.%d\n",height,notaryid,i,nid); - if ( height > 225000 ) - return(-1); + if ( mids[i] == mids[0] ) + { + fprintf(stderr,"ht.%d repeat notaryid.%d in mids[%d]\n",height,mids[0],i); + if ( height > 790000 ) + return(-1); + else break; + } } + return(1); + } else return(0); + } + else + { + if ( height >= 225000 ) + komodo_chosennotary(¬aryid,height,pubkey33,timestamp); + if ( height >= 34000 && notaryid >= 0 ) + { + if ( height < 79693 ) + limit = 64; + else if ( height < 82000 ) + limit = 8; + else limit = 66; + for (i=1; i 0 ) + fprintf(stderr,"ht.%d notaryid.%d already mined -i.%d nid.%d\n",height,notaryid,i,nid); + if ( height > 225000 ) + return(-1); + } + } + //fprintf(stderr,"special notaryid.%d ht.%d limit.%d\n",notaryid,height,limit); + return(1); } - fprintf(stderr,"special notaryid.%d ht.%d limit.%d\n",notaryid,height,limit); - return(1); } return(0); } diff --git a/src/pow.cpp b/src/pow.cpp index 93ef9ab11..ac36dc0a2 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -117,7 +117,7 @@ bool CheckEquihashSolution(const CBlockHeader *pblock, const CChainParams& param } int32_t komodo_chosennotary(int32_t *notaryidp,int32_t height,uint8_t *pubkey33,uint32_t timestamp); -int32_t komodo_is_special(int32_t height,uint8_t pubkey33[33],uint32_t timestamp); +int32_t komodo_is_special(uint8_t pubkeys[66][33],int32_t mids[66],int32_t height,uint8_t pubkey33[33],uint32_t timestamp); int32_t komodo_currentheight(); CBlockIndex *komodo_chainactive(int32_t height); void komodo_index2pubkey33(uint8_t *pubkey33,CBlockIndex *pindex,int32_t height); @@ -125,7 +125,7 @@ extern int32_t KOMODO_CHOSEN_ONE; extern uint64_t ASSETCHAINS_STAKED; extern char ASSETCHAINS_SYMBOL[]; #define KOMODO_ELECTION_GAP 2000 - + int32_t komodo_eligiblenotary(uint8_t pubkeys[66][33],int32_t *mids,int32_t *nonzpkeysp,int32_t height); int32_t KOMODO_LOADINGBLOCKS; @@ -134,27 +134,31 @@ extern std::string NOTARY_PUBKEY; bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned int nBits, const Consensus::Params& params) { extern int32_t KOMODO_REWIND; - bool fNegative,fOverflow; int32_t i,nonzpkeys=0,nonz=0,special=0,special2=0,notaryid=-1,duplicate,flag = 0, mids[66]; uint32_t timestamp = 0; - arith_uint256 bnTarget; CBlockIndex *pindex; uint8_t pubkeys[66][33]; + bool fNegative,fOverflow; int32_t i,nonzpkeys=0,nonz=0,special=0,special2=0,notaryid=-1,flag = 0, mids[66]; uint32_t timestamp = 0; + arith_uint256 bnTarget; uint8_t pubkeys[66][33]; timestamp = komodo_chainactive_timestamp(); bnTarget.SetCompact(nBits, &fNegative, &fOverflow); if ( height == 0 ) - height = komodo_currentheight() + 1; - special = komodo_chosennotary(¬aryid,height,pubkey33,timestamp); - flag = komodo_eligiblenotary(pubkeys,mids,&nonzpkeys,height); - /*if ( ASSETCHAINS_STAKED != 0 ) - bnTarget.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow); - else*/ - if ( height > 34000 && ASSETCHAINS_SYMBOL[0] == 0 ) // 0 -> non-special notary { + height = komodo_currentheight() + 1; + //fprintf(stderr,"set height to %d\n",height); + } + if ( height > 34000 && ASSETCHAINS_SYMBOL[0] == 0 ) // 0 -> non-special notary + { + special = komodo_chosennotary(¬aryid,height,pubkey33,timestamp); for (i=0; i<33; i++) { if ( pubkey33[i] != 0 ) nonz++; } if ( nonz == 0 ) + { + //fprintf(stderr,"ht.%d null pubkey checkproof return\n",height); return(true); // will come back via different path with pubkey set - special2 = komodo_is_special(height,pubkey33,timestamp); + } + flag = komodo_eligiblenotary(pubkeys,mids,&nonzpkeys,height); + special2 = komodo_is_special(pubkeys,mids,height,pubkey33,timestamp); + //fprintf(stderr,"ht.%d notaryid.%d special.%d flag.%d special2.%d\n",height,notaryid,special,flag,special2); if ( notaryid >= 0 ) { if ( height > 10000 && height < 80000 && (special != 0 || special2 > 0) ) @@ -163,37 +167,22 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned in flag = 1; else if ( height >= 108000 && special2 > 0 ) flag = ((height % KOMODO_ELECTION_GAP) > 64 || (height % KOMODO_ELECTION_GAP) == 0); - if ( flag != 0 ) - bnTarget.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow); + else if ( height == 790833 ) + flag = 1; + else if ( special2 < 0 && height > 800000 ) + flag = 0; + } + if ( flag != 0 || special2 > 0 ) + { + //fprintf(stderr,"EASY MINING ht.%d\n",height); + bnTarget.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow); } } if (fNegative || bnTarget == 0 || fOverflow || bnTarget > UintToArith256(params.powLimit)) return error("CheckProofOfWork(): nBits below minimum work"); // Check proof of work matches claimed amount if ( UintToArith256(hash) > bnTarget ) - { - if ( 0 && (height < 235300 || height >= 236000) && KOMODO_LOADINGBLOCKS == 0 && height > 188000 ) - //&& )//186269, 182507&& komodo_chainactive(height) != 0 && nonzpkeys > 0 - { - for (i=31; i>=0; i--) - printf("%02x",((uint8_t *)&hash)[i]); - printf(" hash vs "); - for (i=31; i>=0; i--) - printf("%02x",((uint8_t *)&bnTarget)[i]); - printf(" ht.%d special.%d notaryid.%d ht.%d mod.%d error\n",height,special,notaryid,height,(height % 35)); - for (i=0; i<33; i++) - printf("%02x",pubkey33[i]); - printf(" <- pubkey\n"); - for (i=0; i<66; i++) - printf("%d ",mids[i]); - printf(" minerids from ht.%d\n",height); - if ( KOMODO_REWIND == 0 && (notaryid >= 0 || height > 225000) ) - { - fprintf(stderr,"pow error height.%d loading.%d notaryid.%d\n",height,KOMODO_LOADINGBLOCKS,notaryid); - return error("CheckProofOfWork(): hash doesn't match nBits"); - } else fprintf(stderr,"skip return error height.%d loading.%d\n",height,KOMODO_LOADINGBLOCKS); - } //else fprintf(stderr,"skip height.%d loading.%d\n",height,KOMODO_LOADINGBLOCKS); - } + return false; return true; } From 05912706be9eaa7788e643bad4f91e437a3d7589 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 13 Apr 2018 15:02:52 +0300 Subject: [PATCH 317/339] Change to 792000 --- src/pow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pow.cpp b/src/pow.cpp index ac36dc0a2..d8fc47f86 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -169,7 +169,7 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned in flag = ((height % KOMODO_ELECTION_GAP) > 64 || (height % KOMODO_ELECTION_GAP) == 0); else if ( height == 790833 ) flag = 1; - else if ( special2 < 0 && height > 800000 ) + else if ( special2 < 0 && height > 792000 ) flag = 0; } if ( flag != 0 || special2 > 0 ) From 6864ae44a44ec785f8687f2c5f8a3f8bcc639dbe Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 13 Apr 2018 15:03:21 +0300 Subject: [PATCH 318/339] Change to 792000 --- src/pow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pow.cpp b/src/pow.cpp index ac36dc0a2..d8fc47f86 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -169,7 +169,7 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned in flag = ((height % KOMODO_ELECTION_GAP) > 64 || (height % KOMODO_ELECTION_GAP) == 0); else if ( height == 790833 ) flag = 1; - else if ( special2 < 0 && height > 800000 ) + else if ( special2 < 0 && height > 792000 ) flag = 0; } if ( flag != 0 || special2 > 0 ) From 204e6b350056fb1289e04c3d26dc0bc889ab9275 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 13 Apr 2018 15:21:38 +0300 Subject: [PATCH 319/339] Fix --- src/pow.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pow.cpp b/src/pow.cpp index d8fc47f86..5db2aedb2 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -171,11 +171,11 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned in flag = 1; else if ( special2 < 0 && height > 792000 ) flag = 0; - } - if ( flag != 0 || special2 > 0 ) - { - //fprintf(stderr,"EASY MINING ht.%d\n",height); - bnTarget.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow); + if ( flag != 0 || special2 > 0 ) + { + //fprintf(stderr,"EASY MINING ht.%d\n",height); + bnTarget.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow); + } } } if (fNegative || bnTarget == 0 || fOverflow || bnTarget > UintToArith256(params.powLimit)) From 93684bd008ed3449f09eed8ed1a8118e5c0d3dbd Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 13 Apr 2018 15:22:31 +0300 Subject: [PATCH 320/339] Fix --- src/pow.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pow.cpp b/src/pow.cpp index d8fc47f86..5db2aedb2 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -171,11 +171,11 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned in flag = 1; else if ( special2 < 0 && height > 792000 ) flag = 0; - } - if ( flag != 0 || special2 > 0 ) - { - //fprintf(stderr,"EASY MINING ht.%d\n",height); - bnTarget.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow); + if ( flag != 0 || special2 > 0 ) + { + //fprintf(stderr,"EASY MINING ht.%d\n",height); + bnTarget.SetCompact(KOMODO_MINDIFF_NBITS,&fNegative,&fOverflow); + } } } if (fNegative || bnTarget == 0 || fOverflow || bnTarget > UintToArith256(params.powLimit)) From d4f13ed8018ffaa8afba8c3737854f0db1dd41ad Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 13 Apr 2018 15:24:19 +0300 Subject: [PATCH 321/339] Test --- src/komodo_bitcoind.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 958578b63..d5eab1b0f 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -843,7 +843,7 @@ int32_t komodo_minerids(uint8_t *minerids,int32_t height,int32_t width) // depre int32_t komodo_is_special(uint8_t pubkeys[66][33],int32_t mids[66],int32_t height,uint8_t pubkey33[33],uint32_t timestamp) { int32_t i,notaryid=0,minerid,limit,nid; //uint8_t _pubkey33[33]; - if ( height >= 225000 ) + if ( height >= 790000 ) { if ( mids[0] >= 0 ) { From 7fd353f0224fdbee339f01d1e02f02cafc21e720 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 13 Apr 2018 15:25:05 +0300 Subject: [PATCH 322/339] Test --- src/komodo_bitcoind.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 958578b63..d5eab1b0f 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -843,7 +843,7 @@ int32_t komodo_minerids(uint8_t *minerids,int32_t height,int32_t width) // depre int32_t komodo_is_special(uint8_t pubkeys[66][33],int32_t mids[66],int32_t height,uint8_t pubkey33[33],uint32_t timestamp) { int32_t i,notaryid=0,minerid,limit,nid; //uint8_t _pubkey33[33]; - if ( height >= 225000 ) + if ( height >= 790000 ) { if ( mids[0] >= 0 ) { From f796b1fb8fa9e6aafc798db24bcb52fccc34a271 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 13 Apr 2018 18:44:18 +0300 Subject: [PATCH 323/339] Clean fix and speedup --- src/komodo_bitcoind.h | 244 ++++++++++++++++++++++-------------------- src/main.cpp | 24 ++++- src/pow.cpp | 31 +++++- 3 files changed, 180 insertions(+), 119 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index d5eab1b0f..f6f097940 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright © 2014-2017 The SuperNET Developers. * + * Copyright © 2014-2018 The SuperNET Developers. * * * * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * * the top-level directory of this distribution for the individual copyright * @@ -169,14 +169,14 @@ try_again: curl_handle = curl_easy_init(); init_string(&s); headers = curl_slist_append(0,"Expect:"); - - curl_easy_setopt(curl_handle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )"); + + curl_easy_setopt(curl_handle,CURLOPT_USERAGENT,"mozilla/4.0");//"Mozilla/4.0 (compatible; )"); curl_easy_setopt(curl_handle,CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl_handle,CURLOPT_URL, url); curl_easy_setopt(curl_handle,CURLOPT_WRITEFUNCTION, (void *)accumulatebytes); // send all data to this function curl_easy_setopt(curl_handle,CURLOPT_WRITEDATA, &s); // we pass our 's' struct to the callback curl_easy_setopt(curl_handle,CURLOPT_NOSIGNAL, 1L); // supposed to fix "Alarm clock" and long jump crash - curl_easy_setopt(curl_handle,CURLOPT_NOPROGRESS, 1L); // no progress callback + curl_easy_setopt(curl_handle,CURLOPT_NOPROGRESS, 1L); // no progress callback if ( strncmp(url,"https",5) == 0 ) { curl_easy_setopt(curl_handle,CURLOPT_SSL_VERIFYPEER,0); @@ -198,7 +198,7 @@ try_again: bracket0 = (char *)"["; bracket1 = (char *)"]"; } - + databuf = (char *)malloc(256 + strlen(command) + strlen(params)); sprintf(databuf,"{\"id\":\"jl777\",\"method\":\"%s\",\"params\":%s%s%s}",command,bracket0,params,bracket1); //printf("url.(%s) userpass.(%s) databuf.(%s)\n",url,userpass,databuf); @@ -238,7 +238,7 @@ try_again: free(s.ptr); sleep((1< 10 ) - height -= 10; - if ( ASSETCHAINS_SYMBOL[0] == 0 ) - hash = _komodo_getblockhash(height); - if ( memcmp(&hash,&zero,sizeof(hash)) == 0 ) - hash = komodo_getblockhash(height); - int32_t i; - for (i=0; i<32; i++) - printf("%02x",((uint8_t *)&hash)[i]); - printf(" seed.%d\n",height); - seed = arith_uint256(hash.GetHex()).GetLow64(); - } - else*/ + { + uint256 hash,zero; CBlockIndex *pindex; + memset(&hash,0,sizeof(hash)); + memset(&zero,0,sizeof(zero)); + if ( height > 10 ) + height -= 10; + if ( ASSETCHAINS_SYMBOL[0] == 0 ) + hash = _komodo_getblockhash(height); + if ( memcmp(&hash,&zero,sizeof(hash)) == 0 ) + hash = komodo_getblockhash(height); + int32_t i; + for (i=0; i<32; i++) + printf("%02x",((uint8_t *)&hash)[i]); + printf(" seed.%d\n",height); + seed = arith_uint256(hash.GetHex()).GetLow64(); + } + else*/ { seed = (height << 13) ^ (height << 2); seed <<= 21; @@ -662,7 +662,9 @@ int32_t komodo_block2height(CBlock *block) void komodo_block2pubkey33(uint8_t *pubkey33,CBlock& block) { int32_t n; - memset(pubkey33,0,33); + if ( KOMODO_LOADINGBLOCKS == 0 ) + memset(pubkey33,0xff,33); + else memset(pubkey33,0,33); if ( block.vtx[0].vout.size() > 0 ) { #ifdef KOMODO_ZCASH @@ -722,60 +724,68 @@ uint32_t komodo_heightstamp(int32_t height) return(0); } +void komodo_pindex_init(CBlockIndex *pindex,int32_t height) +{ + int32_t i,num; uint8_t pubkeys[64][33]; CBlock block; + if ( pindex->didinit != 0 ) + return; + //printf("pindex.%d komodo_pindex_init notary.%d from height.%d\n",pindex->nHeight,pindex->notaryid,height); + if ( pindex->didinit == 0 ) + { + pindex->notaryid = -1; + if ( KOMODO_LOADINGBLOCKS == 0 ) + memset(pindex->pubkey33,0xff,33); + else memset(pindex->pubkey33,0,33); + if ( komodo_blockload(block,pindex) == 0 ) + { + komodo_block2pubkey33(pindex->pubkey33,block); + //for (i=0; i<33; i++) + // fprintf(stderr,"%02x",pindex->pubkey33[i]); + //fprintf(stderr," set pubkey at height %d/%d\n",pindex->nHeight,height); + pindex->didinit = (KOMODO_LOADINGBLOCKS == 0); + } // else fprintf(stderr,"error loading block at %d/%d",pindex->nHeight,height); + } + if ( pindex->didinit != 0 && pindex->nHeight >= 0 && (num= komodo_notaries(pubkeys,(int32_t)pindex->nHeight,(uint32_t)pindex->nTime)) > 0 ) + { + for (i=0; ipubkey33,33) == 0 ) + { + pindex->notaryid = i; + break; + } + } + if ( 0 && i == num ) + { + for (i=0; i<33; i++) + fprintf(stderr,"%02x",pindex->pubkey33[i]); + fprintf(stderr," unmatched pubkey at height %d/%d\n",pindex->nHeight,height); + } + } +} + void komodo_index2pubkey33(uint8_t *pubkey33,CBlockIndex *pindex,int32_t height) { - CBlock block; int32_t num,i; uint8_t pubkeys[64][33]; - //komodo_init(height); + CBlock block; int32_t num,i; memset(pubkey33,0,33); if ( pindex != 0 ) { - if ( pindex->pubkey33[0] == 2 || pindex->pubkey33[0] == 3 ) + if ( pindex->didinit != 0 ) { memcpy(pubkey33,pindex->pubkey33,33); return; } - if ( komodo_blockload(block,pindex) == 0 ) - { - komodo_block2pubkey33(pubkey33,block); - if ( (pubkey33[0] == 2 || pubkey33[0] == 3) ) - { - memcpy(pindex->pubkey33,pubkey33,33); - if ( (num= komodo_notaries(pubkeys,(int32_t)pindex->nHeight,(uint32_t)pindex->nTime)) > 0 ) - { - pindex->notaryid = -1; - for (i=0; inotaryid = i; - break; - } - } - } - } else pindex->notaryid = -1; - } - } - else - { - // height -> pubkey33 - //printf("extending chaintip komodo_index2pubkey33 height.%d need to get pubkey33\n",height); + komodo_pindex_init(pindex,height); + memcpy(pubkey33,pindex->pubkey33,33); } } -/*void komodo_connectpindex(CBlockIndex *pindex) -{ - CBlock block; - if ( komodo_blockload(block,pindex) == 0 ) - komodo_connectblock(pindex,block); -}*/ - - int8_t komodo_minerid(int32_t height,uint8_t *pubkey33) { int32_t num,i,numnotaries; CBlockIndex *pindex; uint32_t timestamp=0; uint8_t _pubkey33[33],pubkeys[64][33]; if ( (pindex= chainActive[height]) != 0 ) { - if ( (pindex->pubkey33[0] == 2 || pindex->pubkey33[0] == 3) ) + if ( pindex->didinit != 0 ) { if ( pubkey33 != 0 ) memcpy(pubkey33,pindex->pubkey33,33); @@ -802,7 +812,7 @@ int32_t komodo_eligiblenotary(uint8_t pubkeys[66][33],int32_t *mids,int32_t *non { if ( (pindex= komodo_chainactive(height-i)) != 0 ) { - if ( pindex->notaryid >= 0 && (pindex->pubkey33[0] == 2 || pindex->pubkey33[0] == 3) ) + if ( pindex->notaryid >= 0 && pindex->didinit != 0 ) { memcpy(pubkeys[i],pindex->pubkey33,33); mids[i] = pindex->notaryid; @@ -810,8 +820,9 @@ int32_t komodo_eligiblenotary(uint8_t pubkeys[66][33],int32_t *mids,int32_t *non } else { - komodo_index2pubkey33(pubkey33,pindex,height-i); - memcpy(pubkeys[i],pubkey33,33); + komodo_pindex_init(pindex,height-i); + //komodo_index2pubkey33(pubkey33,pindex,height-i); + memcpy(pubkeys[i],pindex->pubkey33,33); if ( (mids[i]= komodo_minerid(height-i,pubkey33)) >= 0 ) { //mids[i] = *(int32_t *)pubkey33; @@ -830,20 +841,23 @@ int32_t komodo_eligiblenotary(uint8_t pubkeys[66][33],int32_t *mids,int32_t *non int32_t komodo_minerids(uint8_t *minerids,int32_t height,int32_t width) // deprecate { /*int32_t i,n=0; - for (i=0; i= 790000 ) + if ( height >= 225000 ) + komodo_chosennotary(¬aryid,height,pubkey33,timestamp); + if ( height >= 700000 ) { if ( mids[0] >= 0 ) { @@ -862,8 +876,6 @@ int32_t komodo_is_special(uint8_t pubkeys[66][33],int32_t mids[66],int32_t heigh } else { - if ( height >= 225000 ) - komodo_chosennotary(¬aryid,height,pubkey33,timestamp); if ( height >= 34000 && notaryid >= 0 ) { if ( height < 79693 ) @@ -889,10 +901,10 @@ int32_t komodo_is_special(uint8_t pubkeys[66][33],int32_t mids[66],int32_t heigh return(0); } -int32_t komodo_MoM(int32_t *notarized_heightp,uint256 *MoMp,uint256 *kmdtxidp,int32_t nHeight) +int32_t komodo_MoM(int32_t *notarized_heightp,uint256 *MoMp,uint256 *kmdtxidp,int32_t nHeight,uint256 *MoMoMp,int32_t *MoMoMoffsetp,int32_t *MoMoMdepthp,int32_t *kmdstartip,int32_t *kmdendip) { int32_t depth,notarized_ht; uint256 MoM,kmdtxid; - depth = komodo_MoMdata(¬arized_ht,&MoM,&kmdtxid,nHeight); + depth = komodo_MoMdata(¬arized_ht,&MoM,&kmdtxid,nHeight,MoMoMp,MoMoMoffsetp,MoMoMdepthp,kmdstartip,kmdendip); memset(MoMp,0,sizeof(*MoMp)); memset(kmdtxidp,0,sizeof(*kmdtxidp)); *notarized_heightp = 0; diff --git a/src/main.cpp b/src/main.cpp index fb833bff5..0e82ce73a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -53,6 +53,7 @@ using namespace std; CCriticalSection cs_main; extern uint8_t NOTARY_PUBKEY33[33]; +extern int32_t KOMODO_LOADINGBLOCKS; BlockMap mapBlockIndex; CChain chainActive; @@ -4037,6 +4038,7 @@ bool CheckDiskSpace(uint64_t nAdditionalBytes) FILE* OpenDiskFile(const CDiskBlockPos &pos, const char *prefix, bool fReadOnly) { + static int32_t didinit; long fsize,fpos; int32_t incr = 16*1024*1024; if (pos.IsNull()) return NULL; boost::filesystem::path path = GetBlockPosFilename(pos, prefix); @@ -4048,6 +4050,27 @@ FILE* OpenDiskFile(const CDiskBlockPos &pos, const char *prefix, bool fReadOnly) LogPrintf("Unable to open file %s\n", path.string()); return NULL; } + if ( didinit == 0 && strcmp(prefix,(char *)"blk") == 0 ) + { + fpos = ftell(file); + fseek(file,0,SEEK_END); + fsize = ftell(file); + if ( fsize > incr ) + { + char *ignore = (char *)malloc(incr); + if ( ignore != 0 ) + { + rewind(file); + while ( fread(ignore,1,incr,file) == incr ) + fprintf(stderr,"."); + free(ignore); + fprintf(stderr,"loaded %ld bytes set fpos.%ld loading.%d\n",(long)ftell(file),(long)fpos,KOMODO_LOADINGBLOCKS); + } + } + fseek(file,fpos,SEEK_SET); + KOMODO_LOADINGBLOCKS = 0; + didinit = 1; + } if (pos.nPos) { if (fseek(file, pos.nPos, SEEK_SET)) { LogPrintf("Unable to seek to position %u of %s\n", pos.nPos, path.string()); @@ -4491,7 +4514,6 @@ void UnloadBlockIndex() bool LoadBlockIndex() { - extern int32_t KOMODO_LOADINGBLOCKS; // Load block index from databases KOMODO_LOADINGBLOCKS = 1; if (!fReindex && !LoadBlockIndexDB()) diff --git a/src/pow.cpp b/src/pow.cpp index 5db2aedb2..dba8c1403 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -116,6 +116,7 @@ bool CheckEquihashSolution(const CBlockHeader *pblock, const CChainParams& param return true; } +void komodo_pindex_init(CBlockIndex *pindex,int32_t height); int32_t komodo_chosennotary(int32_t *notaryidp,int32_t height,uint8_t *pubkey33,uint32_t timestamp); int32_t komodo_is_special(uint8_t pubkeys[66][33],int32_t mids[66],int32_t height,uint8_t pubkey33[33],uint32_t timestamp); int32_t komodo_currentheight(); @@ -134,7 +135,7 @@ extern std::string NOTARY_PUBKEY; bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned int nBits, const Consensus::Params& params) { extern int32_t KOMODO_REWIND; - bool fNegative,fOverflow; int32_t i,nonzpkeys=0,nonz=0,special=0,special2=0,notaryid=-1,flag = 0, mids[66]; uint32_t timestamp = 0; + bool fNegative,fOverflow; int32_t i,nonzpkeys=0,nonz=0,special=0,special2=0,notaryid=-1,flag = 0, mids[66]; uint32_t timestamp = 0; CBlockIndex *pindex; arith_uint256 bnTarget; uint8_t pubkeys[66][33]; timestamp = komodo_chainactive_timestamp(); bnTarget.SetCompact(nBits, &fNegative, &fOverflow); @@ -145,6 +146,13 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned in } if ( height > 34000 && ASSETCHAINS_SYMBOL[0] == 0 ) // 0 -> non-special notary { + if ( KOMODO_LOADINGBLOCKS == 0 ) + return(true); + if ( (pindex= komodo_chainactive(height)) != 0 ) + { + komodo_pindex_init(pindex,height); + memcpy(pubkey33,pindex->pubkey33,33); + } special = komodo_chosennotary(¬aryid,height,pubkey33,timestamp); for (i=0; i<33; i++) { @@ -158,7 +166,7 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned in } flag = komodo_eligiblenotary(pubkeys,mids,&nonzpkeys,height); special2 = komodo_is_special(pubkeys,mids,height,pubkey33,timestamp); - //fprintf(stderr,"ht.%d notaryid.%d special.%d flag.%d special2.%d\n",height,notaryid,special,flag,special2); + fprintf(stderr,"ht.%d notaryid.%d special.%d flag.%d special2.%d\n",height,notaryid,special,flag,special2); if ( notaryid >= 0 ) { if ( height > 10000 && height < 80000 && (special != 0 || special2 > 0) ) @@ -182,7 +190,26 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned in return error("CheckProofOfWork(): nBits below minimum work"); // Check proof of work matches claimed amount if ( UintToArith256(hash) > bnTarget ) + { + for (i=31; i>=0; i--) + printf("%02x",((uint8_t *)&hash)[i]); + printf(" hash vs "); + for (i=31; i>=0; i--) + printf("%02x",((uint8_t *)&bnTarget)[i]); + printf(" ht.%d special.%d notaryid.%d ht.%d mod.%d error\n",height,special,notaryid,height,(height % 35)); + if ( pindex != 0 ) + { + pindex->didinit = 0; + komodo_pindex_init(pindex,height); + } + for (i=0; i<33; i++) + printf("%02x",pubkey33[i]); + printf(" <- pubkey\n"); + for (i=0; i<66; i++) + printf("%d ",mids[i]); + printf(" minerids from ht.%d pindex.%p\n",height,pindex); return false; + } return true; } From 69c24cd06e93c8a7116b55b32cd564511940c4d0 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 13 Apr 2018 18:47:42 +0300 Subject: [PATCH 324/339] Manual merge --- src/chain.h | 2 +- src/komodo_globals.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chain.h b/src/chain.h index d3c46f9d6..3b8bbd9bd 100644 --- a/src/chain.h +++ b/src/chain.h @@ -177,7 +177,7 @@ public: //! (memory only) Sequential id assigned to distinguish order in which blocks are received. uint32_t nSequenceId; - int8_t notaryid; uint8_t pubkey33[33]; + int8_t notaryid; uint8_t pubkey33[33],didinit; void SetNull() { diff --git a/src/komodo_globals.h b/src/komodo_globals.h index cb8f61988..ecd8bfd6a 100644 --- a/src/komodo_globals.h +++ b/src/komodo_globals.h @@ -18,7 +18,7 @@ uint32_t komodo_heightstamp(int32_t height); void komodo_stateupdate(int32_t height,uint8_t notarypubs[][33],uint8_t numnotaries,uint8_t notaryid,uint256 txhash,uint64_t voutmask,uint8_t numvouts,uint32_t *pvals,uint8_t numpvals,int32_t kheight,uint32_t ktime,uint64_t opretvalue,uint8_t *opretbuf,uint16_t opretlen,uint16_t vout,uint256 MoM,int32_t MoMdepth); void komodo_init(int32_t height); -int32_t komodo_MoMdata(int32_t *notarized_htp,uint256 *MoMp,uint256 *kmdtxidp,int32_t nHeight); +int32_t komodo_MoMdata(int32_t *notarized_htp,uint256 *MoMp,uint256 *kmdtxidp,int32_t nHeight,uint256 *MoMoMp,int32_t *MoMoMoffsetp,int32_t *MoMoMdepthp,int32_t *kmdstartip,int32_t *kmdendip); int32_t komodo_notarizeddata(int32_t nHeight,uint256 *notarized_hashp,uint256 *notarized_desttxidp); char *komodo_issuemethod(char *userpass,char *method,char *params,uint16_t port); void komodo_init(int32_t height); From 2574cf491b6cfb2a9a4644166d5656b15930ae78 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 13 Apr 2018 19:00:42 +0300 Subject: [PATCH 325/339] Fix missing functionality --- src/komodo_notary.h | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/komodo_notary.h b/src/komodo_notary.h index 85bbb021a..393e89796 100644 --- a/src/komodo_notary.h +++ b/src/komodo_notary.h @@ -399,30 +399,29 @@ int32_t komodo_notarized_height(uint256 *hashp,uint256 *txidp) } -int32_t komodo_MoMdata(int32_t *notarized_htp,uint256 *MoMp,uint256 *kmdtxidp,int32_t height) +int32_t komodo_MoMdata(int32_t *notarized_htp,uint256 *MoMp,uint256 *kmdtxidp,int32_t height,uint256 *MoMoMp,int32_t *MoMoMoffsetp,int32_t *MoMoMdepthp,int32_t *kmdstartip,int32_t *kmdendip) { - int32_t i; char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; struct komodo_state *sp; struct notarized_checkpoint *np = 0; - np = 0; - if ( (sp= komodo_stateptr(symbol,dest)) != 0 ) + struct notarized_checkpoint *np = 0; + if ( (np= komodo_npptr(height)) != 0 ) { - for (i=sp->NUM_NPOINTS-1; i>=0; i--) - { - np = &sp->NPOINTS[i]; - if ( np->MoMdepth > 0 && height > np->notarized_height-np->MoMdepth && height <= np->notarized_height ) - { - *notarized_htp = np->notarized_height; - *MoMp = np->MoM; - *kmdtxidp = np->notarized_desttxid; - return(np->MoMdepth); - } - } + *notarized_htp = np->notarized_height; + *MoMp = np->MoM; + *kmdtxidp = np->notarized_desttxid; + *MoMoMp = np->MoMoM; + *MoMoMoffsetp = np->MoMoMoffset; + *MoMoMdepthp = np->MoMoMdepth; + *kmdstartip = np->kmdstarti; + *kmdendip = np->kmdendi; + return(np->MoMdepth); } - *notarized_htp = 0; + *notarized_htp = *MoMoMoffsetp = *MoMoMdepthp = *kmdstartip = *kmdendip = 0; memset(MoMp,0,sizeof(*MoMp)); + memset(MoMoMp,0,sizeof(*MoMoMp)); memset(kmdtxidp,0,sizeof(*kmdtxidp)); return(0); } + int32_t komodo_notarizeddata(int32_t nHeight,uint256 *notarized_hashp,uint256 *notarized_desttxidp) { struct notarized_checkpoint *np = 0; int32_t i=0,flag = 0; char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; struct komodo_state *sp; From 252031d2a33e234ae2b315fbcdefc56c044d75cd Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 13 Apr 2018 19:05:59 +0300 Subject: [PATCH 326/339] Test --- src/komodo_notary.h | 15 +++++++++++++++ src/komodo_structs.h | 4 ++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/komodo_notary.h b/src/komodo_notary.h index 393e89796..5f534957f 100644 --- a/src/komodo_notary.h +++ b/src/komodo_notary.h @@ -399,6 +399,21 @@ int32_t komodo_notarized_height(uint256 *hashp,uint256 *txidp) } +struct notarized_checkpoint *komodo_npptr(int32_t height) +{ + char symbol[KOMODO_ASSETCHAIN_MAXLEN],dest[KOMODO_ASSETCHAIN_MAXLEN]; int32_t i; struct komodo_state *sp; struct notarized_checkpoint *np = 0; + if ( (sp= komodo_stateptr(symbol,dest)) != 0 ) + { + for (i=sp->NUM_NPOINTS-1; i>=0; i--) + { + np = &sp->NPOINTS[i]; + if ( np->MoMdepth > 0 && height > np->notarized_height-np->MoMdepth && height <= np->notarized_height ) + return(np); + } + } + return(0); +} + int32_t komodo_MoMdata(int32_t *notarized_htp,uint256 *MoMp,uint256 *kmdtxidp,int32_t height,uint256 *MoMoMp,int32_t *MoMoMoffsetp,int32_t *MoMoMdepthp,int32_t *kmdstartip,int32_t *kmdendip) { struct notarized_checkpoint *np = 0; diff --git a/src/komodo_structs.h b/src/komodo_structs.h index 38a2b3138..50984eb31 100644 --- a/src/komodo_structs.h +++ b/src/komodo_structs.h @@ -85,8 +85,8 @@ struct knotary_entry { UT_hash_handle hh; uint8_t pubkey[33],notaryid; }; struct knotaries_entry { int32_t height,numnotaries; struct knotary_entry *Notaries; }; struct notarized_checkpoint { - uint256 notarized_hash,notarized_desttxid,MoM; - int32_t nHeight,notarized_height,MoMdepth; + uint256 notarized_hash,notarized_desttxid,MoM,MoMoM; + int32_t nHeight,notarized_height,MoMdepth,MoMoMdepth,MoMoMoffset,kmdstarti,kmdendi; }; struct komodo_state From a9ba7b1169b720d6941b285e67b1b431e173eacf Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 13 Apr 2018 19:11:15 +0300 Subject: [PATCH 327/339] height_MoM --- src/rpcblockchain.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index 010fb051c..f882b1d0f 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -552,7 +552,7 @@ char *bitcoin_address(char *coinaddr,uint8_t addrtype,uint8_t *pubkey_or_rmd160, //uint32_t komodo_interest_args(int32_t *txheightp,uint32_t *tiptimep,uint64_t *valuep,uint256 hash,int32_t n); 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); -int32_t komodo_MoM(int32_t *notarized_htp,uint256 *MoMp,uint256 *kmdtxidp,int32_t nHeight); +int32_t komodo_MoM(int32_t *notarized_htp,uint256 *MoMp,uint256 *kmdtxidp,int32_t nHeight,uint256 *MoMoMp,int32_t *MoMoMoffsetp,int32_t *MoMoMdepthp,int32_t *kmdstartip,int32_t *kmdendip); UniValue kvsearch(const UniValue& params, bool fHelp) { @@ -591,9 +591,9 @@ UniValue kvsearch(const UniValue& params, bool fHelp) UniValue height_MoM(const UniValue& params, bool fHelp) { - int32_t height,depth,notarized_height; uint256 MoM,kmdtxid; uint32_t timestamp = 0; UniValue ret(UniValue::VOBJ); UniValue a(UniValue::VARR); + int32_t height,depth,notarized_height,MoMoMdepth,MoMoMoffset,kmdstarti,kmdendi; uint256 MoM,MoMoM,kmdtxid; uint32_t timestamp = 0; UniValue ret(UniValue::VOBJ); UniValue a(UniValue::VARR); if ( fHelp || params.size() != 1 ) - throw runtime_error("height_MoM needs height\n"); + throw runtime_error("height_MoM height\n"); LOCK(cs_main); height = atoi(params[0].get_str().c_str()); if ( height <= 0 ) @@ -606,7 +606,7 @@ UniValue height_MoM(const UniValue& params, bool fHelp) height = chainActive.Tip()->nHeight; } //fprintf(stderr,"height_MoM height.%d\n",height); - depth = komodo_MoM(¬arized_height,&MoM,&kmdtxid,height); + depth = komodo_MoM(¬arized_height,&MoM,&kmdtxid,height,&MoMoM,&MoMoMoffset,&MoMoMdepth,&kmdstarti,&kmdendi); ret.push_back(Pair("coin",(char *)(ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL))); ret.push_back(Pair("height",height)); ret.push_back(Pair("timestamp",(uint64_t)timestamp)); @@ -616,8 +616,16 @@ UniValue height_MoM(const UniValue& params, bool fHelp) ret.push_back(Pair("notarized_height",notarized_height)); ret.push_back(Pair("MoM",MoM.GetHex())); ret.push_back(Pair("kmdtxid",kmdtxid.GetHex())); + if ( ASSETCHAINS_SYMBOL[0] != 0 ) + { + ret.push_back(Pair("MoMoM",MoMoM.GetHex())); + ret.push_back(Pair("MoMoMoffset",MoMoMoffset)); + ret.push_back(Pair("MoMoMdepth",MoMoMdepth)); + ret.push_back(Pair("kmdstarti",kmdstarti)); + ret.push_back(Pair("kmdendi",kmdendi)); + } } else ret.push_back(Pair("error",(char *)"no MoM for height")); - + return ret; } From 9557a5930137cb559b52a57d04f8ac8770862ed5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 13 Apr 2018 19:14:45 +0300 Subject: [PATCH 328/339] Test --- src/pow.cpp | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/pow.cpp b/src/pow.cpp index dba8c1403..15c5c8732 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -146,7 +146,7 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned in } if ( height > 34000 && ASSETCHAINS_SYMBOL[0] == 0 ) // 0 -> non-special notary { - if ( KOMODO_LOADINGBLOCKS == 0 ) + if ( KOMODO_LOADINGBLOCKS != 0 ) return(true); if ( (pindex= komodo_chainactive(height)) != 0 ) { @@ -191,28 +191,17 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned in // Check proof of work matches claimed amount if ( UintToArith256(hash) > bnTarget ) { - for (i=31; i>=0; i--) - printf("%02x",((uint8_t *)&hash)[i]); - printf(" hash vs "); - for (i=31; i>=0; i--) - printf("%02x",((uint8_t *)&bnTarget)[i]); - printf(" ht.%d special.%d notaryid.%d ht.%d mod.%d error\n",height,special,notaryid,height,(height % 35)); if ( pindex != 0 ) { pindex->didinit = 0; komodo_pindex_init(pindex,height); } - for (i=0; i<33; i++) - printf("%02x",pubkey33[i]); - printf(" <- pubkey\n"); - for (i=0; i<66; i++) - printf("%d ",mids[i]); - printf(" minerids from ht.%d pindex.%p\n",height,pindex); return false; } return true; } + arith_uint256 GetBlockProof(const CBlockIndex& block) { arith_uint256 bnTarget; From 0b5f32ccc257b968f488a6192fd8e26c87c0e943 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 13 Apr 2018 19:16:30 +0300 Subject: [PATCH 329/339] Test --- src/rpcblockchain.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index f882b1d0f..c6a3ab0ec 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -631,9 +631,7 @@ UniValue height_MoM(const UniValue& params, bool fHelp) UniValue txMoMproof(const UniValue& params, bool fHelp) { - uint256 hash, notarisationHash, MoM; - int32_t notarisedHeight, depth; - CBlockIndex* blockIndex; + uint256 hash, notarisationHash, MoM,MoMoM; int32_t notarisedHeight, depth; CBlockIndex* blockIndex; std::vector branch; int nIndex; @@ -651,7 +649,7 @@ UniValue txMoMproof(const UniValue& params, bool fHelp) blockIndex = mapBlockIndex[blockHash]; - depth = komodo_MoM(¬arisedHeight, &MoM, ¬arisationHash, blockIndex->nHeight); + depth = komodo_MoM(¬arisedHeight, &MoM, ¬arisationHash, blockIndex->nHeight,&MoMoM,&MoMoMoffset,&MoMoMdepth,&kmdstarti,&kmdendi); if (!depth) throw runtime_error("notarisation not found"); From d955963d5844126ee5844cad3dc07f5375bf8a5b Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 13 Apr 2018 19:19:31 +0300 Subject: [PATCH 330/339] Test --- src/komodo_bitcoind.h | 4 ++-- src/rpcblockchain.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index f6f097940..629b375fa 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -855,8 +855,6 @@ int32_t komodo_minerids(uint8_t *minerids,int32_t height,int32_t width) // depre int32_t komodo_is_special(uint8_t pubkeys[66][33],int32_t mids[66],int32_t height,uint8_t pubkey33[33],uint32_t timestamp) { int32_t i,notaryid=0,minerid,limit,nid; //uint8_t _pubkey33[33]; - if ( height >= 225000 ) - komodo_chosennotary(¬aryid,height,pubkey33,timestamp); if ( height >= 700000 ) { if ( mids[0] >= 0 ) @@ -878,6 +876,8 @@ int32_t komodo_is_special(uint8_t pubkeys[66][33],int32_t mids[66],int32_t heigh { if ( height >= 34000 && notaryid >= 0 ) { + if ( height >= 225000 ) + komodo_chosennotary(¬aryid,height,pubkey33,timestamp); if ( height < 79693 ) limit = 64; else if ( height < 82000 ) diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp index c6a3ab0ec..a2ac900d2 100644 --- a/src/rpcblockchain.cpp +++ b/src/rpcblockchain.cpp @@ -633,7 +633,7 @@ UniValue txMoMproof(const UniValue& params, bool fHelp) { uint256 hash, notarisationHash, MoM,MoMoM; int32_t notarisedHeight, depth; CBlockIndex* blockIndex; std::vector branch; - int nIndex; + int nIndex,MoMoMdepth,MoMoMoffset,kmdstarti,kmdendi; // parse params and get notarisation data for tx { From 4323ab1cfbfc0f66f513cd1977ed616a13893055 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 13 Apr 2018 19:26:23 +0300 Subject: [PATCH 331/339] Test --- src/init.cpp | 2 ++ src/main.cpp | 10 ++++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 3bacc7087..e16474c02 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -69,6 +69,7 @@ using namespace std; extern void ThreadSendAlert(); +extern int32_t KOMODO_LOADINGBLOCKS; ZCJoinSplit* pzcashParams = NULL; @@ -1421,6 +1422,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) strLoadError = _("Error initializing block database"); break; } + KOMODO_LOADINGBLOCKS = 0; // Check for changed -txindex state if (fTxIndex != GetBoolArg("-txindex", true)) { diff --git a/src/main.cpp b/src/main.cpp index 0e82ce73a..f691a3674 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4038,7 +4038,7 @@ bool CheckDiskSpace(uint64_t nAdditionalBytes) FILE* OpenDiskFile(const CDiskBlockPos &pos, const char *prefix, bool fReadOnly) { - static int32_t didinit; long fsize,fpos; int32_t incr = 16*1024*1024; + static int32_t didinit[1000]; long fsize,fpos; int32_t incr = 16*1024*1024; if (pos.IsNull()) return NULL; boost::filesystem::path path = GetBlockPosFilename(pos, prefix); @@ -4050,7 +4050,7 @@ FILE* OpenDiskFile(const CDiskBlockPos &pos, const char *prefix, bool fReadOnly) LogPrintf("Unable to open file %s\n", path.string()); return NULL; } - if ( didinit == 0 && strcmp(prefix,(char *)"blk") == 0 ) + if ( pos.nFile < sizeof(didinit)/sizeof(*didinit) && didinit[pos.nFile] == 0 && strcmp(prefix,(char *)"blk") == 0 ) { fpos = ftell(file); fseek(file,0,SEEK_END); @@ -4064,12 +4064,11 @@ FILE* OpenDiskFile(const CDiskBlockPos &pos, const char *prefix, bool fReadOnly) while ( fread(ignore,1,incr,file) == incr ) fprintf(stderr,"."); free(ignore); - fprintf(stderr,"loaded %ld bytes set fpos.%ld loading.%d\n",(long)ftell(file),(long)fpos,KOMODO_LOADINGBLOCKS); + fprintf(stderr,"blk.%d loaded %ld bytes set fpos.%ld loading.%d\n",(int)pos.nFile,(long)ftell(file),(long)fpos,KOMODO_LOADINGBLOCKS); } } fseek(file,fpos,SEEK_SET); - KOMODO_LOADINGBLOCKS = 0; - didinit = 1; + didinit[pos.nFile] = 1; } if (pos.nPos) { if (fseek(file, pos.nPos, SEEK_SET)) { @@ -4521,7 +4520,6 @@ bool LoadBlockIndex() KOMODO_LOADINGBLOCKS = 0; return false; } - KOMODO_LOADINGBLOCKS = 0; fprintf(stderr,"finished loading blocks %s\n",ASSETCHAINS_SYMBOL); return true; } From 54f7311d4ee5c4207d7ce65ed4a006d395696bfc Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 13 Apr 2018 22:41:35 +0300 Subject: [PATCH 332/339] -cache --- src/init.cpp | 2 + src/komodo_bitcoind.h | 199 +++++++++++++++++++++--------------------- src/pow.cpp | 33 +++---- 3 files changed, 114 insertions(+), 120 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index e16474c02..7268c362c 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -626,6 +626,7 @@ void ThreadImport(std::vector vImportFiles) LogPrintf("Reindexing finished\n"); // To avoid ending up in a situation without genesis block, re-try initializing (no-op if reindexing worked): InitBlockIndex(); + KOMODO_LOADINGBLOCKS = 0; } // hardcoded $DATADIR/bootstrap.dat @@ -1485,6 +1486,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler) } } } + KOMODO_LOADINGBLOCKS = 0; // As LoadBlockIndex can take several minutes, it's possible the user // requested to kill the GUI during the last operation. If so, exit. diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 629b375fa..ece63942e 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -659,21 +659,21 @@ int32_t komodo_block2height(CBlock *block) return(height); } -void komodo_block2pubkey33(uint8_t *pubkey33,CBlock& block) +void komodo_block2pubkey33(uint8_t *pubkey33,CBlock *block) { int32_t n; if ( KOMODO_LOADINGBLOCKS == 0 ) memset(pubkey33,0xff,33); else memset(pubkey33,0,33); - if ( block.vtx[0].vout.size() > 0 ) + if ( block->vtx[0].vout.size() > 0 ) { #ifdef KOMODO_ZCASH - uint8_t *ptr = (uint8_t *)block.vtx[0].vout[0].scriptPubKey.data(); + uint8_t *ptr = (uint8_t *)block->vtx[0].vout[0].scriptPubKey.data(); #else - uint8_t *ptr = (uint8_t *)&block.vtx[0].vout[0].scriptPubKey[0]; + uint8_t *ptr = (uint8_t *)&block->vtx[0].vout[0].scriptPubKey[0]; #endif //komodo_init(0); - n = block.vtx[0].vout[0].scriptPubKey.size(); + n = block->vtx[0].vout[0].scriptPubKey.size(); if ( n == 35 ) memcpy(pubkey33,ptr+1,33); } @@ -724,111 +724,108 @@ uint32_t komodo_heightstamp(int32_t height) return(0); } -void komodo_pindex_init(CBlockIndex *pindex,int32_t height) -{ - int32_t i,num; uint8_t pubkeys[64][33]; CBlock block; - if ( pindex->didinit != 0 ) - return; - //printf("pindex.%d komodo_pindex_init notary.%d from height.%d\n",pindex->nHeight,pindex->notaryid,height); - if ( pindex->didinit == 0 ) - { - pindex->notaryid = -1; - if ( KOMODO_LOADINGBLOCKS == 0 ) - memset(pindex->pubkey33,0xff,33); - else memset(pindex->pubkey33,0,33); - if ( komodo_blockload(block,pindex) == 0 ) - { - komodo_block2pubkey33(pindex->pubkey33,block); - //for (i=0; i<33; i++) - // fprintf(stderr,"%02x",pindex->pubkey33[i]); - //fprintf(stderr," set pubkey at height %d/%d\n",pindex->nHeight,height); - pindex->didinit = (KOMODO_LOADINGBLOCKS == 0); - } // else fprintf(stderr,"error loading block at %d/%d",pindex->nHeight,height); - } - if ( pindex->didinit != 0 && pindex->nHeight >= 0 && (num= komodo_notaries(pubkeys,(int32_t)pindex->nHeight,(uint32_t)pindex->nTime)) > 0 ) - { - for (i=0; ipubkey33,33) == 0 ) - { - pindex->notaryid = i; - break; - } - } - if ( 0 && i == num ) - { - for (i=0; i<33; i++) - fprintf(stderr,"%02x",pindex->pubkey33[i]); - fprintf(stderr," unmatched pubkey at height %d/%d\n",pindex->nHeight,height); - } - } -} +/*void komodo_pindex_init(CBlockIndex *pindex,int32_t height) gets data corrupted + { + int32_t i,num; uint8_t pubkeys[64][33]; CBlock block; + if ( pindex->didinit != 0 ) + return; + //printf("pindex.%d komodo_pindex_init notary.%d from height.%d\n",pindex->nHeight,pindex->notaryid,height); + if ( pindex->didinit == 0 ) + { + pindex->notaryid = -1; + if ( KOMODO_LOADINGBLOCKS == 0 ) + memset(pindex->pubkey33,0xff,33); + else memset(pindex->pubkey33,0,33); + if ( komodo_blockload(block,pindex) == 0 ) + { + komodo_block2pubkey33(pindex->pubkey33,&block); + //for (i=0; i<33; i++) + // fprintf(stderr,"%02x",pindex->pubkey33[i]); + //fprintf(stderr," set pubkey at height %d/%d\n",pindex->nHeight,height); + //if ( pindex->pubkey33[0] == 2 || pindex->pubkey33[0] == 3 ) + // pindex->didinit = (KOMODO_LOADINGBLOCKS == 0); + } // else fprintf(stderr,"error loading block at %d/%d",pindex->nHeight,height); + } + if ( pindex->didinit != 0 && pindex->nHeight >= 0 && (num= komodo_notaries(pubkeys,(int32_t)pindex->nHeight,(uint32_t)pindex->nTime)) > 0 ) + { + for (i=0; ipubkey33,33) == 0 ) + { + pindex->notaryid = i; + break; + } + } + if ( 0 && i == num ) + { + for (i=0; i<33; i++) + fprintf(stderr,"%02x",pindex->pubkey33[i]); + fprintf(stderr," unmatched pubkey at height %d/%d\n",pindex->nHeight,height); + } + } + }*/ void komodo_index2pubkey33(uint8_t *pubkey33,CBlockIndex *pindex,int32_t height) { - CBlock block; int32_t num,i; + int32_t num,i; CBlock block; memset(pubkey33,0,33); if ( pindex != 0 ) { - if ( pindex->didinit != 0 ) - { - memcpy(pubkey33,pindex->pubkey33,33); - return; - } - komodo_pindex_init(pindex,height); - memcpy(pubkey33,pindex->pubkey33,33); + if ( komodo_blockload(block,pindex) == 0 ) + komodo_block2pubkey33(pubkey33,&block); } } -int8_t komodo_minerid(int32_t height,uint8_t *pubkey33) -{ - int32_t num,i,numnotaries; CBlockIndex *pindex; uint32_t timestamp=0; uint8_t _pubkey33[33],pubkeys[64][33]; - if ( (pindex= chainActive[height]) != 0 ) - { - if ( pindex->didinit != 0 ) - { - if ( pubkey33 != 0 ) - memcpy(pubkey33,pindex->pubkey33,33); - return(pindex->notaryid); - } - if ( pubkey33 != 0 ) - komodo_index2pubkey33(pubkey33,pindex,height); - timestamp = pindex->GetBlockTime(); - if ( (num= komodo_notaries(pubkeys,height,timestamp)) > 0 ) - { - for (i=0; ididinit != 0 ) + { + if ( destpubkey33 != 0 ) + memcpy(destpubkey33,pindex->pubkey33,33); + return(pindex->notaryid); + } + komodo_index2pubkey33(pubkey33,pindex,height); + if ( destpubkey33 != 0 ) + memcpy(destpubkey33,pindex->pubkey33,33); + if ( pindex->didinit != 0 ) + return(pindex->notaryid); + timestamp = pindex->GetBlockTime(); + if ( (num= komodo_notaries(pubkeys,height,timestamp)) > 0 ) + { + for (i=0; inotaryid >= 0 && pindex->didinit != 0 ) + if ( komodo_blockload(block,pindex) == 0 ) { - memcpy(pubkeys[i],pindex->pubkey33,33); - mids[i] = pindex->notaryid; - (*nonzpkeysp)++; - } - else - { - komodo_pindex_init(pindex,height-i); - //komodo_index2pubkey33(pubkey33,pindex,height-i); - memcpy(pubkeys[i],pindex->pubkey33,33); - if ( (mids[i]= komodo_minerid(height-i,pubkey33)) >= 0 ) + komodo_block2pubkey33(pubkeys[i],&block); + for (j=0; j= 0 && i > 0 && mids[i] == mids[0] ) duplicate++; } @@ -854,17 +851,20 @@ int32_t komodo_minerids(uint8_t *minerids,int32_t height,int32_t width) // depre int32_t komodo_is_special(uint8_t pubkeys[66][33],int32_t mids[66],int32_t height,uint8_t pubkey33[33],uint32_t timestamp) { - int32_t i,notaryid=0,minerid,limit,nid; //uint8_t _pubkey33[33]; - if ( height >= 700000 ) + int32_t i,j,notaryid=0,minerid,limit,nid; uint8_t destpubkey33[33]; + komodo_chosennotary(¬aryid,height,pubkey33,timestamp); + if ( height >= 82000 ) { - if ( mids[0] >= 0 ) + if ( notaryid >= 0 ) { for (i=1; i<66; i++) { - if ( mids[i] == mids[0] ) + if ( mids[i] == notaryid ) { - fprintf(stderr,"ht.%d repeat notaryid.%d in mids[%d]\n",height,mids[0],i); - if ( height > 790000 ) + for (j=0; j<66; j++) + fprintf(stderr,"%d ",mids[j]); + fprintf(stderr,"ht.%d repeat notaryid.%d in mids[%d]\n",height,notaryid,i); + if ( height > 792000 ) return(-1); else break; } @@ -876,8 +876,6 @@ int32_t komodo_is_special(uint8_t pubkeys[66][33],int32_t mids[66],int32_t heigh { if ( height >= 34000 && notaryid >= 0 ) { - if ( height >= 225000 ) - komodo_chosennotary(¬aryid,height,pubkey33,timestamp); if ( height < 79693 ) limit = 64; else if ( height < 82000 ) @@ -888,8 +886,9 @@ int32_t komodo_is_special(uint8_t pubkeys[66][33],int32_t mids[66],int32_t heigh komodo_chosennotary(&nid,height-i,pubkey33,timestamp); if ( nid == notaryid ) { - if ( (0) && notaryid > 0 ) - fprintf(stderr,"ht.%d notaryid.%d already mined -i.%d nid.%d\n",height,notaryid,i,nid); + //for (j=0; j<66; j++) + // fprintf(stderr,"%d ",mids[j]); + //fprintf(stderr,"ht.%d repeat mids[%d] nid.%d notaryid.%d\n",height-i,i,nid,notaryid); if ( height > 225000 ) return(-1); } diff --git a/src/pow.cpp b/src/pow.cpp index 15c5c8732..009297242 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -116,7 +116,6 @@ bool CheckEquihashSolution(const CBlockHeader *pblock, const CChainParams& param return true; } -void komodo_pindex_init(CBlockIndex *pindex,int32_t height); int32_t komodo_chosennotary(int32_t *notaryidp,int32_t height,uint8_t *pubkey33,uint32_t timestamp); int32_t komodo_is_special(uint8_t pubkeys[66][33],int32_t mids[66],int32_t height,uint8_t pubkey33[33],uint32_t timestamp); int32_t komodo_currentheight(); @@ -128,15 +127,16 @@ extern char ASSETCHAINS_SYMBOL[]; #define KOMODO_ELECTION_GAP 2000 int32_t komodo_eligiblenotary(uint8_t pubkeys[66][33],int32_t *mids,int32_t *nonzpkeysp,int32_t height); -int32_t KOMODO_LOADINGBLOCKS; +int32_t KOMODO_LOADINGBLOCKS = 1; extern std::string NOTARY_PUBKEY; bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned int nBits, const Consensus::Params& params) { extern int32_t KOMODO_REWIND; - bool fNegative,fOverflow; int32_t i,nonzpkeys=0,nonz=0,special=0,special2=0,notaryid=-1,flag = 0, mids[66]; uint32_t timestamp = 0; CBlockIndex *pindex; + bool fNegative,fOverflow; uint8_t origpubkey33[33]; int32_t i,nonzpkeys=0,nonz=0,special=0,special2=0,notaryid=-1,flag = 0, mids[66]; uint32_t timestamp = 0; CBlockIndex *pindex=0; arith_uint256 bnTarget; uint8_t pubkeys[66][33]; + memcpy(origpubkey33,pubkey33,33); timestamp = komodo_chainactive_timestamp(); bnTarget.SetCompact(nBits, &fNegative, &fOverflow); if ( height == 0 ) @@ -146,13 +146,6 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned in } if ( height > 34000 && ASSETCHAINS_SYMBOL[0] == 0 ) // 0 -> non-special notary { - if ( KOMODO_LOADINGBLOCKS != 0 ) - return(true); - if ( (pindex= komodo_chainactive(height)) != 0 ) - { - komodo_pindex_init(pindex,height); - memcpy(pubkey33,pindex->pubkey33,33); - } special = komodo_chosennotary(¬aryid,height,pubkey33,timestamp); for (i=0; i<33; i++) { @@ -166,7 +159,6 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned in } flag = komodo_eligiblenotary(pubkeys,mids,&nonzpkeys,height); special2 = komodo_is_special(pubkeys,mids,height,pubkey33,timestamp); - fprintf(stderr,"ht.%d notaryid.%d special.%d flag.%d special2.%d\n",height,notaryid,special,flag,special2); if ( notaryid >= 0 ) { if ( height > 10000 && height < 80000 && (special != 0 || special2 > 0) ) @@ -177,8 +169,12 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned in flag = ((height % KOMODO_ELECTION_GAP) > 64 || (height % KOMODO_ELECTION_GAP) == 0); else if ( height == 790833 ) flag = 1; - else if ( special2 < 0 && height > 792000 ) - flag = 0; + else if ( special2 < 0 ) + { + if ( height > 792000 ) + flag = 0; + else fprintf(stderr,"ht.%d notaryid.%d special.%d flag.%d special2.%d\n",height,notaryid,special,flag,special2); + } if ( flag != 0 || special2 > 0 ) { //fprintf(stderr,"EASY MINING ht.%d\n",height); @@ -191,17 +187,14 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned in // Check proof of work matches claimed amount if ( UintToArith256(hash) > bnTarget ) { - if ( pindex != 0 ) - { - pindex->didinit = 0; - komodo_pindex_init(pindex,height); - } - return false; + if ( KOMODO_LOADINGBLOCKS != 0 ) + return true; + if ( height > 792000 ) + return false; } return true; } - arith_uint256 GetBlockProof(const CBlockIndex& block) { arith_uint256 bnTarget; From b5ca03bca7b6ba6b189aa73c54ad5980d81349be Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 13 Apr 2018 22:49:40 +0300 Subject: [PATCH 333/339] Test --- src/chain.h | 1 - src/main.cpp | 10 +++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/chain.h b/src/chain.h index 3b8bbd9bd..a28e4e44a 100644 --- a/src/chain.h +++ b/src/chain.h @@ -177,7 +177,6 @@ public: //! (memory only) Sequential id assigned to distinguish order in which blocks are received. uint32_t nSequenceId; - int8_t notaryid; uint8_t pubkey33[33],didinit; void SetNull() { diff --git a/src/main.cpp b/src/main.cpp index f691a3674..30d46eb05 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1610,7 +1610,7 @@ bool ReadBlockFromDisk(int32_t height,CBlock& block, const CDiskBlockPos& pos) return error("%s: Deserialize or I/O error - %s at %s", __func__, e.what(), pos.ToString()); } // Check the header - komodo_block2pubkey33(pubkey33,block); + komodo_block2pubkey33(pubkey33,(CBlock *)block); if (!(CheckEquihashSolution(&block, Params()) && CheckProofOfWork(height,pubkey33,block.GetHash(), block.nBits, Params().GetConsensus()))) { int32_t i; for (i=0; i<33; i++) @@ -3508,9 +3508,9 @@ bool CheckBlockHeader(int32_t height,CBlockIndex *pindex, const CBlockHeader& bl return state.DoS(100, error("CheckBlockHeader(): Equihash solution invalid"),REJECT_INVALID, "invalid-solution"); // Check proof of work matches claimed amount - komodo_index2pubkey33(pubkey33,pindex,height); + /*komodo_index2pubkey33(pubkey33,pindex,height); if ( fCheckPOW && !CheckProofOfWork(height,pubkey33,blockhdr.GetHash(), blockhdr.nBits, Params().GetConsensus()) ) - return state.DoS(50, error("CheckBlockHeader(): proof of work failed"),REJECT_INVALID, "high-hash"); + return state.DoS(50, error("CheckBlockHeader(): proof of work failed"),REJECT_INVALID, "high-hash");*/ return true; } @@ -3520,12 +3520,16 @@ bool CheckBlock(int32_t height,CBlockIndex *pindex,const CBlock& block, CValidat libzcash::ProofVerifier& verifier, bool fCheckPOW, bool fCheckMerkleRoot) { + uint8_t pubkey33[33]; // These are checks that are independent of context. // Check that the header is valid (particularly PoW). This is mostly // redundant with the call in AcceptBlockHeader. if (!CheckBlockHeader(height,pindex,block,state,fCheckPOW)) return false; + komodo_block2pubkey33(pubkey33,(CBlock *)&block); + if ( fCheckPOW && !CheckProofOfWork(height,pubkey33,block.GetHash(), block.nBits, Params().GetConsensus()) ) + return state.DoS(50, error("CheckBlock(): proof of work failed"),REJECT_INVALID, "high-hash"); // Check the merkle root. if (fCheckMerkleRoot) { From f90c9f681c687ad11993d88a280edad69aef0e41 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 13 Apr 2018 22:53:01 +0300 Subject: [PATCH 334/339] Test --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 30d46eb05..da117a6e2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1610,7 +1610,7 @@ bool ReadBlockFromDisk(int32_t height,CBlock& block, const CDiskBlockPos& pos) return error("%s: Deserialize or I/O error - %s at %s", __func__, e.what(), pos.ToString()); } // Check the header - komodo_block2pubkey33(pubkey33,(CBlock *)block); + komodo_block2pubkey33(pubkey33,(CBlock *)&block); if (!(CheckEquihashSolution(&block, Params()) && CheckProofOfWork(height,pubkey33,block.GetHash(), block.nBits, Params().GetConsensus()))) { int32_t i; for (i=0; i<33; i++) From 188c971923ce88de93585cedb10ff3f7e20e5cc4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Fri, 13 Apr 2018 23:04:29 +0300 Subject: [PATCH 335/339] New notaries --- src/komodo_notary.h | 132 ++++++++++++++++++++++---------------------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/src/komodo_notary.h b/src/komodo_notary.h index 5f534957f..d0e02999a 100644 --- a/src/komodo_notary.h +++ b/src/komodo_notary.h @@ -126,75 +126,75 @@ const char *Notaries_elected0[][2] = { "xxspot2_XX", "03d85b221ea72ebcd25373e7961f4983d12add66a92f899deaf07bab1d8b6f5573" } }; -#define KOMODO_NOTARIES_TIMESTAMP1 1530921600 // 7/7/2017 -#define KOMODO_NOTARIES_HEIGHT1 ((900000 / KOMODO_ELECTION_GAP) * KOMODO_ELECTION_GAP) +#define KOMODO_NOTARIES_TIMESTAMP1 1525132800 // May 1st 2018 1530921600 // 7/7/2017 +#define KOMODO_NOTARIES_HEIGHT1 ((820000 / KOMODO_ELECTION_GAP) * KOMODO_ELECTION_GAP) const char *Notaries_elected1[][2] = { - { "0_jl777_testA", "03b7621b44118017a16043f19b30cc8a4cfe068ac4e42417bae16ba460c80f3828" }, - { "0_jl777_testB", "02ebfc784a4ba768aad88d44d1045d240d47b26e248cafaf1c5169a42d7a61d344" }, - { "0_kolo_testA", "0287aa4b73988ba26cf6565d815786caf0d2c4af704d7883d163ee89cd9977edec" }, - { "artik_AR", "029acf1dcd9f5ff9c455f8bb717d4ae0c703e089d16cf8424619c491dff5994c90" }, - { "artik_EU", "03f54b2c24f82632e3cdebe4568ba0acf487a80f8a89779173cdb78f74514847ce" }, - { "artik_NA", "0224e31f93eff0cc30eaf0b2389fbc591085c0e122c4d11862c1729d090106c842" }, - { "artik_SH", "02bdd8840a34486f38305f311c0e2ae73e84046f6e9c3dd3571e32e58339d20937" }, - { "badass_EU", "0209d48554768dd8dada988b98aca23405057ac4b5b46838a9378b95c3e79b9b9e" }, - { "badass_NA", "02afa1a9f948e1634a29dc718d218e9d150c531cfa852843a1643a02184a63c1a7" }, - { "badass_SH", "026b49dd3923b78a592c1b475f208e23698d3f085c4c3b4906a59faf659fd9530b" }, - { "crackers_EU", "03bc819982d3c6feb801ec3b720425b017d9b6ee9a40746b84422cbbf929dc73c3" }, // 10 - { "crackers_NA", "03205049103113d48c7c7af811b4c8f194dafc43a50d5313e61a22900fc1805b45" }, - { "crackers_SH", "02be28310e6312d1dd44651fd96f6a44ccc269a321f907502aae81d246fabdb03e" }, - { "durerus_EU", "02bcbd287670bdca2c31e5d50130adb5dea1b53198f18abeec7211825f47485d57" }, - { "etszombi_AR", "031c79168d15edabf17d9ec99531ea9baa20039d0cdc14d9525863b83341b210e9" }, - { "etszombi_EU", "0281b1ad28d238a2b217e0af123ce020b79e91b9b10ad65a7917216eda6fe64bf7" }, // 15 - { "etszombi_SH", "025d7a193c0757f7437fad3431f027e7b5ed6c925b77daba52a8755d24bf682dde" }, - { "farl4web_EU", "0300ecf9121cccf14cf9423e2adb5d98ce0c4e251721fa345dec2e03abeffbab3f" }, - { "farl4web_SH", "0396bb5ed3c57aa1221d7775ae0ff751e4c7dc9be220d0917fa8bbdf670586c030" }, - { "fullmoon_AR", "0254b1d64840ce9ff6bec9dd10e33beb92af5f7cee628f999cb6bc0fea833347cc" }, - { "fullmoon_NA", "031fb362323b06e165231c887836a8faadb96eda88a79ca434e28b3520b47d235b" }, // 20 - { "fullmoon_SH", "030e12b42ec33a80e12e570b6c8274ce664565b5c3da106859e96a7208b93afd0d" }, - { "grewal_NA", "03adc0834c203d172bce814df7c7a5e13dc603105e6b0adabc942d0421aefd2132" }, - { "grewal_SH", "03212a73f5d38a675ee3cdc6e82542a96c38c3d1c79d25a1ed2e42fcf6a8be4e68" }, - { "indenodes_AR", "02ec0fa5a40f47fd4a38ea5c89e375ad0b6ddf4807c99733c9c3dc15fb978ee147" }, - { "indenodes_EU", "0221387ff95c44cb52b86552e3ec118a3c311ca65b75bf807c6c07eaeb1be8303c" }, - { "indenodes_NA", "02698c6f1c9e43b66e82dbb163e8df0e5a2f62f3a7a882ca387d82f86e0b3fa988" }, - { "indenodes_SH", "0334e6e1ec8285c4b85bd6dae67e17d67d1f20e7328efad17ce6fd24ae97cdd65e" }, - { "jeezy_EU", "023cb3e593fb85c5659688528e9a4f1c4c7f19206edc7e517d20f794ba686fd6d6" }, - { "jsgalt_NA", "027b3fb6fede798cd17c30dbfb7baf9332b3f8b1c7c513f443070874c410232446" }, - { "karasugoi_NA", "02a348b03b9c1a8eac1b56f85c402b041c9bce918833f2ea16d13452309052a982" }, // 30 - { "kashifali_EU", "033777c52a0190f261c6f66bd0e2bb299d30f012dcb8bfff384103211edb8bb207" }, - { "kolo_AR", "03016d19344c45341e023b72f9fb6e6152fdcfe105f3b4f50b82a4790ff54e9dc6" }, - { "kolo_SH", "02aa24064500756d9b0959b44d5325f2391d8e95c6127e109184937152c384e185" }, - { "metaphilibert_AR", "02adad675fae12b25fdd0f57250b0caf7f795c43f346153a31fe3e72e7db1d6ac6" }, - { "movecrypto_AR", "022783d94518e4dc77cbdf1a97915b29f427d7bc15ea867900a76665d3112be6f3" }, - { "movecrypto_EU", "021ab53bc6cf2c46b8a5456759f9d608966eff87384c2b52c0ac4cc8dd51e9cc42" }, - { "movecrypto_NA", "02efb12f4d78f44b0542d1c60146738e4d5506d27ec98a469142c5c84b29de0a80" }, - { "movecrypto_SH", "031f9739a3ebd6037a967ce1582cde66e79ea9a0551c54731c59c6b80f635bc859" }, - { "muros_AR", "022d77402fd7179335da39479c829be73428b0ef33fb360a4de6890f37c2aa005e" }, - { "noashh_AR", "029d93ef78197dc93892d2a30e5a54865f41e0ca3ab7eb8e3dcbc59c8756b6e355" }, // 40 - { "noashh_EU", "02061c6278b91fd4ac5cab4401100ffa3b2d5a277e8f71db23401cc071b3665546" }, - { "noashh_NA", "033c073366152b6b01535e15dd966a3a8039169584d06e27d92a69889b720d44e1" }, - { "nxtswe_EU", "032fb104e5eaa704a38a52c126af8f67e870d70f82977e5b2f093d5c1c21ae5899" }, - { "polycryptoblog_NA", "02708dcda7c45fb54b78469673c2587bfdd126e381654819c4c23df0e00b679622" }, - { "pondsea_AR", "032e1c213787312099158f2d74a89e8240a991d162d4ce8017d8504d1d7004f735" }, - { "pondsea_EU", "0225aa6f6f19e543180b31153d9e6d55d41bc7ec2ba191fd29f19a2f973544e29d" }, - { "pondsea_NA", "031bcfdbb62268e2ff8dfffeb9ddff7fe95fca46778c77eebff9c3829dfa1bb411" }, - { "pondsea_SH", "02209073bc0943451498de57f802650311b1f12aa6deffcd893da198a544c04f36" }, - { "popcornbag_AR", "02761f106fb34fbfc5ddcc0c0aa831ed98e462a908550b280a1f7bd32c060c6fa3" }, - { "popcornbag_NA", "03c6085c7fdfff70988fda9b197371f1caf8397f1729a844790e421ee07b3a93e8" }, // 50 - { "ptytrader_NA", "0328c61467148b207400b23875234f8a825cce65b9c4c9b664f47410b8b8e3c222" }, - { "ptytrader_SH", "0250c93c492d8d5a6b565b90c22bee07c2d8701d6118c6267e99a4efd3c7748fa4" }, - { "rnr_AR", "029bdb08f931c0e98c2c4ba4ef45c8e33a34168cb2e6bf953cef335c359d77bfcd" }, - { "rnr_EU", "03f5c08dadffa0ffcafb8dd7ffc38c22887bd02702a6c9ac3440deddcf2837692b" }, - { "rnr_NA", "02e17c5f8c3c80f584ed343b8dcfa6d710dfef0889ec1e7728ce45ce559347c58c" }, - { "rnr_SH", "037536fb9bdfed10251f71543fb42679e7c52308bcd12146b2568b9a818d8b8377" }, - { "titomane_AR", "03cda6ca5c2d02db201488a54a548dbfc10533bdc275d5ea11928e8d6ab33c2185" }, - { "titomane_EU", "02e41feded94f0cc59f55f82f3c2c005d41da024e9a805b41105207ef89aa4bfbd" }, - { "titomane_SH", "035f49d7a308dd9a209e894321f010d21b7793461b0c89d6d9231a3fe5f68d9960" }, - { "vanbreuk_EU", "024f3cad7601d2399c131fd070e797d9cd8533868685ddbe515daa53c2e26004c3" }, // 60 - { "xrobesx_NA", "03f0cc6d142d14a40937f12dbd99dbd9021328f45759e26f1877f2a838876709e1" }, - { "xxspot1_XX", "02ef445a392fcaf3ad4176a5da7f43580e8056594e003eba6559a713711a27f955" }, - { "xxspot2_XX", "03d85b221ea72ebcd25373e7961f4983d12add66a92f899deaf07bab1d8b6f5573" } + {"0dev1_jl777", "03b7621b44118017a16043f19b30cc8a4cfe068ac4e42417bae16ba460c80f3828" }, + {"0dev2_kolo", "030f34af4b908fb8eb2099accb56b8d157d49f6cfb691baa80fdd34f385efed961" }, + {"0dev3_kolo", "025af9d2b2a05338478159e9ac84543968fd18c45fd9307866b56f33898653b014" }, + {"0dev4_decker", "028eea44a09674dda00d88ffd199a09c9b75ba9782382cc8f1e97c0fd565fe5707" }, + {"a-team_SH", "03b59ad322b17cb94080dc8e6dc10a0a865de6d47c16fb5b1a0b5f77f9507f3cce" }, + {"artik_AR", "029acf1dcd9f5ff9c455f8bb717d4ae0c703e089d16cf8424619c491dff5994c90" }, + {"artik_EU", "03f54b2c24f82632e3cdebe4568ba0acf487a80f8a89779173cdb78f74514847ce" }, + {"artik_NA", "0224e31f93eff0cc30eaf0b2389fbc591085c0e122c4d11862c1729d090106c842" }, + {"artik_SH", "02bdd8840a34486f38305f311c0e2ae73e84046f6e9c3dd3571e32e58339d20937" }, + {"badass_EU", "0209d48554768dd8dada988b98aca23405057ac4b5b46838a9378b95c3e79b9b9e" }, + {"badass_NA", "02afa1a9f948e1634a29dc718d218e9d150c531cfa852843a1643a02184a63c1a7" }, + {"batman_AR", "033ecb640ec5852f42be24c3bf33ca123fb32ced134bed6aa2ba249cf31b0f2563" }, + {"batman_SH", "02ca5898931181d0b8aafc75ef56fce9c43656c0b6c9f64306e7c8542f6207018c" }, + {"ca333_EU", "03fc87b8c804f12a6bd18efd43b0ba2828e4e38834f6b44c0bfee19f966a12ba99" }, + {"chainmakers_EU", "02f3b08938a7f8d2609d567aebc4989eeded6e2e880c058fdf092c5da82c3bc5ee" }, + {"chainmakers_NA", "0276c6d1c65abc64c8559710b8aff4b9e33787072d3dda4ec9a47b30da0725f57a" }, + {"chainstrike_SH", "0370bcf10575d8fb0291afad7bf3a76929734f888228bc49e35c5c49b336002153" }, + {"cipi_AR", "02c4f89a5b382750836cb787880d30e23502265054e1c327a5bfce67116d757ce8" }, + {"cipi_NA", "02858904a2a1a0b44df4c937b65ee1f5b66186ab87a751858cf270dee1d5031f18" }, + {"crackers_EU", "03bc819982d3c6feb801ec3b720425b017d9b6ee9a40746b84422cbbf929dc73c3" }, + {"crackers_NA", "03205049103113d48c7c7af811b4c8f194dafc43a50d5313e61a22900fc1805b45" }, + {"dwy_EU", "0259c646288580221fdf0e92dbeecaee214504fdc8bbdf4a3019d6ec18b7540424" }, + {"emmanux_SH", "033f316114d950497fc1d9348f03770cd420f14f662ab2db6172df44c389a2667a" }, + {"etszombi_EU", "0281b1ad28d238a2b217e0af123ce020b79e91b9b10ad65a7917216eda6fe64bf7" }, + {"fullmoon_AR", "03380314c4f42fa854df8c471618751879f9e8f0ff5dbabda2bd77d0f96cb35676" }, + {"fullmoon_NA", "030216211d8e2a48bae9e5d7eb3a42ca2b7aae8770979a791f883869aea2fa6eef" }, + {"fullmoon_SH", "03f34282fa57ecc7aba8afaf66c30099b5601e98dcbfd0d8a58c86c20d8b692c64" }, + {"goldenman_EU", "02d6f13a8f745921cdb811e32237bb98950af1a5952be7b3d429abd9152f8e388d" }, + {"indenodes_AR", "02ec0fa5a40f47fd4a38ea5c89e375ad0b6ddf4807c99733c9c3dc15fb978ee147" }, + {"indenodes_EU", "0221387ff95c44cb52b86552e3ec118a3c311ca65b75bf807c6c07eaeb1be8303c" }, + {"indenodes_NA", "02698c6f1c9e43b66e82dbb163e8df0e5a2f62f3a7a882ca387d82f86e0b3fa988" }, + {"indenodes_SH", "0334e6e1ec8285c4b85bd6dae67e17d67d1f20e7328efad17ce6fd24ae97cdd65e" }, + {"jackson_AR", "038ff7cfe34cb13b524e0941d5cf710beca2ffb7e05ddf15ced7d4f14fbb0a6f69" }, + {"jeezy_EU", "023cb3e593fb85c5659688528e9a4f1c4c7f19206edc7e517d20f794ba686fd6d6" }, + {"karasugoi_NA", "02a348b03b9c1a8eac1b56f85c402b041c9bce918833f2ea16d13452309052a982" }, + {"komodoninja_EU", "038e567b99806b200b267b27bbca2abf6a3e8576406df5f872e3b38d30843cd5ba" }, + {"komodoninja_SH", "033178586896915e8456ebf407b1915351a617f46984001790f0cce3d6f3ada5c2" }, + {"komodopioneers_SH", "033ace50aedf8df70035b962a805431363a61cc4e69d99d90726a2d48fb195f68c" }, + {"libscott_SH", "03301a8248d41bc5dc926088a8cf31b65e2daf49eed7eb26af4fb03aae19682b95" }, + {"lukechilds_AR", "031aa66313ee024bbee8c17915cf7d105656d0ace5b4a43a3ab5eae1e14ec02696" }, + {"madmax_AR", "03891555b4a4393d655bf76f0ad0fb74e5159a615b6925907678edc2aac5e06a75" }, + {"meshbits_AR", "02957fd48ae6cb361b8a28cdb1b8ccf5067ff68eb1f90cba7df5f7934ed8eb4b2c" }, + {"meshbits_SH", "025c6e94877515dfd7b05682b9cc2fe4a49e076efe291e54fcec3add78183c1edb" }, + {"metaphilibert_AR", "02adad675fae12b25fdd0f57250b0caf7f795c43f346153a31fe3e72e7db1d6ac6" }, + {"metaphilibert_SH", "0284af1a5ef01503e6316a2ca4abf8423a794e9fc17ac6846f042b6f4adedc3309" }, + {"patchkez_SH", "0296270f394140640f8fa15684fc11255371abb6b9f253416ea2734e34607799c4" }, + {"pbca26_NA", "0276aca53a058556c485bbb60bdc54b600efe402a8b97f0341a7c04803ce204cb5" }, + {"peer2cloud_AR", "034e5563cb885999ae1530bd66fab728e580016629e8377579493b386bf6cebb15" }, + {"peer2cloud_SH", "03396ac453b3f23e20f30d4793c5b8ab6ded6993242df4f09fd91eb9a4f8aede84" }, + {"polycryptoblog_NA", "02708dcda7c45fb54b78469673c2587bfdd126e381654819c4c23df0e00b679622" }, + {"hyper_AR", "020f2f984d522051bd5247b61b080b4374a7ab389d959408313e8062acad3266b4" }, + {"hyper_EU", "03d00cf9ceace209c59fb013e112a786ad583d7de5ca45b1e0df3b4023bb14bf51" }, + {"hyper_SH", "0383d0b37f59f4ee5e3e98a47e461c861d49d0d90c80e9e16f7e63686a2dc071f3" }, + {"hyper_NA", "03d91c43230336c0d4b769c9c940145a8c53168bf62e34d1bccd7f6cfc7e5592de" }, + {"popcornbag_AR", "02761f106fb34fbfc5ddcc0c0aa831ed98e462a908550b280a1f7bd32c060c6fa3" }, + {"popcornbag_NA", "03c6085c7fdfff70988fda9b197371f1caf8397f1729a844790e421ee07b3a93e8" }, + {"alien_AR", "0348d9b1fc6acf81290405580f525ee49b4749ed4637b51a28b18caa26543b20f0" }, + {"alien_EU", "020aab8308d4df375a846a9e3b1c7e99597b90497efa021d50bcf1bbba23246527" }, + {"thegaltmines_NA", "031bea28bec98b6380958a493a703ddc3353d7b05eb452109a773eefd15a32e421" }, + {"titomane_AR", "029d19215440d8cb9cc6c6b7a4744ae7fb9fb18d986e371b06aeb34b64845f9325" }, + {"titomane_EU", "0360b4805d885ff596f94312eed3e4e17cb56aa8077c6dd78d905f8de89da9499f" }, + {"titomane_SH", "03573713c5b20c1e682a2e8c0f8437625b3530f278e705af9b6614de29277a435b" }, + {"webworker01_NA", "03bb7d005e052779b1586f071834c5facbb83470094cff5112f0072b64989f97d7" }, + {"xrobesx_NA", "03f0cc6d142d14a40937f12dbd99dbd9021328f45759e26f1877f2a838876709e1" }, }; int32_t komodo_notaries(uint8_t pubkeys[64][33],int32_t height,uint32_t timestamp) From 56aa66a0db2718b63fbd7ad51ba63d72dffc3bd5 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 14 Apr 2018 00:20:47 +0300 Subject: [PATCH 336/339] Test --- src/pow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pow.cpp b/src/pow.cpp index 009297242..b7b945353 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -189,7 +189,7 @@ bool CheckProofOfWork(int32_t height,uint8_t *pubkey33,uint256 hash, unsigned in { if ( KOMODO_LOADINGBLOCKS != 0 ) return true; - if ( height > 792000 ) + if ( ASSETCHAINS_SYMBOL[0] != 0 || height > 792000 ) return false; } return true; From 2689bd1275e04f48191125ea588e7226bb5b174f Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 14 Apr 2018 00:26:03 +0300 Subject: [PATCH 337/339] -print --- src/komodo_bitcoind.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index ece63942e..4d513ca90 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -861,9 +861,9 @@ int32_t komodo_is_special(uint8_t pubkeys[66][33],int32_t mids[66],int32_t heigh { if ( mids[i] == notaryid ) { - for (j=0; j<66; j++) - fprintf(stderr,"%d ",mids[j]); - fprintf(stderr,"ht.%d repeat notaryid.%d in mids[%d]\n",height,notaryid,i); + //for (j=0; j<66; j++) + // fprintf(stderr,"%d ",mids[j]); + //fprintf(stderr,"ht.%d repeat notaryid.%d in mids[%d]\n",height,notaryid,i); if ( height > 792000 ) return(-1); else break; From a20f07e7d17f6d4000358a3b580a495b02193fdf Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 14 Apr 2018 15:19:14 +0300 Subject: [PATCH 338/339] Fix buffer overflows and reduce KMD men usage --- src/komodo_events.h | 94 ++++++++++++++++++++++++--------------------- 1 file changed, 51 insertions(+), 43 deletions(-) diff --git a/src/komodo_events.h b/src/komodo_events.h index 4d9ff87dc..b301f8a25 100644 --- a/src/komodo_events.h +++ b/src/komodo_events.h @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright © 2014-2017 The SuperNET Developers. * + * Copyright © 2014-2018 The SuperNET Developers. * * * * See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at * * the top-level directory of this distribution for the individual copyright * @@ -20,7 +20,7 @@ struct komodo_event *komodo_eventadd(struct komodo_state *sp,int32_t height,char *symbol,uint8_t type,uint8_t *data,uint16_t datalen) { struct komodo_event *ep=0; uint16_t len = (uint16_t)(sizeof(*ep) + datalen); - if ( sp != 0 ) + if ( sp != 0 && ASSETCHAINS_SYMBOL[0] != 0 ) { portable_mutex_lock(&komodo_mutex); ep = (struct komodo_event *)calloc(1,len); @@ -55,7 +55,7 @@ void komodo_eventadd_notarized(struct komodo_state *sp,char *symbol,int32_t heig N.notarizedheight = notarizedheight; N.MoM = MoM; N.MoMdepth = MoMdepth; - strcpy(N.dest,dest); + strncpy(N.dest,dest,sizeof(N.dest)-1); komodo_eventadd(sp,height,symbol,KOMODO_EVENT_NOTARIZED,(uint8_t *)&N,sizeof(N)); if ( sp != 0 ) komodo_notarized_update(sp,height,notarizedheight,notarized_hash,notarized_desttxid,MoM,MoMdepth); @@ -77,27 +77,34 @@ void komodo_eventadd_pubkeys(struct komodo_state *sp,char *symbol,int32_t height void komodo_eventadd_pricefeed(struct komodo_state *sp,char *symbol,int32_t height,uint32_t *prices,uint8_t num) { struct komodo_event_pricefeed F; - memset(&F,0,sizeof(F)); - F.num = num; - memcpy(F.prices,prices,sizeof(*F.prices) * num); - komodo_eventadd(sp,height,symbol,KOMODO_EVENT_PRICEFEED,(uint8_t *)&F,(int32_t)(sizeof(F.num) + sizeof(*F.prices) * num)); - if ( sp != 0 ) - komodo_pvals(height,prices,num); + if ( num == sizeof(F.prices)/sizeof(*F.prices) ) + { + memset(&F,0,sizeof(F)); + F.num = num; + memcpy(F.prices,prices,sizeof(*F.prices) * num); + komodo_eventadd(sp,height,symbol,KOMODO_EVENT_PRICEFEED,(uint8_t *)&F,(int32_t)(sizeof(F.num) + sizeof(*F.prices) * num)); + if ( sp != 0 ) + komodo_pvals(height,prices,num); + } else fprintf(stderr,"skip pricefeed[%d]\n",num); } void komodo_eventadd_opreturn(struct komodo_state *sp,char *symbol,int32_t height,uint256 txid,uint64_t value,uint16_t vout,uint8_t *buf,uint16_t opretlen) { - struct komodo_event_opreturn O; uint8_t opret[16384]; - memset(&O,0,sizeof(O)); - O.txid = txid; - O.value = value; - O.vout = vout; - memcpy(opret,&O,sizeof(O)); - memcpy(&opret[sizeof(O)],buf,opretlen); - O.oplen = (int32_t)(opretlen + sizeof(O)); - komodo_eventadd(sp,height,symbol,KOMODO_EVENT_OPRETURN,opret,O.oplen); - if ( sp != 0 ) - komodo_opreturn(height,value,buf,opretlen,txid,vout,symbol); + struct komodo_event_opreturn O; uint8_t *opret; + if ( ASSETCHAINS_SYMBOL[0] != 0 ) + { + opret = (uint8_t *)calloc(1,sizeof(O) + opretlen + 16); + O.txid = txid; + O.value = value; + O.vout = vout; + memcpy(opret,&O,sizeof(O)); + memcpy(&opret[sizeof(O)],buf,opretlen); + O.oplen = (int32_t)(opretlen + sizeof(O)); + komodo_eventadd(sp,height,symbol,KOMODO_EVENT_OPRETURN,opret,O.oplen); + free(opret); + if ( sp != 0 ) + komodo_opreturn(height,value,buf,opretlen,txid,vout,symbol); + } } void komodo_event_undo(struct komodo_state *sp,struct komodo_event *ep) @@ -171,6 +178,7 @@ void komodo_eventadd_kmdheight(struct komodo_state *sp,char *symbol,int32_t heig } else { + //fprintf(stderr,"REWIND kmdheight.%d\n",kmdheight); kmdheight = -kmdheight; komodo_eventadd(sp,height,symbol,KOMODO_EVENT_REWIND,(uint8_t *)&height,sizeof(height)); if ( sp != 0 ) @@ -180,30 +188,30 @@ void komodo_eventadd_kmdheight(struct komodo_state *sp,char *symbol,int32_t heig /*void komodo_eventadd_deposit(int32_t actionflag,char *symbol,int32_t height,uint64_t komodoshis,char *fiat,uint64_t fiatoshis,uint8_t rmd160[20],bits256 kmdtxid,uint16_t kmdvout,uint64_t price) -{ - uint8_t opret[512]; uint16_t opretlen; - komodo_eventadd_opreturn(symbol,height,KOMODO_OPRETURN_DEPOSIT,kmdtxid,komodoshis,kmdvout,opret,opretlen); -} - -void komodo_eventadd_issued(int32_t actionflag,char *symbol,int32_t height,int32_t fiatheight,bits256 fiattxid,uint16_t fiatvout,bits256 kmdtxid,uint16_t kmdvout,uint64_t fiatoshis) -{ - uint8_t opret[512]; uint16_t opretlen; - komodo_eventadd_opreturn(symbol,height,KOMODO_OPRETURN_ISSUED,fiattxid,fiatoshis,fiatvout,opret,opretlen); -} - -void komodo_eventadd_withdraw(int32_t actionflag,char *symbol,int32_t height,uint64_t komodoshis,char *fiat,uint64_t fiatoshis,uint8_t rmd160[20],bits256 fiattxid,int32_t fiatvout,uint64_t price) -{ - uint8_t opret[512]; uint16_t opretlen; - komodo_eventadd_opreturn(symbol,height,KOMODO_OPRETURN_WITHDRAW,fiattxid,fiatoshis,fiatvout,opret,opretlen); -} - -void komodo_eventadd_redeemed(int32_t actionflag,char *symbol,int32_t height,bits256 kmdtxid,uint16_t kmdvout,int32_t fiatheight,bits256 fiattxid,uint16_t fiatvout,uint64_t komodoshis) -{ - uint8_t opret[512]; uint16_t opretlen; - komodo_eventadd_opreturn(symbol,height,KOMODO_OPRETURN_REDEEMED,kmdtxid,komodoshis,kmdvout,opret,opretlen); -}*/ + { + uint8_t opret[512]; uint16_t opretlen; + komodo_eventadd_opreturn(symbol,height,KOMODO_OPRETURN_DEPOSIT,kmdtxid,komodoshis,kmdvout,opret,opretlen); + } + + void komodo_eventadd_issued(int32_t actionflag,char *symbol,int32_t height,int32_t fiatheight,bits256 fiattxid,uint16_t fiatvout,bits256 kmdtxid,uint16_t kmdvout,uint64_t fiatoshis) + { + uint8_t opret[512]; uint16_t opretlen; + komodo_eventadd_opreturn(symbol,height,KOMODO_OPRETURN_ISSUED,fiattxid,fiatoshis,fiatvout,opret,opretlen); + } + + void komodo_eventadd_withdraw(int32_t actionflag,char *symbol,int32_t height,uint64_t komodoshis,char *fiat,uint64_t fiatoshis,uint8_t rmd160[20],bits256 fiattxid,int32_t fiatvout,uint64_t price) + { + uint8_t opret[512]; uint16_t opretlen; + komodo_eventadd_opreturn(symbol,height,KOMODO_OPRETURN_WITHDRAW,fiattxid,fiatoshis,fiatvout,opret,opretlen); + } + + void komodo_eventadd_redeemed(int32_t actionflag,char *symbol,int32_t height,bits256 kmdtxid,uint16_t kmdvout,int32_t fiatheight,bits256 fiattxid,uint16_t fiatvout,uint64_t komodoshis) + { + uint8_t opret[512]; uint16_t opretlen; + komodo_eventadd_opreturn(symbol,height,KOMODO_OPRETURN_REDEEMED,kmdtxid,komodoshis,kmdvout,opret,opretlen); + }*/ // process events -// +// #endif From 862285c784153a6b7ce6a328416361aec6fdad69 Mon Sep 17 00:00:00 2001 From: jl777 Date: Sat, 14 Apr 2018 15:27:25 +0300 Subject: [PATCH 339/339] -print --- src/komodo_events.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/komodo_events.h b/src/komodo_events.h index b301f8a25..c64ccbaa2 100644 --- a/src/komodo_events.h +++ b/src/komodo_events.h @@ -85,7 +85,7 @@ void komodo_eventadd_pricefeed(struct komodo_state *sp,char *symbol,int32_t heig komodo_eventadd(sp,height,symbol,KOMODO_EVENT_PRICEFEED,(uint8_t *)&F,(int32_t)(sizeof(F.num) + sizeof(*F.prices) * num)); if ( sp != 0 ) komodo_pvals(height,prices,num); - } else fprintf(stderr,"skip pricefeed[%d]\n",num); + } //else fprintf(stderr,"skip pricefeed[%d]\n",num); } void komodo_eventadd_opreturn(struct komodo_state *sp,char *symbol,int32_t height,uint256 txid,uint64_t value,uint16_t vout,uint8_t *buf,uint16_t opretlen)